/[svn]/ircd-hybrid/branches/8.0.x/modules/core/m_nick.c
ViewVC logotype

Contents of /ircd-hybrid/branches/8.0.x/modules/core/m_nick.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1685 - (show annotations)
Wed Dec 19 20:24:52 2012 UTC (7 years, 7 months ago) by michael
File MIME type: text/x-chdr
File size: 31083 byte(s)
- STATS q|Q now shows how many times a resv{} block has been matched.
  (Just like STATS x|X)

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

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28