ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_nick.c
Revision: 3175
Committed: Tue Mar 18 19:48:30 2014 UTC (10 years, 1 month ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_nick.c
File size: 26686 byte(s)
Log Message:
- m_nick.c:perform_nick_collides(): incorporate Adam's "Send kills due to nick collisions back to the source."
  changes. Original commit message:

  Send kills due to nick collisions back to the source.

  This fixes a race condition with users changing hosts and then nick
  colliding which causes servers to disagree on whether or not the
  colliding users are the same user.

  With this patch if this happens both users are killed instead, even if
  their timestamps differ.

  The proper way to fix this is to compare a 'real host', which we do not
  store, or IP.

  With TS5 and prior we could not do this because the KILLs would be
  targeting nicks and not UIDs, which would not work as both sides would
  always lose, but we can do this now as the other side can safely drop
  the KILL for a nonexistant UID if the servers do agree.

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

Properties

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