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: 3109
Committed: Thu Mar 6 19:25:12 2014 UTC (10 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_nick.c
File size: 29569 byte(s)
Log Message:
- Applied Adam's sendto_one_numeric() changes

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

Properties

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