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: 6919
Committed: Thu Dec 10 12:59:48 2015 UTC (8 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 28180 byte(s)
Log Message:
- Removed backwards compatibility hack for older servers that allowed client->sockhost being "0"

File Contents

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

Properties

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