ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_nick.c
Revision: 1559
Committed: Sun Oct 14 01:38:28 2012 UTC (11 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/core/m_nick.c
File size: 30790 byte(s)
Log Message:
- Replaced TimeStamp based services IDs with more flexible account names

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

Properties

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