ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_nick.c
Revision: 3300
Committed: Sat Apr 12 18:26:22 2014 UTC (10 years ago) by michael
Content type: text/x-csrc
File size: 26708 byte(s)
Log Message:
- doxygen

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 source_p->id, 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 /* parse usermodes */
292 for (const char *m = &parv[4][1]; *m; ++m)
293 {
294 unsigned int flag = user_modes[(unsigned char)*m];
295
296 if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
297 ++Count.invisi;
298 if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER))
299 ++Count.oper;
300
301 source_p->umodes |= flag & SEND_UMODES;
302 }
303
304 register_remote_user(source_p, parv[5], parv[6], parv[7]);
305 return;
306 }
307 }
308 else if (source_p->name[0])
309 {
310 samenick = !irccmp(source_p->name, nick);
311
312 /* Client changing their nick */
313 if (!samenick)
314 {
315 DelUMode(source_p, UMODE_REGISTERED);
316 watch_check_hash(source_p, RPL_LOGOFF);
317 source_p->tsinfo = newts ? newts : CurrentTime;
318 }
319
320 sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s",
321 source_p->name, source_p->username,
322 source_p->host, nick);
323
324 whowas_add_history(source_p, 1);
325 sendto_server(source_p, NOCAPS, NOCAPS, ":%s NICK %s :%lu",
326 source_p->id, nick, (unsigned long)source_p->tsinfo);
327 }
328
329 /* set the new nick name */
330 if (source_p->name[0])
331 hash_del_client(source_p);
332
333 strlcpy(source_p->name, nick, sizeof(source_p->name));
334 hash_add_client(source_p);
335
336 if (!samenick)
337 watch_check_hash(source_p, RPL_LOGON);
338 }
339
340 /*
341 * client_from_server()
342 */
343 static void
344 uid_from_server(struct Client *source_p, int parc,
345 char *parv[], time_t newts, const char *svsid, char *nick, char *ugecos)
346 {
347 const char *servername = source_p->name;
348
349 source_p = make_client(source_p->from);
350 dlinkAdd(source_p, &source_p->node, &global_client_list);
351
352 source_p->hopcount = atoi(parv[2]);
353 source_p->tsinfo = newts;
354 strlcpy(source_p->svid, svsid, sizeof(source_p->svid));
355
356 /* copy the nick in place */
357 strlcpy(source_p->name, nick, sizeof(source_p->name));
358 strlcpy(source_p->id, parv[8], sizeof(source_p->id));
359 strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
360 strlcpy(source_p->info, ugecos, sizeof(source_p->info));
361
362 hash_add_client(source_p);
363 hash_add_id(source_p);
364
365 /* parse usermodes */
366 for (const char *m = &parv[4][1]; *m; ++m)
367 {
368 unsigned int flag = user_modes[(unsigned char)*m];
369
370 if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
371 ++Count.invisi;
372 if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER))
373 ++Count.oper;
374
375 source_p->umodes |= flag & SEND_UMODES;
376 }
377
378 register_remote_user(source_p, parv[5], parv[6], servername);
379 }
380
381 static void
382 perform_nick_collides(struct Client *source_p,
383 struct Client *target_p, int parc, char *parv[],
384 time_t newts, const char *svsid, char *nick, char *gecos, char *uid)
385 {
386 int sameuser = 0;
387
388 /* Server introducing new nick */
389 if (IsServer(source_p))
390 {
391 /* If we don't have a TS, or their TS's are the same, kill both */
392 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
393 {
394 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
395 "Nick collision on %s(%s <- %s)(both killed)",
396 target_p->name, target_p->from->name,
397 source_p->from->name);
398
399 /* if we have a UID, issue a kill for it */
400 if (uid)
401 sendto_one(source_p, ":%s KILL %s :%s (Nick collision (new))",
402 me.id, uid, me.name);
403
404 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick collision (new))",
405 me.id, target_p->id, me.name);
406
407 ++ServerStats.is_kill;
408 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
409
410 AddFlag(target_p, FLAGS_KILLED);
411 exit_client(target_p, "Nick collision (new)");
412 return;
413 }
414 /* the timestamps are different */
415 else
416 {
417 sameuser = !irccmp(target_p->username, parv[5]) &&
418 !irccmp(target_p->host, parv[6]);
419
420 /*
421 * If the users are the same (loaded a client on a different server)
422 * and the new users ts is older, or the users are different and the
423 * new users ts is newer, ignore the new client and let it do the kill
424 */
425 if ((sameuser && newts < target_p->tsinfo) ||
426 (!sameuser && newts > target_p->tsinfo))
427 {
428 if (uid)
429 sendto_one(source_p, ":%s KILL %s :%s (Nick collision (new))",
430 me.id, uid, me.name);
431 return;
432 }
433 else
434 {
435 if (sameuser)
436 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
437 "Nick collision on %s(%s <- %s)(older killed)",
438 target_p->name, target_p->from->name,
439 source_p->from->name);
440 else
441 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
442 "Nick collision on %s(%s <- %s)(newer killed)",
443 target_p->name, target_p->from->name,
444 source_p->from->name);
445
446 ++ServerStats.is_kill;
447 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
448
449 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick collision (new))",
450 me.id, target_p->id, me.name);
451
452 AddFlag(target_p, FLAGS_KILLED);
453 exit_client(target_p, "Nick collision");
454
455 if (!uid && (parc == 9 || parc == 10))
456 nick_from_server(source_p, parc, parv, newts, svsid, nick, gecos);
457 else if (uid && (parc == 10 || parc == 11))
458 uid_from_server(source_p, parc, parv, newts, svsid, nick, gecos);
459 return;
460 }
461 }
462 }
463
464 /* its a client changing nick and causing a collide */
465 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
466 {
467 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
468 "Nick change collision from %s to %s(%s <- %s)(both killed)",
469 source_p->name, target_p->name, target_p->from->name,
470 source_p->from->name);
471
472 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
473 ++ServerStats.is_kill;
474
475
476 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick change collision)",
477 me.id, source_p->id, me.name);
478
479 ++ServerStats.is_kill;
480
481 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick change collision)",
482 me.id, target_p->id, me.name);
483
484 AddFlag(target_p, FLAGS_KILLED);
485 exit_client(target_p, "Nick collision (new)");
486
487 AddFlag(source_p, FLAGS_KILLED);
488 exit_client(source_p, "Nick collision (old)");
489 return;
490 }
491 else
492 {
493 sameuser = !irccmp(target_p->username, source_p->username) &&
494 !irccmp(target_p->host, source_p->host);
495
496 if ((sameuser && newts < target_p->tsinfo) ||
497 (!sameuser && newts > target_p->tsinfo))
498 {
499 if (sameuser)
500 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
501 "Nick change collision from %s to %s(%s <- %s)(older killed)",
502 source_p->name, target_p->name, target_p->from->name,
503 source_p->from->name);
504 else
505 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
506 "Nick change collision from %s to %s(%s <- %s)(newer killed)",
507 source_p->name, target_p->name, target_p->from->name,
508 source_p->from->name);
509
510 ++ServerStats.is_kill;
511
512 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick change collision)",
513 me.id, source_p->id, 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 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (Nick collision)",
536 me.id, target_p->id, me.name);
537
538 ++ServerStats.is_kill;
539 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
540
541 AddFlag(target_p, FLAGS_KILLED);
542 exit_client(target_p, "Nick collision");
543 }
544 }
545
546 /*
547 * we should only ever call nick_from_server() here, as
548 * this is a client changing nick, not a new client
549 */
550 nick_from_server(source_p, parc, parv, newts, svsid, nick, gecos);
551 }
552
553 /*! \brief NICK command handler
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
609 *
610 * \param source_p Pointer to allocated Client struct from which the message
611 * originally comes from. This can be a local or remote client.
612 * \param parc Integer holding the number of supplied arguments.
613 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
614 * pointers.
615 * \note Valid arguments for this command are:
616 * - parv[0] = command
617 * - parv[1] = nickname
618 */
619 static int
620 m_nick(struct Client *source_p, int parc, char *parv[])
621 {
622 char nick[NICKLEN + 1] = { '\0' };
623 struct Client *target_p = NULL;
624 struct MaskItem *conf = NULL;
625
626 assert(MyClient(source_p));
627
628 if (parc < 2 || EmptyString(parv[1]))
629 {
630 sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN);
631 return 0;
632 }
633
634 /* mark end of grace period, to prevent nickflooding */
635 if (!IsFloodDone(source_p))
636 flood_endgrace(source_p);
637
638 /* terminate nick to NICKLEN */
639 strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ServerInfo.max_nick_length + 1));
640
641 /* check the nickname is ok */
642 if (!valid_nickname(nick, 1))
643 {
644 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, "Erroneous Nickname");
645 return 0;
646 }
647
648 if (!IsExemptResv(source_p) &&
649 !(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv) &&
650 (conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0)))
651 {
652 ++conf->count;
653 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, conf->reason);
654 sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
655 "Forbidding reserved nick %s from user %s",
656 nick, get_client_name(source_p, HIDE_IP));
657 return 0;
658 }
659
660 if ((target_p = hash_find_client(nick)) == NULL)
661 change_local_nick(source_p, nick);
662 else if (target_p == source_p)
663 {
664 /*
665 * If (target_p == source_p) the client is changing nicks between
666 * equivalent nicknames ie: [nick] -> {nick}
667 */
668
669 /* Check the nick isn't exactly the same */
670 if (strcmp(target_p->name, nick))
671 change_local_nick(source_p, nick);
672 }
673 else if (IsUnknown(target_p))
674 {
675 /*
676 * If the client that has the nick isn't registered yet (nick but no
677 * user) then drop the unregged client
678 */
679 exit_client(target_p, "Overridden");
680 change_local_nick(source_p, nick);
681 }
682 else
683 sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, nick);
684
685 return 0;
686 }
687
688 /*! \brief NICK command handler
689 *
690 * \param source_p Pointer to allocated Client struct from which the message
691 * originally comes from. This can be a local or remote client.
692 * \param parc Integer holding the number of supplied arguments.
693 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
694 * pointers.
695 * \note Valid arguments for this command are:
696 *
697 * server -> server nick change
698 * - parv[0] = command
699 * - parv[1] = nickname
700 * - parv[2] = TS when nick change
701 */
702 static int
703 ms_nick(struct Client *source_p, int parc, char *parv[])
704 {
705 struct Client *target_p = NULL;
706 time_t newts = 0;
707
708 if (parc < 3 || EmptyString(parv[parc - 1]))
709 return 0;
710
711 if (IsServer(source_p))
712 /* Servers can't change nicks.. */
713 return 0;
714
715 if (check_clean_nick(source_p, parv[1], source_p->servptr))
716 return 0;
717
718 newts = atol(parv[2]);
719
720 /* If the nick doesnt exist, allow it and process like normal */
721 if ((target_p = hash_find_client(parv[1])) == NULL)
722 nick_from_server(source_p, parc, parv, newts, NULL, parv[1], parv[parc-1]);
723 else if (IsUnknown(target_p))
724 {
725 /* We're not living in the past anymore, an unknown client is local only. */
726 exit_client(target_p, "Overridden");
727 nick_from_server(source_p, parc, parv, newts, NULL, parv[1], parv[parc-1]);
728 }
729 else if (target_p == source_p)
730 {
731 if (strcmp(target_p->name, parv[1]))
732 nick_from_server(source_p, parc, parv, newts, NULL, parv[1], parv[parc-1]);
733 }
734 else
735 perform_nick_collides(source_p, target_p, parc, parv,
736 newts, NULL, parv[1], parv[parc-1], NULL);
737 return 0;
738 }
739
740 /*! \brief UID command handler
741 *
742 * \param source_p Pointer to allocated Client struct from which the message
743 * originally comes from. This can be a local or remote client.
744 * \param parc Integer holding the number of supplied arguments.
745 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
746 * pointers.
747 * \note Valid arguments for this command are:
748 *
749 * server introducing new nick (without services support)
750 * - parv[0] = command
751 * - parv[1] = nickname
752 * - parv[2] = hop count
753 * - parv[3] = TS
754 * - parv[4] = umode
755 * - parv[5] = username
756 * - parv[6] = hostname
757 * - parv[7] = ip
758 * - parv[8] = uid
759 * - parv[9] = ircname (gecos)
760 *
761 * server introducing new nick (with services support)
762 * - parv[ 0] = command
763 * - parv[ 1] = nickname
764 * - parv[ 2] = hop count
765 * - parv[ 3] = TS
766 * - parv[ 4] = umode
767 * - parv[ 5] = username
768 * - parv[ 6] = hostname
769 * - parv[ 7] = ip
770 * - parv[ 8] = uid
771 * - parv[ 9] = services id (timestamp)
772 * - parv[10] = ircname (gecos)
773 */
774 static int
775 ms_uid(struct Client *source_p, int parc, char *parv[])
776 {
777 struct Client *target_p = NULL;
778 time_t newts = 0;
779 const char *svsid = "0";
780
781 if (parc < 10 || EmptyString(parv[parc-1]))
782 return 0;
783
784 if (check_clean_nick(source_p, parv[1], source_p) ||
785 check_clean_user(source_p, parv[1], parv[5], source_p) ||
786 check_clean_host(source_p, parv[1], parv[6], source_p))
787 return 0;
788
789 newts = atol(parv[3]);
790 svsid = parc == 11 ? parv[9] : "0";
791
792 /*
793 * If there is an ID collision, kill our client, and kill theirs.
794 * This may generate 401's, but it ensures that both clients always
795 * go, even if the other server refuses to do the right thing.
796 */
797 if ((target_p = hash_find_id(parv[8])) != NULL)
798 {
799 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
800 "ID collision on %s(%s <- %s)(both killed)",
801 target_p->name, target_p->from->name,
802 source_p->from->name);
803
804 sendto_server(NULL, NOCAPS, NOCAPS, ":%s KILL %s :%s (ID collision)",
805 me.id, target_p->id, me.name);
806
807 ++ServerStats.is_kill;
808 AddFlag(target_p, FLAGS_KILLED);
809 exit_client(target_p, "ID Collision");
810 return 0;
811 }
812
813 if ((target_p = hash_find_client(parv[1])) == NULL)
814 uid_from_server(source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
815 else if (IsUnknown(target_p))
816 {
817 exit_client(target_p, "Overridden");
818 uid_from_server(source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
819 }
820 else
821 perform_nick_collides(source_p, target_p, parc, parv, newts, svsid, parv[1],
822 parv[parc-1], parv[8]);
823 return 0;
824 }
825
826 static struct Message nick_msgtab =
827 {
828 "NICK", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
829 { mr_nick, m_nick, ms_nick, m_ignore, m_nick, m_ignore }
830 };
831
832 static struct Message uid_msgtab =
833 {
834 "UID", 0, 0, 10, MAXPARA, MFLG_SLOW, 0,
835 { m_ignore, m_ignore, ms_uid, m_ignore, m_ignore, m_ignore }
836 };
837
838 static void
839 module_init(void)
840 {
841 mod_add_cmd(&uid_msgtab);
842 mod_add_cmd(&nick_msgtab);
843 }
844
845 static void
846 module_exit(void)
847 {
848 mod_del_cmd(&uid_msgtab);
849 mod_del_cmd(&nick_msgtab);
850 }
851
852 struct module module_entry =
853 {
854 .node = { NULL, NULL, NULL },
855 .name = NULL,
856 .version = "$Revision$",
857 .handle = NULL,
858 .modinit = module_init,
859 .modexit = module_exit,
860 .flags = MODULE_FLAG_CORE
861 };

Properties

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