ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_nick.c
Revision: 7599
Committed: Mon Jun 13 18:56:33 2016 UTC (7 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 26866 byte(s)
Log Message:
- Minor cleanup to send_umode() to get rid of the redundant struct Client * pointer

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2016 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
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, 1, 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 = strtoumax(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 * - parv[ 0] = command
328 * - parv[ 1] = nickname
329 * - parv[ 2] = hop count
330 * - parv[ 3] = TS
331 * - parv[ 4] = umode
332 * - parv[ 5] = username
333 * - parv[ 6] = hostname
334 * - parv[ 7] = ip
335 * - parv[ 8] = uid
336 * - parv[ 9] = services account
337 * - parv[10] = ircname (gecos)
338 */
339 static void
340 uid_from_server(struct Client *source_p, int parc, char *parv[])
341 {
342 struct Client *client_p = NULL;
343
344 client_p = make_client(source_p->from);
345 client_p->servptr = source_p;
346 client_p->hopcount = atoi(parv[2]);
347 client_p->tsinfo = strtoumax(parv[3], NULL, 10);
348
349 strlcpy(client_p->account, parv[9], sizeof(client_p->account));
350 strlcpy(client_p->name, parv[1], sizeof(client_p->name));
351 strlcpy(client_p->id, parv[8], sizeof(client_p->id));
352 strlcpy(client_p->sockhost, parv[7], sizeof(client_p->sockhost));
353 strlcpy(client_p->info, parv[parc - 1], sizeof(client_p->info));
354 strlcpy(client_p->host, parv[6], sizeof(client_p->host));
355 strlcpy(client_p->username, parv[5], sizeof(client_p->username));
356
357 hash_add_client(client_p);
358 hash_add_id(client_p);
359
360 /* Parse user modes */
361 for (const char *m = &parv[4][1]; *m; ++m)
362 {
363 const struct user_modes *tab = umode_map[(unsigned char)*m];
364
365 if (!tab)
366 continue;
367 if ((tab->flag & UMODE_INVISIBLE) && !HasUMode(client_p, UMODE_INVISIBLE))
368 ++Count.invisi;
369 if ((tab->flag & UMODE_OPER) && !HasUMode(client_p, UMODE_OPER))
370 ++Count.oper;
371
372 AddUMode(client_p, tab->flag);
373 }
374
375 register_remote_user(client_p);
376 }
377
378 /*!
379 *
380 * \param source_p Pointer to allocated Client struct from which the message
381 * originally comes from. This can be a local or remote client.
382 * \param parc Integer holding the number of supplied arguments.
383 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
384 * pointers.
385 * \note Valid arguments for this command are:
386 *
387 * - parv[ 0] = command
388 * - parv[ 1] = nickname
389 * - parv[ 2] = hop count
390 * - parv[ 3] = TS
391 * - parv[ 4] = umode
392 * - parv[ 5] = username
393 * - parv[ 6] = hostname
394 * - parv[ 7] = ip
395 * - parv[ 8] = uid
396 * - parv[ 9] = services id (account name)
397 * - parv[10] = ircname (gecos)
398 */
399 static int
400 perform_uid_introduction_collides(struct Client *source_p, struct Client *target_p,
401 int parc, char *parv[])
402 {
403 const char *uid = parv[8];
404 uintmax_t newts = strtoumax(parv[3], NULL, 10);
405 int sameuser = 0;
406
407 assert(IsServer(source_p));
408 assert(IsClient(target_p));
409
410 /* Server introducing new nick */
411
412 /* If we don't have a TS, or their TS's are the same, kill both */
413 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
414 {
415 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
416 "Nick collision on %s(%s <- %s)(both killed)",
417 target_p->name, target_p->from->name,
418 source_p->from->name);
419
420 sendto_one(source_p, ":%s KILL %s :%s (Nick collision (new))",
421 me.id, uid, me.name);
422 sendto_server(NULL, 0, 0, ":%s KILL %s :%s (Nick collision (new))",
423 me.id, target_p->id, me.name);
424
425 ++ServerStats.is_kill;
426 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
427
428 AddFlag(target_p, FLAGS_KILLED);
429 exit_client(target_p, "Nick collision (new)");
430 return 0;
431 }
432
433 /* The timestamps are different */
434 sameuser = !irccmp(target_p->username, parv[5]) &&
435 !irccmp(target_p->sockhost, parv[7]);
436
437 /*
438 * If the users are the same (loaded a client on a different server)
439 * and the new users ts is older, or the users are different and the
440 * new users ts is newer, ignore the new client and let it do the kill
441 */
442 if ((sameuser && newts < target_p->tsinfo) ||
443 (!sameuser && newts > target_p->tsinfo))
444 {
445 sendto_one(source_p, ":%s KILL %s :%s (Nick collision (new))",
446 me.id, uid, me.name);
447 return 0;
448 }
449
450 if (sameuser)
451 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
452 "Nick collision on %s(%s <- %s)(older killed)",
453 target_p->name, target_p->from->name,
454 source_p->from->name);
455 else
456 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
457 "Nick collision on %s(%s <- %s)(newer killed)",
458 target_p->name, target_p->from->name,
459 source_p->from->name);
460
461 ++ServerStats.is_kill;
462 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
463
464 sendto_server(NULL, 0, 0, ":%s KILL %s :%s (Nick collision (new))",
465 me.id, target_p->id, me.name);
466
467 AddFlag(target_p, FLAGS_KILLED);
468 exit_client(target_p, "Nick collision");
469
470 return 1;
471 }
472
473 /*!
474 *
475 * \param source_p Pointer to allocated Client struct from which the message
476 * originally comes from. This can be a local or remote client.
477 * \param parc Integer holding the number of supplied arguments.
478 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
479 * pointers.
480 * \note Valid arguments for this command are:
481 *
482 * - parv[0] = command
483 * - parv[1] = nickname
484 * - parv[2] = timestamp
485 */
486 static int
487 perform_nick_change_collides(struct Client *source_p, struct Client *target_p,
488 int parc, char *parv[])
489 {
490 int sameuser = 0;
491 uintmax_t newts = strtoumax(parv[2], NULL, 10);
492
493 assert(IsClient(source_p));
494 assert(IsClient(target_p));
495 assert(newts > 0);
496
497 /* It's a client changing nick and causing a collide */
498 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
499 {
500 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
501 "Nick change collision from %s to %s(%s <- %s)(both killed)",
502 source_p->name, target_p->name, target_p->from->name,
503 source_p->from->name);
504
505 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
506 ServerStats.is_kill += 2;
507
508 sendto_server(NULL, 0, 0, ":%s KILL %s :%s (Nick change collision)",
509 me.id, source_p->id, me.name);
510 sendto_server(NULL, 0, 0, ":%s KILL %s :%s (Nick change collision)",
511 me.id, target_p->id, me.name);
512
513 AddFlag(source_p, FLAGS_KILLED);
514 AddFlag(target_p, FLAGS_KILLED);
515 exit_client(source_p, "Nick collision (old)");
516 exit_client(target_p, "Nick collision (new)");
517 return 0;
518 }
519
520 /* The timestamps are different */
521 sameuser = !irccmp(target_p->username, source_p->username) &&
522 !irccmp(target_p->sockhost, source_p->sockhost);
523
524 if ((sameuser && newts < target_p->tsinfo) ||
525 (!sameuser && newts > target_p->tsinfo))
526 {
527 if (sameuser)
528 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
529 "Nick change collision from %s to %s(%s <- %s)(older killed)",
530 source_p->name, target_p->name, target_p->from->name,
531 source_p->from->name);
532 else
533 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
534 "Nick change collision from %s to %s(%s <- %s)(newer killed)",
535 source_p->name, target_p->name, target_p->from->name,
536 source_p->from->name);
537
538 ++ServerStats.is_kill;
539
540 sendto_server(NULL, 0, 0, ":%s KILL %s :%s (Nick change collision)",
541 me.id, source_p->id, me.name);
542 AddFlag(source_p, FLAGS_KILLED);
543
544 if (sameuser)
545 exit_client(source_p, "Nick collision (old)");
546 else
547 exit_client(source_p, "Nick collision (new)");
548 return 0;
549 }
550
551 if (sameuser)
552 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
553 "Nick collision on %s(%s <- %s)(older killed)",
554 target_p->name, target_p->from->name,
555 source_p->from->name);
556 else
557 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
558 "Nick collision on %s(%s <- %s)(newer killed)",
559 target_p->name, target_p->from->name,
560 source_p->from->name);
561
562 sendto_server(NULL, 0, 0, ":%s KILL %s :%s (Nick collision)",
563 me.id, target_p->id, me.name);
564
565 ++ServerStats.is_kill;
566 sendto_one_numeric(target_p, &me, ERR_NICKCOLLISION, target_p->name);
567
568 AddFlag(target_p, FLAGS_KILLED);
569 exit_client(target_p, "Nick collision");
570
571 return 1;
572 }
573
574 /*! \brief NICK command handler
575 *
576 * \param source_p Pointer to allocated Client struct from which the message
577 * originally comes from. This can be a local or remote client.
578 * \param parc Integer holding the number of supplied arguments.
579 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
580 * pointers.
581 * \note Valid arguments for this command are:
582 * - parv[0] = command
583 * - parv[1] = nickname
584 */
585 static int
586 mr_nick(struct Client *source_p, int parc, char *parv[])
587 {
588 char nick[NICKLEN + 1] = "";
589 struct Client *target_p = NULL;
590 const struct ResvItem *resv = NULL;
591
592 if (parc < 2 || EmptyString(parv[1]))
593 {
594 sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN);
595 return 0;
596 }
597
598 /* Copy the nick and terminate it */
599 strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ConfigServerInfo.max_nick_length + 1));
600
601 /* Check the nickname is ok */
602 if (!valid_nickname(nick, 1))
603 {
604 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, parv[1], "Erroneous Nickname");
605 return 0;
606 }
607
608 /* Check if the nick is resv'd */
609 if ((resv = resv_find(nick, match)))
610 {
611 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, resv->reason);
612 sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
613 "Forbidding reserved nick %s from user %s",
614 nick, get_client_name(source_p, HIDE_IP));
615 return 0;
616 }
617
618 if ((target_p = hash_find_client(nick)) == NULL || target_p == source_p)
619 set_initial_nick(source_p, nick);
620 else
621 sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, target_p->name);
622
623 return 0;
624 }
625
626 /*! \brief NICK command handler
627 *
628 * \param source_p Pointer to allocated Client struct from which the message
629 * originally comes from. This can be a local or remote client.
630 * \param parc Integer holding the number of supplied arguments.
631 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
632 * pointers.
633 * \note Valid arguments for this command are:
634 * - parv[0] = command
635 * - parv[1] = nickname
636 */
637 static int
638 m_nick(struct Client *source_p, int parc, char *parv[])
639 {
640 char nick[NICKLEN + 1] = "";
641 struct Client *target_p = NULL;
642 const struct ResvItem *resv = NULL;
643
644 assert(MyClient(source_p));
645
646 if (parc < 2 || EmptyString(parv[1]))
647 {
648 sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN);
649 return 0;
650 }
651
652 /* Mark end of grace period, to prevent nickflooding */
653 if (!IsFloodDone(source_p))
654 flood_endgrace(source_p);
655
656 /* Terminate nick to NICKLEN */
657 strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ConfigServerInfo.max_nick_length + 1));
658
659 /* Check the nickname is ok */
660 if (!valid_nickname(nick, 1))
661 {
662 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, "Erroneous Nickname");
663 return 0;
664 }
665
666 if (!HasFlag(source_p, FLAGS_EXEMPTRESV) &&
667 !(HasUMode(source_p, UMODE_OPER) && HasOFlag(source_p, OPER_FLAG_NICK_RESV)) &&
668 (resv = resv_find(nick, match)))
669 {
670 sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, resv->reason);
671 sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
672 "Forbidding reserved nick %s from user %s",
673 nick, get_client_name(source_p, HIDE_IP));
674 return 0;
675 }
676
677 if ((target_p = hash_find_client(nick)) == NULL)
678 change_local_nick(source_p, nick);
679 else if (target_p == source_p)
680 {
681 /*
682 * If (target_p == source_p) the client is changing nicks between
683 * equivalent nicknames ie: [nick] -> {nick}
684 */
685
686 /* Check the nick isn't exactly the same */
687 if (strcmp(target_p->name, nick))
688 change_local_nick(source_p, nick);
689 }
690 else if (IsUnknown(target_p))
691 {
692 /*
693 * If the client that has the nick isn't registered yet (nick but no
694 * user) then drop the unregged client
695 */
696 exit_client(target_p, "Overridden by other sign on");
697 change_local_nick(source_p, nick);
698 }
699 else
700 sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, target_p->name);
701
702 return 0;
703 }
704
705 /*! \brief NICK command handler
706 *
707 * \param source_p Pointer to allocated Client struct from which the message
708 * originally comes from. This can be a local or remote client.
709 * \param parc Integer holding the number of supplied arguments.
710 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
711 * pointers.
712 * \note Valid arguments for this command are:
713 *
714 * server -> server nick change
715 * - parv[0] = command
716 * - parv[1] = nickname
717 * - parv[2] = timestamp
718 */
719 static int
720 ms_nick(struct Client *source_p, int parc, char *parv[])
721 {
722 struct Client *target_p = NULL;
723
724 if (parc != 3 || EmptyString(parv[parc - 1]))
725 return 0;
726
727 if (!IsClient(source_p))
728 return 0; /* Servers and unknown clients can't change nicks.. */
729
730 if (check_clean_nick(source_p, parv[1]))
731 return 0;
732
733 /* If the nick doesn't exist, allow it and process like normal */
734 if ((target_p = hash_find_client(parv[1])) == NULL)
735 change_remote_nick(source_p, parv);
736 else if (IsUnknown(target_p))
737 {
738 /* We're not living in the past anymore, an unknown client is local only. */
739 exit_client(target_p, "Overridden by other sign on");
740 change_remote_nick(source_p, parv);
741 }
742 else if (target_p == source_p)
743 {
744 if (strcmp(target_p->name, parv[1]))
745 change_remote_nick(source_p, parv);
746 }
747 else if (perform_nick_change_collides(source_p, target_p, parc, parv))
748 change_remote_nick(source_p, parv);
749 return 0;
750 }
751
752 /*! \brief UID command handler
753 *
754 * \param source_p Pointer to allocated Client struct from which the message
755 * originally comes from. This can be a local or remote client.
756 * \param parc Integer holding the number of supplied arguments.
757 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
758 * pointers.
759 * \note Valid arguments for this command are:
760 *
761 * - parv[ 0] = command
762 * - parv[ 1] = nickname
763 * - parv[ 2] = hop count
764 * - parv[ 3] = TS
765 * - parv[ 4] = umode
766 * - parv[ 5] = username
767 * - parv[ 6] = hostname
768 * - parv[ 7] = ip
769 * - parv[ 8] = uid
770 * - parv[ 9] = services id (account name)
771 * - parv[10] = ircname (gecos)
772 */
773 static int
774 ms_uid(struct Client *source_p, int parc, char *parv[])
775 {
776 struct Client *target_p = NULL;
777
778 if (check_clean_nick(source_p, parv[1]) ||
779 check_clean_user(source_p, parv[1], parv[5]) ||
780 check_clean_host(source_p, parv[1], parv[6]) ||
781 check_clean_uid(source_p, parv[1], parv[8]))
782 return 0;
783
784 /*
785 * If there is an ID collision, kill our client, and kill theirs.
786 * This may generate 401's, but it ensures that both clients always
787 * go, even if the other server refuses to do the right thing.
788 */
789 if ((target_p = hash_find_id(parv[8])))
790 {
791 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
792 "ID collision on %s(%s <- %s)(both killed)",
793 target_p->name, target_p->from->name,
794 source_p->from->name);
795
796 sendto_server(NULL, 0, 0, ":%s KILL %s :%s (ID collision)",
797 me.id, target_p->id, me.name);
798
799 ++ServerStats.is_kill;
800 AddFlag(target_p, FLAGS_KILLED);
801 exit_client(target_p, "ID Collision");
802 return 0;
803 }
804
805 if ((target_p = hash_find_client(parv[1])) == NULL)
806 uid_from_server(source_p, parc, parv);
807 else if (IsUnknown(target_p))
808 {
809 exit_client(target_p, "Overridden by other sign on");
810 uid_from_server(source_p, parc, parv);
811 }
812 else if (perform_uid_introduction_collides(source_p, target_p, parc, parv))
813 uid_from_server(source_p, parc, parv);
814 return 0;
815 }
816
817 static struct Message nick_msgtab =
818 {
819 .cmd = "NICK",
820 .args_max = MAXPARA,
821 .handlers[UNREGISTERED_HANDLER] = mr_nick,
822 .handlers[CLIENT_HANDLER] = m_nick,
823 .handlers[SERVER_HANDLER] = ms_nick,
824 .handlers[ENCAP_HANDLER] = m_ignore,
825 .handlers[OPER_HANDLER] = m_nick
826 };
827
828 static struct Message uid_msgtab =
829 {
830 .cmd = "UID",
831 .args_min = 11,
832 .args_max = MAXPARA,
833 .handlers[UNREGISTERED_HANDLER] = m_ignore,
834 .handlers[CLIENT_HANDLER] = m_ignore,
835 .handlers[SERVER_HANDLER] = ms_uid,
836 .handlers[ENCAP_HANDLER] = m_ignore,
837 .handlers[OPER_HANDLER] = m_ignore
838 };
839
840 static void
841 module_init(void)
842 {
843 mod_add_cmd(&uid_msgtab);
844 mod_add_cmd(&nick_msgtab);
845 }
846
847 static void
848 module_exit(void)
849 {
850 mod_del_cmd(&uid_msgtab);
851 mod_del_cmd(&nick_msgtab);
852 }
853
854 struct module module_entry =
855 {
856 .version = "$Revision$",
857 .modinit = module_init,
858 .modexit = module_exit,
859 .flags = MODULE_FLAG_CORE
860 };

Properties

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