ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_nick.c
Revision: 3178
Committed: Wed Mar 19 18:27:44 2014 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 26851 byte(s)
Log Message:
- Get rid of kill_client_serv_butone()

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2014 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22 /*! \file m_nick.c
23 * \brief Includes required functions for processing the NICK command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "hash.h"
31 #include "fdlist.h"
32 #include "irc_string.h"
33 #include "ircd.h"
34 #include "numeric.h"
35 #include "conf.h"
36 #include "s_user.h"
37 #include "whowas.h"
38 #include "s_serv.h"
39 #include "send.h"
40 #include "channel.h"
41 #include "channel_mode.h"
42 #include "log.h"
43 #include "resv.h"
44 #include "parse.h"
45 #include "modules.h"
46 #include "packet.h"
47 #include "watch.h"
48 #include "s_misc.h"
49
50
51 /* check_clean_nick()
52 *
53 * input - pointer to source
54 * -
55 * - nickname
56 * - truncated nickname
57 * - origin of client
58 * - pointer to server nick is coming from
59 * output - none
60 * side effects - if nickname is erroneous, or a different length to
61 * truncated nickname, return 1
62 */
63 static int
64 check_clean_nick(struct Client *source_p, char *nick, struct Client *server_p)
65 {
66 /* the old code did some wacky stuff here, if the nick is invalid, kill it
67 * and dont bother messing at all
68 */
69 if (!valid_nickname(nick, 0))
70 {
71 ++ServerStats.is_kill;
72 sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE,
73 "Bad/long Nick: %s From: %s(via %s)",
74 nick, server_p->name, source_p->from->name);
75
76 sendto_one(source_p, ":%s KILL %s :%s (Bad Nickname)",
77 me.name, nick, me.name);
78
79 /* bad nick change */
80 if (!MyConnect(source_p))
81 {
82 sendto_server(source_p, NOCAPS, NOCAPS, ":%s KILL %s :%s (Bad Nickname)",
83 me.id, source_p->id, me.name);
84 AddFlag(source_p, FLAGS_KILLED);
85 exit_client(source_p, "Bad Nickname");
86 }
87
88 return 1;
89 }
90
91 return 0;
92 }
93
94 /* check_clean_user()
95 *
96 * input - pointer to client sending data
97 * - nickname
98 * - username to check
99 * - origin of NICK
100 * output - none
101 * side effects - if username is erroneous, return 1
102 */
103 static int
104 check_clean_user(struct Client *source_p, char *nick,
105 char *user, struct Client *server_p)
106 {
107 if (!valid_username(user, 0))
108 {
109 ++ServerStats.is_kill;
110 sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE,
111 "Bad/Long Username: %s Nickname: %s From: %s(via %s)",
112 user, nick, server_p->name, source_p->from->name);
113 sendto_one(source_p, ":%s KILL %s :%s (Bad Username)",
114 me.name, nick, me.name);
115 return 1;
116 }
117
118 return 0;
119 }
120
121 /* check_clean_host()
122 *
123 * input - pointer to client sending us data
124 * - nickname
125 * - hostname to check
126 * - source name
127 * output - none
128 * side effects - if hostname is erroneous, return 1
129 */
130 static int
131 check_clean_host(struct Client *source_p, char *nick,
132 char *host, struct Client *server_p)
133 {
134 if (!valid_hostname(host))
135 {
136 ++ServerStats.is_kill;
137 sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE,
138 "Bad/Long Hostname: %s Nickname: %s From: %s(via %s)",
139 host, nick, server_p->name, source_p->from->name);
140 sendto_one(source_p, ":%s KILL %s :%s (Bad Hostname)",
141 me.name, nick, me.name);
142 return 1;
143 }
144
145 return 0;
146 }
147
148 /* set_initial_nick()
149 *
150 * inputs
151 * output
152 * side effects -
153 *
154 * This function is only called to set up an initially registering
155 * client.
156 */
157 static void
158 set_initial_nick(struct Client *source_p, const char *nick)
159 {
160 /* Client setting NICK the first time */
161
162 /* This had to be copied here to avoid problems.. */
163 source_p->tsinfo = CurrentTime;
164 source_p->localClient->registration &= ~REG_NEED_NICK;
165
166 if (source_p->name[0])
167 hash_del_client(source_p);
168
169 strlcpy(source_p->name, nick, sizeof(source_p->name));
170 hash_add_client(source_p);
171
172 /* fd_desc is long enough */
173 fd_note(&source_p->localClient->fd, "Nick: %s", nick);
174
175 if (!source_p->localClient->registration)
176 register_local_user(source_p);
177 }
178
179 /* change_local_nick()
180 *
181 * inputs - pointer to server
182 * - pointer to client
183 * - nick
184 * output -
185 * side effects - changes nick of a LOCAL user
186 */
187 static void
188 change_local_nick(struct Client *source_p, const char *nick)
189 {
190 int samenick = 0;
191
192 assert(source_p->name[0] && !EmptyString(nick));
193 assert(MyConnect(source_p));
194
195 /*
196 * Client just changing his/her nick. If he/she is
197 * on a channel, send note of change to all clients
198 * on that channel. Propagate notice to other servers.
199 */
200 if ((source_p->localClient->last_nick_change +
201 ConfigFileEntry.max_nick_time) < CurrentTime)
202 source_p->localClient->number_of_nick_changes = 0;
203
204 if (ConfigFileEntry.anti_nick_flood &&
205 !HasUMode(source_p, UMODE_OPER) &&
206 source_p->localClient->number_of_nick_changes >
207 ConfigFileEntry.max_nick_changes)
208 {
209 sendto_one_numeric(source_p, &me, ERR_NICKTOOFAST, source_p->name, nick,
210 ConfigFileEntry.max_nick_time);
211 return;
212 }
213
214 source_p->localClient->last_nick_change = CurrentTime;
215 source_p->localClient->number_of_nick_changes++;
216
217 samenick = !irccmp(source_p->name, nick);
218
219 if (!samenick)
220 {
221 source_p->tsinfo = CurrentTime;
222 clear_ban_cache_client(source_p);
223 watch_check_hash(source_p, RPL_LOGOFF);
224
225 if (HasUMode(source_p, UMODE_REGISTERED))
226 {
227 unsigned int oldmodes = source_p->umodes;
228 char modebuf[IRCD_BUFSIZE] = { '\0' };
229
230 DelUMode(source_p, UMODE_REGISTERED);
231 send_umode(source_p, source_p, oldmodes, 0xffffffff, modebuf);
232 }
233 }
234
235 sendto_realops_flags(UMODE_NCHANGE, L_ALL, SEND_NOTICE,
236 "Nick change: From %s to %s [%s@%s]",
237 source_p->name, nick, source_p->username, source_p->host);
238 sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s",
239 source_p->name, source_p->username,
240 source_p->host, nick);
241 whowas_add_history(source_p, 1);
242
243 sendto_server(source_p, NOCAPS, NOCAPS, ":%s NICK %s :%lu",
244 ID(source_p), nick, (unsigned long)source_p->tsinfo);
245
246 hash_del_client(source_p);
247 strlcpy(source_p->name, nick, sizeof(source_p->name));
248 hash_add_client(source_p);
249
250 if (!samenick)
251 watch_check_hash(source_p, RPL_LOGON);
252
253 /* fd_desc is long enough */
254 fd_note(&source_p->localClient->fd, "Nick: %s", nick);
255 }
256
257 /*
258 * nick_from_server()
259 */
260 static void
261 nick_from_server(struct Client *source_p, int parc,
262 char *parv[], time_t newts, const char *svsid, char *nick, char *ngecos)
263 {
264 int samenick = 0;
265
266 if (IsServer(source_p))
267 {
268 const char *server = source_p->name;
269 /* A server introducing a new client, change source */
270 source_p = make_client(source_p->from);
271 dlinkAdd(source_p, &source_p->node, &global_client_list);
272
273 if (parc > 2)
274 source_p->hopcount = atoi(parv[2]);
275 if (newts)
276 source_p->tsinfo = newts;
277 else
278 {
279 newts = source_p->tsinfo = CurrentTime;
280 sendto_realops_flags_ratelimited("Remote nick %s (%s) introduced without a TS", nick, server);
281 }
282
283 strlcpy(source_p->svid, svsid, sizeof(source_p->svid));
284 strlcpy(source_p->info, ngecos, sizeof(source_p->info));
285 /* copy the nick in place */
286 strlcpy(source_p->name, nick, sizeof(source_p->name));
287 hash_add_client(source_p);
288
289 if (parc > 8)
290 {
291 const char *m;
292
293 /* parse usermodes */
294 for (m = &parv[4][1]; *m; ++m)
295 {
296 unsigned int flag = user_modes[(unsigned char)*m];
297
298 if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
299 ++Count.invisi;
300 if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER))
301 ++Count.oper;
302
303 source_p->umodes |= flag & SEND_UMODES;
304 }
305
306 register_remote_user(source_p, parv[5], parv[6], parv[7]);
307 return;
308 }
309 }
310 else if (source_p->name[0])
311 {
312 samenick = !irccmp(source_p->name, nick);
313
314 /* Client changing their nick */
315 if (!samenick)
316 {
317 DelUMode(source_p, UMODE_REGISTERED);
318 watch_check_hash(source_p, RPL_LOGOFF);
319 source_p->tsinfo = newts ? newts : CurrentTime;
320 }
321
322 sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s",
323 source_p->name, source_p->username,
324 source_p->host, nick);
325
326 whowas_add_history(source_p, 1);
327 sendto_server(source_p, NOCAPS, NOCAPS, ":%s NICK %s :%lu",
328 ID(source_p), nick, (unsigned long)source_p->tsinfo);
329 }
330
331 /* set the new nick name */
332 if (source_p->name[0])
333 hash_del_client(source_p);
334
335 strlcpy(source_p->name, nick, sizeof(source_p->name));
336 hash_add_client(source_p);
337
338 if (!samenick)
339 watch_check_hash(source_p, RPL_LOGON);
340 }
341
342 /*
343 * client_from_server()
344 */
345 static void
346 uid_from_server(struct Client *source_p, int parc,
347 char *parv[], time_t newts, const char *svsid, char *nick, char *ugecos)
348 {
349 const char *m = NULL;
350 const char *servername = source_p->name;
351
352 source_p = make_client(source_p->from);
353 dlinkAdd(source_p, &source_p->node, &global_client_list);
354
355 source_p->hopcount = atoi(parv[2]);
356 source_p->tsinfo = newts;
357 strlcpy(source_p->svid, svsid, sizeof(source_p->svid));
358
359 /* copy the nick in place */
360 strlcpy(source_p->name, nick, sizeof(source_p->name));
361 strlcpy(source_p->id, parv[8], sizeof(source_p->id));
362 strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
363 strlcpy(source_p->info, ugecos, sizeof(source_p->info));
364
365 hash_add_client(source_p);
366 hash_add_id(source_p);
367
368 /* parse usermodes */
369 for (m = &parv[4][1]; *m; ++m)
370 {
371 unsigned int flag = user_modes[(unsigned char)*m];
372
373 if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
374 ++Count.invisi;
375 if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER))
376 ++Count.oper;
377
378 source_p->umodes |= flag & SEND_UMODES;
379 }
380
381 register_remote_user(source_p, parv[5], parv[6], servername);
382 }
383
384 static void
385 perform_nick_collides(struct Client *source_p,
386 struct Client *target_p, int parc, char *parv[],
387 time_t newts, const char *svsid, char *nick, char *gecos, char *uid)
388 {
389 int sameuser = 0;
390
391 /* Server introducing new nick */
392 if (IsServer(source_p))
393 {
394 /* If we don't have a TS, or their TS's are the same, kill both */
395 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
396 {
397 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
398 "Nick collision on %s(%s <- %s)(both killed)",
399 target_p->name, target_p->from->name,
400 source_p->from->name);
401
402 /* if we have a UID, issue a kill for it */
403 if (uid)
404 sendto_one(source_p, ":%s KILL %s :%s (Nick collision (new))",
405 me.id, uid, me.name);
406
407 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick collision (new))",
408 me.id, target_p->id, me.name);
409
410 ++ServerStats.is_kill;
411 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
412
413 AddFlag(target_p, FLAGS_KILLED);
414 exit_client(target_p, "Nick collision (new)");
415 return;
416 }
417 /* the timestamps are different */
418 else
419 {
420 sameuser = !irccmp(target_p->username, parv[5]) &&
421 !irccmp(target_p->host, parv[6]);
422
423 /*
424 * If the users are the same (loaded a client on a different server)
425 * and the new users ts is older, or the users are different and the
426 * new users ts is newer, ignore the new client and let it do the kill
427 */
428 if ((sameuser && newts < target_p->tsinfo) ||
429 (!sameuser && newts > target_p->tsinfo))
430 {
431 if (uid)
432 sendto_one(source_p, ":%s KILL %s :%s (Nick collision (new))",
433 me.id, uid, me.name);
434 return;
435 }
436 else
437 {
438 if (sameuser)
439 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
440 "Nick collision on %s(%s <- %s)(older killed)",
441 target_p->name, target_p->from->name,
442 source_p->from->name);
443 else
444 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
445 "Nick collision on %s(%s <- %s)(newer killed)",
446 target_p->name, target_p->from->name,
447 source_p->from->name);
448
449 ++ServerStats.is_kill;
450 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
451
452 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick collision (new))",
453 me.id, target_p->id, me.name);
454
455 AddFlag(target_p, FLAGS_KILLED);
456 exit_client(target_p, "Nick collision");
457
458 if (!uid && (parc == 9 || parc == 10))
459 nick_from_server(source_p, parc, parv, newts, svsid, nick, gecos);
460 else if (uid && (parc == 10 || parc == 11))
461 uid_from_server(source_p, parc, parv, newts, svsid, nick, gecos);
462 return;
463 }
464 }
465 }
466
467 /* its a client changing nick and causing a collide */
468 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
469 {
470 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
471 "Nick change collision from %s to %s(%s <- %s)(both killed)",
472 source_p->name, target_p->name, target_p->from->name,
473 source_p->from->name);
474
475 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
476 ++ServerStats.is_kill;
477
478
479 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick change collision)",
480 me.id, source_p->id, me.name);
481
482 ++ServerStats.is_kill;
483
484 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick change collision)",
485 me.id, target_p->id, me.name);
486
487 AddFlag(target_p, FLAGS_KILLED);
488 exit_client(target_p, "Nick collision (new)");
489
490 AddFlag(source_p, FLAGS_KILLED);
491 exit_client(source_p, "Nick collision (old)");
492 return;
493 }
494 else
495 {
496 sameuser = !irccmp(target_p->username, source_p->username) &&
497 !irccmp(target_p->host, source_p->host);
498
499 if ((sameuser && newts < target_p->tsinfo) ||
500 (!sameuser && newts > target_p->tsinfo))
501 {
502 if (sameuser)
503 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
504 "Nick change collision from %s to %s(%s <- %s)(older killed)",
505 source_p->name, target_p->name, target_p->from->name,
506 source_p->from->name);
507 else
508 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
509 "Nick change collision from %s to %s(%s <- %s)(newer killed)",
510 source_p->name, target_p->name, target_p->from->name,
511 source_p->from->name);
512
513 ++ServerStats.is_kill;
514
515 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick change collision)",
516 me.id, source_p->id, me.name);
517 AddFlag(source_p, FLAGS_KILLED);
518
519 if (sameuser)
520 exit_client(source_p, "Nick collision (old)");
521 else
522 exit_client(source_p, "Nick collision (new)");
523 return;
524 }
525 else
526 {
527 if (sameuser)
528 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
529 "Nick collision on %s(%s <- %s)(older killed)",
530 target_p->name, target_p->from->name,
531 source_p->from->name);
532 else
533 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
534 "Nick collision on %s(%s <- %s)(newer killed)",
535 target_p->name, target_p->from->name,
536 source_p->from->name);
537
538 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick collision)",
539 me.id, target_p->id, me.name);
540
541 ++ServerStats.is_kill;
542 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
543
544 AddFlag(target_p, FLAGS_KILLED);
545 exit_client(target_p, "Nick collision");
546 }
547 }
548
549 /*
550 * we should only ever call nick_from_server() here, as
551 * this is a client changing nick, not a new client
552 */
553 nick_from_server(source_p, parc, parv, newts, svsid, nick, gecos);
554 }
555
556 /*! \brief NICK command handler (called by unregistered,
557 * locally connected clients)
558 *
559 * \param source_p Pointer to allocated Client struct from which the message
560 * originally comes from. This can be a local or remote client.
561 * \param parc Integer holding the number of supplied arguments.
562 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
563 * pointers.
564 * \note Valid arguments for this command are:
565 * - parv[0] = command
566 * - parv[1] = nickname
567 */
568 static int
569 mr_nick(struct Client *source_p, int parc, char *parv[])
570 {
571 char nick[NICKLEN + 1] = { '\0' };
572 struct Client *target_p = NULL;
573 struct MaskItem *conf = NULL;
574
575 if (parc < 2 || EmptyString(parv[1]))
576 {
577 sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN);
578 return 0;
579 }
580
581 /* Copy the nick and terminate it */
582 strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ServerInfo.max_nick_length + 1));
583
584 /* Check the nickname is ok */
585 if (!valid_nickname(nick, 1))
586 {
587 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, parv[1], "Erroneous Nickname");
588 return 0;
589 }
590
591 /* Check if the nick is resv'd */
592 if ((conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0)))
593 {
594 ++conf->count;
595 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, conf->reason);
596 sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
597 "Forbidding reserved nick %s from user %s",
598 nick, get_client_name(source_p, HIDE_IP));
599 return 0;
600 }
601
602 if ((target_p = hash_find_client(nick)) == NULL)
603 set_initial_nick(source_p, nick);
604 else if (source_p == target_p)
605 strlcpy(source_p->name, nick, sizeof(source_p->name));
606 else
607 sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, nick);
608
609 return 0;
610 }
611
612 /*! \brief NICK command handler (called by already registered,
613 * locally connected clients)
614 *
615 * \param source_p Pointer to allocated Client struct from which the message
616 * originally comes from. This can be a local or remote client.
617 * \param parc Integer holding the number of supplied arguments.
618 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
619 * pointers.
620 * \note Valid arguments for this command are:
621 * - parv[0] = command
622 * - parv[1] = nickname
623 */
624 static int
625 m_nick(struct Client *source_p, int parc, char *parv[])
626 {
627 char nick[NICKLEN + 1] = { '\0' };
628 struct Client *target_p = NULL;
629 struct MaskItem *conf = NULL;
630
631 assert(MyClient(source_p));
632
633 if (parc < 2 || EmptyString(parv[1]))
634 {
635 sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN);
636 return 0;
637 }
638
639 /* mark end of grace period, to prevent nickflooding */
640 if (!IsFloodDone(source_p))
641 flood_endgrace(source_p);
642
643 /* terminate nick to NICKLEN */
644 strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ServerInfo.max_nick_length + 1));
645
646 /* check the nickname is ok */
647 if (!valid_nickname(nick, 1))
648 {
649 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, "Erroneous Nickname");
650 return 0;
651 }
652
653 if (!IsExemptResv(source_p) &&
654 !(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv) &&
655 (conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0)))
656 {
657 ++conf->count;
658 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, conf->reason);
659 sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
660 "Forbidding reserved nick %s from user %s",
661 nick, get_client_name(source_p, HIDE_IP));
662 return 0;
663 }
664
665 if ((target_p = hash_find_client(nick)) == NULL)
666 change_local_nick(source_p, nick);
667 else if (target_p == source_p)
668 {
669 /*
670 * If (target_p == source_p) the client is changing nicks between
671 * equivalent nicknames ie: [nick] -> {nick}
672 */
673
674 /* Check the nick isn't exactly the same */
675 if (strcmp(target_p->name, nick))
676 change_local_nick(source_p, nick);
677 }
678 else if (IsUnknown(target_p))
679 {
680 /*
681 * If the client that has the nick isn't registered yet (nick but no
682 * user) then drop the unregged client
683 */
684 exit_client(target_p, "Overridden");
685 change_local_nick(source_p, nick);
686 }
687 else
688 sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, nick);
689
690 return 0;
691 }
692
693 /*! \brief NICK command handler (called by servers and remotely
694 * connected clients)
695 *
696 * \param source_p Pointer to allocated Client struct from which the message
697 * originally comes from. This can be a local or remote client.
698 * \param parc Integer holding the number of supplied arguments.
699 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
700 * pointers.
701 * \note Valid arguments for this command are:
702 *
703 * server -> server nick change
704 * - parv[0] = command
705 * - parv[1] = nickname
706 * - parv[2] = TS when nick change
707 *
708 */
709 static int
710 ms_nick(struct Client *source_p, int parc, char *parv[])
711 {
712 struct Client *target_p = NULL;
713 time_t newts = 0;
714
715 if (parc < 3 || EmptyString(parv[parc - 1]))
716 return 0;
717
718 if (IsServer(source_p))
719 /* Servers can't change nicks.. */
720 return 0;
721
722 if (check_clean_nick(source_p, parv[1], source_p->servptr))
723 return 0;
724
725 newts = atol(parv[2]);
726
727 /* If the nick doesnt exist, allow it and process like normal */
728 if ((target_p = hash_find_client(parv[1])) == NULL)
729 nick_from_server(source_p, parc, parv, newts, NULL, parv[1], parv[parc-1]);
730 else if (IsUnknown(target_p))
731 {
732 /* We're not living in the past anymore, an unknown client is local only. */
733 exit_client(target_p, "Overridden");
734 nick_from_server(source_p, parc, parv, newts, NULL, parv[1], parv[parc-1]);
735 }
736 else if (target_p == source_p)
737 {
738 if (strcmp(target_p->name, parv[1]))
739 nick_from_server(source_p, parc, parv, newts, NULL, parv[1], parv[parc-1]);
740 }
741 else
742 perform_nick_collides(source_p, target_p, parc, parv,
743 newts, NULL, parv[1], parv[parc-1], NULL);
744 return 0;
745 }
746
747 /*! \brief UID command handler (called by servers)
748 *
749 * \param source_p Pointer to allocated Client struct from which the message
750 * originally comes from. This can be a local or remote client.
751 * \param parc Integer holding the number of supplied arguments.
752 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
753 * pointers.
754 * \note Valid arguments for this command are:
755 *
756 * server introducing new nick (without services support)
757 * - parv[0] = command
758 * - parv[1] = nickname
759 * - parv[2] = hop count
760 * - parv[3] = TS
761 * - parv[4] = umode
762 * - parv[5] = username
763 * - parv[6] = hostname
764 * - parv[7] = ip
765 * - parv[8] = uid
766 * - parv[9] = ircname (gecos)
767 *
768 * server introducing new nick (with services support)
769 * - parv[ 0] = command
770 * - parv[ 1] = nickname
771 * - parv[ 2] = hop count
772 * - parv[ 3] = TS
773 * - parv[ 4] = umode
774 * - parv[ 5] = username
775 * - parv[ 6] = hostname
776 * - parv[ 7] = ip
777 * - parv[ 8] = uid
778 * - parv[ 9] = services id (timestamp)
779 * - parv[10] = ircname (gecos)
780 */
781 static int
782 ms_uid(struct Client *source_p, int parc, char *parv[])
783 {
784 struct Client *target_p = NULL;
785 time_t newts = 0;
786 const char *svsid = "0";
787
788 if (parc < 10 || EmptyString(parv[parc-1]))
789 return 0;
790
791 if (check_clean_nick(source_p, parv[1], source_p) ||
792 check_clean_user(source_p, parv[1], parv[5], source_p) ||
793 check_clean_host(source_p, parv[1], parv[6], source_p))
794 return 0;
795
796 newts = atol(parv[3]);
797 svsid = parc == 11 ? parv[9] : "0";
798
799 /*
800 * If there is an ID collision, kill our client, and kill theirs.
801 * This may generate 401's, but it ensures that both clients always
802 * go, even if the other server refuses to do the right thing.
803 */
804 if ((target_p = hash_find_id(parv[8])) != NULL)
805 {
806 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
807 "ID collision on %s(%s <- %s)(both killed)",
808 target_p->name, target_p->from->name,
809 source_p->from->name);
810
811 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (ID collision)",
812 me.id, target_p->id, me.name);
813
814 ++ServerStats.is_kill;
815 AddFlag(target_p, FLAGS_KILLED);
816 exit_client(target_p, "ID Collision");
817 return 0;
818 }
819
820 if ((target_p = hash_find_client(parv[1])) == NULL)
821 uid_from_server(source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
822 else if (IsUnknown(target_p))
823 {
824 exit_client(target_p, "Overridden");
825 uid_from_server(source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
826 }
827 else
828 perform_nick_collides(source_p, target_p, parc, parv, newts, svsid, parv[1],
829 parv[parc-1], parv[8]);
830 return 0;
831 }
832
833 static struct Message nick_msgtab =
834 {
835 "NICK", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
836 { mr_nick, m_nick, ms_nick, m_ignore, m_nick, m_ignore }
837 };
838
839 static struct Message uid_msgtab =
840 {
841 "UID", 0, 0, 10, MAXPARA, MFLG_SLOW, 0,
842 { m_ignore, m_ignore, ms_uid, m_ignore, m_ignore, m_ignore }
843 };
844
845 static void
846 module_init(void)
847 {
848 mod_add_cmd(&uid_msgtab);
849 mod_add_cmd(&nick_msgtab);
850 }
851
852 static void
853 module_exit(void)
854 {
855 mod_del_cmd(&uid_msgtab);
856 mod_del_cmd(&nick_msgtab);
857 }
858
859 struct module module_entry =
860 {
861 .node = { NULL, NULL, NULL },
862 .name = NULL,
863 .version = "$Revision$",
864 .handle = NULL,
865 .modinit = module_init,
866 .modexit = module_exit,
867 .flags = MODULE_FLAG_CORE
868 };

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision