ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.1.x/modules/core/m_nick.c
Revision: 1243
Committed: Fri Sep 30 10:47:53 2011 UTC (12 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/core/m_nick.c
File size: 30354 byte(s)
Log Message:
- move content of msg.h, ircd_handler.h and handlers.h into parse.h and
  remove headers accordingly
- killed common.h
- remove m_killhost.c and m_flags.c from contrib/
- sort out unused header includes here and there

File Contents

# Content
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 "s_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 "s_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, time_t, char *, char *);
50 static void uid_from_server(struct Client *, struct Client *, int, char **,
51 time_t, time_t, 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, time_t, 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, NULL, CAP_TS6, NOCAPS,
156 ":%s NICK %s :%lu",
157 ID(source_p), nick, (unsigned long)source_p->tsinfo);
158 sendto_server(source_p, NULL, 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 char nick[NICKLEN];
198 char *s = NULL;
199
200 if (parc < 2 || EmptyString(parv[1]))
201 {
202 sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name,
203 source_p->name[0] ? source_p->name : "*");
204 return;
205 }
206
207 /* Terminate the nick at the first ~ */
208 if ((s = strchr(parv[1], '~')) != NULL)
209 *s = '\0';
210
211 /* copy the nick and terminate it */
212 strlcpy(nick, parv[1], sizeof(nick));
213
214 /* check the nickname is ok */
215 if (!valid_nickname(nick, 1))
216 {
217 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name,
218 source_p->name[0] ? source_p->name : "*", parv[1]);
219 return;
220 }
221
222 /* check if the nick is resv'd */
223 if (find_matching_name_conf(NRESV_TYPE, nick, NULL, NULL, 0) &&
224 !IsExemptResv(source_p))
225 {
226 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name,
227 source_p->name[0] ? source_p->name : "*", nick);
228 return;
229 }
230
231 if ((target_p = hash_find_client(nick)) == NULL)
232 set_initial_nick(source_p, nick);
233 else if (source_p == target_p)
234 strlcpy(source_p->name, nick, sizeof(source_p->name));
235 else
236 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
237 }
238
239
240 /*! \brief NICK command handler (called by already registered,
241 * locally connected clients)
242 *
243 * \param client_p Pointer to allocated Client struct with physical connection
244 * to this server, i.e. with an open socket connected.
245 * \param source_p Pointer to allocated Client struct from which the message
246 * originally comes from. This can be a local or remote client.
247 * \param parc Integer holding the number of supplied arguments.
248 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
249 * pointers.
250 * \note Valid arguments for this command are:
251 * - parv[0] = sender prefix
252 * - parv[1] = nickname
253 */
254 static void
255 m_nick(struct Client *client_p, struct Client *source_p,
256 int parc, char *parv[])
257 {
258 char nick[NICKLEN];
259 struct Client *target_p = NULL;
260
261 assert(source_p == client_p);
262
263 if (parc < 2 || EmptyString(parv[1]))
264 {
265 sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
266 me.name, source_p->name);
267 return;
268 }
269
270 /* mark end of grace period, to prevent nickflooding */
271 if (!IsFloodDone(source_p))
272 flood_endgrace(source_p);
273
274 /* terminate nick to NICKLEN */
275 strlcpy(nick, parv[1], sizeof(nick));
276
277 /* check the nickname is ok */
278 if (!valid_nickname(nick, 1))
279 {
280 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
281 me.name, source_p->name, nick);
282 return;
283 }
284
285 if (find_matching_name_conf(NRESV_TYPE, nick,
286 NULL, NULL, 0) && !IsExemptResv(source_p) &&
287 !(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv))
288 {
289 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
290 me.name, source_p->name, nick);
291 return;
292 }
293
294 if ((target_p = hash_find_client(nick)) == NULL)
295 change_local_nick(source_p, nick);
296 else if (target_p == source_p)
297 {
298 /*
299 * If (target_p == source_p) the client is changing nicks between
300 * equivalent nicknames ie: [nick] -> {nick}
301 */
302
303 /* check the nick isnt exactly the same */
304 if (strcmp(target_p->name, nick))
305 change_local_nick(source_p, nick);
306 }
307 else if (IsUnknown(target_p))
308 {
309 /*
310 * if the client that has the nick isn't registered yet (nick but no
311 * user) then drop the unregged client
312 */
313 exit_client(target_p, &me, "Overridden");
314 change_local_nick(source_p, nick);
315 }
316 else
317 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name,
318 source_p->name, nick);
319 }
320
321
322 /*! \brief NICK command handler (called by servers and remotely
323 * connected clients)
324 *
325 * \param client_p Pointer to allocated Client struct with physical connection
326 * to this server, i.e. with an open socket connected.
327 * \param source_p Pointer to allocated Client struct from which the message
328 * originally comes from. This can be a local or remote client.
329 * \param parc Integer holding the number of supplied arguments.
330 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
331 * pointers.
332 * \note Valid arguments for this command are:
333 *
334 * server -> server nick change
335 * - parv[0] = sender prefix
336 * - parv[1] = nickname
337 * - parv[2] = TS when nick change
338 *
339 * server introducing new nick (without services support)
340 * - parv[0] = sender prefix
341 * - parv[1] = nickname
342 * - parv[2] = hop count
343 * - parv[3] = TS
344 * - parv[4] = umode
345 * - parv[5] = username
346 * - parv[6] = hostname
347 * - parv[7] = server
348 * - parv[8] = ircname
349 *
350 * server introducing new nick (with services support)
351 * - parv[0] = sender prefix
352 * - parv[1] = nickname
353 * - parv[2] = hop count
354 * - parv[3] = TS
355 * - parv[4] = umode
356 * - parv[5] = username
357 * - parv[6] = hostname
358 * - parv[7] = server
359 * - parv[8] = services id (timestamp)
360 * - parv[9] = ircname
361 */
362 static void
363 ms_nick(struct Client *client_p, struct Client *source_p,
364 int parc, char *parv[])
365 {
366 struct Client *target_p = NULL;
367 time_t newts = 0;
368 time_t svsid = 0;
369
370 if (parc < 2 || EmptyString(parv[1]))
371 return;
372
373 if (parc >= 9)
374 {
375 struct Client *server_p = hash_find_server(parv[7]);
376
377 if (server_p == NULL)
378 {
379 sendto_realops_flags(UMODE_ALL, L_ALL,
380 "Invalid server %s from %s for NICK %s",
381 parv[7], source_p->name, parv[1]);
382 sendto_one(client_p, ":%s KILL %s :%s (Server doesn't exist!)",
383 me.name, parv[1], me.name);
384 return;
385 }
386
387 if (check_clean_nick(client_p, source_p, parv[1], server_p) ||
388 check_clean_user(client_p, parv[1], parv[5], server_p) ||
389 check_clean_host(client_p, parv[1], parv[6], server_p))
390 return;
391
392 if (IsServer(source_p))
393 newts = atol(parv[3]);
394 if (IsServer(source_p) && parc == 10)
395 svsid = atol(parv[8]);
396 }
397 else if (parc == 3)
398 {
399 if (IsServer(source_p))
400 /* Servers can't change nicks.. */
401 return;
402
403 if (check_clean_nick(client_p, source_p, parv[1],
404 source_p->servptr))
405 return;
406
407 newts = atol(parv[2]);
408 }
409
410 /* if the nick doesnt exist, allow it and process like normal */
411 if ((target_p = hash_find_client(parv[1])) == NULL)
412 nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
413 else if (IsUnknown(target_p))
414 {
415 /* we're not living in the past anymore, an unknown client is local only. */
416 exit_client(target_p, &me, "Overridden");
417 nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
418 }
419 else if (target_p == source_p)
420 {
421 if (strcmp(target_p->name, parv[1]))
422 nick_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
423 }
424 else
425 perform_nick_collides(source_p, client_p, target_p, parc, parv,
426 newts, svsid, parv[1], parv[parc-1], NULL);
427 }
428
429
430 /*! \brief UID command handler (called by servers)
431 *
432 * \param client_p Pointer to allocated Client struct with physical connection
433 * to this server, i.e. with an open socket connected.
434 * \param source_p Pointer to allocated Client struct from which the message
435 * originally comes from. This can be a local or remote client.
436 * \param parc Integer holding the number of supplied arguments.
437 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
438 * pointers.
439 * \note Valid arguments for this command are:
440 *
441 * server introducing new nick (without services support)
442 * - parv[0] = sender prefix
443 * - parv[1] = nickname
444 * - parv[2] = hop count
445 * - parv[3] = TS
446 * - parv[4] = umode
447 * - parv[5] = username
448 * - parv[6] = hostname
449 * - parv[7] = ip
450 * - parv[8] = uid
451 * - parv[9] = ircname (gecos)
452 *
453 * server introducing new nick (with services support)
454 * - parv[ 0] = sender prefix
455 * - parv[ 1] = nickname
456 * - parv[ 2] = hop count
457 * - parv[ 3] = TS
458 * - parv[ 4] = umode
459 * - parv[ 5] = username
460 * - parv[ 6] = hostname
461 * - parv[ 7] = ip
462 * - parv[ 8] = uid
463 * - parv[ 9] = services id (timestamp)
464 * - parv[10] = ircname (gecos)
465 */
466 static void
467 ms_uid(struct Client *client_p, struct Client *source_p,
468 int parc, char *parv[])
469 {
470 struct Client *target_p = NULL;
471 time_t newts = 0;
472 time_t svsid = 0;
473
474 if (parc < 10 || EmptyString(parv[parc-1]))
475 return;
476
477 if (check_clean_nick(client_p, source_p, parv[1], source_p) ||
478 check_clean_user(client_p, parv[1], parv[5], source_p) ||
479 check_clean_host(client_p, parv[1], parv[6], source_p))
480 return;
481
482 newts = atol(parv[3]);
483 svsid = parc == 11 ? atol(parv[9]) : 0;
484
485 /*
486 * if there is an ID collision, kill our client, and kill theirs.
487 * this may generate 401's, but it ensures that both clients always
488 * go, even if the other server refuses to do the right thing.
489 */
490 if ((target_p = hash_find_id(parv[8])) != NULL)
491 {
492 sendto_realops_flags(UMODE_ALL, L_ALL,
493 "ID collision on %s(%s <- %s)(both killed)",
494 target_p->name, target_p->from->name,
495 client_p->name);
496 kill_client_ll_serv_butone(NULL, target_p, "%s (ID collision)",
497 me.name);
498
499 ++ServerStats.is_kill;
500 AddFlag(target_p, FLAGS_KILLED);
501 exit_client(target_p, &me, "ID Collision");
502 return;
503 }
504
505 if ((target_p = hash_find_client(parv[1])) == NULL)
506 uid_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
507 else if (IsUnknown(target_p))
508 {
509 exit_client(target_p, &me, "Overridden");
510 uid_from_server(client_p, source_p, parc, parv, newts, svsid, parv[1], parv[parc-1]);
511 }
512 else
513 perform_nick_collides(source_p, client_p, target_p, parc, parv, newts, svsid, parv[1],
514 parv[parc-1], parv[8]);
515 }
516
517 /* check_clean_nick()
518 *
519 * input - pointer to source
520 * -
521 * - nickname
522 * - truncated nickname
523 * - origin of client
524 * - pointer to server nick is coming from
525 * output - none
526 * side effects - if nickname is erroneous, or a different length to
527 * truncated nickname, return 1
528 */
529 static int
530 check_clean_nick(struct Client *client_p, struct Client *source_p,
531 char *nick, struct Client *server_p)
532 {
533 /* the old code did some wacky stuff here, if the nick is invalid, kill it
534 * and dont bother messing at all
535 */
536 if (!valid_nickname(nick, 0))
537 {
538 ++ServerStats.is_kill;
539 sendto_realops_flags(UMODE_DEBUG, L_ALL,
540 "Bad/long Nick: %s From: %s(via %s)",
541 nick, server_p->name, client_p->name);
542
543 sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)",
544 me.name, nick, me.name);
545
546 /* bad nick change */
547 if (source_p != client_p)
548 {
549 kill_client_ll_serv_butone(client_p, source_p,
550 "%s (Bad Nickname)",
551 me.name);
552 AddFlag(source_p, FLAGS_KILLED);
553 exit_client(source_p, &me, "Bad Nickname");
554 }
555
556 return 1;
557 }
558
559 return 0;
560 }
561
562 /* check_clean_user()
563 *
564 * input - pointer to client sending data
565 * - nickname
566 * - username to check
567 * - origin of NICK
568 * output - none
569 * side effects - if username is erroneous, return 1
570 */
571 static int
572 check_clean_user(struct Client *client_p, char *nick,
573 char *user, struct Client *server_p)
574 {
575 if (!clean_user_name(user))
576 {
577 ++ServerStats.is_kill;
578 sendto_realops_flags(UMODE_DEBUG, L_ALL,
579 "Bad/Long Username: %s Nickname: %s From: %s(via %s)",
580 user, nick, server_p->name, client_p->name);
581 sendto_one(client_p, ":%s KILL %s :%s (Bad Username)",
582 me.name, nick, me.name);
583 return 1;
584 }
585
586 return 0;
587 }
588
589 /* check_clean_host()
590 *
591 * input - pointer to client sending us data
592 * - nickname
593 * - hostname to check
594 * - source name
595 * output - none
596 * side effects - if hostname is erroneous, return 1
597 */
598 static int
599 check_clean_host(struct Client *client_p, char *nick,
600 char *host, struct Client *server_p)
601 {
602 if (!clean_host_name(host))
603 {
604 ++ServerStats.is_kill;
605 sendto_realops_flags(UMODE_DEBUG, L_ALL,
606 "Bad/Long Hostname: %s Nickname: %s From: %s(via %s)",
607 host, nick, server_p->name, client_p->name);
608 sendto_one(client_p, ":%s KILL %s :%s (Bad Hostname)",
609 me.name, nick, me.name);
610 return 1;
611 }
612
613 return 0;
614 }
615
616 /* clean_user_name()
617 *
618 * input - username
619 * output - none
620 * side effects - walks through the username, returning 0 if erroneous
621 */
622 static int
623 clean_user_name(const char *user)
624 {
625 const char *p = user;
626
627 assert(user && *user);
628
629 for (; *p; ++p)
630 if (!IsUserChar(*p))
631 return 0;
632
633 return p - user <= USERLEN;
634 }
635
636 /* clean_host_name()
637 * input - hostname
638 * output - none
639 * side effects - walks through the hostname, returning 0 if erroneous
640 */
641 static int
642 clean_host_name(const char *host)
643 {
644 const char *p = host;
645
646 assert(host && *host);
647
648 for (; *p; ++p)
649 if (!IsHostChar(*p))
650 return 0;
651
652 return p - host <= HOSTLEN;
653 }
654
655 /*
656 * nick_from_server()
657 */
658 static void
659 nick_from_server(struct Client *client_p, struct Client *source_p, int parc,
660 char *parv[], time_t newts, time_t svsid, char *nick, char *ngecos)
661 {
662 int samenick = 0;
663
664 if (IsServer(source_p))
665 {
666 /* A server introducing a new client, change source */
667 source_p = make_client(client_p);
668 dlinkAdd(source_p, &source_p->node, &global_client_list);
669
670 if (parc > 2)
671 source_p->hopcount = atoi(parv[2]);
672 if (newts)
673 source_p->tsinfo = newts;
674 else
675 {
676 newts = source_p->tsinfo = CurrentTime;
677 ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]);
678 }
679
680 source_p->servicestamp = svsid;
681 strlcpy(source_p->info, ngecos, sizeof(source_p->info));
682 /* copy the nick in place */
683 strlcpy(source_p->name, nick, sizeof(source_p->name));
684 hash_add_client(source_p);
685
686 if (parc > 8)
687 {
688 const char *m;
689
690 /* parse usermodes */
691 for (m = &parv[4][1]; *m; ++m)
692 {
693 unsigned int flag = user_modes[(unsigned char)*m];
694
695 if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
696 ++Count.invisi;
697 if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER))
698 ++Count.oper;
699
700 source_p->umodes |= flag & SEND_UMODES;
701 }
702
703 register_remote_user(source_p, parv[5], parv[6],
704 parv[7], ngecos);
705 return;
706 }
707 }
708 else if (source_p->name[0])
709 {
710 samenick = !irccmp(source_p->name, nick);
711
712 /* client changing their nick */
713 if (!samenick)
714 {
715 DelUMode(source_p, UMODE_REGISTERED);
716 watch_check_hash(source_p, RPL_LOGOFF);
717 source_p->tsinfo = newts ? newts : CurrentTime;
718 }
719
720 sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
721 source_p->name,source_p->username,
722 source_p->host, nick);
723
724 add_history(source_p, 1);
725 sendto_server(client_p, NULL, CAP_TS6, NOCAPS,
726 ":%s NICK %s :%lu",
727 ID(source_p), nick, (unsigned long)source_p->tsinfo);
728 sendto_server(client_p, NULL, NOCAPS, CAP_TS6,
729 ":%s NICK %s :%lu",
730 source_p->name, nick, (unsigned long)source_p->tsinfo);
731 }
732
733 /* set the new nick name */
734 if (source_p->name[0])
735 hash_del_client(source_p);
736
737 strlcpy(source_p->name, nick, sizeof(source_p->name));
738 hash_add_client(source_p);
739
740 if (!samenick)
741 watch_check_hash(source_p, RPL_LOGON);
742 }
743
744 /*
745 * client_from_server()
746 */
747 static void
748 uid_from_server(struct Client *client_p, struct Client *source_p, int parc,
749 char *parv[], time_t newts, time_t svsid, char *nick, char *ugecos)
750 {
751 const char *m = NULL;
752 const char *servername = source_p->name;
753
754 source_p = make_client(client_p);
755 dlinkAdd(source_p, &source_p->node, &global_client_list);
756
757 source_p->hopcount = atoi(parv[2]);
758 source_p->tsinfo = newts;
759 source_p->servicestamp = svsid;
760
761 /* copy the nick in place */
762 strcpy(source_p->name, nick);
763 strlcpy(source_p->id, parv[8], sizeof(source_p->id));
764 strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
765 strlcpy(source_p->info, ugecos, sizeof(source_p->info));
766
767 hash_add_client(source_p);
768 hash_add_id(source_p);
769
770 /* parse usermodes */
771 for (m = &parv[4][1]; *m; ++m)
772 {
773 unsigned int flag = user_modes[(unsigned char)*m];
774
775 if ((flag & UMODE_INVISIBLE) && !HasUMode(source_p, UMODE_INVISIBLE))
776 ++Count.invisi;
777 if ((flag & UMODE_OPER) && !HasUMode(source_p, UMODE_OPER))
778 ++Count.oper;
779
780 source_p->umodes |= flag & SEND_UMODES;
781 }
782
783 register_remote_user(source_p, parv[5], parv[6],
784 servername, ugecos);
785 }
786
787 static void
788 perform_nick_collides(struct Client *source_p, struct Client *client_p,
789 struct Client *target_p, int parc, char *parv[],
790 time_t newts, time_t svsid, char *nick, char *gecos, char *uid)
791 {
792 int sameuser;
793
794 /* server introducing new nick */
795 if (IsServer(source_p))
796 {
797 /* if we dont have a ts, or their TS's are the same, kill both */
798 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
799 {
800 sendto_realops_flags(UMODE_ALL, L_ALL,
801 "Nick collision on %s(%s <- %s)(both killed)",
802 target_p->name, target_p->from->name,
803 client_p->name);
804
805 /* if we have a UID, issue a kill for it */
806 if (uid)
807 sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
808 me.id, uid, me.name);
809
810 kill_client_ll_serv_butone(NULL, target_p,
811 "%s (Nick collision (new))",
812 me.name);
813 ++ServerStats.is_kill;
814 sendto_one(target_p, form_str(ERR_NICKCOLLISION),
815 me.name, target_p->name, target_p->name);
816
817 AddFlag(target_p, FLAGS_KILLED);
818 exit_client(target_p, &me, "Nick collision (new)");
819 return;
820 }
821 /* the timestamps are different */
822 else
823 {
824 sameuser = !irccmp(target_p->username, parv[5]) &&
825 !irccmp(target_p->host, parv[6]);
826
827 /* if the users are the same (loaded a client on a different server)
828 * and the new users ts is older, or the users are different and the
829 * new users ts is newer, ignore the new client and let it do the kill
830 */
831 if ((sameuser && newts < target_p->tsinfo) ||
832 (!sameuser && newts > target_p->tsinfo))
833 {
834 if (uid)
835 sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
836 me.id, uid, me.name);
837 return;
838 }
839 else
840 {
841 if (sameuser)
842 sendto_realops_flags(UMODE_ALL, L_ALL,
843 "Nick collision on %s(%s <- %s)(older killed)",
844 target_p->name, target_p->from->name,
845 client_p->name);
846 else
847 sendto_realops_flags(UMODE_ALL, L_ALL,
848 "Nick collision on %s(%s <- %s)(newer killed)",
849 target_p->name, target_p->from->name,
850 client_p->name);
851
852 ++ServerStats.is_kill;
853 sendto_one(target_p, form_str(ERR_NICKCOLLISION),
854 me.name, target_p->name, target_p->name);
855
856 /* if it came from a LL server, itd have been source_p,
857 * so we dont need to mark target_p as known
858 */
859 kill_client_ll_serv_butone(source_p, target_p,
860 "%s (Nick collision (new))",
861 me.name);
862
863 AddFlag(target_p, FLAGS_KILLED);
864 exit_client(target_p, &me, "Nick collision");
865
866 if (!uid && (parc == 9 || parc == 10))
867 nick_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos);
868 else if (uid && (parc == 10 || parc == 11))
869 uid_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos);
870
871 return;
872 }
873 }
874 }
875
876 /* its a client changing nick and causing a collide */
877 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
878 {
879 sendto_realops_flags(UMODE_ALL, L_ALL,
880 "Nick change collision from %s to %s(%s <- %s)(both killed)",
881 source_p->name, target_p->name, target_p->from->name,
882 client_p->name);
883
884 sendto_one(target_p, form_str(ERR_NICKCOLLISION), me.name,
885 target_p->name, target_p->name);
886
887 ++ServerStats.is_kill;
888 kill_client_ll_serv_butone(NULL, source_p, "%s (Nick change collision)",
889 me.name);
890
891 ++ServerStats.is_kill;
892 kill_client_ll_serv_butone(NULL, target_p, "%s (Nick change collision)",
893 me.name);
894
895 AddFlag(target_p, FLAGS_KILLED);
896 exit_client(target_p, &me, "Nick collision (new)");
897
898 AddFlag(source_p, FLAGS_KILLED);
899 exit_client(source_p, &me, "Nick collision (old)");
900 return;
901 }
902 else
903 {
904 sameuser = !irccmp(target_p->username, source_p->username) &&
905 !irccmp(target_p->host, source_p->host);
906
907 if ((sameuser && newts < target_p->tsinfo) ||
908 (!sameuser && newts > target_p->tsinfo))
909 {
910 if (sameuser)
911 sendto_realops_flags(UMODE_ALL, L_ALL,
912 "Nick change collision from %s to %s(%s <- %s)(older killed)",
913 source_p->name, target_p->name, target_p->from->name,
914 client_p->name);
915 else
916 sendto_realops_flags(UMODE_ALL, L_ALL,
917 "Nick change collision from %s to %s(%s <- %s)(newer killed)",
918 source_p->name, target_p->name, target_p->from->name,
919 client_p->name);
920
921 ++ServerStats.is_kill;
922 kill_client_ll_serv_butone(client_p, source_p,
923 "%s (Nick change collision)",
924 me.name);
925
926 AddFlag(source_p, FLAGS_KILLED);
927
928 if (sameuser)
929 exit_client(source_p, &me, "Nick collision (old)");
930 else
931 exit_client(source_p, &me, "Nick collision (new)");
932 return;
933 }
934 else
935 {
936 if (sameuser)
937 sendto_realops_flags(UMODE_ALL, L_ALL,
938 "Nick collision on %s(%s <- %s)(older killed)",
939 target_p->name, target_p->from->name,
940 client_p->name);
941 else
942 sendto_realops_flags(UMODE_ALL, L_ALL,
943 "Nick collision on %s(%s <- %s)(newer killed)",
944 target_p->name, target_p->from->name,
945 client_p->name);
946
947 kill_client_ll_serv_butone(source_p, target_p,
948 "%s (Nick collision)",
949 me.name);
950
951 ++ServerStats.is_kill;
952 sendto_one(target_p, form_str(ERR_NICKCOLLISION),
953 me.name, target_p->name, target_p->name);
954
955 AddFlag(target_p, FLAGS_KILLED);
956 exit_client(target_p, &me, "Nick collision");
957 }
958 }
959
960 /* we should only ever call nick_from_server() here, as
961 * this is a client changing nick, not a new client
962 */
963 nick_from_server(client_p, source_p, parc, parv, newts, svsid, nick, gecos);
964 }
965
966 static struct Message nick_msgtab = {
967 "NICK", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
968 {mr_nick, m_nick, ms_nick, m_ignore, m_nick, m_ignore}
969 };
970
971 static struct Message uid_msgtab = {
972 "UID", 0, 0, 10, MAXPARA, MFLG_SLOW, 0,
973 {m_ignore, m_ignore, ms_uid, m_ignore, m_ignore, m_ignore}
974 };
975
976 static void
977 module_init(void)
978 {
979 mod_add_cmd(&uid_msgtab);
980 mod_add_cmd(&nick_msgtab);
981 }
982
983 static void
984 module_exit(void)
985 {
986 mod_del_cmd(&uid_msgtab);
987 mod_del_cmd(&nick_msgtab);
988 }
989
990 struct module module_entry = {
991 .node = { NULL, NULL, NULL },
992 .name = NULL,
993 .version = "$Revision$",
994 .handle = NULL,
995 .modinit = module_init,
996 .modexit = module_exit,
997 .flags = MODULE_FLAG_CORE
998 };

Properties

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