/[svn]/ircd-hybrid/branches/8.2.x/modules/core/m_nick.c
ViewVC logotype

Contents of /ircd-hybrid/branches/8.2.x/modules/core/m_nick.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8589 - (show annotations)
Sun Oct 21 10:52:11 2018 UTC (4 years, 7 months ago) by michael
File MIME type: text/x-chdr
File size: 29253 byte(s)
- Sprinkle some assert(); cleanup existing ones

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

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.30