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: 4970
Committed: Mon Dec 1 14:59:38 2014 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 27692 byte(s)
Log Message:
- m_nick.c: if possible compare ip addresses rather than hostnames in both
  perform_nick_change_collides() and perform_uid_introduction_collides()

File Contents

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

Properties

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