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: 3156
Committed: Fri Mar 14 19:57:38 2014 UTC (10 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_nick.c
File size: 26917 byte(s)
Log Message:
- Removed client_p pointers from everywhere

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, &me, "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, &me, "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 /* if it came from a LL server, itd have been source_p,
453 * so we dont need to mark target_p as known
454 */
455 kill_client_serv_butone(source_p, target_p,
456 "%s (Nick collision (new))", me.name);
457
458 AddFlag(target_p, FLAGS_KILLED);
459 exit_client(target_p, &me, "Nick collision");
460
461 if (!uid && (parc == 9 || parc == 10))
462 nick_from_server(source_p, parc, parv, newts, svsid, nick, gecos);
463 else if (uid && (parc == 10 || parc == 11))
464 uid_from_server(source_p, parc, parv, newts, svsid, nick, gecos);
465 return;
466 }
467 }
468 }
469
470 /* its a client changing nick and causing a collide */
471 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
472 {
473 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
474 "Nick change collision from %s to %s(%s <- %s)(both killed)",
475 source_p->name, target_p->name, target_p->from->name,
476 source_p->from->name);
477
478 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
479 ++ServerStats.is_kill;
480
481 kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)",
482 me.name);
483
484 ++ServerStats.is_kill;
485 kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)",
486 me.name);
487
488 AddFlag(target_p, FLAGS_KILLED);
489 exit_client(target_p, &me, "Nick collision (new)");
490
491 AddFlag(source_p, FLAGS_KILLED);
492 exit_client(source_p, &me, "Nick collision (old)");
493 return;
494 }
495 else
496 {
497 sameuser = !irccmp(target_p->username, source_p->username) &&
498 !irccmp(target_p->host, source_p->host);
499
500 if ((sameuser && newts < target_p->tsinfo) ||
501 (!sameuser && newts > target_p->tsinfo))
502 {
503 if (sameuser)
504 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
505 "Nick change collision from %s to %s(%s <- %s)(older killed)",
506 source_p->name, target_p->name, target_p->from->name,
507 source_p->from->name);
508 else
509 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
510 "Nick change collision from %s to %s(%s <- %s)(newer killed)",
511 source_p->name, target_p->name, target_p->from->name,
512 source_p->from->name);
513
514 ++ServerStats.is_kill;
515 kill_client_serv_butone(source_p, source_p,
516 "%s (Nick change collision)", me.name);
517 AddFlag(source_p, FLAGS_KILLED);
518
519 if (sameuser)
520 exit_client(source_p, &me, "Nick collision (old)");
521 else
522 exit_client(source_p, &me, "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 kill_client_serv_butone(source_p, target_p,
539 "%s (Nick collision)", 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, &me, "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, &me, "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, &me, "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 kill_client_serv_butone(NULL, target_p, "%s (ID collision)",
811 me.name);
812
813 ++ServerStats.is_kill;
814 AddFlag(target_p, FLAGS_KILLED);
815 exit_client(target_p, &me, "ID Collision");
816 return 0;
817 }
818
819 if ((target_p = hash_find_client(parv[1])) == NULL)
820 uid_from_server(source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
821 else if (IsUnknown(target_p))
822 {
823 exit_client(target_p, &me, "Overridden");
824 uid_from_server(source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
825 }
826 else
827 perform_nick_collides(source_p, target_p, parc, parv, newts, svsid, parv[1],
828 parv[parc-1], parv[8]);
829 return 0;
830 }
831
832 static struct Message nick_msgtab =
833 {
834 "NICK", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
835 { mr_nick, m_nick, ms_nick, m_ignore, m_nick, m_ignore }
836 };
837
838 static struct Message uid_msgtab =
839 {
840 "UID", 0, 0, 10, MAXPARA, MFLG_SLOW, 0,
841 { m_ignore, m_ignore, ms_uid, m_ignore, m_ignore, m_ignore }
842 };
843
844 static void
845 module_init(void)
846 {
847 mod_add_cmd(&uid_msgtab);
848 mod_add_cmd(&nick_msgtab);
849 }
850
851 static void
852 module_exit(void)
853 {
854 mod_del_cmd(&uid_msgtab);
855 mod_del_cmd(&nick_msgtab);
856 }
857
858 struct module module_entry =
859 {
860 .node = { NULL, NULL, NULL },
861 .name = NULL,
862 .version = "$Revision$",
863 .handle = NULL,
864 .modinit = module_init,
865 .modexit = module_exit,
866 .flags = MODULE_FLAG_CORE
867 };

Properties

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