ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_nick.c
Revision: 1832
Committed: Fri Apr 19 19:16:09 2013 UTC (10 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 30723 byte(s)
Log Message:
- Made all numeric defines use the actual string instead of the numeric value
  which allows to use gcc's printf format attribute
- Remove current message locale implementation

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

Properties

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