1 /************************************************************************
2 * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
5 *
6 * See file AUTHORS in IRC package for additional names of
7 * the programmers.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #ifndef lint
25 static const volatile char rcsid[] = "@(#)$Id: s_user.c,v 1.280 2010/08/12 16:29:30 bif Exp $";
26 #endif
27
28 #include "os.h"
29 #include "s_defines.h"
30 #define S_USER_C
31 #include "s_externs.h"
32 #undef S_USER_C
33
34 static void save_user (aClient *, aClient *, char *);
35
36 static char buf[BUFSIZE], buf2[BUFSIZE];
37
38 static int user_modes[] = { FLAGS_OPER, 'o',
39 FLAGS_LOCOP, 'O',
40 FLAGS_INVISIBLE, 'i',
41 FLAGS_WALLOP, 'w',
42 FLAGS_RESTRICT, 'r',
43 FLAGS_AWAY, 'a',
44 0, 0 };
45
46 /*
47 ** m_functions execute protocol messages on this server:
48 **
49 ** cptr is always NON-NULL, pointing to a *LOCAL* client
50 ** structure (with an open socket connected!). This
51 ** identifies the physical socket where the message
52 ** originated (or which caused the m_function to be
53 ** executed--some m_functions may call others...).
54 **
55 ** sptr is the source of the message, defined by the
56 ** prefix part of the message if present. If not
57 ** or prefix not found, then sptr==cptr.
58 **
59 ** (!IsServer(cptr)) => (cptr == sptr), because
60 ** prefixes are taken *only* from servers...
61 **
62 ** (IsServer(cptr))
63 ** (sptr == cptr) => the message didn't
64 ** have the prefix.
65 **
66 ** (sptr != cptr && IsServer(sptr) means
67 ** the prefix specified servername. (?)
68 **
69 ** (sptr != cptr && !IsServer(sptr) means
70 ** that message originated from a remote
71 ** user (not local).
72 **
73 ** combining
74 **
75 ** (!IsServer(sptr)) means that, sptr can safely
76 ** taken as defining the target structure of the
77 ** message in this server.
78 **
79 ** *Always* true (if 'parse' and others are working correct):
80 **
81 ** 1) sptr->from == cptr (note: cptr->from == cptr)
82 **
83 ** 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
84 ** *cannot* be a local connection, unless it's
85 ** actually cptr!). [MyConnect(x) should probably
86 ** be defined as (x == x->from) --msa ]
87 **
88 ** parc number of variable parameter strings (if zero,
89 ** parv is allowed to be NULL)
90 **
91 ** parv a NULL terminated list of parameter pointers,
92 **
93 ** parv[0], sender (prefix string), if not present
94 ** this points to an empty string.
95 ** parv[1]...parv[parc-1]
96 ** pointers to additional parameters
97 ** parv[parc] == NULL, *always*
98 **
99 ** note: it is guaranteed that parv[0]..parv[parc-1] are all
100 ** non-NULL pointers.
101 */
102
103 /*
104 ** next_client
105 ** Local function to find the next matching client. The search
106 ** can be continued from the specified client entry. Normal
107 ** usage loop is:
108 **
109 ** for (x = client; x = next_client(x,mask); x = x->next)
110 ** HandleMatchingClient;
111 **
112 ** Parameters:
113 ** aClient *next First client to check
114 ** char *ch Search string (may include wilds)
115 **
116 */
next_client(aClient * next,char * ch)117 aClient *next_client(aClient *next, char *ch)
118 {
119 Reg aClient *tmp = next;
120
121 next = find_client(ch, tmp);
122 if (tmp && tmp->prev == next)
123 return NULL;
124 if (next != tmp)
125 return next;
126 for ( ; next; next = next->next)
127 if (!match(ch,next->name) || !match(next->name,ch))
128 break;
129 return next;
130 }
131
132 /*
133 ** hunt_server
134 **
135 ** Do the basic thing in delivering the message (command)
136 ** across the relays to the specific server (server) for
137 ** actions.
138 **
139 ** Note: The command is a format string and *MUST* be
140 ** of prefixed style (e.g. ":%s COMMAND %s ...").
141 ** Command can have only max 8 parameters.
142 **
143 ** server parv[server] is the parameter identifying the
144 ** target server.
145 **
146 ** *WARNING*
147 ** parv[server] is replaced with the pointer to the
148 ** real servername from the matched client (I'm lazy
149 ** now --msa).
150 **
151 ** returns: (see #defines)
152 */
hunt_server(aClient * cptr,aClient * sptr,char * command,int server,int parc,char * parv[])153 int hunt_server(aClient *cptr, aClient *sptr, char *command, int server,
154 int parc, char *parv[])
155 {
156 aClient *acptr;
157
158 /*
159 ** Assume it's me, if no server
160 */
161 if (parc <= server || BadPtr(parv[server]) ||
162 match(ME, parv[server]) == 0 ||
163 match(parv[server], ME) == 0)
164 return (HUNTED_ISME);
165 /*
166 ** These are to pickup matches that would cause the following
167 ** message to go in the wrong direction while doing quick fast
168 ** non-matching lookups.
169 */
170 if ((acptr = find_client(parv[server], NULL)))
171 if (acptr->from == sptr->from && !MyConnect(acptr))
172 acptr = NULL;
173 /* Match SID */
174 if (!acptr && (acptr = find_sid(parv[server], NULL)))
175 if (acptr->from == sptr->from && !MyConnect(acptr))
176 acptr = NULL;
177 /* Match *.masked.servers */
178 if (!acptr && (acptr = find_server(parv[server], NULL)))
179 if (acptr->from == sptr->from && !MyConnect(acptr))
180 acptr = NULL;
181 /* Remote services@servers */
182 if (!acptr && (acptr = find_service(parv[server], NULL)))
183 if (acptr->from == sptr->from && !MyConnect(acptr))
184 acptr = NULL;
185 if (!acptr)
186 for (acptr = client, (void)collapse(parv[server]);
187 (acptr = next_client(acptr, parv[server]));
188 acptr = acptr->next)
189 {
190 if (acptr->from == sptr->from && !MyConnect(acptr))
191 continue;
192 /*
193 * Fix to prevent looping in case the parameter for
194 * some reason happens to match someone from the from
195 * link --jto
196 */
197 if (IsRegistered(acptr) && (acptr != cptr))
198 break;
199 }
200 if (acptr)
201 {
202 if (!IsRegistered(acptr))
203 return HUNTED_ISME;
204 if (IsMe(acptr) || MyClient(acptr) || MyService(acptr))
205 return HUNTED_ISME;
206 if (match(acptr->name, parv[server]))
207 parv[server] = acptr->name;
208 if (IsService(sptr)
209 && (IsServer(acptr->from)
210 && match(sptr->service->dist,acptr->name) != 0
211 && match(sptr->service->dist,acptr->serv->sid) != 0))
212 {
213 sendto_one(sptr, replies[ERR_NOSUCHSERVER], ME, BadTo(parv[0]),
214 parv[server]);
215 return(HUNTED_NOSUCH);
216 }
217 sendto_one(acptr, command, parv[0],
218 parv[1], parv[2], parv[3], parv[4],
219 parv[5], parv[6], parv[7], parv[8]);
220 return(HUNTED_PASS);
221 }
222 sendto_one(sptr, replies[ERR_NOSUCHSERVER], ME, BadTo(parv[0]), parv[server]);
223 return(HUNTED_NOSUCH);
224 }
225
226 /*
227 ** 'do_nick_name' ensures that the given parameter (nick) is
228 ** really a proper string for a nickname (note, the 'nick'
229 ** may be modified in the process...)
230 **
231 ** RETURNS the length of the final NICKNAME (0, if
232 ** nickname is illegal)
233 **
234 ** Nickname characters are in range
235 ** 'A'..'}', '_', '-', '0'..'9'
236 ** anything outside the above set will terminate nickname.
237 ** In addition, the first character cannot be '-' or a digit.
238 ** Finally forbid the use of "anonymous" because of possible
239 ** abuses related to anonymous channnels. -kalt
240 **
241 */
242
do_nick_name(char * nick,int server)243 int do_nick_name(char *nick, int server)
244 {
245 Reg char *ch;
246
247 if (*nick == '-') /* first character '-' */
248 return 0;
249
250 if (isdigit(*nick) && !server) /* first character in [0..9] */
251 return 0;
252
253 if (strcasecmp(nick, "anonymous") == 0)
254 return 0;
255
256 #ifdef MINLOCALNICKLEN
257 if (!server && nick[MINLOCALNICKLEN-1] == '\0')
258 return 0;
259 #endif
260
261 for (ch = nick; *ch && (ch-nick) < (server?NICKLEN:LOCALNICKLEN); ch++)
262 {
263 if (!isvalidnick(*ch))
264 {
265 break;
266 }
267 }
268
269 *ch = '\0';
270
271 return (ch - nick);
272 }
273
274
275 /*
276 ** canonize
277 **
278 ** reduce a string of duplicate list entries to contain only the unique
279 ** items. Unavoidably O(n^2).
280 */
canonize(char * buffer)281 char *canonize(char *buffer)
282 {
283 static char cbuf[BUFSIZ];
284 Reg char *s, *t, *cp = cbuf;
285 Reg int l = 0;
286 char *p = NULL, *p2;
287
288 *cp = '\0';
289
290 for (s = strtoken(&p, buffer, ","); s; s = strtoken(&p, NULL, ","))
291 {
292 if (l)
293 {
294 for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t;
295 t = strtoken(&p2, NULL, ","))
296 if (!mycmp(s, t))
297 break;
298 else if (p2)
299 p2[-1] = ',';
300 }
301 else
302 t = NULL;
303 if (!t)
304 {
305 if (l)
306 *(cp-1) = ',';
307 else
308 l = 1;
309 (void)strcpy(cp, s);
310 if (p)
311 cp += (p - s);
312 }
313 else if (p2)
314 p2[-1] = ',';
315 }
316 return cbuf;
317 }
318
319 /*
320 ** register_user
321 ** This function is called when both NICK and USER messages
322 ** have been accepted for the client, in whatever order. Only
323 ** after this the UNICK message is propagated.
324 */
325
register_user(aClient * cptr,aClient * sptr,char * nick,char * username)326 int register_user(aClient *cptr, aClient *sptr, char *nick, char *username)
327 {
328 Reg aConfItem *aconf;
329 aClient *acptr;
330 anUser *user = sptr->user;
331 char *parv[3];
332 #ifndef NO_PREFIX
333 char prefix;
334 #endif
335 int i;
336 #ifdef XLINE
337 static char savedusername[USERLEN+1];
338
339 strncpyzt(savedusername, username, USERLEN+1);
340 #endif
341
342 user->last = timeofday;
343 parv[0] = sptr->name;
344 parv[1] = parv[2] = NULL;
345
346 if (MyConnect(sptr))
347 {
348 char *reason = NULL;
349 #ifdef RESTRICT_USERNAMES
350 char *lbuf = NULL;
351 #endif
352 #if defined(USE_IAUTH)
353 static time_t last = 0;
354 static u_int count = 0;
355 #endif
356 #ifdef XLINE
357 aConfItem *xtmp;
358
359 /* Just for clarification, so there's less confusion:
360 X-lines read from config have their fields stored
361 in aConf in the following fields:
362 host, passwd, name, name2, name3, source_ip.
363 (see s_conf.c/initconf(), look for XLINE);
364 these are used to check against USER and NICK
365 commands parameters during registration:
366 USER 1st 2nd 3rd :4th
367 NICK 5th
368 additionally user ip and/or hostname are
369 being matched against X-line last field
370 (conveniently kept in aconf->source_ip). --B. */
371
372 for (xtmp = conf; xtmp; xtmp = xtmp->next)
373 {
374 if (xtmp->status != CONF_XLINE)
375 continue;
376 if (!BadPtr(xtmp->host) &&
377 match(xtmp->host, username))
378 continue;
379 if (!BadPtr(xtmp->passwd) &&
380 match(xtmp->passwd, sptr->user2))
381 continue;
382 if (!BadPtr(xtmp->name) &&
383 match(xtmp->name, sptr->user3))
384 continue;
385 if (!BadPtr(xtmp->name2) &&
386 match(xtmp->name2, sptr->info))
387 continue;
388 if (!BadPtr(xtmp->name3) &&
389 match(xtmp->name3, nick))
390 continue;
391 if (!BadPtr(xtmp->source_ip) &&
392 (match(xtmp->source_ip, (sptr->hostp ?
393 sptr->hostp->h_name : sptr->sockhost)) &&
394 match(xtmp->source_ip, sptr->user->sip) &&
395 strchr(xtmp->source_ip, '/') &&
396 match_ipmask(xtmp->source_ip, sptr, 0)))
397 continue;
398 SetXlined(sptr);
399 break;
400 }
401
402 if (IsXlined(sptr))
403 {
404 sptr->exitc = EXITC_XLINE;
405 return exit_client(cptr, sptr, &me,
406 XLINE_EXIT_REASON);
407 }
408 #endif
409
410 #if defined(USE_IAUTH)
411 if (iauth_options & XOPT_EARLYPARSE && DoingXAuth(cptr))
412 {
413 cptr->flags |= FLAGS_WXAUTH;
414 /* fool check_pings() and give iauth more time! */
415 cptr->firsttime = timeofday;
416 cptr->lasttime = timeofday;
417 strncpyzt(sptr->user->username, username, USERLEN+1);
418 if (sptr->passwd[0])
419 sendto_iauth("%d P %s", sptr->fd, sptr->passwd);
420 sendto_iauth("%d U %s", sptr->fd, sptr->user->username);
421 return 1;
422 }
423 if (!DoneXAuth(sptr) && (iauth_options & XOPT_REQUIRED))
424 {
425 if (iauth_options & XOPT_NOTIMEOUT)
426 {
427 count += 1;
428 if (timeofday - last > 300)
429 {
430 sendto_flag(SCH_AUTH,
431 "iauth may be not running! (refusing new user connections)");
432 last = timeofday;
433 }
434 sptr->exitc = EXITC_AUTHFAIL;
435 }
436 else
437 sptr->exitc = EXITC_AUTHTOUT;
438 return exit_client(cptr, cptr, &me,
439 "Authentication failure! - no iauth?");
440 }
441 if (timeofday - last > 300 && count)
442 {
443 sendto_flag(SCH_AUTH, "%d users rejected.", count);
444 count = 0;
445 }
446
447 /* this should not be needed, but there's a bug.. -kalt */
448 /* haven't seen any notice like this, ever.. no bug no more? */
449 if (*cptr->username == '\0')
450 {
451 sendto_flag(SCH_AUTH,
452 "Ouch! Null username for %s (%d %X)",
453 get_client_name(cptr, TRUE), cptr->fd,
454 cptr->flags);
455 sendto_iauth("%d E Null username [%s] %X", cptr->fd,
456 get_client_name(cptr, TRUE), cptr->flags);
457 return exit_client(cptr, sptr, &me,
458 "Fatal Bug - Try Again");
459 }
460 #endif
461 #ifdef RESTRICT_USERNAMES
462 /*
463 ** Do not allow special chars in the username.
464 */
465 if ((sptr->flags & FLAGS_GOTID) &&
466 ! (*sptr->username == '-' ||
467 index(sptr->username, '@')))
468 {
469 /* got ident and it is not OTHER
470 * (which could be encrypted), so check
471 * this one for validity */
472 lbuf = sptr->username;
473 }
474 else
475 {
476 /* either no ident or ident OTHER */
477 lbuf = username;
478 }
479 if (!isvalidusername(lbuf))
480 {
481 ircstp->is_ref++;
482 sendto_flag(SCH_LOCAL, "Invalid username: %s@%s.",
483 lbuf, sptr->sockhost);
484 sptr->exitc = EXITC_REF;
485 return exit_client(cptr, sptr, &me, "Invalid username");
486 }
487 #endif
488 /*
489 ** the following insanity used to be after check_client()
490 ** but check_client()->attach_Iline() now needs to know the
491 ** username for global u@h limits.
492 ** moving this shit here shouldn't be a problem. -krys
493 ** what a piece of $#@!.. restricted can only be known
494 ** *after* attach_Iline(), so it matters and I have to move
495 ** come of it back below. so global u@h limits really suck.
496 */
497 #ifndef NO_PREFIX
498 /*
499 ** ident is fun.. ahem
500 ** prefixes used:
501 ** none I line with ident
502 ** ^ I line with OTHER type ident
503 ** ~ I line, no ident
504 ** + i line with ident
505 ** = i line with OTHER type ident
506 ** - i line, no ident
507 */
508 if (!(sptr->flags & FLAGS_GOTID))
509 prefix = '~';
510 else
511 if (*sptr->username == '-' ||
512 index(sptr->username, '@'))
513 prefix = '^';
514 else
515 prefix = '\0';
516
517 /* OTHER type idents have '-' prefix (from s_auth.c), */
518 /* and they are not supposed to be used as userid (rfc1413) */
519 /* @ isn't valid in usernames (m_user()) */
520 if (sptr->flags & FLAGS_GOTID && *sptr->username != '-' &&
521 index(sptr->username, '@') == NULL)
522 strncpyzt(buf2, sptr->username, USERLEN+1);
523 else /* No ident, or unusable ident string */
524 /* because username may point to user->username */
525 strncpyzt(buf2, username, USERLEN+1);
526
527 if (prefix)
528 {
529 *user->username = prefix;
530 strncpy(&user->username[1], buf2, USERLEN);
531 }
532 else
533 strncpy(user->username, buf2, USERLEN+1);
534 user->username[USERLEN] = '\0';
535 /* eos */
536 #else
537 strncpyzt(user->username, username, USERLEN+1);
538 #endif
539
540 if (sptr->exitc == EXITC_AREF || sptr->exitc == EXITC_AREFQ)
541 {
542 if (sptr->exitc == EXITC_AREF)
543 sendto_flag(SCH_LOCAL,
544 "Denied connection from %s.",
545 get_client_host(sptr));
546 return exit_client(cptr, cptr, &me,
547 sptr->reason ? sptr->reason : "Denied access");
548 }
549 if ((i = check_client(sptr)))
550 {
551 struct msg_set { char shortm; char *longm; };
552 #define EXIT_MSG_COUNT 8
553 static struct msg_set exit_msg[EXIT_MSG_COUNT] = {
554 { EXITC_BADPASS, "Bad password" },
555 { EXITC_GUHMAX, "Too many user connections (global)" },
556 { EXITC_GHMAX, "Too many host connections (global)" },
557 { EXITC_LUHMAX, "Too many user connections (local)" },
558 { EXITC_LHMAX, "Too many host connections (local)" },
559 { EXITC_YLINEMAX, "Too many connections" },
560 { EXITC_NOILINE, "Unauthorized connection" },
561 { EXITC_FAILURE, "Connect failure" } };
562
563 if (i > -1)
564 {
565 i = -1;
566 }
567 i += EXIT_MSG_COUNT;
568 if (i > EXIT_MSG_COUNT)
569 {
570 i = EXIT_MSG_COUNT;
571 }
572 #undef EXIT_MSG_COUNT
573
574 ircstp->is_ref++;
575 sptr->exitc = exit_msg[i].shortm;
576 if (exit_msg[i].shortm != EXITC_BADPASS)
577 {
578 sendto_flag(SCH_LOCAL, "%s from %s.",
579 exit_msg[i].longm,
580 get_client_host(sptr));
581 }
582 return exit_client(cptr, cptr, &me, exit_msg[i].longm);
583 }
584 #ifndef NO_PREFIX
585 if (IsRestricted(sptr))
586 {
587 if (!(sptr->flags & FLAGS_GOTID))
588 prefix = '-';
589 else
590 if (*sptr->username == '-' ||
591 index(sptr->username, '@'))
592 prefix = '=';
593 else
594 prefix = '+';
595 *user->username = prefix;
596 strncpy(&user->username[1], buf2, USERLEN);
597 user->username[USERLEN] = '\0';
598 }
599 #endif
600
601 aconf = sptr->confs->value.aconf;
602 #ifdef UNIXPORT
603 if (IsUnixSocket(sptr))
604 {
605 strncpyzt(user->host, me.sockhost, HOSTLEN+1);
606 }
607 else
608 #endif
609 {
610 if (IsConfNoResolveMatch(aconf))
611 {
612 /* sockhost contains resolved hostname (if any),
613 * which we'll use in match_modeid to match. */
614 strncpyzt(user->host, user->sip,
615 HOSTLEN+1);
616 }
617 else
618 {
619 strncpyzt(user->host, sptr->sockhost,
620 HOSTLEN+1);
621 }
622 }
623
624 /* hmpf, why that? --B. */
625 /* so already authenticated clients don't have password
626 ** kept in ircd memory? --B. */
627 bzero(sptr->passwd, sizeof(sptr->passwd));
628 /*
629 * following block for the benefit of time-dependent K:-lines
630 * how come "time-dependant"? I don't see it. --B.
631 */
632 if (!IsKlineExempt(sptr) && find_kill(sptr, 0, &reason))
633 {
634 sendto_flag(SCH_LOCAL, "K-lined %s@%s.",
635 user->username, sptr->sockhost);
636 ircstp->is_ref++;
637 sptr->exitc = EXITC_KLINE;
638 if (reason)
639 sprintf(buf, "K-lined: %.80s", reason);
640 return exit_client(cptr, sptr, &me,
641 (reason) ? buf : "K-lined");
642 }
643 }
644 else
645 {
646 /* Received from other server in UNICK */
647 strncpyzt(user->username, username, USERLEN+1);
648 }
649
650 SetClient(sptr);
651 if (!MyConnect(sptr))
652 {
653 acptr = find_server(user->server, NULL);
654 if (acptr && acptr->from != cptr)
655 {
656 /* I think this is not possible anymore. --B. */
657 sendto_one(cptr, ":%s KILL %s :%s (%s != %s[%s])",
658 ME, user->uid, ME, user->server,
659 acptr->from->name, acptr->from->sockhost);
660 sptr->flags |= FLAGS_KILLED;
661 return exit_client(cptr, sptr, &me,
662 "UNICK server wrong direction");
663 }
664 send_umode(NULL, sptr, 0, SEND_UMODES, buf);
665 }
666 /* below !MyConnect, as it can remove user */
667 if (IsInvisible(sptr)) /* Can be initialized in m_user() */
668 {
669 istat.is_user[1]++; /* Local and server defaults +i */
670 user->servp->usercnt[1]++;
671 }
672 else
673 {
674 user->servp->usercnt[0]++;
675 istat.is_user[0]++;
676 }
677
678 check_split();
679
680 if ((istat.is_user[1] + istat.is_user[0]) > istat.is_m_users)
681 {
682
683 istat.is_m_users = istat.is_user[1] + istat.is_user[0];
684 if (timeofday - istat.is_m_users_t >= CLCHSEC)
685 {
686 sendto_flag(SCH_NOTICE,
687 "New highest global client connection: %d",
688 istat.is_m_users);
689 istat.is_m_users_t = timeofday;
690 }
691 }
692
693 if (MyConnect(sptr))
694 {
695 char **isup;
696
697 istat.is_unknown--;
698 istat.is_myclnt++;
699 if (istat.is_myclnt > istat.is_m_myclnt)
700 {
701
702 istat.is_m_myclnt = istat.is_myclnt;
703 if (timeofday - istat.is_m_myclnt_t >= CLCHSEC)
704 {
705 sendto_flag(SCH_NOTICE,
706 "New highest local client "
707 "connection: %d", istat.is_m_myclnt);
708 istat.is_m_myclnt_t = timeofday;
709 }
710 }
711 if (istat.is_myclnt % CLCHNO == 0 &&
712 istat.is_myclnt != istat.is_l_myclnt)
713 {
714 sendto_flag(SCH_NOTICE,
715 "Local %screase from %d to %d clients "
716 "in %d seconds",
717 istat.is_myclnt>istat.is_l_myclnt?"in":"de",
718 istat.is_l_myclnt, istat.is_myclnt,
719 timeofday - istat.is_l_myclnt_t);
720 istat.is_l_myclnt_t = timeofday;
721 istat.is_l_myclnt = istat.is_myclnt;
722 }
723 strcpy(sptr->user->uid, next_uid());
724 if (nick[0] == '0' && nick[1] == '\0')
725 {
726 strncpyzt(nick, sptr->user->uid, UIDLEN + 1);
727 (void)strcpy(sptr->name, nick);
728 (void)add_to_client_hash_table(nick, sptr);
729 }
730 # if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_CONN)
731 sendto_flag(SCH_CLIENT, "%s %s %s %s CONN %s"
732 # if (CLIENTS_CHANNEL_LEVEL & CCL_CONNINFO)
733 # ifdef XLINE
734 " %s %s %s"
735 # endif
736 " :%s"
737 # endif
738 , user->uid, nick, user->username,
739 user->host, user->sip
740 # if (CLIENTS_CHANNEL_LEVEL & CCL_CONNINFO)
741 # ifdef XLINE
742 , savedusername, sptr->user2, sptr->user3
743 # endif
744 , sptr->info
745 # endif
746 );
747 #endif
748 sprintf(buf, "%s!%s@%s", nick, user->username, user->host);
749 add_to_uid_hash_table(sptr->user->uid, sptr);
750 sptr->exitc = EXITC_REG;
751 sendto_one(sptr, replies[RPL_WELCOME], ME, BadTo(nick), buf);
752 /* This is a duplicate of the NOTICE but see below...*/
753 sendto_one(sptr, replies[RPL_YOURHOST], ME, BadTo(nick),
754 get_client_name(&me, FALSE), version);
755 sendto_one(sptr, replies[RPL_CREATED], ME, BadTo(nick), creation);
756 sendto_one(sptr, replies[RPL_MYINFO], ME, BadTo(parv[0]),
757 ME, version);
758
759 isup = isupport;
760 while (*isup)
761 {
762 sendto_one(sptr,replies[RPL_ISUPPORT], ME,
763 BadTo(parv[0]), *isup);
764 isup++;
765 }
766
767 sendto_one(sptr, replies[RPL_YOURID], ME, BadTo(parv[0]),
768 sptr->user->uid);
769 (void)m_lusers(sptr, sptr, 1, parv);
770 (void)m_motd(sptr, sptr, 1, parv);
771 if (IsRestricted(sptr))
772 sendto_one(sptr, replies[ERR_RESTRICTED], ME, BadTo(nick));
773 if (IsConfNoResolve(sptr->confs->value.aconf))
774 {
775 sendto_one(sptr, ":%s NOTICE %s :Due to an administrative"
776 " decision, your hostname is not shown.",
777 ME, nick);
778 }
779 else if (IsConfNoResolveMatch(sptr->confs->value.aconf))
780 {
781 sendto_one(sptr, ":%s NOTICE %s :Due to an administrative"
782 " decision, your hostname is not shown,"
783 " but still matches channel MODEs.",
784 ME, nick);
785 }
786 send_umode(sptr, sptr, 0, ALL_UMODES, buf);
787 nextping = timeofday;
788
789 #ifdef SPLIT_CONNECT_NOTICE
790 if (IsSplit())
791 {
792 sendto_one(sptr, ":%s NOTICE %s :%s", ME, nick,
793 SPLIT_CONNECT_NOTICE);
794 }
795 #endif
796 }
797
798 for (i = fdas.highest; i >= 0; i--)
799 {
800 /* Find my leaf servers and feed the new client to them */
801 if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
802 acptr == cptr || IsMe(acptr))
803 {
804 continue;
805 }
806 sendto_one(acptr,
807 ":%s UNICK %s %s %s %s %s %s :%s",
808 user->servp->sid, nick, user->uid,
809 user->username, user->host, user->sip,
810 (*buf) ? buf : "+", sptr->info);
811 } /* for(my-leaf-servers) */
812 #ifdef USE_SERVICES
813 #if 0
814 check_services_butone(SERVICE_WANT_NICK, user->servp, NULL,
815 "NICK %s :%d", nick, sptr->hopcount+1);
816 check_services_butone(SERVICE_WANT_USER, user->servp, sptr,
817 ":%s USER %s %s %s :%s", nick, user->username,
818 user->host, user->server, sptr->info);
819 if (MyConnect(sptr)) /* all modes about local users */
820 send_umode(NULL, sptr, 0, ALL_UMODES, buf);
821 check_services_butone(SERVICE_WANT_UMODE, user->servp, sptr,
822 ":%s MODE %s :%s", nick, nick, buf);
823 #endif
824 if (MyConnect(sptr)) /* all modes about local users */
825 send_umode(NULL, sptr, 0, ALL_UMODES, buf);
826 check_services_num(sptr, buf);
827 #endif
828 #ifdef USE_HOSTHASH
829 add_to_hostname_hash_table(user->host, user);
830 #endif
831 #ifdef USE_IPHASH
832 add_to_ip_hash_table(user->sip, user);
833 #endif
834 return 1;
835 }
836
837 /*
838 ** m_nick
839 ** parv[0] = sender prefix
840 ** parv[1] = nickname
841 */
m_nick(aClient * cptr,aClient * sptr,int parc,char * parv[])842 int m_nick(aClient *cptr, aClient *sptr, int parc, char *parv[])
843 {
844 aClient *acptr;
845 int delayed = 0;
846 char nick[NICKLEN+2], *user, *host;
847 Link *lp = NULL;
848 int allowednicklen;
849
850 if (MyConnect(cptr) && IsUnknown(cptr) &&
851 IsConfServeronly(cptr->acpt->confs->value.aconf))
852 {
853 sendto_flag(SCH_LOCAL, "User connection to server-only P-line "
854 "from %s", get_client_host(cptr));
855 find_bounce(cptr, -1, -1);
856 return exit_client(cptr, cptr, &me, "Server only port");
857 }
858 if (IsService(sptr))
859 {
860 sendto_one(sptr, replies[ERR_ALREADYREGISTRED], ME, BadTo(parv[0]));
861 return 1;
862 }
863
864 /* local clients' nick size can be LOCALNICKLEN max */
865 allowednicklen = MyConnect(sptr) ? LOCALNICKLEN : NICKLEN;
866 strncpyzt(nick, parv[1], allowednicklen + 1);
867
868 if (IsServer(cptr))
869 {
870 if (parc != 2)
871 {
872 char buf[BUFSIZE];
873 int k;
874
875 badparamcountkills:
876 sendto_flag(SCH_NOTICE,
877 "Bad NICK param count (%d) for %s from %s via %s",
878 parc, parv[1], sptr->name,
879 get_client_name(cptr, FALSE));
880 buf[0] = '\0';
881 for (k = 1; k < parc; k++)
882 {
883 strcat(buf, " ");
884 strcat(buf, parv[k]);
885 }
886 sendto_flag(SCH_ERROR,
887 "Bad NICK param count (%d) from %s via %s: %s NICK%s",
888 parc, sptr->name,
889 get_client_name(cptr, FALSE),
890 parv[0], buf[0] ? buf : "");
891 return 0;
892 }
893 else /* parc == 2 */
894 {
895 /* :old NICK new */
896 user = sptr->user->username;
897 host = sptr->user->host;
898 }
899 }
900 else
901 {
902 if (sptr->user)
903 {
904 user = sptr->user->username;
905 host = sptr->user->host;
906 }
907 else
908 user = host = "";
909 }
910 /* Only local unregistered clients, I hope. --B. */
911 if (MyConnect(sptr) && IsUnknown(sptr)
912 && nick[0] == '0' && nick[1] == '\0')
913 {
914 /* Allow registering with nick "0", this will be
915 ** overwritten in register_user() */
916 #ifdef DISABLE_NICK0_REGISTRATION
917 sendto_one(sptr, replies[ERR_ERRONEOUSNICKNAME], ME,
918 BadTo(parv[0]), nick);
919 return 2;
920 #else
921 goto nickkilldone;
922 #endif
923 }
924
925 if (MyPerson(sptr))
926 {
927 if (!strcmp(sptr->name, nick))
928 {
929 /*
930 ** This is just ':old NICK old' type thing.
931 ** Just forget the whole thing here. There is
932 ** no point forwarding it to anywhere.
933 */
934 return 2; /* NICK Message ignored */
935 }
936 /* "NICK 0" or "NICK UID" received */
937 if ((nick[0] == '0' && nick[1] == '\0') ||
938 !mycmp(nick, sptr->user->uid))
939 {
940 /* faster equivalent of
941 ** !strcmp(sptr->name, sptr->user->uid) */
942 if (isdigit(sptr->name[0]))
943 {
944 /* user nick is already an UID */
945 return 2; /* NICK message ignored */
946 }
947 else
948 {
949 /* user changing his nick to UID */
950 strncpyzt(nick, sptr->user->uid, UIDLEN + 1);
951 goto nickkilldone;
952 }
953 }
954 }
955 if (IsServer(cptr) && isdigit(nick[0])
956 && !strncasecmp(me.serv->sid, nick, SIDLEN))
957 {
958 /* Remote server send us remote user changing his nick
959 ** to uid-like with our! sid. Burn the bastard. --B. */
960 sendto_flag(SCH_KILL, "Bad SID Nick Prefix: %s From: %s %s",
961 parv[1], parv[0],
962 get_client_name(cptr, FALSE));
963 sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s] != %s)",
964 me.name, sptr->user->uid, me.name,
965 sptr->name, sptr->from->name,
966 get_client_name(cptr, TRUE));
967 sptr->flags |= FLAGS_KILLED;
968 (void) exit_client(NULL, sptr, &me, "Fake SID Nick Prefix");
969 return exit_client(NULL, cptr, &me, "Fake SID Nick Prefix");
970 }
971 /*
972 * if do_nick_name() returns a null name OR if the server sent a nick
973 * name and do_nick_name() changed it in some way (due to rules of nick
974 * creation) then reject it. If from a server and we reject it,
975 * we have to KILL it. -avalon 4/4/92
976 */
977 if (do_nick_name(nick, IsServer(cptr)) == 0 ||
978 strncmp(nick, parv[1], allowednicklen))
979 {
980 sendto_one(sptr, replies[ERR_ERRONEOUSNICKNAME], ME, BadTo(parv[0]),
981 parv[1]);
982
983 if (IsServer(cptr))
984 {
985 ircstp->is_kill++;
986 sendto_flag(SCH_KILL, "Bad Nick: %s From: %s %s",
987 parv[1], parv[0],
988 get_client_name(cptr, FALSE));
989 if (sptr != cptr && sptr->user) /* bad nick change */
990 {
991 sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])",
992 ME, sptr->user->uid, ME, parv[1],
993 nick, cptr->name);
994 sendto_serv_butone(cptr,
995 ":%s KILL %s :%s (%s <- %s!%s@%s)",
996 ME, sptr->user->uid, ME,
997 get_client_name(cptr, FALSE),
998 parv[0], user, host);
999 sptr->flags |= FLAGS_KILLED;
1000 return exit_client(cptr,sptr,&me,"BadNick");
1001 }
1002 }
1003 return 2;
1004 }
1005
1006 if (!(acptr = find_client(nick, NULL)))
1007 {
1008 aClient *acptr2;
1009
1010 if (IsServer(cptr) || !(bootopt & BOOT_PROT))
1011 goto nickkilldone;
1012 if ((acptr2 = get_history(nick, (long)(KILLCHASETIMELIMIT))) &&
1013 !MyConnect(acptr2))
1014 /*
1015 ** Lock nick for KCTL so one cannot nick collide
1016 ** (due to kill chase) people who recently changed
1017 ** their nicks. --Beeth
1018 */
1019 delayed = 1;
1020 else
1021 /*
1022 ** Let ND work
1023 */
1024 delayed = find_history(nick, (long)(DELAYCHASETIMELIMIT));
1025 if (!delayed)
1026 goto nickkilldone; /* No collisions, all clear... */
1027 }
1028 /*
1029 ** If acptr == sptr, then we have a client doing a nick
1030 ** change between *equivalent* nicknames as far as server
1031 ** is concerned (user is changing the case of his/her
1032 ** nickname or somesuch)
1033 */
1034 if (acptr == sptr)
1035 {
1036 /*
1037 ** Allows change of case in his/her nick
1038 */
1039 goto nickkilldone; /* -- go and process change */
1040 }
1041 /*
1042 ** Note: From this point forward it can be assumed that
1043 ** acptr != sptr (points to different client structures).
1044 */
1045 /*
1046 ** If the older one is "non-person", the new entry is just
1047 ** allowed to overwrite it. Just silently drop non-person,
1048 ** and proceed with the nick. This should take care of the
1049 ** "dormant nick" way of generating collisions...
1050 */
1051 if (acptr && IsUnknown(acptr) && MyConnect(acptr))
1052 {
1053 (void) exit_client(acptr, acptr, &me, "Overridden");
1054 goto nickkilldone;
1055 }
1056 /*
1057 ** Decide, we really have a nick collision and deal with it
1058 */
1059 if (!IsServer(cptr))
1060 {
1061 /*
1062 ** NICK is coming from local client connection. Just
1063 ** send error reply and ignore the command.
1064 */
1065 sendto_one(sptr, replies[(delayed) ? ERR_UNAVAILRESOURCE
1066 : ERR_NICKNAMEINUSE],
1067 ME, BadTo(parv[0]), nick);
1068 return 2; /* NICK message ignored */
1069 }
1070 /*
1071 ** NICK was coming from a server connection. Means that the same
1072 ** nick is registered for different users by different server.
1073 ** This is either a race condition (two users coming online about
1074 ** same time, or net reconnecting) or just two net fragments becoming
1075 ** joined and having same nicks in use. We cannot have TWO users with
1076 ** same nick--purge this NICK from the system with a KILL... >;)
1077 **
1078 ** Since 2.11, we SAVE both users, not KILL.
1079 */
1080
1081 /*
1082 ** This seemingly obscure test (sptr == cptr) differentiates
1083 ** between "NICK new" (TRUE) and ":old NICK new" (FALSE) forms.
1084 */
1085 if (sptr == cptr)
1086 {
1087 /* 2.11+ do not introduce clients with NICK. --B. */
1088 goto badparamcountkills;
1089 }
1090
1091 /*
1092 ** Since it's not a new client, it must have an UID here,
1093 ** so SAVE them both.
1094 */
1095 /* assert(sptr->user!=NULL); assert(acptr->user!=NULL); */
1096 {
1097 char path[BUFSIZE];
1098
1099 /* Save acptr */
1100 sprintf(path, "(%s@%s[%s](%s) <- %s@%s[%s])",
1101 acptr->user->username, acptr->user->host,
1102 acptr->from->name, acptr->name, user, host, cptr->name);
1103 save_user(NULL, acptr, path);
1104
1105 /* Save sptr */
1106 sprintf(path, "(%s@%s[%s] <- %s@%s[%s](%s))",
1107 acptr->user->username, acptr->user->host,
1108 acptr->from->name, user, host, cptr->name, sptr->name);
1109 save_user(NULL, sptr, path);
1110
1111 /* Everything is done */
1112 ircstp->is_save++;
1113 return 2;
1114 }
1115
1116 nickkilldone:
1117 if (IsServer(sptr))
1118 {
1119 /* 2.11+ do not introduce clients with NICK. --B. */
1120 goto badparamcountkills;
1121 }
1122 else if (sptr->name[0]) /* NICK received before, changing */
1123 {
1124 if (MyConnect(sptr))
1125 {
1126 if (!IsPerson(sptr)) /* Unregistered client */
1127 return 2; /* Ignore new NICKs */
1128 /*
1129 ** Restricted clients cannot change nicks
1130 ** with exception of changing nick from SAVEd UID.
1131 ** We could check for this earlier, so we would not
1132 ** do all those checks, just return error. --Beeth
1133 */
1134 if (IsRestricted(sptr) && !isdigit(*parv[0]))
1135 {
1136 sendto_one(sptr, replies[ERR_RESTRICTED],
1137 ME, BadTo(parv[0]));
1138 return 2;
1139 }
1140 /* Can the user speak on all channels? */
1141 for (lp = sptr->user->channel; lp; lp = lp->next)
1142 if (can_send(sptr, lp->value.chptr) &&
1143 !IsQuiet(lp->value.chptr))
1144 break;
1145 /* If (lp), we give bigger penalty at the end. */
1146 #ifdef DISABLE_NICKCHANGE_WHEN_BANNED
1147 if (lp)
1148 {
1149 sendto_one(sptr, replies[ERR_CANNOTSENDTOCHAN],
1150 ME, BadTo(parv[0]),
1151 lp->value.chptr->chname);
1152 return 2;
1153 }
1154 #endif
1155 }
1156 /*
1157 ** Client just changing his/her nick. If he/she is
1158 ** on a channel, send note of change to all clients
1159 ** on that channel. Propagate notice to other servers.
1160 */
1161 sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
1162 #if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_NICK)
1163 if (MyConnect(sptr))
1164 sendto_flag(SCH_CLIENT, "%s %s %s %s NICK %s",
1165 sptr->user->uid, parv[0],
1166 sptr->user->username, sptr->user->host, nick);
1167 #endif
1168 if (sptr->user) /* should always be true.. */
1169 {
1170 add_history(sptr, sptr);
1171 #ifdef USE_SERVICES
1172 check_services_butone(SERVICE_WANT_NICK,
1173 sptr->user->servp, sptr,
1174 ":%s NICK :%s", parv[0], nick);
1175 #endif
1176 }
1177 else
1178 sendto_flag(SCH_NOTICE,
1179 "Illegal NICK change: %s -> %s from %s",
1180 parv[0], nick, get_client_name(cptr,TRUE));
1181 sendto_serv_butone(cptr, ":%s NICK :%s", sptr->user->uid, nick);
1182 if (sptr->name[0])
1183 (void)del_from_client_hash_table(sptr->name, sptr);
1184 (void)strcpy(sptr->name, nick);
1185 }
1186 else
1187 {
1188 /* Client setting NICK the first time */
1189
1190 /* This had to be copied here to avoid problems.. */
1191 (void)strcpy(sptr->name, nick);
1192 if (sptr->user)
1193 {
1194 /*
1195 ** USER already received, now we have NICK.
1196 ** *NOTE* For servers "NICK" *must* precede the
1197 ** user message (giving USER before NICK is possible
1198 ** only for local client connection!). register_user
1199 ** may reject the client and call exit_client for it
1200 ** --must test this and exit m_nick too!!!
1201 */
1202 if (register_user(cptr, sptr, nick,
1203 sptr->user->username)
1204 == FLUSH_BUFFER)
1205 return FLUSH_BUFFER;
1206 }
1207 /* If we returned from register_user, then the user registered
1208 ** and sptr->name is not "0" anymore; add_to_client_hash_table
1209 ** (few lines down) would be called second time for that client
1210 ** because register_user does that for "NICK 0" after copying
1211 ** UID onto client nick.
1212 ** OTOH, if no USER was yet received, isdigit is true only for
1213 ** client trying to register with "NICK 0". As we would have
1214 ** returned without adding "0" to client hash table anyway,
1215 ** we can safely return here. --B. */
1216 if (isdigit(sptr->name[0]))
1217 {
1218 return 3;
1219 }
1220 }
1221 /* Registered client doing "NICK 0" already has UID in sptr->name.
1222 ** If sptr->name is "0" here, it means there was no "USER" (thanks
1223 ** to that fiction's "isdigit" check above after register_user), so
1224 ** do not add_to_client_hash_table with nick "0", let register_user
1225 ** fill in UID first and add that to client hash table. --B. */
1226 if (sptr->name[0] != '0' || sptr->name[1] != '\0')
1227 {
1228 /* Finally set new nick name. */
1229 (void)add_to_client_hash_table(nick, sptr);
1230 }
1231 if (lp)
1232 return 15;
1233 else
1234 return 3;
1235 }
1236
1237 /*
1238 ** m_unick
1239 ** parv[0] = sender prefix
1240 ** parv[1] = nickname
1241 ** parv[2] = uid
1242 ** parv[3] = username (login name, account)
1243 ** parv[4] = client host name
1244 ** parv[5] = client ip
1245 ** parv[6] = users mode
1246 ** parv[7] = users real name info
1247 */
m_unick(aClient * cptr,aClient * sptr,int parc,char * parv[])1248 int m_unick(aClient *cptr, aClient *sptr, int parc, char *parv[])
1249 {
1250 aClient *acptr;
1251 char *uid, nick[NICKLEN+2], *user, *host, *realname;
1252
1253 strncpyzt(nick, parv[1], NICKLEN+1);
1254 uid = parv[2];
1255 user = parv[3];
1256 host = parv[4];
1257 realname = parv[7];
1258
1259 /*
1260 * if do_nick_name() returns a null name OR if the server sent a nick
1261 * name and do_nick_name() changed it in some way (due to rules of nick
1262 * creation) then reject it. If from a server and we reject it,
1263 * and KILL it. -avalon 4/4/92
1264 */
1265 if (do_nick_name(nick, 1) == 0 || strcmp(nick, parv[1]))
1266 {
1267 sendto_one(sptr, replies[ERR_ERRONEOUSNICKNAME], ME, BadTo(parv[0]),
1268 parv[1]);
1269
1270 ircstp->is_kill++;
1271 sendto_flag(SCH_KILL, "Bad UNick: %s From: %s %s", parv[1],
1272 parv[0], get_client_name(cptr, FALSE));
1273 sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])", ME, uid, ME,
1274 parv[1], nick, cptr->name);
1275 return 2;
1276 }
1277
1278 /*
1279 ** Check validity of UID.
1280 */
1281 if (!check_uid(uid, sptr->serv->sid))
1282 {
1283 /* This is so bad, that I really don't want to deal with it! */
1284 sendto_ops_butone(NULL, ME,
1285 "Bad UID (%s) from %s",
1286 uid, get_client_name(cptr, FALSE));
1287 return exit_client(cptr, cptr, &me, "Bad UID");
1288 }
1289
1290 /*
1291 ** Check against UID collisions,
1292 ** they should never happen, but never say never.
1293 */
1294 acptr = find_uid(uid, NULL);
1295 if (acptr)
1296 {
1297 /* This is so bad, that I really don't want to deal with it! */
1298 sendto_ops_butone(NULL, ME,
1299 "UID collision for %s from %s",
1300 uid, get_client_name(cptr, FALSE));
1301 return exit_client(cptr, cptr, &me, "UID collision");
1302 }
1303
1304 /*
1305 ** Check against NICK collisions,
1306 ** and if possible save the two users.
1307 */
1308 acptr = find_client(nick, NULL);
1309 if (acptr)
1310 {
1311 /*
1312 ** If the older one is "non-person", the new entry is just
1313 ** allowed to overwrite it. Just silently drop non-person,
1314 ** and proceed with the unick.
1315 */
1316 if (IsUnknown(acptr) && MyConnect(acptr))
1317 {
1318 (void) exit_client(acptr, acptr, &me, "Overridden");
1319 }
1320 else
1321 /*
1322 ** Ouch, this new client is trying to take an already
1323 ** existing nickname..
1324 */
1325 if (*acptr->user->uid)
1326 {
1327 char path[BUFSIZE];
1328
1329 /* both users have a UID, save them */
1330
1331 /* Save the other user. Send it to all servers. */
1332 sprintf(path, "(%s@%s)%s <- (%s@%s)%s",
1333 acptr->user->username, acptr->user->host,
1334 acptr->user->server, user, host, cptr->name);
1335 save_user(NULL, acptr, path);
1336
1337 /*
1338 ** We need to send a SAVE for the new user back.
1339 ** It isn't introduced yet, so we can't just call
1340 ** save_user().
1341 */
1342 sendto_one(cptr,
1343 ":%s SAVE %s :%s (%s@%s)%s <- (%s@%s)%s",
1344 me.serv->sid, uid, ME,
1345 acptr->user->username, acptr->user->host,
1346 acptr->user->server, user, host, cptr->name);
1347
1348 /* Just introduce him with the uid to the rest. */
1349 strcpy(nick, uid);
1350 ircstp->is_save++;
1351 }
1352 else
1353 {
1354 /*
1355 ** sadly, both have to be killed because:
1356 ** - we cannot rely on cptr do kill acptr
1357 ** as the new user introduced here may have changed
1358 ** nicknames before the collision happens on cptr
1359 ** - sending a kill to cptr means nick chasing will
1360 ** get to the new user introduced here.
1361 */
1362 sendto_one(acptr,
1363 replies[ERR_NICKCOLLISION], ME, BadTo(acptr->name),
1364 acptr->name, user, host);
1365 sendto_flag(SCH_KILL,
1366 "Nick collision on %s (%s@%s)%s <- (%s@%s)%s",
1367 acptr->name,
1368 (acptr->user)?acptr->user->username:"???",
1369 (acptr->user) ? acptr->user->host : "???",
1370 acptr->from->name,
1371 user, host, get_client_name(cptr, FALSE));
1372 ircstp->is_kill++;
1373 sendto_serv_butone(NULL,
1374 ":%s KILL %s :%s ((%s@%s)%s <- (%s@%s)%s)",
1375 ME, acptr->name, ME,
1376 (acptr->user) ? acptr->user->username:"???",
1377 (acptr->user) ? acptr->user->host : "???",
1378 acptr->from->name, user, host,
1379 get_client_name(cptr, FALSE));
1380 acptr->flags |= FLAGS_KILLED;
1381 return exit_client(NULL, acptr, &me, "Nick collision");
1382 }
1383 }
1384
1385 /*
1386 ** the following is copied from m_user() as we need only
1387 ** few things from it here, as we assume (should we?) it
1388 ** is all ok since UNICK can come only from other server
1389 */
1390 acptr = make_client(cptr);
1391 add_client_to_list(acptr);
1392 (void)make_user(acptr, strlen(parv[5]));
1393 /* more corrrect is this, but we don't yet have ->mask, so...
1394 acptr->user->servp = find_server_name(sptr->serv->mask->serv->snum);
1395 ... just remember to change it one day --Beeth */
1396 acptr->user->servp = sptr->serv;
1397 sptr->serv->refcnt++;
1398 acptr->user->server = find_server_string(sptr->serv->snum);
1399 if (strlen(realname) > REALLEN)
1400 {
1401 realname[REALLEN] = '\0';
1402 }
1403 acptr->info = mystrdup(realname);
1404 strncpyzt(acptr->user->username, parv[3], USERLEN+1);
1405 strncpyzt(acptr->user->host, host, sizeof(acptr->user->host));
1406 reorder_client_in_list(acptr);
1407
1408 /*
1409 ** NOTE: acptr->name has to be set *after* calling m_user();
1410 ** else it will already introduce the client which
1411 ** can't have the uid set yet.
1412 ** the extended m_nick() does things the other way around..
1413 ** I hope this will not cause trouble sometime later. -kalt
1414 ** You could do things like m_nick(), but you then you should
1415 ** stop it from making a call to register_user().
1416 */
1417 /* The nick is already checked for size, and is a local var. */
1418 strcpy(acptr->name, nick);
1419 add_to_client_hash_table(nick, acptr);
1420 /* we don't have hopcount in unick, we take it from sptr */
1421 acptr->hopcount = sptr->hopcount;
1422 /* The client is already killed if the uid is too long. */
1423 strcpy(acptr->user->uid, uid);
1424 strcpy(acptr->user->sip, parv[5]);
1425 add_to_uid_hash_table(uid, acptr);
1426 {
1427 char *pv[4];
1428
1429 pv[0] = ME;
1430 pv[1] = acptr->name;
1431 pv[2] = parv[6];
1432 pv[3] = NULL;
1433 m_umode(NULL, acptr, 3, pv);
1434 }
1435 register_user(cptr, acptr, nick, user);
1436 return 0;
1437 }
1438
1439 /*
1440 ** m_message (used in m_private() and m_notice())
1441 ** the general function to deliver MSG's between users/channels
1442 **
1443 ** parv[0] = sender prefix
1444 ** parv[1] = receiver list
1445 ** parv[2] = message text
1446 **
1447 ** massive cleanup
1448 ** rev argv 6/91
1449 **
1450 */
1451
m_message(aClient * cptr,aClient * sptr,int parc,char * parv[],int notice)1452 static int m_message(aClient *cptr, aClient *sptr, int parc,
1453 char *parv[], int notice)
1454 {
1455 Reg aClient *acptr;
1456 Reg char *s;
1457 aChannel *chptr;
1458 char *nick, *server, *p, *cmd, *user, *host;
1459 int count = 0, penalty = 0, syntax = 0;
1460
1461 cmd = notice ? "NOTICE" : "PRIVMSG";
1462
1463 if (MyConnect(sptr))
1464 parv[1] = canonize(parv[1]);
1465 for (p = NULL, nick = strtoken(&p, parv[1], ","); nick;
1466 nick = strtoken(&p, NULL, ","), penalty++)
1467 {
1468 /*
1469 ** restrict destination list to MAXPENALTY/2 recipients to
1470 ** solve SPAM problem --Yegg
1471 */
1472 if (2*penalty >= MAXPENALTY) {
1473 if (!notice)
1474 sendto_one(sptr, replies[ERR_TOOMANYTARGETS],
1475 ME, BadTo(parv[0]),
1476 "Too many",nick,"No Message Delivered");
1477 continue;
1478 }
1479 /*
1480 ** nickname addressed?
1481 */
1482 if (((IsServer(cptr) || IsService(cptr))
1483 && (acptr = find_uid(nick, NULL))) ||
1484 (acptr = find_person(nick, NULL)))
1485 {
1486 if (!notice && MyConnect(sptr) &&
1487 acptr->user && (acptr->user->flags & FLAGS_AWAY))
1488 send_away(sptr, acptr);
1489 sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
1490 parv[0], cmd, acptr->name, parv[2]);
1491 continue;
1492 }
1493 /*
1494 ** channel msg?
1495 */
1496 if ((IsPerson(sptr) || IsService(sptr) || IsServer(sptr)) &&
1497 (chptr = find_channel(nick, NullChn)))
1498 {
1499 if (can_send(sptr, chptr) == 0 || IsServer(sptr))
1500 sendto_channel_butone(cptr, sptr, chptr,
1501 ":%s %s %s :%s",
1502 parv[0], cmd, nick,
1503 parv[2]);
1504 else if (!notice)
1505 sendto_one(sptr, replies[ERR_CANNOTSENDTOCHAN],
1506 ME, BadTo(parv[0]), nick);
1507 continue;
1508 }
1509
1510 /*
1511 ** the following two cases allow masks in NOTICEs
1512 ** (for OPERs only)
1513 **
1514 ** Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
1515 **
1516 ** NOTE: 2.11 changed syntax from $/#-mask to $$/$#-mask
1517 */
1518 if (IsAnOper(sptr))
1519 {
1520 if (*nick == '$')
1521 {
1522 if (*(nick+1) == '$')
1523 {
1524 syntax = MATCH_SERVER;
1525 }
1526 else if (*(nick+1) == '#')
1527 {
1528 syntax = MATCH_HOST;
1529 }
1530 }
1531 }
1532 if (syntax)
1533 {
1534 if (!(s = (char *)rindex(nick, '.')))
1535 {
1536 sendto_one(sptr, replies[ERR_NOTOPLEVEL],
1537 ME, BadTo(parv[0]), nick);
1538 continue;
1539 }
1540 while (*++s)
1541 if (*s == '.' || *s == '*' || *s == '?')
1542 break;
1543 if (*s == '*' || *s == '?')
1544 {
1545 sendto_one(sptr, replies[ERR_WILDTOPLEVEL],
1546 ME, BadTo(parv[0]), nick);
1547 continue;
1548 }
1549 sendto_match_butone(
1550 IsServer(cptr) ? cptr : NULL,
1551 sptr, nick + 2, syntax,
1552 ":%s %s %s :%s", parv[0],
1553 cmd, nick, parv[2]);
1554 continue;
1555 } /* syntax */
1556
1557 /*
1558 ** nick!user@host addressed?
1559 */
1560 if ((user = (char *)index(nick, '!')) &&
1561 (host = (char *)index(nick, '@')))
1562 {
1563 *user = '\0';
1564 *host = '\0';
1565 if ((acptr = find_person(nick, NULL)) &&
1566 !mycmp(user+1, acptr->user->username) &&
1567 !mycmp(host+1, acptr->user->host))
1568 {
1569 sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
1570 parv[0], cmd, nick, parv[2]);
1571 *user = '!';
1572 *host = '@';
1573 continue;
1574 }
1575 *user = '!';
1576 *host = '@';
1577 }
1578
1579 /*
1580 ** user[%host]@server addressed?
1581 */
1582 if ((server = (char *)index(nick, '@')) &&
1583 (acptr = find_server(server + 1, NULL)))
1584 {
1585 /*
1586 ** Not destined for a user on me :-(
1587 */
1588 if (!IsMe(acptr))
1589 {
1590 sendto_one(acptr,":%s %s %s :%s", parv[0],
1591 cmd, nick, parv[2]);
1592 continue;
1593 }
1594 *server = '\0';
1595
1596 if ((host = (char *)index(nick, '%')))
1597 *host++ = '\0';
1598
1599 /*
1600 ** Look for users which match the destination host
1601 ** (no host == wildcard) and if one and one only is
1602 ** found connected to me, deliver message!
1603 */
1604 acptr = find_userhost(nick, host, NULL, &count);
1605 if (server)
1606 *server = '@';
1607 if (host)
1608 *--host = '%';
1609 if (acptr)
1610 {
1611 if (count == 1)
1612 sendto_prefix_one(acptr, sptr,
1613 ":%s %s %s :%s",
1614 parv[0], cmd,
1615 nick, parv[2]);
1616 else if (!notice)
1617 sendto_one(sptr, replies[ERR_TOOMANYTARGETS],
1618 ME, BadTo(parv[0]), "Duplicate", nick,
1619 "No Message Delivered");
1620 continue;
1621 }
1622 }
1623 else if ((host = (char *)index(nick, '%')))
1624 {
1625 /*
1626 ** user%host addressed?
1627 */
1628 *host++ = '\0';
1629 acptr = find_userhost(nick, host, NULL, &count);
1630 *--host = '%';
1631 if (acptr)
1632 {
1633 if (count == 1)
1634 sendto_prefix_one(acptr, sptr,
1635 ":%s %s %s :%s",
1636 parv[0], cmd,
1637 nick, parv[2]);
1638 else if (!notice)
1639 sendto_one(sptr, replies[ERR_TOOMANYTARGETS],
1640 ME, BadTo(parv[0]), "Duplicate", nick,
1641 "No Message Delivered");
1642 continue;
1643 }
1644 }
1645 if (!notice)
1646 sendto_one(sptr, replies[ERR_NOSUCHNICK], ME, BadTo(parv[0]),
1647 nick);
1648 }
1649 return penalty;
1650 }
1651
1652 /*
1653 ** m_private
1654 ** parv[0] = sender prefix
1655 ** parv[1] = receiver list
1656 ** parv[2] = message text
1657 */
1658
m_private(aClient * cptr,aClient * sptr,int parc,char * parv[])1659 int m_private(aClient *cptr, aClient *sptr, int parc, char *parv[])
1660 {
1661 return m_message(cptr, sptr, parc, parv, 0);
1662 }
1663
1664 /*
1665 ** m_notice
1666 ** parv[0] = sender prefix
1667 ** parv[1] = receiver list
1668 ** parv[2] = notice text
1669 */
1670
m_notice(aClient * cptr,aClient * sptr,int parc,char * parv[])1671 int m_notice(aClient *cptr, aClient *sptr, int parc, char *parv[])
1672 {
1673 return m_message(cptr, sptr, parc, parv, 1);
1674 }
1675
1676 /*
1677 ** who_one
1678 ** sends one RPL_WHOREPLY to sptr concerning acptr & repchan
1679 */
who_one(aClient * sptr,aClient * acptr,aChannel * repchan,Link * lp)1680 static void who_one(aClient *sptr, aClient *acptr, aChannel *repchan,
1681 Link *lp)
1682 {
1683 char status[5];
1684 int i = 0;
1685
1686 if (acptr->user->flags & FLAGS_AWAY)
1687 status[i++] = 'G';
1688 else
1689 status[i++] = 'H';
1690 if (IsAnOper(acptr))
1691 status[i++] = '*';
1692 if ((repchan != NULL) && (lp == NULL))
1693 lp = find_user_link(repchan->members, acptr);
1694 if (lp != NULL)
1695 {
1696 if (lp->flags & CHFL_CHANOP)
1697 status[i++] = '@';
1698 else if (lp->flags & CHFL_VOICE)
1699 status[i++] = '+';
1700 }
1701 status[i] = '\0';
1702 sendto_one(sptr, replies[RPL_WHOREPLY], ME, BadTo(sptr->name),
1703 (repchan) ? (repchan->chname) : "*", acptr->user->username,
1704 acptr->user->host, acptr->user->server, acptr->name,
1705 status, acptr->hopcount, acptr->user->servp->sid, acptr->info);
1706 }
1707
1708
1709 /*
1710 ** who_channel
1711 ** lists all users on a given channel
1712 */
who_channel(aClient * sptr,aChannel * chptr,int oper)1713 static void who_channel(aClient *sptr, aChannel *chptr, int oper)
1714 {
1715 Reg Link *lp;
1716 int member;
1717
1718 if (!IsAnonymous(chptr))
1719 {
1720 member = IsMember(sptr, chptr);
1721 if (member || !SecretChannel(chptr))
1722 {
1723 for (lp = chptr->members; lp; lp = lp->next)
1724 {
1725 if (oper && !IsAnOper(lp->value.cptr))
1726 {
1727 continue;
1728 }
1729 if (IsInvisible(lp->value.cptr) && !member)
1730 {
1731 continue;
1732 }
1733 who_one(sptr, lp->value.cptr, chptr, lp);
1734 }
1735 }
1736 }
1737 else if ((lp = find_user_link(chptr->members, sptr)))
1738 {
1739 who_one(sptr, lp->value.cptr, chptr, lp);
1740 }
1741 }
1742
1743 /*
1744 ** who_find
1745 ** lists all (matching) users.
1746 ** CPU intensive, but what can be done?
1747 **
1748 ** Reduced CPU load - 05/2001
1749 */
who_find(aClient * sptr,char * mask,int oper)1750 static void who_find(aClient *sptr, char *mask, int oper)
1751 {
1752 aChannel *chptr = NULL;
1753 Link *lp,*lp2;
1754 aClient *acptr;
1755
1756 /* first, show INvisible matching users on common channels */
1757 if (sptr->user) /* service can request who as well */
1758 for (lp = sptr->user->channel; lp ;lp = lp->next)
1759 {
1760 chptr = lp->value.chptr;
1761 if (IsAnonymous(chptr))
1762 continue;
1763 for (lp2 = chptr->members; lp2 ;lp2 = lp2->next)
1764 {
1765 acptr = lp2->value.cptr;
1766
1767 if (!IsInvisible(acptr)
1768 || (acptr->flags & FLAGS_HIDDEN))
1769 {
1770 continue;
1771 }
1772
1773 if (oper && !IsAnOper(acptr))
1774 {
1775 continue;
1776 }
1777
1778 /* Mark user with FLAGS_HIDDEN to prevent multiple
1779 * checking.
1780 */
1781
1782 acptr->flags |= FLAGS_HIDDEN;
1783 if (!mask ||
1784 match(mask, acptr->name) == 0 ||
1785 match(mask, acptr->user->username) == 0 ||
1786 match(mask, acptr->user->host) == 0 ||
1787 match(mask, acptr->user->server) == 0 ||
1788 match(mask, acptr->info) == 0)
1789 who_one(sptr, acptr, chptr, NULL);
1790
1791 }
1792 }
1793
1794 for (acptr = client; acptr; acptr = acptr->next)
1795 {
1796
1797 if (!IsPerson(acptr))
1798 continue;
1799
1800 /* clear the flag */
1801 if (acptr->flags & FLAGS_HIDDEN)
1802 {
1803 acptr->flags &= ~FLAGS_HIDDEN;
1804 continue;
1805 }
1806
1807 /* allow local opers to see matching clients
1808 * on _LOCAL_ server and show the user himself */
1809 if (IsInvisible(acptr) && (acptr != sptr)
1810 && !(MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
1811 )
1812 {
1813 continue;
1814 }
1815
1816 /* we wanted only opers */
1817 if (oper && !IsAnOper(acptr))
1818 {
1819 continue;
1820 }
1821
1822 /*
1823 ** This is brute force solution, not efficient...? ;(
1824 ** Show entry, if no mask or any of the fields match
1825 ** the mask. --msa
1826 */
1827 if (!mask ||
1828 match(mask, acptr->name) == 0 ||
1829 match(mask, acptr->user->username) == 0 ||
1830 match(mask, acptr->user->host) == 0 ||
1831 match(mask, acptr->user->server) == 0 ||
1832 match(mask, acptr->info) == 0)
1833 who_one(sptr, acptr, NULL, NULL);
1834 }
1835
1836 }
1837
1838
1839 /*
1840 ** m_who
1841 ** parv[0] = sender prefix
1842 ** parv[1] = nickname mask list
1843 ** parv[2] = additional selection flag, only 'o' for now.
1844 */
m_who(aClient * cptr,aClient * sptr,int parc,char * parv[])1845 int m_who(aClient *cptr, aClient *sptr, int parc, char *parv[])
1846 {
1847 aChannel *chptr;
1848 int oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */
1849 int penalty = 0;
1850 char *p, *mask, *channame;
1851
1852 if (parc < 2)
1853 {
1854 who_find(sptr, NULL, oper);
1855 sendto_one(sptr, replies[RPL_ENDOFWHO], ME, BadTo(parv[0]), "*");
1856 /* it was very CPU intensive */
1857 return MAXPENALTY;
1858 }
1859
1860 /* get rid of duplicates */
1861 parv[1] = canonize(parv[1]);
1862
1863 for (p = NULL, mask = strtoken(&p, parv[1], ",");
1864 mask && penalty <= MAXPENALTY;
1865 mask = strtoken(&p, NULL, ","))
1866 {
1867 channame = NULL;
1868 penalty += 1;
1869
1870 /* find channel user last joined, we might need it later */
1871 if (sptr->user && sptr->user->channel)
1872 channame = sptr->user->channel->value.chptr->chname;
1873
1874 if (clean_channelname(mask) == -1)
1875 /* maybe we should tell user? --B. */
1876 continue;
1877
1878 /*
1879 ** We can never have here !mask
1880 ** or *mask == '\0', since it would be equal
1881 ** to parc == 1, that is 'WHO' and/or would not
1882 ** pass through above for loop.
1883 */
1884 if (mask[1] == '\0' && mask[0] == '0')
1885 {
1886 /*
1887 ** 'WHO 0' - do who_find() later
1888 */
1889 mask = NULL;
1890 channame = NULL;
1891 }
1892 else if (mask[1] == '\0' && mask[0] == '*')
1893 {
1894 /*
1895 ** 'WHO *'
1896 ** If user was on any channel, list the one
1897 ** he joined last.
1898 */
1899 mask = NULL;
1900 }
1901 else
1902 {
1903 /*
1904 ** Try if mask was channelname and if yes, do
1905 ** who_channel, else if mask was nick, do who_one.
1906 ** Else do horrible who_find()
1907 */
1908 channame = mask;
1909 }
1910
1911 if (IsChannelName(channame))
1912 {
1913 chptr = find_channel(channame, NULL);
1914 if (chptr)
1915 {
1916 who_channel(sptr, chptr, oper);
1917 }
1918 else
1919 {
1920 /*
1921 ** 'WHO #nonexistant'.
1922 */
1923 penalty += 1;
1924 }
1925 }
1926 else
1927 {
1928 aClient *acptr = NULL;
1929
1930 if (mask)
1931 {
1932 /*
1933 ** Here mask can be NULL. It doesn't matter,
1934 ** since find_client would return NULL.
1935 ** Just saving one function call. ;)
1936 */
1937 acptr = find_client(mask, NULL);
1938 if (acptr && !IsClient(acptr))
1939 {
1940 acptr = NULL;
1941 }
1942 }
1943 if (acptr)
1944 {
1945 /* We found client, so send WHO for it */
1946 who_one(sptr, acptr, NULL, NULL);
1947 }
1948 else
1949 {
1950 /*
1951 ** All nice chances lost above.
1952 ** We must hog our server with that.
1953 */
1954
1955 /* simplify mask */
1956 (void)collapse(mask);
1957
1958 who_find(sptr, mask, oper);
1959 penalty += MAXPENALTY;
1960 }
1961 }
1962 sendto_one(sptr, replies[RPL_ENDOFWHO], ME, BadTo(parv[0]),
1963 BadPtr(mask) ? "*" : mask);
1964 }
1965 return penalty;
1966 }
1967
1968 /* send_whois() is used by m_whois() to send whois reply to sptr, for acptr */
send_whois(aClient * sptr,aClient * acptr)1969 static void send_whois(aClient *sptr, aClient *acptr)
1970 {
1971 static anUser UnknownUser =
1972 {
1973 NULL, /* channel */
1974 NULL, /* invited */
1975 NULL, /* uwas */
1976 NULL, /* away */
1977 0, /* last */
1978 1, /* refcount */
1979 0, /* joined */
1980 0, /* flags */
1981 NULL, /* servp */
1982 0, NULL, NULL, /* hashc, uhnext, bcptr */
1983 "<Unknown>", /* user */
1984 "0", /* uid */
1985 "<Unknown>", /* host */
1986 "<Unknown>", /* server */
1987 };
1988 Link *lp;
1989 anUser *user;
1990 aChannel *chptr;
1991 aClient *a2cptr;
1992 int len, mlen;
1993 char *name;
1994
1995 user = acptr->user ? acptr->user : &UnknownUser;
1996 name = (!*acptr->name) ? "?" : acptr->name;
1997
1998 a2cptr = find_server(user->server, NULL);
1999
2000 sendto_one(sptr, replies[RPL_WHOISUSER], ME, BadTo(sptr->name),
2001 name, user->username, user->host, acptr->info);
2002
2003 mlen = strlen(ME) + strlen(sptr->name) + 6 + strlen(name);
2004
2005 for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next)
2006 {
2007 chptr = lp->value.chptr;
2008 if ((!IsAnonymous(chptr) || acptr == sptr) &&
2009 ShowChannel(sptr, chptr))
2010 {
2011 if (len + strlen(chptr->chname)
2012 > (size_t) BUFSIZE - 4 - mlen)
2013 {
2014 sendto_one(sptr, ":%s %d %s %s :%s", ME,
2015 RPL_WHOISCHANNELS, sptr->name, name,
2016 buf);
2017 *buf = '\0';
2018 len = 0;
2019 }
2020 if (is_chan_op(acptr, chptr))
2021 *(buf + len++) = '@';
2022 else if (has_voice(acptr, chptr))
2023 *(buf + len++) = '+';
2024 if (len)
2025 *(buf + len) = '\0';
2026 (void)strcpy(buf + len, chptr->chname);
2027 len += strlen(chptr->chname);
2028 (void)strcat(buf + len, " ");
2029 len++;
2030 }
2031 }
2032 if (buf[0] != '\0')
2033 sendto_one(sptr, replies[RPL_WHOISCHANNELS], ME, BadTo(sptr->name), name,
2034 buf);
2035
2036 sendto_one(sptr, replies[RPL_WHOISSERVER], ME, BadTo(sptr->name),
2037 name, user->server,
2038 a2cptr ? a2cptr->info:"*Not On This Net*");
2039
2040 if (user->flags & FLAGS_AWAY)
2041 send_away(sptr, user->bcptr);
2042
2043 if (IsAnOper(acptr))
2044 sendto_one(sptr, replies[RPL_WHOISOPERATOR], ME, BadTo(sptr->name), name);
2045
2046 if (acptr->user && MyConnect(acptr))
2047 sendto_one(sptr, replies[RPL_WHOISIDLE], ME, BadTo(sptr->name),
2048 name, (long)(timeofday - user->last)
2049 #ifdef WHOIS_SIGNON_TIME
2050 , (long)acptr->firsttime
2051 #endif
2052 );
2053 }
2054
2055 /*
2056 ** m_whois
2057 ** parv[0] = sender prefix
2058 ** parv[1] = nickname masklist
2059 */
m_whois(aClient * cptr,aClient * sptr,int parc,char * parv[])2060 int m_whois(aClient *cptr, aClient *sptr, int parc, char *parv[])
2061 {
2062 Link *lp;
2063 aClient *acptr;
2064 aChannel *chptr;
2065 char *nick, *tmp, *tmp2;
2066 char *p = NULL;
2067 int found = 0;
2068
2069 if (parc < 2)
2070 {
2071 sendto_one(sptr, replies[ERR_NONICKNAMEGIVEN], ME, BadTo(parv[0]));
2072 return 1;
2073 }
2074
2075 if (parc > 2)
2076 {
2077 if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) !=
2078 HUNTED_ISME)
2079 return 3;
2080 parv[1] = parv[2];
2081 }
2082
2083 tmp = mystrdup(parv[1]);
2084
2085 for (tmp2 = canonize(tmp); (nick = strtoken(&p, tmp2, ","));
2086 tmp2 = NULL)
2087 {
2088 int invis, showperson, member, wilds;
2089
2090 found &= 0x0f; /* high/boolean, low/counter */
2091 (void)collapse(nick);
2092 wilds = (index(nick, '?') || index(nick, '*'));
2093 /*
2094 * We're no longer allowing remote users to generate
2095 * requests with wildcard, nor local users with more
2096 * than one wildcard target per command.
2097 * Max 3 targets per command allowed.
2098 */
2099 if ((wilds && (!MyConnect(sptr) || p)) || found++ > 3)
2100 break;
2101
2102 if (!wilds)
2103 {
2104 acptr = hash_find_client(nick, (aClient *)NULL);
2105 if (!acptr || !IsPerson(acptr))
2106 sendto_one(sptr,
2107 replies[ERR_NOSUCHNICK], ME, BadTo(parv[0]),
2108 nick);
2109 else
2110 send_whois(sptr, acptr);
2111 continue;
2112 }
2113
2114 for (acptr = client; (acptr = next_client(acptr, nick));
2115 acptr = acptr->next)
2116 {
2117 if (IsServer(acptr) || IsService(acptr))
2118 continue;
2119 /*
2120 * I'm always last :-) and acptr->next == NULL!!
2121 */
2122 if (IsMe(acptr))
2123 break;
2124 /*
2125 * 'Rules' established for sending a WHOIS reply:
2126 * - if wildcards are being used don't send a reply if
2127 * the querier isnt any common channels and the
2128 * client in question is invisible and wildcards are
2129 * in use (allow exact matches only);
2130 * - only send replies about common or public channels
2131 * the target user(s) are on;
2132 */
2133 invis = (acptr->user) ?
2134 (acptr->user->flags & FLAGS_INVISIBLE) : 0;
2135 member = (acptr->user && acptr->user->channel) ? 1 : 0;
2136 showperson = (wilds && !invis && !member) || !wilds;
2137 for (lp = (acptr->user) ? acptr->user->channel : NULL;
2138 lp; lp = lp->next)
2139 {
2140 chptr = lp->value.chptr;
2141 if (IsAnonymous(chptr))
2142 continue;
2143 member = IsMember(sptr, chptr);
2144 if (invis && !member)
2145 continue;
2146 if (member || (!invis && PubChannel(chptr)))
2147 {
2148 showperson = 1;
2149 break;
2150 }
2151 if (!invis && HiddenChannel(chptr) &&
2152 !SecretChannel(chptr))
2153 showperson = 1;
2154 }
2155 if (!showperson)
2156 continue;
2157
2158 found |= 0x10;
2159
2160 send_whois(sptr, acptr);
2161 }
2162 if (!(found & 0x10))
2163 {
2164 if (strlen(nick) > (size_t) NICKLEN)
2165 nick[NICKLEN] = '\0';
2166 sendto_one(sptr, replies[ERR_NOSUCHNICK], ME, BadTo(parv[0]),
2167 nick);
2168 }
2169 if (p)
2170 p[-1] = ',';
2171 }
2172 sendto_one(sptr, replies[RPL_ENDOFWHOIS], ME, BadTo(parv[0]), parv[1]);
2173
2174 MyFree(tmp);
2175
2176 return 2;
2177 }
2178
2179 /*
2180 ** m_user
2181 ** parv[0] = sender prefix
2182 ** parv[1] = username (login name, account)
2183 ** parv[2] = user modes
2184 ** parv[3] = unused
2185 ** parv[4] = real name info
2186 **
2187 ** NOTE: As of 2.11.1 we no longer call m_user() internally. --B.
2188 */
m_user(aClient * cptr,aClient * sptr,int parc,char * parv[])2189 int m_user(aClient *cptr, aClient *sptr, int parc, char *parv[])
2190 {
2191 #define UFLAGS (FLAGS_INVISIBLE|FLAGS_WALLOP|FLAGS_RESTRICT)
2192 struct umodes_arr_s
2193 {
2194 char umode;
2195 int flag;
2196 } umodes_arr[] =
2197 { {'i', FLAGS_INVISIBLE},
2198 {'r', FLAGS_RESTRICT},
2199 {'w', FLAGS_WALLOP},
2200 {'\0', 0}
2201 };
2202
2203 char *username, *umodes, *server, *realname;
2204 anUser *user;
2205 char ipbuf[BUFSIZE];
2206 int what,i;
2207 char *s;
2208
2209 if (MyConnect(cptr) && IsUnknown(cptr) &&
2210 IsConfServeronly(cptr->acpt->confs->value.aconf))
2211 {
2212 sendto_flag(SCH_LOCAL, "User connection to server-only P-line "
2213 "from %s", get_client_host(cptr));
2214 find_bounce(cptr, -1, -1);
2215 return exit_client(cptr, cptr, &me, "Server only port");
2216 }
2217 /* Reject new USER */
2218 if (IsServer(sptr) || IsService(sptr) || sptr->user)
2219 {
2220 sendto_one(sptr, replies[ERR_ALREADYREGISTRED], ME, BadTo(parv[0]));
2221 return 1;
2222 }
2223 if ((username = (char *)index(parv[1],'@')))
2224 *username = '\0';
2225
2226 /* Copy parameters into better documenting variables */
2227
2228 username = parv[1];
2229 umodes = parv[2];
2230 server = parv[3];
2231 realname = parv[4];
2232
2233 #ifdef INET6
2234 inetntop(AF_INET6, (char *)&sptr->ip, ipbuf, sizeof(ipbuf));
2235 #else
2236 strcpy(ipbuf, (char *)inetntoa((char *)&sptr->ip));
2237 #endif
2238 user = make_user(sptr, strlen(ipbuf));
2239 strcpy(user->sip, ipbuf);
2240
2241 user->servp = me.serv;
2242 me.serv->refcnt++;
2243 #ifdef DEFAULT_INVISIBLE
2244 SetInvisible(sptr);
2245 #endif
2246 /* parse desired user modes sent in USER */
2247 /* rfc behaviour - bits */
2248 if (isdigit(*umodes))
2249 {
2250 for (s = umodes+1; *s; s++)
2251 if (!isdigit(*s))
2252 break;
2253 if (*s == '\0')
2254 /* allows only umodes specified in UFLAGS - see above */
2255 sptr->user->flags |= (UFLAGS & atoi(umodes));
2256 }
2257 else /* new behaviour */
2258 {
2259 /* 0 here is intentional. User MUST specify + or -,
2260 * as we don't want to restrict (broken) clients which send
2261 * their hostname in mode field (and happen to have r there).
2262 * - jv
2263 */
2264 what = 0;
2265 for (s = umodes; *s; s++)
2266 {
2267 switch (*s)
2268 {
2269 case '+':
2270 what = MODE_ADD;
2271 continue;
2272 case '-':
2273 what = MODE_DEL;
2274 continue;
2275 default:
2276 break;
2277 }
2278 /* If mode does not start with - or +, don't bother. */
2279 if (what == 0)
2280 break;
2281 for (i = 0; umodes_arr[i].umode != '\0'; i++)
2282 {
2283 if (*s == umodes_arr[i].umode)
2284 {
2285 if (what == MODE_ADD)
2286 {
2287 sptr->user->flags |=
2288 umodes_arr[i].flag;
2289 }
2290 if (what == MODE_DEL)
2291 {
2292 sptr->user->flags &=
2293 ~(umodes_arr[i].flag);
2294 }
2295 }
2296 }
2297 }
2298 }
2299 user->server = find_server_string(me.serv->snum);
2300
2301 reorder_client_in_list(sptr);
2302 if (sptr->info != DefInfo)
2303 MyFree(sptr->info);
2304 if (strlen(realname) > REALLEN)
2305 realname[REALLEN] = '\0';
2306 sptr->info = mystrdup(realname);
2307 #ifdef XLINE
2308 sptr->user2 = mystrdup(umodes);
2309 sptr->user3 = mystrdup(server);
2310 #endif
2311 if (sptr->name[0]) /* NICK already received, now we have USER... */
2312 {
2313 return register_user(cptr, sptr, sptr->name, username);
2314 }
2315 else
2316 {
2317 strncpyzt(sptr->user->username, username, USERLEN+1);
2318 }
2319 return 2;
2320 }
2321
2322 /* Fear www proxy abusers... aliased to QUIT, muhaha --B. */
m_post(aClient * cptr,aClient * sptr,int parc,char * parv[])2323 int m_post(aClient *cptr, aClient *sptr, int parc, char *parv[])
2324 {
2325 sendto_flag(SCH_LOCAL, "Denied http-post connection from %s.",
2326 cptr->sockhost);
2327 return m_quit(cptr, sptr, parc, parv);
2328 }
2329
2330 /*
2331 ** m_quit
2332 ** parv[0] = sender prefix
2333 ** parv[1] = comment
2334 */
m_quit(aClient * cptr,aClient * sptr,int parc,char * parv[])2335 int m_quit(aClient *cptr, aClient *sptr, int parc, char *parv[])
2336 {
2337 static char comment[TOPICLEN+1];
2338
2339 if (IsServer(sptr))
2340 return 0;
2341
2342 if (MyConnect(sptr))
2343 {
2344 (void) snprintf(comment, TOPICLEN, "\"%s",
2345 (parc > 1 && parv[1]) ? parv[1] : "");
2346 (void) strcat(comment, "\"");
2347 }
2348 else
2349 {
2350 (void) snprintf(comment, TOPICLEN + 1, "%s",
2351 (parc > 1 && parv[1]) ? parv[1] : "");
2352 }
2353 return exit_client(cptr, sptr, sptr, comment);
2354 }
2355
2356 /*
2357 ** m_kill
2358 ** parv[0] = sender prefix
2359 ** parv[1] = kill victim
2360 ** parv[2] = kill path
2361 */
m_kill(aClient * cptr,aClient * sptr,int parc,char * parv[])2362 int m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[])
2363 {
2364 aClient *acptr = NULL;
2365 char *inpath = cptr->name;
2366 char *user, *path, *killer;
2367 int chasing = 0;
2368
2369 if (!is_allowed(sptr, ACL_KILL))
2370 return m_nopriv(cptr, sptr, parc, parv);
2371
2372 user = parv[1];
2373 path = parv[2];
2374
2375 if (IsAnOper(cptr) && strlen(path) > (size_t) TOPICLEN)
2376 path[TOPICLEN] = '\0';
2377
2378 /* first, _if coming from a server_ check for kill on UID */
2379 if (IsServer(cptr))
2380 acptr = find_uid(user, NULL);
2381 if (acptr == NULL)
2382 acptr = find_client(user, NULL);
2383 if (acptr == NULL)
2384 {
2385 /*
2386 ** If the user has recently changed nick, we automaticly
2387 ** rewrite the KILL for this new nickname--this keeps
2388 ** servers in synch when nick change and kill collide
2389 */
2390 if (!(acptr = get_history(user, (long)KILLCHASETIMELIMIT)))
2391 {
2392 if (!IsServer(sptr))
2393 sendto_one(sptr, replies[ERR_NOSUCHNICK],
2394 ME, BadTo(parv[0]), user);
2395 return 1;
2396 }
2397 sendto_one(sptr,":%s NOTICE %s :KILL changed from %s to %s",
2398 ME, parv[0], user, acptr->name);
2399 chasing = 1;
2400 }
2401 if (!MyConnect(acptr) && !is_allowed(cptr, ACL_KILLREMOTE))
2402 {
2403 return m_nopriv(cptr, sptr, parc, parv);
2404 }
2405 if (IsServer(acptr) || IsMe(acptr))
2406 {
2407 sendto_flag(SCH_ERROR, "%s tried to KILL server %s: %s %s %s",
2408 sptr->name, acptr->name, parv[0], parv[1], parv[2]);
2409 sendto_one(sptr, replies[ERR_CANTKILLSERVER], ME, BadTo(parv[0]),
2410 acptr->name);
2411 return 1;
2412 }
2413 if (!IsServer(cptr))
2414 {
2415 /*
2416 ** The kill originates from this server, initialize path.
2417 ** (In which case the 'path' may contain user suplied
2418 ** explanation ...or some nasty comment, sigh... >;-)
2419 **
2420 ** ...!operhost!oper
2421 ** ...!operhost!oper (comment)
2422 */
2423 #ifdef UNIXPORT
2424 if (IsUnixSocket(cptr)) /* Don't use get_client_name syntax */
2425 inpath = ME;
2426 else
2427 #endif
2428 inpath = cptr->sockhost;
2429 sprintf(buf, "%s%s (%s)",
2430 cptr->name, IsOper(sptr) ? "" : "(L)", path);
2431 path = buf;
2432 }
2433 /*
2434 ** Notify all *local* opers about the KILL (this includes the one
2435 ** originating the kill, if from this server--the special numeric
2436 ** reply message is not generated anymore).
2437 **
2438 ** Note: "acptr->name" is used instead of "user" because we may
2439 ** have changed the target because of the nickname change.
2440 */
2441 if (IsService(acptr))
2442 {
2443 sendto_flag(SCH_KILL, "Received KILL message for %s[%s]. "
2444 "From %s Path: %s!%s", acptr->name,
2445 isdigit(acptr->service->servp->sid[0]) ?
2446 acptr->service->servp->sid : "2.10", parv[0], inpath,
2447 path);
2448 }
2449 else
2450 {
2451 sendto_flag(SCH_KILL, "Received KILL message for "
2452 "%s!%s@%s[%s/%s]. From %s Path: %s!%s",
2453 acptr->name, acptr->user->username, acptr->user->host,
2454 acptr->user->servp->bcptr->name,
2455 isdigit(acptr->user->servp->sid[0]) ?
2456 acptr->user->servp->sid : "2.10", parv[0], inpath,
2457 path);
2458 }
2459 #if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
2460 if (IsOper(sptr))
2461 {
2462 if (IsService(acptr))
2463 {
2464 syslog(LOG_DEBUG, "KILL From %s For %s[%s] Path %s!%s",
2465 parv[0], acptr->name,
2466 isdigit(acptr->service->servp->sid[0]) ?
2467 acptr->service->servp->sid : "2.10",
2468 inpath, path);
2469 }
2470 else
2471 {
2472 syslog(LOG_DEBUG, "KILL From %s For %s!%s@%s[%s/%s] "
2473 "Path %s!%s", parv[0], acptr->name,
2474 acptr->user->username, acptr->user->host,
2475 acptr->user->servp->bcptr->name,
2476 isdigit(acptr->user->servp->sid[0]) ?
2477 acptr->user->servp->sid : "2.10",
2478 inpath, path);
2479 }
2480 }
2481 #endif
2482 /*
2483 ** And pass on the message to other servers. Note, that if KILL
2484 ** was changed, the message has to be sent to all links, also
2485 ** back.
2486 ** Suicide kills are NOT passed on --SRB
2487 */
2488 if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
2489 {
2490 if (acptr->user)
2491 {
2492 sendto_serv_v(cptr, SV_UID, ":%s KILL %s :%s!%s",
2493 parv[0], acptr->user->uid, inpath, path);
2494 }
2495 else
2496 sendto_serv_butone(cptr, ":%s KILL %s :%s!%s",
2497 parv[0], acptr->name, inpath, path);
2498 if (chasing && !IsClient(cptr))
2499 sendto_one(cptr, ":%s KILL %s :%s!%s",
2500 ME, acptr->name, inpath, path);
2501 acptr->flags |= FLAGS_KILLED;
2502 }
2503 #ifdef USE_SERVICES
2504 check_services_butone(SERVICE_WANT_KILL, NULL, sptr,
2505 ":%s KILL %s :%s!%s", parv[0], acptr->name,
2506 inpath, path);
2507 #endif
2508
2509 /*
2510 ** Tell the victim she/he has been zapped, but *only* if
2511 ** the victim is on current server--no sense in sending the
2512 ** notification chasing the above kill, it won't get far
2513 ** anyway (as this user don't exist there any more either)
2514 */
2515 if (MyConnect(acptr))
2516 sendto_prefix_one(acptr, sptr,":%s KILL %s :%s!%s",
2517 parv[0], acptr->name, inpath, path);
2518 /*
2519 ** Set FLAGS_KILLED. This prevents exit_one_client from sending
2520 ** the unnecessary QUIT for this. (This flag should never be
2521 ** set in any other place)
2522 */
2523 if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
2524 {
2525 acptr->exitc = EXITC_KILL;
2526 sprintf(buf2, "Local Kill by %s (%s)", sptr->name, parv[2]);
2527 }
2528 else
2529 {
2530 if ((killer = index(path, ' ')))
2531 {
2532 while (killer > path && *killer != '!')
2533 killer--;
2534 if (killer != path)
2535 killer++;
2536 }
2537 else
2538 killer = path;
2539 sprintf(buf2, "Killed (%s)", killer);
2540 }
2541 return exit_client(cptr, acptr, sptr, buf2);
2542 }
2543
2544 /***********************************************************************
2545 * m_away() - Added 14 Dec 1988 by jto.
2546 * Not currently really working, I don't like this
2547 * call at all...
2548 *
2549 * ...trying to make it work. I don't like it either,
2550 * but perhaps it's worth the load it causes to net.
2551 * This requires flooding of the whole net like NICK,
2552 * USER, MODE, etc messages... --msa
2553 ***********************************************************************/
2554
2555 /*
2556 ** m_away
2557 ** parv[0] = sender prefix
2558 ** parv[1] = away message
2559 */
m_away(aClient * cptr,aClient * sptr,int parc,char * parv[])2560 int m_away(aClient *cptr, aClient *sptr, int parc, char *parv[])
2561 {
2562 Reg char *away, *awy2 = parv[1];
2563 int len;
2564
2565 away = sptr->user->away;
2566
2567 if (parc < 2 || !*awy2) /* Marking as not away */
2568 {
2569 if (away)
2570 {
2571 istat.is_away--;
2572 istat.is_awaymem -= (strlen(away) + 1);
2573 MyFree(away);
2574 sptr->user->away = NULL;
2575 }
2576 if (sptr->user->flags & FLAGS_AWAY)
2577 sendto_serv_butone(cptr, ":%s MODE %s :-a",
2578 sptr->user->uid, parv[0]);
2579 /* sendto_serv_butone(cptr, ":%s AWAY", parv[0]); */
2580 if (MyConnect(sptr))
2581 sendto_one(sptr, replies[RPL_UNAWAY], ME, BadTo(parv[0]));
2582 #ifdef USE_SERVICES
2583 check_services_butone(SERVICE_WANT_AWAY, NULL, sptr,
2584 ":%s AWAY", parv[0]);
2585 #endif
2586 sptr->user->flags &= ~FLAGS_AWAY;
2587 return 1;
2588 }
2589
2590 /* Marking as away */
2591
2592 if ((len = strlen(awy2)) > (size_t) TOPICLEN)
2593 {
2594 len = TOPICLEN;
2595 awy2[TOPICLEN] = '\0';
2596 }
2597 len++;
2598 /* sendto_serv_butone(cptr, ":%s AWAY :%s", parv[0], awy2); */
2599 #ifdef USE_SERVICES
2600 check_services_butone(SERVICE_WANT_AWAY, NULL, sptr,
2601 ":%s AWAY :%s", parv[0], awy2);
2602 #endif
2603
2604 if (away)
2605 {
2606 istat.is_awaymem -= (strlen(away) + 1);
2607 away = (char *)MyRealloc(away, len);
2608 istat.is_awaymem += len;
2609 }
2610 else
2611 {
2612 istat.is_away++;
2613 istat.is_awaymem += len;
2614 away = (char *)MyMalloc(len);
2615 sendto_serv_butone(cptr, ":%s MODE %s :+a",
2616 sptr->user->uid, parv[0]);
2617 }
2618
2619 sptr->user->flags |= FLAGS_AWAY;
2620 if (MyConnect(sptr))
2621 {
2622 sptr->user->away = away;
2623 (void)strcpy(away, awy2);
2624 sendto_one(sptr, replies[RPL_NOWAWAY], ME, BadTo(parv[0]));
2625 }
2626 return 2;
2627 }
2628
2629 /*
2630 ** m_ping
2631 ** parv[0] = sender prefix
2632 ** parv[1] = origin
2633 ** parv[2] = destination
2634 */
m_ping(aClient * cptr,aClient * sptr,int parc,char * parv[])2635 int m_ping(aClient *cptr, aClient *sptr, int parc, char *parv[])
2636 {
2637 aClient *acptr;
2638 char *origin, *destination;
2639
2640 origin = parv[1];
2641 destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */
2642
2643 acptr = find_client(origin, NULL);
2644 if (!acptr)
2645 acptr = find_server(origin, NULL);
2646 if (!acptr || acptr != sptr)
2647 origin = cptr->name;
2648 if (!BadPtr(destination) && match(destination, ME) != 0)
2649 {
2650 if ((acptr = find_server(destination, NULL)))
2651 sendto_one(acptr, ":%s PING %s :%s", parv[0],
2652 origin, destination);
2653 else
2654 {
2655 sendto_one(sptr, replies[ERR_NOSUCHSERVER],
2656 ME, BadTo(parv[0]), destination);
2657 return 1;
2658 }
2659 }
2660 else
2661 sendto_one(sptr, ":%s PONG %s :%s", ME,
2662 (destination) ? destination : ME, parv[1]);
2663 return 1;
2664 }
2665
2666 /*
2667 ** m_pong
2668 ** parv[0] = sender prefix
2669 ** parv[1] = origin
2670 ** parv[2] = destination
2671 */
m_pong(aClient * cptr,aClient * sptr,int parc,char * parv[])2672 int m_pong(aClient *cptr, aClient *sptr, int parc, char *parv[])
2673 {
2674 aClient *acptr;
2675 char *origin, *destination;
2676
2677 if (parc < 2 || *parv[1] == '\0')
2678 {
2679 sendto_one(sptr, replies[ERR_NOORIGIN], ME, BadTo(parv[0]));
2680 return 1;
2681 }
2682
2683 origin = parv[1];
2684 destination = parv[2];
2685
2686 sptr->flags &= ~FLAGS_PINGSENT;
2687 if (destination)
2688 {
2689 acptr = find_target(destination, cptr);
2690 }
2691 else
2692 {
2693 acptr = &me;
2694 }
2695 if (!acptr)
2696 {
2697 sendto_one(sptr, replies[ERR_NOSUCHSERVER], ME, BadTo(parv[0]),
2698 destination);
2699 return 2;
2700 }
2701 if (!IsMe(acptr))
2702 {
2703 if (!(MyClient(sptr) && mycmp(origin, sptr->name)))
2704 sendto_one(acptr,":%s PONG %s %s",
2705 parv[0], origin, destination);
2706 return 2;
2707 }
2708 return 1;
2709 }
2710
2711
2712 /*
2713 ** m_oper
2714 ** parv[0] = sender prefix
2715 ** parv[1] = oper name
2716 ** parv[2] = oper password
2717 */
m_oper(aClient * cptr,aClient * sptr,int parc,char * parv[])2718 int m_oper(aClient *cptr, aClient *sptr, int parc, char *parv[])
2719 {
2720 aConfItem *aconf;
2721 char *name, *password, *encr;
2722 char *logstring = NULL;
2723
2724 name = parv[1];
2725 password = parv[2];
2726
2727 if (IsAnOper(sptr))
2728 {
2729 if (MyConnect(sptr))
2730 sendto_one(sptr, replies[RPL_YOUREOPER], ME, BadTo(parv[0]));
2731 return 1;
2732 }
2733 if (!(aconf = find_Oline(name, sptr)))
2734 {
2735 sendto_one(sptr, replies[ERR_NOOPERHOST], ME, BadTo(parv[0]));
2736 return 1;
2737 }
2738 if (aconf->clients >= MaxLinks(Class(aconf)))
2739 {
2740 sendto_one(sptr, ":%s %d %s :Too many opers", ME, ERR_NOOPERHOST, BadTo(parv[0]));
2741 return 1;
2742 }
2743 #ifdef CRYPT_OPER_PASSWORD
2744 /* pass whole aconf->passwd as salt, let crypt() deal with it */
2745
2746 if (password && aconf->passwd)
2747 {
2748 extern char *crypt();
2749
2750 encr = crypt(password, aconf->passwd);
2751 if (encr == NULL)
2752 {
2753 sendto_flag(SCH_ERROR, "crypt() returned NULL");
2754 sendto_one(sptr,replies[ERR_PASSWDMISMATCH], ME,BadTo(parv[0]));
2755 return 3;
2756 }
2757 }
2758 else
2759 encr = "";
2760 #else
2761 encr = password;
2762 #endif /* CRYPT_OPER_PASSWORD */
2763
2764 if ((aconf->status & CONF_OPS) &&
2765 StrEq(encr, aconf->passwd) && !attach_conf(sptr, aconf))
2766 {
2767 int old = (sptr->user->flags & ALL_UMODES);
2768 char *s;
2769
2770 s = index(aconf->host, '@');
2771 *s++ = '\0';
2772 #ifndef NO_OPER_REMOTE
2773 if (aconf->flags & ACL_LOCOP)
2774 #else
2775 if ((match(s,me.sockhost) && !IsLocal(sptr)) ||
2776 aconf->flags & ACL_LOCOP)
2777 #endif
2778 SetLocOp(sptr);
2779 else
2780 SetOper(sptr);
2781 *--s = '@';
2782 sendto_flag(SCH_NOTICE, "%s (%s@%s) is now operator (%c)",
2783 parv[0], sptr->user->username, sptr->user->host,
2784 IsOper(sptr) ? 'o' : 'O');
2785 send_umode_out(cptr, sptr, old);
2786 sendto_one(sptr, replies[RPL_YOUREOPER], ME, BadTo(parv[0]));
2787 #ifdef USE_SERVICES
2788 check_services_butone(SERVICE_WANT_OPER, sptr->user->servp,
2789 sptr, ":%s MODE %s :+%c", parv[0],
2790 parv[0], IsOper(sptr) ? 'o' : 'O');
2791 #endif
2792 if (IsAnOper(sptr))
2793 {
2794 istat.is_oper++;
2795 sptr->user->servp->usercnt[2]++;
2796 }
2797 logstring = "";
2798 }
2799 else /* Wrong password or attach_conf() failed */
2800 {
2801 (void)detach_conf(sptr, aconf);
2802 if (!StrEq(encr, aconf->passwd))
2803 sendto_one(sptr,replies[ERR_PASSWDMISMATCH], ME, BadTo(parv[0]));
2804 else
2805 sendto_one(sptr,":%s %d %s :Too many connections",
2806 ME, ERR_PASSWDMISMATCH, BadTo(parv[0]));
2807 #ifdef FAILED_OPERLOG
2808 sendto_flag(SCH_NOTICE, "FAILED OPER attempt by %s!%s@%s",
2809 parv[0], sptr->user->username, sptr->user->host);
2810 logstring = "FAILED ";
2811 #endif
2812 }
2813
2814 if (logstring)
2815 {
2816 #if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
2817 syslog(LOG_INFO, "%sOPER (%s) by (%s!%s@%s) [%s@%s]",
2818 logstring,
2819 name, parv[0], sptr->user->username, sptr->user->host,
2820 sptr->auth,
2821 #ifdef UNIXPORT
2822 IsUnixSocket(sptr) ? sptr->sockhost :
2823 #endif
2824 #ifdef INET6
2825 inet_ntop(AF_INET6, (char *)&sptr->ip, ipv6string,
2826 sizeof(ipv6string))
2827 #else
2828 inetntoa((char *)&sptr->ip)
2829 #endif
2830 );
2831 #endif /* defined(USE_SYSLOG) && defined(SYSLOG_OPER) */
2832
2833 #ifdef FNAME_OPERLOG
2834 {
2835 int logfile;
2836
2837 /*
2838 * This conditional makes the logfile active only after
2839 * it's been created - thus logging can be turned off by
2840 * removing the file.
2841 *
2842 * stop NFS hangs...most systems should be able to open a
2843 * file in 3 seconds. -avalon (curtesy of wumpus)
2844 */
2845 (void)alarm(3);
2846 if (IsPerson(sptr) &&
2847 (logfile = open(FNAME_OPERLOG, O_WRONLY|O_APPEND
2848 #ifdef LOGFILES_ALWAYS_CREATE
2849 |O_CREAT, S_IRUSR|S_IWUSR
2850 #endif
2851 )) != -1)
2852 {
2853 (void)alarm(0);
2854 sprintf(buf, "%s %sOPER (%s) by (%s!%s@%s)"
2855 " [%s@%s]\n",
2856 myctime(timeofday),
2857 logstring,
2858 name, parv[0],
2859 sptr->user->username, sptr->user->host,
2860 sptr->auth,
2861 #ifdef UNIXPORT
2862 IsUnixSocket(sptr) ? sptr->sockhost :
2863 #endif
2864 #ifdef INET6
2865 inetntop(AF_INET6, (char *)&sptr->ip,
2866 ipv6string, sizeof(ipv6string))
2867 #else
2868 inetntoa((char *)&sptr->ip)
2869 #endif
2870 );
2871 (void)alarm(3);
2872 (void)write(logfile, buf, strlen(buf));
2873 (void)alarm(0);
2874 (void)close(logfile);
2875 }
2876 (void)alarm(0);
2877 /* Modification by pjg */
2878 }
2879 #endif /* FNAME_OPERLOG */
2880
2881 } /* logstring != NULL */
2882
2883 return 3;
2884 }
2885
2886 /***************************************************************************
2887 * m_pass() - Added Sat, 4 March 1989
2888 ***************************************************************************/
2889
2890 /*
2891 ** m_pass
2892 ** parv[0] = sender prefix
2893 ** parv[1] = password
2894 ** parv[2] = protocol & server versions (server only)
2895 ** parv[3] = server id & options (server only)
2896 ** parv[4] = (optional) link options (server only)
2897 */
m_pass(aClient * cptr,aClient * sptr,int parc,char * parv[])2898 int m_pass(aClient *cptr, aClient *sptr, int parc, char *parv[])
2899 {
2900 char *password = parv[1];
2901
2902 strncpyzt(cptr->passwd, password, sizeof(cptr->passwd));
2903 if (cptr->user || cptr->service)
2904 {
2905 /* If we have one of these structures allocated, it means
2906 ** that PASS was issued after USER or SERVICE. No need to
2907 ** copy PASS parameters to info field, then. */
2908 return 1;
2909 }
2910 /* Temporarily store PASS pwd *parameters* into info field.
2911 ** This will be used as version in m_server() and cleared
2912 ** in m_user(). */
2913 if (parc > 2 && parv[2])
2914 {
2915 strncpyzt(buf, parv[2], 15);
2916 if (parc > 3 && parv[3])
2917 {
2918 strcat(buf, " ");
2919 strncat(buf, parv[3], 100);
2920 if (parc > 4 && parv[4])
2921 {
2922 strcat(buf, " ");
2923 strncat(buf, parv[4], 5);
2924 }
2925 }
2926 if (cptr->info != DefInfo)
2927 MyFree(cptr->info);
2928 cptr->info = mystrdup(buf);
2929 }
2930 return 1;
2931 }
2932
2933 /*
2934 * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
2935 * the need for complicated requests like WHOIS. It returns user/host
2936 * information only (no spurious AWAY labels or channels).
2937 */
m_userhost(aClient * cptr,aClient * sptr,int parc,char * parv[])2938 int m_userhost(aClient *cptr, aClient *sptr, int parc, char *parv[])
2939 {
2940 char *p = NULL;
2941 aClient *acptr;
2942 Reg char *s;
2943 Reg int i, len;
2944 int idx = 1;
2945
2946 (void)sprintf(buf, replies[RPL_USERHOST], ME, BadTo(parv[0]));
2947 len = strlen(buf);
2948 *buf2 = '\0';
2949
2950 for (i = 5, s = strtoken(&p, parv[idx], " "); i && s; i--)
2951 {
2952 if ((acptr = find_person(s, NULL)))
2953 {
2954 if (*buf2)
2955 (void)strcat(buf, " ");
2956 sprintf(buf2, "%s%s=%c%s@%s", acptr->name,
2957 IsAnOper(acptr) ? "*" : "",
2958 (acptr->user->flags & FLAGS_AWAY) ? '-' : '+',
2959 acptr->user->username, acptr->user->host);
2960 (void)strncat(buf, buf2, sizeof(buf) - len);
2961 len += strlen(buf2);
2962 if (len > BUFSIZE - (NICKLEN + 5 + HOSTLEN + USERLEN))
2963 {
2964 sendto_one(sptr, "%s", buf);
2965 (void)sprintf(buf, replies[RPL_USERHOST],
2966 ME, BadTo(parv[0]));
2967 len = strlen(buf);
2968 *buf2 = '\0';
2969 }
2970 }
2971 s = strtoken(&p, (char *)NULL, " ");
2972 if (!s && parv[++idx])
2973 {
2974 p = NULL;
2975 s = strtoken(&p, parv[idx], " ");
2976 }
2977 }
2978 sendto_one(sptr, "%s", buf);
2979 return 1;
2980 }
2981
2982 /*
2983 * m_ison added by Darren Reed 13/8/91 to act as an efficent user indicator
2984 * with respect to cpu/bandwidth used. Implemented for NOTIFY feature in
2985 * clients. Designed to reduce number of whois requests. Can process
2986 * nicknames in batches as long as the maximum buffer length.
2987 *
2988 * format:
2989 * ISON :nicklist
2990 */
2991
m_ison(aClient * cptr,aClient * sptr,int parc,char * parv[])2992 int m_ison(aClient *cptr, aClient *sptr, int parc, char *parv[])
2993 {
2994 Reg aClient *acptr;
2995 Reg char *s, **pav = parv;
2996 Reg int len = 0, i;
2997 char *p = NULL;
2998
2999 (void)sprintf(buf, replies[RPL_ISON], ME, BadTo(*parv));
3000 len = strlen(buf);
3001
3002 for (s = strtoken(&p, *++pav, " "); s; s = strtoken(&p, NULL, " "))
3003 if ((acptr = find_person(s, NULL)))
3004 {
3005 i = strlen(acptr->name);
3006 if (len + i > sizeof(buf) - 4)
3007 {
3008 /* leave room for " \r\n\0" */
3009 break;
3010 }
3011 (void) strcpy(buf + len, acptr->name);
3012 len += i;
3013 (void) strcpy(buf + len++, " ");
3014 }
3015 sendto_one(sptr, "%s", buf);
3016 return 1;
3017 }
3018
3019 /*
3020 * m_umode() added 15/10/91 By Darren Reed.
3021 * parv[0] - sender (can be NULL, see below..)
3022 * parv[1] - username to change mode for
3023 * parv[2] - modes to change
3024 */
m_umode(aClient * cptr,aClient * sptr,int parc,char * parv[])3025 int m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[])
3026 {
3027 Reg int flag;
3028 Reg int *s;
3029 Reg char **p, *m;
3030 aClient *acptr = NULL;
3031 int what, setflags, penalty = 0;
3032
3033 what = MODE_ADD;
3034
3035 if (cptr && !(acptr = find_person(parv[1], NULL)))
3036 {
3037 if (MyConnect(sptr))
3038 sendto_one(sptr, replies[ERR_NOSUCHCHANNEL], ME, BadTo(parv[0]),
3039 parv[1]);
3040 return 1;
3041 }
3042 if (cptr == NULL)
3043 /* internal call which has to be handled in a special way */
3044 acptr = sptr;
3045
3046 if ((cptr != NULL) &&
3047 ((IsServer(sptr) || sptr != acptr || acptr->from != sptr->from)))
3048 {
3049 if (IsServer(cptr))
3050 sendto_ops_butone(NULL, ME,
3051 "MODE for User %s From %s!%s", parv[1],
3052 get_client_name(cptr, FALSE), sptr->name);
3053 else
3054 sendto_one(sptr, replies[ERR_USERSDONTMATCH], ME, BadTo(parv[0]));
3055 return 1;
3056 }
3057
3058 if (parc < 3)
3059 {
3060 m = buf;
3061 *m++ = '+';
3062 for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4);
3063 s += 2)
3064 if (sptr->user->flags & flag)
3065 *m++ = (char)(*(s+1));
3066 *m = '\0';
3067 sendto_one(sptr, replies[RPL_UMODEIS], ME, BadTo(parv[0]), buf);
3068 return 1;
3069 }
3070
3071 /* find flags already set for user */
3072 setflags = 0;
3073 for (s = user_modes; (flag = *s); s += 2)
3074 if (sptr->user->flags & flag)
3075 setflags |= flag;
3076
3077 /*
3078 * parse mode change string(s)
3079 */
3080 for (p = &parv[2]; p && *p; p++ )
3081 for (m = *p; *m; m++)
3082 switch(*m)
3083 {
3084 case '+' :
3085 what = MODE_ADD;
3086 break;
3087 case '-' :
3088 what = MODE_DEL;
3089 break;
3090 /* we may not get these,
3091 * but they shouldnt be in default
3092 */
3093 case ' ' :
3094 case '\n' :
3095 case '\r' :
3096 case '\t' :
3097 break;
3098 case 'a' : /* fall through case */
3099 /* users should use the AWAY message */
3100 if (cptr && !IsServer(cptr))
3101 break;
3102 if (what == MODE_DEL && sptr->user->away)
3103 {
3104 istat.is_away--;
3105 istat.is_awaymem -= (strlen(sptr->user->away) + 1);
3106 MyFree(sptr->user->away);
3107 sptr->user->away = NULL;
3108 #ifdef USE_SERVICES
3109 check_services_butone(SERVICE_WANT_AWAY,
3110 sptr->user->servp, sptr,
3111 ":%s AWAY", parv[0]);
3112 #endif
3113 }
3114 #ifdef USE_SERVICES
3115 if (what == MODE_ADD)
3116 check_services_butone(SERVICE_WANT_AWAY,
3117 sptr->user->servp, sptr,
3118 ":%s AWAY :", parv[0]);
3119 #endif
3120 default :
3121 for (s = user_modes; (flag = *s); s += 2)
3122 if (*m == (char)(*(s+1)))
3123 {
3124 if (what == MODE_ADD)
3125 sptr->user->flags |= flag;
3126 else
3127 sptr->user->flags &= ~flag;
3128 penalty += 1;
3129 break;
3130 }
3131 if (flag == 0 && MyConnect(sptr))
3132 sendto_one(sptr, replies[ERR_UMODEUNKNOWNFLAG],
3133 ME, BadTo(parv[0]), *m);
3134 break;
3135 }
3136 if (cptr)
3137 {
3138 /* stop users making themselves operators too easily */
3139 if (!(setflags & FLAGS_OPER) && IsOper(sptr) &&
3140 !IsServer(cptr))
3141 ClearOper(sptr);
3142 if (!(setflags & FLAGS_LOCOP) && IsLocOp(sptr))
3143 ClearLocOp(sptr);
3144 /* but once they are, set their status */
3145 SetClient(sptr);
3146 if ((setflags & FLAGS_RESTRICT) &&
3147 !IsRestricted(sptr))
3148 {
3149 sendto_one(sptr, replies[ERR_RESTRICTED], ME, BadTo(parv[0]));
3150 SetRestricted(sptr);
3151 /* Can't return; here since it could mess counters */
3152 }
3153 if ((setflags & (FLAGS_OPER|FLAGS_LOCOP)) && !IsAnOper(sptr) &&
3154 MyConnect(sptr))
3155 det_confs_butmask(sptr, CONF_CLIENT);
3156
3157 /*
3158 * compare new flags with old flags and send string which
3159 * will cause servers to update correctly.
3160 */
3161 if (!IsInvisible(sptr) && (setflags & FLAGS_INVISIBLE))
3162 {
3163 istat.is_user[1]--;
3164 istat.is_user[0]++;
3165 sptr->user->servp->usercnt[1]--;
3166 sptr->user->servp->usercnt[0]++;
3167 }
3168 if (IsInvisible(sptr) && !(setflags & FLAGS_INVISIBLE))
3169 {
3170 istat.is_user[1]++;
3171 istat.is_user[0]--;
3172 sptr->user->servp->usercnt[1]++;
3173 sptr->user->servp->usercnt[0]--;
3174 }
3175 send_umode_out(cptr, sptr, setflags);
3176 }
3177
3178 /* update counters */
3179 if (IsOper(sptr) && !(setflags & FLAGS_OPER))
3180 {
3181 istat.is_oper++;
3182 sptr->user->servp->usercnt[2]++;
3183 #ifdef USE_SERVICES
3184 check_services_butone(SERVICE_WANT_OPER, sptr->user->servp,
3185 sptr, ":%s MODE %s :+o", parv[0],
3186 parv[0]);
3187 #endif
3188 }
3189 else if (!IsOper(sptr) && (setflags & FLAGS_OPER))
3190 {
3191 istat.is_oper--;
3192 sptr->user->servp->usercnt[2]--;
3193 #ifdef USE_SERVICES
3194 check_services_butone(SERVICE_WANT_OPER, sptr->user->servp,
3195 sptr, ":%s MODE %s :-o", parv[0],
3196 parv[0]);
3197 #endif
3198 }
3199 else if (MyConnect(sptr) && !IsLocOp(sptr) && (setflags & FLAGS_LOCOP))
3200 {
3201 istat.is_oper--;
3202 sptr->user->servp->usercnt[2]--;
3203 #ifdef USE_SERVICES
3204 check_services_butone(SERVICE_WANT_OPER, sptr->user->servp,
3205 sptr, ":%s MODE %s :-O", parv[0],
3206 parv[0]);
3207 #endif
3208 }
3209
3210 return penalty;
3211 }
3212
3213 /*
3214 * send the MODE string for user (user) to connection cptr
3215 * -avalon
3216 */
send_umode(aClient * cptr,aClient * sptr,int old,int sendmask,char * umode_buf)3217 void send_umode(aClient *cptr, aClient *sptr, int old, int sendmask,
3218 char *umode_buf)
3219 {
3220 Reg int *s, flag;
3221 Reg char *m;
3222 int what = MODE_NULL;
3223
3224 if (!sptr->user)
3225 return;
3226 /*
3227 * build a string in umode_buf to represent the change in the user's
3228 * mode between the new (sptr->flag) and 'old'.
3229 */
3230 m = umode_buf;
3231 *m = '\0';
3232 for (s = user_modes; (flag = *s); s += 2)
3233 {
3234 if (MyClient(sptr) && !(flag & sendmask))
3235 continue;
3236 if ((flag & old) && !(sptr->user->flags & flag))
3237 {
3238 if (what == MODE_DEL)
3239 *m++ = *(s+1);
3240 else
3241 {
3242 what = MODE_DEL;
3243 *m++ = '-';
3244 *m++ = *(s+1);
3245 }
3246 }
3247 else if (!(flag & old) && (sptr->user->flags & flag))
3248 {
3249 if (what == MODE_ADD)
3250 *m++ = *(s+1);
3251 else
3252 {
3253 what = MODE_ADD;
3254 *m++ = '+';
3255 *m++ = *(s+1);
3256 }
3257 }
3258 }
3259 *m = '\0';
3260 if (*umode_buf && cptr)
3261 sendto_one(cptr, ":%s MODE %s :%s",
3262 sptr->name, sptr->name, umode_buf);
3263 }
3264
3265 /*
3266 * added Sat Jul 25 07:30:42 EST 1992
3267 */
send_umode_out(aClient * cptr,aClient * sptr,int old)3268 void send_umode_out(aClient *cptr, aClient *sptr, int old)
3269 {
3270 Reg int i;
3271 Reg aClient *acptr;
3272
3273 send_umode(NULL, sptr, old, SEND_UMODES, buf);
3274
3275 if (*buf)
3276 for (i = fdas.highest; i >= 0; i--)
3277 {
3278 if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr))
3279 continue;
3280 if (acptr == cptr || acptr == sptr)
3281 continue;
3282 sendto_one(acptr, ":%s MODE %s :%s",
3283 sptr->user->uid, sptr->name, buf);
3284 }
3285
3286 if (cptr && MyClient(cptr))
3287 send_umode(cptr, sptr, old, ALL_UMODES, buf);
3288 #ifdef USE_SERVICES
3289 /* buf contains all modes for local users, and iow only for remotes */
3290 if (*buf)
3291 check_services_butone(SERVICE_WANT_UMODE, sptr->user->servp,
3292 sptr, ":%s MODE %s :%s", sptr->name,
3293 sptr->name, buf);
3294 #endif
3295 }
3296
3297 /*
3298 ** save_user() added 990618 by Christope Kalt
3299 **
3300 ** This will save the user sptr, and put the nick he's currently using in
3301 ** nick delay.
3302 ** It will send SAVE to the servers that can deal with it, and just a nick
3303 ** change to the rest.
3304 ** It will adjust the path, to include the link we got the SAVE message from.
3305 ** For internal calls, set cptr to NULL.
3306 */
save_user(aClient * cptr,aClient * sptr,char * path)3307 static void save_user(aClient *cptr, aClient *sptr, char *path)
3308 {
3309 if (MyConnect(sptr))
3310 {
3311 sendto_one(sptr, replies[RPL_SAVENICK], cptr ? cptr->name : ME,
3312 sptr->name, sptr->user->uid);
3313 #if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_NICK)
3314 sendto_flag(SCH_CLIENT, "%s %s %s %s NICK %s",
3315 sptr->user->uid, sptr->name, sptr->user->username,
3316 sptr->user->host, sptr->user->uid);
3317 #endif
3318 }
3319
3320 sendto_common_channels(sptr, ":%s NICK :%s",
3321 sptr->name, sptr->user->uid);
3322 add_history(sptr, NULL);
3323 #ifdef USE_SERVICES
3324 check_services_butone(SERVICE_WANT_NICK, sptr->user->servp, sptr,
3325 ":%s NICK :%s", sptr->name, sptr->user->uid);
3326 #endif
3327 sendto_serv_v(cptr, SV_UID, ":%s SAVE %s :%s%c%s",
3328 cptr ? cptr->serv->sid : me.serv->sid, sptr->user->uid,
3329 cptr ? cptr->name : ME, cptr ? '!' : ' ', path);
3330 sendto_flag(SCH_SAVE, "Received SAVE message for %s. Path: %s!%s",
3331 sptr->name, cptr ? cptr->name : ME, path);
3332 del_from_client_hash_table(sptr->name, sptr);
3333 strcpy(sptr->name, sptr->user->uid);
3334 add_to_client_hash_table(sptr->name, sptr);
3335 }
3336
3337 /*
3338 ** m_save() added 990618 by Christope Kalt
3339 ** parv[0] = sender prefix
3340 ** parv[1] = saved user
3341 ** parv[2] = save path
3342 */
m_save(aClient * cptr,aClient * sptr,int parc,char * parv[])3343 int m_save(aClient *cptr, aClient *sptr, int parc, char *parv[])
3344 {
3345 aClient *acptr;
3346 char *path = (parc > 2) ? parv[2] : "*no-path*";
3347
3348 if (parc < 2)
3349 {
3350 sendto_flag(SCH_ERROR, "Save with not enough parameters "
3351 "from %s", cptr->name);
3352 return 1;
3353 }
3354
3355 /* need sanity checks here -syrk */
3356 acptr = find_uid(parv[1], NULL);
3357 if (acptr && strcasecmp(acptr->name, acptr->user->uid))
3358 {
3359 save_user(cptr, acptr, path);
3360 ircstp->is_save++;
3361 }
3362
3363 return 0;
3364 }
3365
3366 /*
3367 ** Given client cptr and function decide access.
3368 ** Return 1 for OK, 0 for forbidden.
3369 */
3370
is_allowed(aClient * cptr,long function)3371 int is_allowed(aClient *cptr, long function)
3372 {
3373 Link *tmp;
3374
3375 /* We cannot judge not our clients. Yet. */
3376 if (!MyConnect(cptr) || IsServer(cptr))
3377 return 1;
3378
3379 /* minimal control, but nothing else service can do anyway. */
3380 if (IsService(cptr))
3381 {
3382 if (function == ACL_TKLINE &&
3383 (cptr->service->wants & SERVICE_WANT_TKLINE))
3384 return 1;
3385 if (function == ACL_KLINE &&
3386 (cptr->service->wants & SERVICE_WANT_KLINE))
3387 return 1;
3388 return 0;
3389 }
3390
3391 for (tmp = cptr->confs; tmp; tmp = tmp->next)
3392 {
3393 if (tmp->value.aconf->status & CONF_OPERATOR)
3394 break;
3395 }
3396
3397 /* no O: conf found */
3398 if (!tmp)
3399 return 0;
3400
3401 /* check access */
3402 if ((tmp->value.aconf->flags & function))
3403 return 1;
3404
3405 return 0;
3406 }
3407
send_away(aClient * sptr,aClient * acptr)3408 void send_away(aClient *sptr, aClient *acptr)
3409 {
3410 if (acptr->user->away)
3411 {
3412 sendto_one(sptr, replies[RPL_AWAY], ME, sptr->name,
3413 acptr->name, acptr->user->away);
3414 }
3415 else
3416 {
3417 #ifdef AWAY_MOREINFO
3418 /* Building buffer and using it instead of "Gone" would be
3419 * a better code, but a bit slower; just rememeber about this
3420 * one when ever changing RPL_AWAY --B. */
3421 sendto_one(sptr, ":%s 301 %s %s :"
3422 "Gone, for more info use WHOIS %s %s",
3423 ME, sptr->name, acptr->name,
3424 acptr->name, acptr->name);
3425 #else
3426 sendto_one(sptr, replies[RPL_AWAY], ME, sptr->name,
3427 acptr->name, "Gone");
3428 #endif
3429 }
3430 }
3431