ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_nick.c
Revision: 9292
Committed: Sun Feb 23 10:37:06 2020 UTC (6 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 29504 byte(s)
Log Message:
- Extban $n of type 'acting' has been implemented. This extban prevents matching users from changing their
  nick while in the channel. Users with voice or above are not affected.
- Channel mode +N has been changed so channel members with +v can change nick names, too

File Contents

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

Properties

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