]> jfr.im git - solanum.git/blame - modules/core/m_nick.c
modules: chase MsgBuf API change
[solanum.git] / modules / core / m_nick.c
CommitLineData
212380e3
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_nick.c: Sets a users nick.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
66b4a7ae 24 * $Id: m_nick.c 3518 2007-06-22 21:59:09Z jilles $
212380e3
AC
25 */
26
27#include "stdinc.h"
28#include "client.h"
29#include "hash.h"
4562c604 30#include "match.h"
212380e3
AC
31#include "ircd.h"
32#include "numeric.h"
33#include "s_conf.h"
34#include "s_stats.h"
35#include "s_user.h"
36#include "hash.h"
37#include "whowas.h"
38#include "s_serv.h"
39#include "send.h"
40#include "channel.h"
4016731b 41#include "logger.h"
212380e3
AC
42#include "msg.h"
43#include "parse.h"
44#include "modules.h"
45#include "common.h"
46#include "packet.h"
47#include "scache.h"
48#include "s_newconf.h"
49#include "monitor.h"
77d3d2db 50#include "s_assert.h"
212380e3 51
3f7e0642
JT
52/* Give all UID nicks the same TS. This ensures nick TS is always the same on
53 * all servers for each nick-user pair, also if a user with a UID nick changes
54 * their nick but is collided again (the server detecting the collision will
55 * not propagate the nick change further). -- jilles
56 */
57#define SAVE_NICKTS 100
58
428ca87b
AC
59static int mr_nick(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
60static int m_nick(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
61static int mc_nick(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
62static int ms_nick(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
63static int ms_uid(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
64static int ms_euid(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
65static int ms_save(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
212380e3
AC
66static int can_save(struct Client *);
67static void save_user(struct Client *, struct Client *, struct Client *);
ad35b2cd 68static void bad_nickname(struct Client *, const char *);
212380e3
AC
69
70struct Message nick_msgtab = {
71 "NICK", 0, 0, 0, MFLG_SLOW,
6c77f1f7 72 {{mr_nick, 0}, {m_nick, 0}, {mc_nick, 3}, {ms_nick, 0}, mg_ignore, {m_nick, 0}}
212380e3
AC
73};
74struct Message uid_msgtab = {
75 "UID", 0, 0, 0, MFLG_SLOW,
76 {mg_ignore, mg_ignore, mg_ignore, {ms_uid, 9}, mg_ignore, mg_ignore}
77};
78struct Message euid_msgtab = {
79 "EUID", 0, 0, 0, MFLG_SLOW,
80 {mg_ignore, mg_ignore, mg_ignore, {ms_euid, 12}, mg_ignore, mg_ignore}
81};
82struct Message save_msgtab = {
83 "SAVE", 0, 0, 0, MFLG_SLOW,
84 {mg_ignore, mg_ignore, mg_ignore, {ms_save, 3}, mg_ignore, mg_ignore}
85};
86
87mapi_clist_av1 nick_clist[] = { &nick_msgtab, &uid_msgtab, &euid_msgtab,
88 &save_msgtab, NULL };
89
66b4a7ae 90DECLARE_MODULE_AV1(nick, NULL, NULL, nick_clist, NULL, NULL, "$Revision: 3518 $");
212380e3
AC
91
92static int change_remote_nick(struct Client *, struct Client *, time_t,
93 const char *, int);
94
212380e3
AC
95static int clean_username(const char *);
96static int clean_host(const char *);
561d7efc 97static int clean_uid(const char *uid, const char *sid);
212380e3
AC
98
99static void set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick);
100static void change_local_nick(struct Client *client_p, struct Client *source_p, char *nick, int);
101static int register_client(struct Client *client_p, struct Client *server,
102 const char *nick, time_t newts, int parc, const char *parv[]);
103
104static int perform_nick_collides(struct Client *, struct Client *,
105 struct Client *, int, const char **,
106 time_t, const char *, const char *);
107static int perform_nickchange_collides(struct Client *, struct Client *,
108 struct Client *, int, const char **, time_t, const char *);
109
110/* mr_nick()
212380e3
AC
111 * parv[1] = nickname
112 */
113static int
428ca87b 114mr_nick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
115{
116 struct Client *target_p;
117 char nick[NICKLEN];
212380e3
AC
118
119 if (strlen(client_p->id) == 3)
120 {
121 exit_client(client_p, client_p, client_p, "Mixing client and server protocol");
122 return 0;
123 }
124
fda96b89 125 if(parc < 2 || EmptyString(parv[1]))
212380e3
AC
126 {
127 sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
128 me.name, EmptyString(source_p->name) ? "*" : source_p->name);
129 return 0;
130 }
131
212380e3 132 /* copy the nick and terminate it */
b583faf9 133 rb_strlcpy(nick, parv[1], ConfigFileEntry.nicklen);
212380e3
AC
134
135 /* check the nickname is ok */
136 if(!clean_nick(nick, 1))
137 {
138 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
3dfaa671 139 me.name, EmptyString(source_p->name) ? "*" : source_p->name, parv[1]);
212380e3
AC
140 return 0;
141 }
142
143 /* check if the nick is resv'd */
144 if(find_nick_resv(nick))
145 {
146 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
147 me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick);
148 return 0;
149 }
150
b37021a4 151 if(irc_dictionary_find(nd_dict, nick))
212380e3
AC
152 {
153 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
154 me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick);
155 return 0;
156 }
157
158 if((target_p = find_named_client(nick)) == NULL)
159 set_initial_nick(client_p, source_p, nick);
160 else if(source_p == target_p)
161 strcpy(source_p->name, nick);
162 else
163 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
164
165 return 0;
166}
167
168/* m_nick()
212380e3
AC
169 * parv[1] = nickname
170 */
171static int
428ca87b 172m_nick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
173{
174 struct Client *target_p;
175 char nick[NICKLEN];
212380e3 176
fda96b89 177 if(parc < 2 || EmptyString(parv[1]))
212380e3
AC
178 {
179 sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, source_p->name);
180 return 0;
181 }
182
212380e3
AC
183 /* mark end of grace period, to prevent nickflooding */
184 if(!IsFloodDone(source_p))
185 flood_endgrace(source_p);
186
187 /* terminate nick to NICKLEN, we dont want clean_nick() to error! */
b583faf9 188 rb_strlcpy(nick, parv[1], ConfigFileEntry.nicklen);
212380e3
AC
189
190 /* check the nickname is ok */
191 if(!clean_nick(nick, 1))
192 {
3dfaa671 193 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick);
212380e3
AC
194 return 0;
195 }
196
197 if(!IsExemptResv(source_p) && find_nick_resv(nick))
198 {
199 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME), me.name, source_p->name, nick);
200 return 0;
201 }
202
b37021a4 203 if(irc_dictionary_find(nd_dict, nick))
212380e3
AC
204 {
205 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
206 me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick);
207 return 0;
208 }
209
210 if((target_p = find_named_client(nick)))
211 {
212 /* If(target_p == source_p) the client is changing nicks between
213 * equivalent nicknames ie: [nick] -> {nick}
214 */
215 if(target_p == source_p)
216 {
217 /* check the nick isnt exactly the same */
218 if(strcmp(target_p->name, nick))
219 change_local_nick(client_p, source_p, nick, 1);
220
221 }
222
223 /* drop unregged client */
224 else if(IsUnknown(target_p))
225 {
226 exit_client(NULL, target_p, &me, "Overridden");
227 change_local_nick(client_p, source_p, nick, 1);
228 }
229 else
3dfaa671 230 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, source_p->name, nick);
212380e3
AC
231
232 return 0;
233 }
234 else
235 change_local_nick(client_p, source_p, nick, 1);
236
237 return 0;
238}
239
6c77f1f7 240/* mc_nick()
55abcbb2 241 *
212380e3 242 * server -> server nick change
212380e3
AC
243 * parv[1] = nickname
244 * parv[2] = TS when nick change
212380e3
AC
245 */
246static int
428ca87b 247mc_nick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
248{
249 struct Client *target_p;
250 time_t newts = 0;
251
252 /* if nicks erroneous, or too long, kill */
253 if(!clean_nick(parv[1], 0))
254 {
ad35b2cd 255 bad_nickname(client_p, parv[1]);
212380e3
AC
256 return 0;
257 }
258
259 newts = atol(parv[2]);
260 target_p = find_named_client(parv[1]);
261
262 /* if the nick doesnt exist, allow it and process like normal */
263 if(target_p == NULL)
264 {
265 change_remote_nick(client_p, source_p, newts, parv[1], 1);
266 }
267 else if(IsUnknown(target_p))
268 {
269 exit_client(NULL, target_p, &me, "Overridden");
270 change_remote_nick(client_p, source_p, newts, parv[1], 1);
271 }
272 else if(target_p == source_p)
273 {
274 /* client changing case of nick */
275 if(strcmp(target_p->name, parv[1]))
276 change_remote_nick(client_p, source_p, newts, parv[1], 1);
277 }
278 /* we've got a collision! */
279 else
280 perform_nickchange_collides(source_p, client_p, target_p,
281 parc, parv, newts, parv[1]);
282
283 return 0;
284}
285
286static int
428ca87b 287ms_nick(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3 288{
6c77f1f7 289 const char *nick, *server;
212380e3 290
6c77f1f7
JT
291 nick = parc > 1 ? parv[1] : "?";
292 server = parc > 7 ? parv[7] : "?";
212380e3 293
6c77f1f7
JT
294 sendto_wallops_flags(UMODE_WALLOP, &me,
295 "Link %s cancelled, TS5 nickname %s on %s introduced (old server?)",
296 client_p->name, nick, server);
297 sendto_server(NULL, NULL, CAP_TS6, NOCAPS,
298 ":%s WALLOPS :Link %s cancelled, TS5 nickname %s on %s introduced (old server?)",
299 me.id, client_p->name, nick, server);
300 ilog(L_SERVER, "Link %s cancelled, TS5 nickname %s on %s introduced (old server?)",
301 client_p->name, nick, server);
212380e3 302
6c77f1f7 303 exit_client(client_p, client_p, &me, "TS5 nickname introduced");
212380e3
AC
304
305 return 0;
306}
307
308/* ms_uid()
309 * parv[1] - nickname
310 * parv[2] - hops
311 * parv[3] - TS
312 * parv[4] - umodes
313 * parv[5] - username
314 * parv[6] - hostname
315 * parv[7] - IP
316 * parv[8] - UID
317 * parv[9] - gecos
318 */
319static int
428ca87b 320ms_uid(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
321{
322 struct Client *target_p;
323 time_t newts = 0;
4a5655b2 324 char squitreason[120];
212380e3
AC
325
326 newts = atol(parv[3]);
327
328 if(parc != 10)
329 {
330 sendto_realops_snomask(SNO_GENERAL, L_ALL,
331 "Dropping server %s due to (invalid) command 'UID' "
332 "with %d arguments (expecting 10)", client_p->name, parc);
333 ilog(L_SERVER, "Excess parameters (%d) for command 'UID' from %s.",
334 parc, client_p->name);
5203cba5 335 snprintf(squitreason, sizeof squitreason,
56023eb2
JT
336 "Excess parameters (%d) to %s command, expecting %d",
337 parc, "UID", 10);
338 exit_client(client_p, client_p, client_p, squitreason);
212380e3
AC
339 return 0;
340 }
341
342 /* if nicks erroneous, or too long, kill */
343 if(!clean_nick(parv[1], 0))
344 {
ad35b2cd 345 bad_nickname(client_p, parv[1]);
212380e3
AC
346 return 0;
347 }
348
561d7efc 349 if(!clean_uid(parv[8], source_p->id))
212380e3 350 {
5203cba5 351 snprintf(squitreason, sizeof squitreason,
e0c7937a
JT
352 "Invalid UID %s for nick %s on %s/%s",
353 parv[8], parv[1], source_p->name, source_p->id);
4a5655b2 354 exit_client(client_p, client_p, client_p, squitreason);
212380e3
AC
355 return 0;
356 }
357
4a5655b2 358 if(!clean_username(parv[5]) || !clean_host(parv[6]))
212380e3 359 {
47adde3d 360 ServerStats.is_kill++;
212380e3 361 sendto_realops_snomask(SNO_DEBUG, L_ALL,
4a5655b2
JT
362 "Bad user@host: %s@%s From: %s(via %s)",
363 parv[5], parv[6], source_p->name, client_p->name);
364 sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name);
212380e3
AC
365 return 0;
366 }
367
368 /* check length of clients gecos */
369 if(strlen(parv[9]) > REALLEN)
370 {
371 char *s = LOCAL_COPY(parv[9]);
372 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Long realname from server %s for %s",
3dfaa671 373 source_p->name, parv[1]);
212380e3
AC
374 s[REALLEN] = '\0';
375 parv[9] = s;
376 }
377
378 target_p = find_named_client(parv[1]);
379
380 if(target_p == NULL)
381 {
382 register_client(client_p, source_p, parv[1], newts, parc, parv);
383 }
384 else if(IsUnknown(target_p))
385 {
386 exit_client(NULL, target_p, &me, "Overridden");
387 register_client(client_p, source_p, parv[1], newts, parc, parv);
388 }
389 /* we've got a collision! */
390 else
391 perform_nick_collides(source_p, client_p, target_p, parc, parv,
392 newts, parv[1], parv[8]);
393
394 return 0;
395}
396
397/* ms_euid()
398 * parv[1] - nickname
399 * parv[2] - hops
400 * parv[3] - TS
401 * parv[4] - umodes
402 * parv[5] - username
403 * parv[6] - hostname
404 * parv[7] - IP
405 * parv[8] - UID
406 * parv[9] - realhost
407 * parv[10] - account
408 * parv[11] - gecos
409 */
410static int
428ca87b 411ms_euid(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
412{
413 struct Client *target_p;
414 time_t newts = 0;
4a5655b2 415 char squitreason[120];
212380e3
AC
416
417 newts = atol(parv[3]);
418
419 if(parc != 12)
420 {
421 sendto_realops_snomask(SNO_GENERAL, L_ALL,
422 "Dropping server %s due to (invalid) command 'EUID' "
423 "with %d arguments (expecting 12)", client_p->name, parc);
424 ilog(L_SERVER, "Excess parameters (%d) for command 'EUID' from %s.",
425 parc, client_p->name);
5203cba5 426 snprintf(squitreason, sizeof squitreason,
56023eb2
JT
427 "Excess parameters (%d) to %s command, expecting %d",
428 parc, "EUID", 12);
429 exit_client(client_p, client_p, client_p, squitreason);
212380e3
AC
430 return 0;
431 }
432
433 /* if nicks erroneous, or too long, kill */
434 if(!clean_nick(parv[1], 0))
435 {
ad35b2cd 436 bad_nickname(client_p, parv[1]);
212380e3
AC
437 return 0;
438 }
439
561d7efc 440 if(!clean_uid(parv[8], source_p->id))
212380e3 441 {
5203cba5 442 snprintf(squitreason, sizeof squitreason,
e0c7937a
JT
443 "Invalid UID %s for nick %s on %s/%s",
444 parv[8], parv[1], source_p->name, source_p->id);
4a5655b2 445 exit_client(client_p, client_p, client_p, squitreason);
212380e3
AC
446 return 0;
447 }
448
4a5655b2 449 if(!clean_username(parv[5]) || !clean_host(parv[6]))
212380e3 450 {
47adde3d 451 ServerStats.is_kill++;
212380e3 452 sendto_realops_snomask(SNO_DEBUG, L_ALL,
4a5655b2
JT
453 "Bad user@host: %s@%s From: %s(via %s)",
454 parv[5], parv[6], source_p->name, client_p->name);
455 sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name);
212380e3
AC
456 return 0;
457 }
458
459 if(strcmp(parv[9], "*") && !clean_host(parv[9]))
460 {
47adde3d 461 ServerStats.is_kill++;
212380e3
AC
462 sendto_realops_snomask(SNO_DEBUG, L_ALL,
463 "Bad realhost: %s From: %s(via %s)",
464 parv[9], source_p->name, client_p->name);
465 sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)", me.id, parv[8], me.name);
466 return 0;
467 }
468
469 /* check length of clients gecos */
470 if(strlen(parv[11]) > REALLEN)
471 {
472 char *s = LOCAL_COPY(parv[11]);
473 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Long realname from server %s for %s",
3dfaa671 474 source_p->name, parv[1]);
212380e3
AC
475 s[REALLEN] = '\0';
476 parv[11] = s;
477 }
478
479 target_p = find_named_client(parv[1]);
480
481 if(target_p == NULL)
482 {
483 register_client(client_p, source_p, parv[1], newts, parc, parv);
484 }
485 else if(IsUnknown(target_p))
486 {
487 exit_client(NULL, target_p, &me, "Overridden");
488 register_client(client_p, source_p, parv[1], newts, parc, parv);
489 }
490 /* we've got a collision! */
491 else
492 perform_nick_collides(source_p, client_p, target_p, parc, parv,
493 newts, parv[1], parv[8]);
494
495 return 0;
496}
497
498/* ms_save()
499 * parv[1] - UID
500 * parv[2] - TS
501 */
502static int
428ca87b 503ms_save(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
504{
505 struct Client *target_p;
506
507 target_p = find_id(parv[1]);
508 if (target_p == NULL)
509 return 0;
510 if (!IsPerson(target_p))
511 sendto_realops_snomask(SNO_GENERAL, L_ALL,
512 "Ignored SAVE message for non-person %s from %s",
513 target_p->name, source_p->name);
514 else if (IsDigit(target_p->name[0]))
515 sendto_realops_snomask(SNO_DEBUG, L_ALL,
516 "Ignored noop SAVE message for %s from %s",
517 target_p->name, source_p->name);
518 else if (target_p->tsinfo == atol(parv[2]))
519 save_user(client_p, source_p, target_p);
520 else
521 sendto_realops_snomask(SNO_SKILL, L_ALL,
522 "Ignored SAVE message for %s from %s",
523 target_p->name, source_p->name);
524 return 0;
525}
526
212380e3
AC
527/* clean_username()
528 *
529 * input - username to check
530 * output - 0 if erroneous, else 0
531 * side effects -
532 */
533static int
534clean_username(const char *username)
535{
536 int len = 0;
537
538 for(; *username; username++)
539 {
540 len++;
541
542 if(!IsUserChar(*username))
543 return 0;
544 }
545
546 if(len > USERLEN)
547 return 0;
548
549 return 1;
550}
551
552/* clean_host()
553 *
554 * input - host to check
555 * output - 0 if erroneous, else 0
556 * side effects -
557 */
558static int
559clean_host(const char *host)
560{
561 int len = 0;
562
563 for(; *host; host++)
564 {
565 len++;
566
567 if(!IsHostChar(*host))
568 return 0;
569 }
570
571 if(len > HOSTLEN)
572 return 0;
573
574 return 1;
575}
576
577static int
561d7efc 578clean_uid(const char *uid, const char *sid)
212380e3
AC
579{
580 int len = 1;
581
561d7efc
JT
582 if(strncmp(uid, sid, strlen(sid)))
583 return 0;
584
212380e3
AC
585 if(!IsDigit(*uid++))
586 return 0;
587
588 for(; *uid; uid++)
589 {
590 len++;
591
592 if(!IsIdChar(*uid))
593 return 0;
594 }
595
596 if(len != IDLEN - 1)
597 return 0;
598
599 return 1;
600}
601
602static void
603set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick)
604{
0e7cb7e6 605 char note[NICKLEN + 10];
212380e3
AC
606
607 /* This had to be copied here to avoid problems.. */
e3354945 608 source_p->tsinfo = rb_current_time();
212380e3
AC
609 if(source_p->name[0])
610 del_from_client_hash(source_p->name, source_p);
611
612 strcpy(source_p->name, nick);
613 add_to_client_hash(nick, source_p);
614
5203cba5 615 snprintf(note, sizeof(note), "Nick: %s", nick);
0e7cb7e6 616 rb_note(client_p->localClient->F, note);
212380e3
AC
617
618 if(source_p->flags & FLAGS_SENTUSER)
619 {
212380e3 620 /* got user, heres nick. */
21251822 621 register_local_user(client_p, source_p);
212380e3
AC
622 }
623}
624
625static void
626change_local_nick(struct Client *client_p, struct Client *source_p,
627 char *nick, int dosend)
628{
629 struct Client *target_p;
637c4932 630 rb_dlink_node *ptr, *next_ptr;
212380e3 631 struct Channel *chptr;
0e7cb7e6 632 char note[NICKLEN + 10];
212380e3
AC
633 int samenick;
634
635 if (dosend)
636 {
637 chptr = find_bannickchange_channel(source_p);
638 if (chptr != NULL)
639 {
640 sendto_one_numeric(source_p, ERR_BANNICKCHANGE,
641 form_str(ERR_BANNICKCHANGE),
642 nick, chptr->chname);
643 return;
644 }
e3354945 645 if((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < rb_current_time())
212380e3
AC
646 source_p->localClient->number_of_nick_changes = 0;
647
e3354945 648 source_p->localClient->last_nick_change = rb_current_time();
212380e3
AC
649 source_p->localClient->number_of_nick_changes++;
650
651 if(ConfigFileEntry.anti_nick_flood && !IsOper(source_p) &&
652 source_p->localClient->number_of_nick_changes > ConfigFileEntry.max_nick_changes)
653 {
654 sendto_one(source_p, form_str(ERR_NICKTOOFAST),
655 me.name, source_p->name, source_p->name,
656 nick, ConfigFileEntry.max_nick_time);
657 return;
658 }
659 }
660
661 samenick = irccmp(source_p->name, nick) ? 0 : 1;
662
663 /* dont reset TS if theyre just changing case of nick */
664 if(!samenick)
665 {
95ffa685 666 /* force the TS to increase -- jilles */
e3354945 667 if (source_p->tsinfo >= rb_current_time())
95ffa685
JT
668 source_p->tsinfo++;
669 else
e3354945 670 source_p->tsinfo = rb_current_time();
212380e3
AC
671 monitor_signoff(source_p);
672 /* we only do bancache for local users -- jilles */
673 if(source_p->user)
674 invalidate_bancache_user(source_p);
675 }
676
677 sendto_realops_snomask(SNO_NCHANGE, L_ALL,
678 "Nick change: From %s to %s [%s@%s]",
679 source_p->name, nick, source_p->username, source_p->host);
680
681 /* send the nick change to the users channels */
583f064f 682 sendto_common_channels_local(source_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s",
212380e3
AC
683 source_p->name, source_p->username, source_p->host, nick);
684
685 /* send the nick change to servers.. */
686 if(source_p->user)
687 {
b47f8a4f 688 whowas_add_history(source_p, 1);
212380e3
AC
689
690 if (dosend)
691 {
692 sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
693 use_id(source_p), nick, (long) source_p->tsinfo);
212380e3
AC
694 }
695 }
696
697 /* Finally, add to hash */
698 del_from_client_hash(source_p->name, source_p);
699 strcpy(source_p->name, nick);
700 add_to_client_hash(nick, source_p);
701
702 if(!samenick)
703 monitor_signon(source_p);
704
705 /* Make sure everyone that has this client on its accept list
55abcbb2 706 * loses that reference.
212380e3
AC
707 */
708 /* we used to call del_all_accepts() here, but theres no real reason
709 * to clear a clients own list of accepted clients. So just remove
710 * them from everyone elses list --anfl
711 */
637c4932 712 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, source_p->on_allow_list.head)
212380e3
AC
713 {
714 target_p = ptr->data;
715
555ac41f
JT
716 rb_dlinkFindDestroy(source_p, &target_p->localClient->allow_list);
717 rb_dlinkDestroy(ptr, &source_p->on_allow_list);
212380e3
AC
718 }
719
5203cba5 720 snprintf(note, sizeof(note), "Nick: %s", nick);
0e7cb7e6 721 rb_note(client_p->localClient->F, note);
212380e3
AC
722
723 return;
724}
725
726/*
727 * change_remote_nick()
728 */
729static int
730change_remote_nick(struct Client *client_p, struct Client *source_p,
731 time_t newts, const char *nick, int dosend)
732{
733 struct nd_entry *nd;
734 int samenick = irccmp(source_p->name, nick) ? 0 : 1;
735
736 /* client changing their nick - dont reset ts if its same */
737 if(!samenick)
738 {
e3354945 739 source_p->tsinfo = newts ? newts : rb_current_time();
212380e3
AC
740 monitor_signoff(source_p);
741 }
742
583f064f 743 sendto_common_channels_local(source_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s",
212380e3
AC
744 source_p->name, source_p->username, source_p->host, nick);
745
746 if(source_p->user)
747 {
b47f8a4f 748 whowas_add_history(source_p, 1);
212380e3
AC
749 if (dosend)
750 {
751 sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
752 use_id(source_p), nick, (long) source_p->tsinfo);
212380e3
AC
753 }
754 }
755
756 del_from_client_hash(source_p->name, source_p);
757
758 /* invalidate nick delay when a remote client uses the nick.. */
b37021a4 759 if((nd = irc_dictionary_retrieve(nd_dict, nick)))
212380e3
AC
760 free_nd_entry(nd);
761
762 strcpy(source_p->name, nick);
763 add_to_client_hash(nick, source_p);
764
765 if(!samenick)
766 monitor_signon(source_p);
767
768 /* remove all accepts pointing to the client */
769 del_all_accepts(source_p);
770
771 return 0;
772}
773
774static int
775perform_nick_collides(struct Client *source_p, struct Client *client_p,
776 struct Client *target_p, int parc, const char *parv[],
777 time_t newts, const char *nick, const char *uid)
778{
779 int sameuser;
780 int use_save;
781 const char *action;
782
783 use_save = ConfigFileEntry.collision_fnc && can_save(target_p) &&
784 uid != NULL && can_save(source_p);
785 action = use_save ? "saved" : "killed";
786
787 /* if we dont have a ts, or their TS's are the same, kill both */
788 if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
789 {
9d107a71 790 sendto_realops_snomask(SNO_SKILL, L_ALL,
212380e3
AC
791 "Nick collision on %s(%s <- %s)(both %s)",
792 target_p->name, target_p->from->name, client_p->name, action);
793
794 if (use_save)
795 {
796 save_user(&me, &me, target_p);
47adde3d 797 ServerStats.is_save++;
212380e3
AC
798 sendto_one(client_p, ":%s SAVE %s %ld", me.id,
799 uid, (long)newts);
800 register_client(client_p, source_p,
3f7e0642 801 uid, SAVE_NICKTS, parc, parv);
212380e3
AC
802 }
803 else
804 {
805 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
806 form_str(ERR_NICKCOLLISION), target_p->name);
807
808 /* if the new client being introduced has a UID, we need to
809 * issue a KILL for it..
810 */
811 if(uid)
812 sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
813 me.id, uid, me.name);
814
815 /* we then need to KILL the old client everywhere */
816 kill_client_serv_butone(NULL, target_p, "%s (Nick collision (new))", me.name);
47adde3d 817 ServerStats.is_kill++;
212380e3
AC
818
819 target_p->flags |= FLAGS_KILLED;
820 exit_client(client_p, target_p, &me, "Nick collision (new)");
821 }
822 return 0;
823 }
824 /* the timestamps are different */
825 else
826 {
827 sameuser = (target_p->user) && !irccmp(target_p->username, parv[5])
828 && !irccmp(target_p->host, parv[6]);
829
830 if((sameuser && newts < target_p->tsinfo) ||
831 (!sameuser && newts > target_p->tsinfo))
832 {
833 /* if we have a UID, then we need to issue a KILL,
834 * otherwise we do nothing and hope that the other
835 * client will collide it..
836 */
837 if (use_save)
838 {
839 sendto_one(client_p, ":%s SAVE %s %ld", me.id,
840 uid, (long)newts);
841 register_client(client_p, source_p,
3f7e0642 842 uid, SAVE_NICKTS, parc, parv);
212380e3
AC
843 }
844 else if(uid)
845 sendto_one(client_p,
846 ":%s KILL %s :%s (Nick collision (new))",
847 me.id, uid, me.name);
848 return 0;
849 }
850 else
851 {
852 if(sameuser)
9d107a71 853 sendto_realops_snomask(SNO_SKILL, L_ALL,
212380e3
AC
854 "Nick collision on %s(%s <- %s)(older %s)",
855 target_p->name, target_p->from->name,
856 client_p->name, action);
857 else
9d107a71 858 sendto_realops_snomask(SNO_SKILL, L_ALL,
212380e3
AC
859 "Nick collision on %s(%s <- %s)(newer %s)",
860 target_p->name, target_p->from->name,
861 client_p->name, action);
862
863 if (use_save)
864 {
47adde3d 865 ServerStats.is_save++;
212380e3
AC
866 save_user(&me, &me, target_p);
867 }
868 else
869 {
47adde3d 870 ServerStats.is_kill++;
212380e3
AC
871 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
872 form_str(ERR_NICKCOLLISION), target_p->name);
873
874 /* now we just need to kill the existing client */
875 kill_client_serv_butone(client_p, target_p,
876 "%s (Nick collision (new))", me.name);
877
878 target_p->flags |= FLAGS_KILLED;
879 (void) exit_client(client_p, target_p, &me, "Nick collision");
880 }
881
463947ad 882 register_client(client_p, source_p,
212380e3
AC
883 nick, newts, parc, parv);
884
885 return 0;
886 }
887 }
888}
889
890
891static int
892perform_nickchange_collides(struct Client *source_p, struct Client *client_p,
893 struct Client *target_p, int parc,
894 const char *parv[], time_t newts, const char *nick)
895{
896 int sameuser;
897 int use_save;
898 const char *action;
899
900 use_save = ConfigFileEntry.collision_fnc && can_save(target_p) &&
901 can_save(source_p);
902 action = use_save ? "saved" : "killed";
903
904 /* its a client changing nick and causing a collide */
905 if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user)
906 {
9d107a71 907 sendto_realops_snomask(SNO_SKILL, L_ALL,
212380e3
AC
908 "Nick change collision from %s to %s(%s <- %s)(both %s)",
909 source_p->name, target_p->name, target_p->from->name,
910 client_p->name, action);
911
912 if (use_save)
913 {
47adde3d 914 ServerStats.is_save += 2;
212380e3
AC
915 save_user(&me, &me, target_p);
916 sendto_one(client_p, ":%s SAVE %s %ld", me.id,
917 source_p->id, (long)newts);
918 /* don't send a redundant nick change */
919 if (!IsDigit(source_p->name[0]))
3f7e0642 920 change_remote_nick(client_p, source_p, SAVE_NICKTS, source_p->id, 1);
212380e3
AC
921 }
922 else
923 {
47adde3d 924 ServerStats.is_kill++;
212380e3
AC
925 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
926 form_str(ERR_NICKCOLLISION), target_p->name);
927
928 kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name);
929
47adde3d 930 ServerStats.is_kill++;
212380e3
AC
931
932 kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name);
933
934 target_p->flags |= FLAGS_KILLED;
935 exit_client(NULL, target_p, &me, "Nick collision(new)");
936 source_p->flags |= FLAGS_KILLED;
937 exit_client(client_p, source_p, &me, "Nick collision(old)");
938 }
939 return 0;
940 }
941 else
942 {
943 sameuser = !irccmp(target_p->username, source_p->username) &&
944 !irccmp(target_p->host, source_p->host);
945
946 if((sameuser && newts < target_p->tsinfo) ||
947 (!sameuser && newts > target_p->tsinfo))
948 {
949 if(sameuser)
9d107a71 950 sendto_realops_snomask(SNO_SKILL, L_ALL,
212380e3
AC
951 "Nick change collision from %s to %s(%s <- %s)(older %s)",
952 source_p->name, target_p->name,
953 target_p->from->name, client_p->name, action);
954 else
9d107a71 955 sendto_realops_snomask(SNO_SKILL, L_ALL,
212380e3
AC
956 "Nick change collision from %s to %s(%s <- %s)(newer %s)",
957 source_p->name, target_p->name,
958 target_p->from->name, client_p->name, action);
959
960 if (use_save)
961 {
47adde3d 962 ServerStats.is_save++;
212380e3
AC
963 /* can't broadcast a SAVE because the
964 * nickchange has happened at client_p
965 * but not in other directions -- jilles */
966 sendto_one(client_p, ":%s SAVE %s %ld", me.id,
967 source_p->id, (long)newts);
212380e3
AC
968 /* send a :<id> NICK <id> <ts> (!) */
969 if (!IsDigit(source_p->name[0]))
3f7e0642 970 change_remote_nick(client_p, source_p, SAVE_NICKTS, source_p->id, 1);
212380e3
AC
971 }
972 else
973 {
47adde3d 974 ServerStats.is_kill++;
212380e3 975
ce782b68
JT
976 sendto_one_numeric(source_p, ERR_NICKCOLLISION,
977 form_str(ERR_NICKCOLLISION), source_p->name);
212380e3
AC
978
979 /* kill the client issuing the nickchange */
980 kill_client_serv_butone(client_p, source_p,
981 "%s (Nick change collision)", me.name);
982
983 source_p->flags |= FLAGS_KILLED;
984
985 if(sameuser)
986 exit_client(client_p, source_p, &me, "Nick collision(old)");
987 else
988 exit_client(client_p, source_p, &me, "Nick collision(new)");
989 }
990 return 0;
991 }
992 else
993 {
994 if(sameuser)
9d107a71 995 sendto_realops_snomask(SNO_SKILL, L_ALL,
212380e3
AC
996 "Nick collision on %s(%s <- %s)(older %s)",
997 target_p->name, target_p->from->name,
998 client_p->name, action);
999 else
9d107a71 1000 sendto_realops_snomask(SNO_SKILL, L_ALL,
212380e3
AC
1001 "Nick collision on %s(%s <- %s)(newer %s)",
1002 target_p->name, target_p->from->name,
1003 client_p->name, action);
1004
1005 if (use_save)
1006 {
47adde3d 1007 ServerStats.is_save++;
212380e3
AC
1008 save_user(&me, &me, target_p);
1009 }
1010 else
1011 {
1012 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
1013 form_str(ERR_NICKCOLLISION), target_p->name);
1014
1015 /* kill the client who existed before hand */
1016 kill_client_serv_butone(client_p, target_p, "%s (Nick collision)", me.name);
1017
47adde3d 1018 ServerStats.is_kill++;
212380e3
AC
1019
1020 target_p->flags |= FLAGS_KILLED;
1021 (void) exit_client(client_p, target_p, &me, "Nick collision");
1022 }
1023 }
1024 }
1025
1026 change_remote_nick(client_p, source_p, newts, nick, 1);
1027
1028 return 0;
1029}
1030
1031static int
1032register_client(struct Client *client_p, struct Client *server,
1033 const char *nick, time_t newts, int parc, const char *parv[])
1034{
1035 struct Client *source_p;
1036 struct User *user;
1037 struct nd_entry *nd;
1038 const char *m;
1039 int flag;
1040
1041 source_p = make_client(client_p);
1042 user = make_user(source_p);
0e7cb7e6 1043 rb_dlinkAddTail(source_p, &source_p->node, &global_client_list);
212380e3
AC
1044
1045 source_p->hopcount = atoi(parv[2]);
1046 source_p->tsinfo = newts;
1047
1048 strcpy(source_p->name, nick);
f427c8b0
VY
1049 rb_strlcpy(source_p->username, parv[5], sizeof(source_p->username));
1050 rb_strlcpy(source_p->host, parv[6], sizeof(source_p->host));
1051 rb_strlcpy(source_p->orighost, source_p->host, sizeof(source_p->orighost));
212380e3
AC
1052
1053 if(parc == 12)
1054 {
f427c8b0
VY
1055 rb_strlcpy(source_p->info, parv[11], sizeof(source_p->info));
1056 rb_strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
1057 rb_strlcpy(source_p->id, parv[8], sizeof(source_p->id));
212380e3
AC
1058 add_to_id_hash(source_p->id, source_p);
1059 if (strcmp(parv[9], "*"))
1060 {
f427c8b0 1061 rb_strlcpy(source_p->orighost, parv[9], sizeof(source_p->orighost));
212380e3
AC
1062 if (irccmp(source_p->host, source_p->orighost))
1063 SetDynSpoof(source_p);
1064 }
1065 if (strcmp(parv[10], "*"))
f427c8b0 1066 rb_strlcpy(source_p->user->suser, parv[10], sizeof(source_p->user->suser));
212380e3
AC
1067 }
1068 else if(parc == 10)
1069 {
f427c8b0
VY
1070 rb_strlcpy(source_p->info, parv[9], sizeof(source_p->info));
1071 rb_strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
1072 rb_strlcpy(source_p->id, parv[8], sizeof(source_p->id));
212380e3
AC
1073 add_to_id_hash(source_p->id, source_p);
1074 }
1075 else
1076 {
463947ad 1077 s_assert(0);
212380e3
AC
1078 }
1079
1080 /* remove any nd entries for this nick */
b37021a4 1081 if((nd = irc_dictionary_retrieve(nd_dict, nick)))
212380e3
AC
1082 free_nd_entry(nd);
1083
1084 add_to_client_hash(nick, source_p);
66b4a7ae 1085 add_to_hostname_hash(source_p->orighost, source_p);
212380e3
AC
1086 monitor_signon(source_p);
1087
1088 m = &parv[4][1];
1089 while(*m)
1090 {
1091 flag = user_modes[(unsigned char) *m];
1092
1093 if(flag & UMODE_SERVICE)
1094 {
1095 int hit = 0;
5b96d9a6 1096 rb_dlink_node *ptr;
212380e3 1097
5b96d9a6 1098 RB_DLINK_FOREACH(ptr, service_list.head)
212380e3 1099 {
c88cdb00 1100 if(!irccmp((const char *) ptr->data, server->name))
212380e3
AC
1101 {
1102 hit++;
1103 break;
1104 }
1105 }
1106
1107 if(!hit)
1108 {
1109 m++;
1110 continue;
1111 }
1112 }
1113
1114 /* increment +i count if theyre invis */
1115 if(!(source_p->umodes & UMODE_INVISIBLE) && (flag & UMODE_INVISIBLE))
1116 Count.invisi++;
1117
1118 /* increment opered count if theyre opered */
1119 if(!(source_p->umodes & UMODE_OPER) && (flag & UMODE_OPER))
1120 Count.oper++;
1121
1122 source_p->umodes |= flag;
1123 m++;
1124 }
1125
1126 if(IsOper(source_p) && !IsService(source_p))
0e7cb7e6 1127 rb_dlinkAddAlloc(source_p, &oper_list);
212380e3
AC
1128
1129 SetRemoteClient(source_p);
1130
1131 if(++Count.total > Count.max_tot)
1132 Count.max_tot = Count.total;
1133
64449595 1134 source_p->servptr = server;
212380e3 1135
0e7cb7e6 1136 rb_dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
212380e3 1137
212380e3
AC
1138 call_hook(h_new_remote_user, source_p);
1139
1140 return (introduce_client(client_p, source_p, user, nick, parc == 12));
1141}
1142
1143/* Check if we can do SAVE. target_p can be a client to save or a
1144 * server introducing a client -- jilles */
1145static int
1146can_save(struct Client *target_p)
1147{
1148 struct Client *serv_p;
1149
1150 if (MyClient(target_p))
1151 return 1;
1152 if (!has_id(target_p))
1153 return 0;
1154 serv_p = IsServer(target_p) ? target_p : target_p->servptr;
1155 while (serv_p != NULL && serv_p != &me)
1156 {
1157 if (!(serv_p->serv->caps & CAP_SAVE))
1158 return 0;
1159 serv_p = serv_p->servptr;
1160 }
1161 return serv_p == &me;
1162}
1163
1164static void
1165save_user(struct Client *client_p, struct Client *source_p,
1166 struct Client *target_p)
1167{
1168 if (!MyConnect(target_p) && (!has_id(target_p) || !IsCapable(target_p->from, CAP_SAVE)))
1169 {
1170 /* This shouldn't happen */
1171 /* Note we only need SAVE support in this direction */
1172 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1173 "Killed %s!%s@%s for nick collision detected by %s (%s does not support SAVE)",
1174 target_p->name, target_p->username, target_p->host, source_p->name, target_p->from->name);
1175 kill_client_serv_butone(NULL, target_p, "%s (Nick collision (no SAVE support))", me.name);
47adde3d 1176 ServerStats.is_kill++;
212380e3
AC
1177
1178 target_p->flags |= FLAGS_KILLED;
1179 (void) exit_client(NULL, target_p, &me, "Nick collision (no SAVE support)");
1180 return;
1181 }
1182 sendto_server(client_p, NULL, CAP_SAVE|CAP_TS6, NOCAPS, ":%s SAVE %s %ld",
1183 source_p->id, target_p->id, (long)target_p->tsinfo);
1184 sendto_server(client_p, NULL, CAP_TS6, CAP_SAVE, ":%s NICK %s :%ld",
3f7e0642 1185 target_p->id, target_p->id, (long)SAVE_NICKTS);
212380e3
AC
1186 if (!IsMe(client_p))
1187 sendto_realops_snomask(SNO_SKILL, L_ALL,
1188 "Received SAVE message for %s from %s",
1189 target_p->name, source_p->name);
1190 if (MyClient(target_p))
1191 {
1192 sendto_one_numeric(target_p, RPL_SAVENICK,
1193 form_str(RPL_SAVENICK), target_p->id);
1194 change_local_nick(target_p, target_p, target_p->id, 0);
3f7e0642 1195 target_p->tsinfo = SAVE_NICKTS;
212380e3
AC
1196 }
1197 else
3f7e0642 1198 change_remote_nick(target_p, target_p, SAVE_NICKTS, target_p->id, 0);
212380e3 1199}
ad35b2cd
JT
1200
1201static void bad_nickname(struct Client *client_p, const char *nick)
1202{
1203 char squitreason[100];
1204
1205 sendto_wallops_flags(UMODE_WALLOP, &me,
1206 "Squitting %s because of bad nickname %s (NICKLEN mismatch?)",
1207 client_p->name, nick);
1208 sendto_server(NULL, NULL, CAP_TS6, NOCAPS,
1209 ":%s WALLOPS :Squitting %s because of bad nickname %s (NICKLEN mismatch?)",
1210 me.id, client_p->name, nick);
4dd5d304
JT
1211 ilog(L_SERVER, "Link %s cancelled, bad nickname %s sent (NICKLEN mismatch?)",
1212 client_p->name, nick);
ad35b2cd 1213
5203cba5 1214 snprintf(squitreason, sizeof squitreason,
ad35b2cd
JT
1215 "Bad nickname introduced [%s]", nick);
1216 exit_client(client_p, client_p, &me, squitreason);
1217}