1 /************************************************************************
2 * IRC - Internet Relay Chat, ircd/s_misc.c (formerly ircd/date.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_misc.c,v 1.119 2009/11/13 20:08:11 chopin Exp $";
26 #endif
27
28 #include "os.h"
29 #include "s_defines.h"
30 #define S_MISC_C
31 #include "s_externs.h"
32 #undef S_MISC_C
33
34 static void exit_one_client (aClient *, aClient *, aClient *, const char *);
35 static void exit_server(aClient *, aClient *, aClient *, const char *,
36 const char *);
37
38
39 static char *months[] = {
40 "January", "February", "March", "April",
41 "May", "June", "July", "August",
42 "September", "October", "November", "December"
43 };
44
45 static char *weekdays[] = {
46 "Sunday", "Monday", "Tuesday", "Wednesday",
47 "Thursday", "Friday", "Saturday"
48 };
49
50 /*
51 * stats stuff
52 */
53 struct stats ircst, *ircstp = &ircst;
54
date(time_t clock)55 char *date(time_t clock)
56 {
57 static char buf[80], plus;
58 Reg struct tm *lt, *gm;
59 struct tm gmbuf;
60 int minswest;
61
62 if (!clock)
63 time(&clock);
64 gm = gmtime(&clock);
65 bcopy((char *)gm, (char *)&gmbuf, sizeof(gmbuf));
66 gm = &gmbuf;
67 lt = localtime(&clock);
68
69 minswest = (gm->tm_hour - lt->tm_hour) * 60
70 + (gm->tm_min - lt->tm_min);
71 if (lt->tm_yday != gm->tm_yday)
72 {
73 if ((lt->tm_yday > gm->tm_yday
74 && lt->tm_year == gm->tm_year)
75 || (lt->tm_yday < gm->tm_yday
76 && lt->tm_year != gm->tm_year))
77 {
78 minswest -= 24 * 60;
79 }
80 else
81 {
82 minswest += 24 * 60;
83 }
84 }
85
86 plus = (minswest > 0) ? '-' : '+';
87 if (minswest < 0)
88 minswest = -minswest;
89
90 (void)sprintf(buf, "%s %s %d %d -- %02d:%02d %c%02d:%02d",
91 weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday,
92 lt->tm_year + 1900, lt->tm_hour, lt->tm_min,
93 plus, minswest/60, minswest%60);
94
95 return buf;
96 }
97
98 /*
99 ** check_registered_user is used to cancel message, if the
100 ** originator is a server or not registered yet. In other
101 ** words, passing this test, *MUST* guarantee that the
102 ** sptr->user exists (not checked after this--let there
103 ** be coredumps to catch bugs... this is intentional --msa ;)
104 **
105 ** There is this nagging feeling... should this NOT_REGISTERED
106 ** error really be sent to remote users? This happening means
107 ** that remote servers have this user registered, althout this
108 ** one has it not... Not really users fault... Perhaps this
109 ** error message should be restricted to local clients and some
110 ** other thing generated for remotes...
111 */
check_registered_user(aClient * sptr)112 int check_registered_user(aClient *sptr)
113 {
114 if (!IsRegisteredUser(sptr))
115 {
116 sendto_one(sptr, replies[ERR_NOTREGISTERED], ME, "*");
117 return -1;
118 }
119 return 0;
120 }
121
122 /*
123 ** check_registered user cancels message, if 'x' is not
124 ** registered (e.g. we don't know yet whether a server
125 ** or user)
126 */
check_registered(aClient * sptr)127 int check_registered(aClient *sptr)
128 {
129 if (!IsRegistered(sptr))
130 {
131 sendto_one(sptr, replies[ERR_NOTREGISTERED], ME, "*");
132 return -1;
133 }
134 return 0;
135 }
136
137 /*
138 ** check_registered_service cancels message, if 'x' is not
139 ** a registered service.
140 */
check_registered_service(aClient * sptr)141 int check_registered_service(aClient *sptr)
142 {
143 if (!IsService(sptr))
144 {
145 sendto_one(sptr, replies[ERR_NOTREGISTERED], ME, "*");
146 return -1;
147 }
148 return 0;
149 }
150
151 /*
152 ** get_client_name
153 ** Return the name of the client for various tracking and
154 ** admin purposes. The main purpose of this function is to
155 ** return the "socket host" name of the client, if that
156 ** differs from the advertised name (other than case).
157 ** But, this can be used to any client structure.
158 **
159 ** Returns:
160 ** "name[user@ip#.port]" if 'showip' is true;
161 ** "name[username@sockethost]", if name and sockhost are different and
162 ** showip is false; else
163 ** "name".
164 **
165 ** NOTE 1:
166 ** Watch out the allocation of "nbuf", if either sptr->name
167 ** or sptr->sockhost gets changed into pointers instead of
168 ** directly allocated within the structure...
169 **
170 ** NOTE 2:
171 ** Function return either a pointer to the structure (sptr) or
172 ** to internal buffer (nbuf). *NEVER* use the returned pointer
173 ** to modify what it points!!!
174 */
175
get_client_name(aClient * sptr,int showip)176 char *get_client_name(aClient *sptr, int showip)
177 {
178 static char nbuf[HOSTLEN * 2 + USERLEN + 5];
179
180 if (MyConnect(sptr))
181 {
182 #ifdef UNIXPORT
183 if (IsUnixSocket(sptr))
184 {
185 if (showip)
186 sprintf(nbuf, "%s[%s]",
187 sptr->name, sptr->sockhost);
188 else
189 sprintf(nbuf, "%s[%s]",
190 sptr->name, me.sockhost);
191 }
192 else
193 #endif
194 {
195 if (showip)
196 (void)sprintf(nbuf, "%s[%.*s@%s]",
197 sptr->name, USERLEN,
198 (!(sptr->flags & FLAGS_GOTID)) ? "" :
199 sptr->auth, sptr->user ? sptr->user->sip :
200 #ifdef INET6
201 inetntop(AF_INET6,
202 (char *)&sptr->ip,
203 ipv6string, sizeof(ipv6string))
204 #else
205 inetntoa((char *)&sptr->ip)
206 #endif
207 );
208 else
209 {
210 if (mycmp(sptr->name, sptr->sockhost))
211 /* Show username for clients and
212 * ident for others.
213 */
214 sprintf(nbuf, "%s[%.*s@%s]",
215 sptr->name, USERLEN,
216 IsPerson(sptr) ?
217 sptr->user->username :
218 sptr->auth,
219 IsPerson(sptr) ? sptr->user->host :
220 sptr->sockhost);
221 else
222 return sptr->name;
223 }
224 }
225 return nbuf;
226 }
227 return sptr->name;
228 }
229
get_client_host(aClient * cptr)230 char *get_client_host(aClient *cptr)
231 {
232 static char nbuf[HOSTLEN * 2 + USERLEN + 5];
233
234 if (!MyConnect(cptr))
235 return cptr->name;
236 if (!cptr->user)
237 return get_client_name(cptr, TRUE);
238 #ifdef UNIXPORT
239 if (IsUnixSocket(cptr))
240 sprintf(nbuf, "%s[%s]", cptr->name, ME);
241 else
242 #endif
243 (void)sprintf(nbuf, "%s[%-.*s@%-.*s]",
244 cptr->name, USERLEN,
245 (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->auth,
246 HOSTLEN, cptr->user->sip);
247 return nbuf;
248 }
249
250 /*
251 * Form sockhost such that if the host is of form user@host, only the host
252 * portion is copied.
253 */
get_sockhost(aClient * cptr,char * host)254 void get_sockhost(aClient *cptr, char *host)
255 {
256 Reg char *s;
257
258 if (!cptr || !host)
259 {
260 /* however unlikely this is, don't risk */
261 return;
262 }
263 if ((s = (char *)index(host, '@')))
264 {
265 s++;
266 }
267 else
268 {
269 s = host;
270 }
271 strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost));
272 Debug((DEBUG_DNS,"get_sockhost %s",s));
273 }
274
275 /*
276 * Return wildcard name of my server name according to given config entry
277 * --Jto
278 */
my_name_for_link(char * name,int count)279 char *my_name_for_link(char *name, int count)
280 {
281 static char namebuf[HOSTLEN];
282 Reg char *start = name;
283
284 if (count <= 0 || count > 5)
285 return start;
286
287 while (count-- && name)
288 {
289 name++;
290 name = (char *)index(name, '.');
291 }
292 if (!name)
293 return start;
294
295 namebuf[0] = '*';
296 (void)strncpy(&namebuf[1], name, HOSTLEN - 1);
297 namebuf[HOSTLEN - 1] = '\0';
298
299 return namebuf;
300 }
301
302 /*
303 * Goes thru the list of locally connected servers (except cptr),
304 * check if my neighbours can see the server "server" (or if it is hidden
305 * by a hostmask)
306 * Returns the number of marked servers
307 */
mark_blind_servers(aClient * cptr,aClient * server)308 int mark_blind_servers (aClient *cptr, aClient *server)
309 {
310 Reg int i, j = 0;
311 Reg aClient *acptr;
312 Reg aConfItem *aconf;
313
314 for (i = fdas.highest; i >= 0; i--)
315 {
316 if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr))
317 continue;
318 if (acptr == cptr->from || IsMe(acptr))
319 {
320 acptr->flags &= ~FLAGS_HIDDEN;
321 continue;
322 }
323 if (((aconf = acptr->serv->nline) &&
324 !match(my_name_for_link(ME, aconf->port), server->name)))
325 {
326 acptr->flags |= FLAGS_HIDDEN;
327 j++;
328 }
329 else
330 {
331 acptr->flags &= ~FLAGS_HIDDEN;
332 }
333 }
334 return j;
335 }
336
337 /*
338 ** exit_server(): Removes all dependent servers and clients, and
339 ** sends the right messages to the right client/servers.
340 **
341 ** We will send all SQUITs to &servers, and QUITs to local users.
342 ** We only send 1 SQUIT to a 2.11 servers.
343 ** We send all SQUITs to a 2.10 servers that can see it, or QUITs otherwise.
344 **
345 ** Argument:
346 ** cptr: The real server to SQUIT.
347 ** acptr: One of the depended servers to SQUIT.
348 ** from: Originator of SQUIT.
349 ** comment: The original comment for the SQUIT. (Only for cptr itself.)
350 ** comment2: The comment for (S)QUIT reasons for the rest.
351 */
exit_server(aClient * cptr,aClient * acptr,aClient * from,const char * comment,const char * comment2)352 static void exit_server(aClient *cptr, aClient *acptr, aClient *from,
353 const char *comment, const char *comment2)
354 {
355 aClient *acptr2;
356 int flags;
357
358 /* Remove all the servers recursively. */
359 while (acptr->serv->down)
360 {
361 exit_server(cptr, acptr->serv->down, from, comment, comment2);
362 }
363 /* Here we should send "Received SQUIT" for last server,
364 ** but exit_client() is doing (well, almost) this --Beeth */
365
366 /* This server doesn't have any depedent servers anymore, only
367 ** users/services left. */
368
369 flags = FLAGS_SPLIT;
370
371 /*
372 ** We'll mark all servers that can't see that server as hidden.
373 ** If we found any, we'll also mark all users on that server hidden.
374 ** If a user is marked hidden, and we try to send it to a currently
375 ** marked server, the server can't see that user's server.
376 ** Note that a 2.11 can see it, so we don't have to send the QUITs
377 ** to it.
378 */
379 if (mark_blind_servers(cptr, acptr))
380 {
381 flags |= FLAGS_HIDDEN;
382 }
383
384 /* Quit all users and services. */
385 while (GotDependantClient(acptr))
386 {
387 acptr2 = acptr->prev;
388 acptr2->flags |= flags;
389 exit_one_client(cptr->from, acptr2, from, comment2);
390 }
391
392 /* Make sure we only send the last SQUIT to a 2.11 server. */
393 if (acptr == cptr)
394 {
395 acptr->flags |= FLAGS_SQUIT;
396 }
397 if (!IsMasked(acptr))
398 {
399 sendto_flag(SCH_SERVER,
400 "Received SQUIT %s from %s (%s)", acptr->name,
401 from->name,
402 acptr == cptr ? comment : comment2);
403 }
404 exit_one_client(cptr->from, acptr, from,
405 acptr == cptr ? comment : comment2);
406
407 return;
408 }
409
410 /*
411 ** exit_client
412 ** This is old "m_bye". Name changed, because this is not a
413 ** protocol function, but a general server utility function.
414 **
415 ** This function exits a client of *any* type (user, server, etc)
416 ** from this server. Also, this generates all necessary prototol
417 ** messages that this exit may cause.
418 **
419 ** 1) If the client is a local client, then this implicitly
420 ** exits all other clients depending on this connection (e.g.
421 ** remote clients having 'from'-field that points to this.
422 **
423 ** 2) If the client is a remote client, then only this is exited.
424 **
425 ** For convenience, this function returns a suitable value for
426 ** m_funtion return value:
427 **
428 ** FLUSH_BUFFER if (cptr == sptr)
429 ** 0 if (cptr != sptr)
430 **
431 ** Parameters:
432 **
433 ** aClient *cptr
434 ** The local client originating the exit or NULL, if this
435 ** exit is generated by this server for internal reasons.
436 ** This will not get any of the generated messages.
437 ** aClient *sptr
438 ** Client exiting
439 ** aClient *from
440 ** Client firing off this Exit, never NULL!
441 ** char *comment
442 ** Reason for the exit
443 */
exit_client(aClient * cptr,aClient * sptr,aClient * from,const char * comment)444 int exit_client(aClient *cptr, aClient *sptr, aClient *from,
445 const char *comment)
446 {
447 char comment1[HOSTLEN + HOSTLEN + 2];
448
449 if (MyConnect(sptr))
450 {
451 if (sptr->flags & FLAGS_KILLED)
452 {
453 sendto_flag(SCH_NOTICE, "Killed: %s.",
454 get_client_name(sptr, TRUE));
455 sptr->exitc = EXITC_KILL;
456 }
457
458 sptr->flags |= FLAGS_CLOSING;
459 #if (defined(FNAME_USERLOG) || defined(FNAME_CONNLOG) \
460 || defined(USE_SERVICES)) \
461 || (defined(USE_SYSLOG) && (defined(SYSLOG_USERS) || defined(SYSLOG_CONN)))
462 if (IsPerson(sptr))
463 {
464 # if defined(FNAME_USERLOG) || defined(USE_SERVICES) || \
465 (defined(USE_SYSLOG) && defined(SYSLOG_USERS))
466 sendto_flog(sptr, EXITC_REG, sptr->user->username,
467 sptr->user->host);
468 # endif
469 # if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_QUIT)
470 sendto_flag(SCH_CLIENT, "%s %s %s %s QUIT %c"
471 # if (CLIENTS_CHANNEL_LEVEL & CCL_QUITINFO)
472 " :%s"
473 # endif
474 , sptr->user->uid, sptr->name,
475 sptr->user->username, sptr->user->host,
476 sptr->exitc
477 # if (CLIENTS_CHANNEL_LEVEL & CCL_QUITINFO)
478 , comment
479 # endif
480 );
481 # endif
482 }
483 else if (!IsService(sptr))
484 {
485 # if defined(FNAME_CONNLOG) || defined(USE_SERVICES) || \
486 (defined(USE_SYSLOG) && defined(SYSLOG_CONN))
487 if (sptr->exitc == '\0' || sptr->exitc == EXITC_REG)
488 {
489 sptr->exitc = EXITC_UNDEF;
490 }
491 sendto_flog(sptr, sptr->exitc,
492 sptr->user && sptr->user->username ?
493 sptr->user->username : "",
494 #ifdef UNIXPORT
495 (IsUnixSocket(sptr)) ? me.sockhost :
496 #endif
497 ((sptr->hostp) ? sptr->hostp->h_name :
498 sptr->sockhost));
499 # endif
500 }
501 #endif
502 if (MyConnect(sptr))
503 {
504 if (IsPerson(sptr))
505 {
506 istat.is_myclnt--;
507 }
508 else if (IsServer(sptr))
509 {
510 istat.is_myserv--;
511 }
512 else if (IsService(sptr))
513 {
514 istat.is_myservice--;
515 }
516 else
517 {
518 istat.is_unknown--;
519 }
520
521 if (istat.is_myclnt % CLCHNO == 0 &&
522 istat.is_myclnt != istat.is_l_myclnt)
523 {
524 sendto_flag(SCH_NOTICE,
525 "Local %screase from %d to %d clients "
526 "in %d seconds",
527 istat.is_myclnt>istat.is_l_myclnt?"in":"de",
528 istat.is_l_myclnt, istat.is_myclnt,
529 timeofday - istat.is_l_myclnt_t);
530 istat.is_l_myclnt_t = timeofday;
531 istat.is_l_myclnt = istat.is_myclnt;
532 }
533 /* Send SQUIT message to 2.11 servers to tell them
534 * the squit reason for rebroadcast on the other side
535 * - jv
536 */
537 if (IsServer(sptr))
538 {
539 sendto_one(sptr, ":%s SQUIT %s :%s",
540 me.serv->sid, sptr->serv->sid,
541 comment);
542 }
543
544 if (cptr != NULL && sptr != cptr)
545 {
546 sendto_one(sptr, "ERROR :Closing Link: "
547 "%s %s (%s)",
548 get_client_name(sptr,FALSE),
549 cptr->name, comment);
550 }
551 else
552 {
553 sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
554 get_client_name(sptr,FALSE), comment);
555 }
556
557 if (sptr->auth != sptr->username)
558 {
559 istat.is_authmem -= strlen(sptr->auth) + 1;
560 istat.is_auth -= 1;
561 MyFree(sptr->auth);
562 sptr->auth = sptr->username;
563 }
564 }
565 /*
566 ** Currently only server connections can have
567 ** depending remote clients here, but it does no
568 ** harm to check for all local clients. In
569 ** future some other clients than servers might
570 ** have remotes too...
571 ** now, I think it harms big client servers... - krys
572 **
573 ** Close the Client connection first and mark it
574 ** so that no messages are attempted to send to it.
575 ** (The following *must* make MyConnect(sptr) == FALSE!).
576 ** It also makes sptr->from == NULL, thus it's unnecessary
577 ** to test whether "sptr != acptr" in the following loops.
578 */
579 close_connection(sptr);
580
581 } /* if (MyConnect(sptr) */
582
583 if (IsServer(sptr))
584 {
585 /* Remove all dependent servers and clients. */
586 if (!IsMasked(sptr))
587 {
588 sprintf(comment1, "%s %s", sptr->serv->up->name,
589 sptr->name);
590 }
591 else
592 {
593 /* It was a masked server, the squit reason should
594 ** give the right quit reason for clients. */
595 strncpyzt(comment1, comment, sizeof(comment1));
596 }
597 /* cptr != sptr means non-local server */
598 if (cptr != sptr &&
599 nextconnect == 0 && find_conf_name(sptr->name,
600 (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)))
601 {
602 /* try AC */
603 nextconnect = timeofday + HANGONRETRYDELAY;
604 }
605 exit_server(sptr, sptr, from, comment, comment1);
606 check_split();
607 if ((cptr == sptr))
608 {
609 /* It serves no purpose. --B.
610 sendto_flag(SCH_SERVER, "Sending SQUIT %s (%s)",
611 cptr->name, comment);
612 */
613 return FLUSH_BUFFER;
614 }
615 return 0;
616 }
617
618 /*
619 ** Try to guess from comment if the client is exiting
620 ** normally (KILL or issued QUIT), or if it is splitting
621 ** It requires comment for splitting users to be
622 ** "server.some.where splitting.some.where"
623 */
624 comment1[0] = '\0';
625 if ((sptr->flags & FLAGS_KILLED) == 0)
626 {
627 if (comment[0] == '"')
628 {
629 /* definitely user quit, see m_quit */
630 sptr->flags |= FLAGS_QUIT;
631 }
632 else
633 {
634 const char *c = comment;
635 int i = 0;
636 while (*c && *c != ' ')
637 if (*c++ == '.')
638 i++;
639 if (*c++ && i)
640 {
641 i = 0;
642 while (*c && *c != ' ')
643 if (*c++ == '.')
644 i++;
645 if (!i || *c)
646 sptr->flags |= FLAGS_QUIT;
647 }
648 else
649 {
650 sptr->flags |= FLAGS_QUIT;
651 }
652 }
653
654 if (sptr == cptr && !(sptr->flags & FLAGS_QUIT))
655 {
656 /*
657 ** This will avoid nick delay to be abused by
658 ** letting local users put a comment looking
659 ** like a server split.
660 */
661 strncpyzt(comment1, comment, HOSTLEN + HOSTLEN);
662 strcat(comment1, " ");
663 sptr->flags |= FLAGS_QUIT;
664 }
665 }
666
667 exit_one_client(cptr, sptr, from, (*comment1) ? comment1 : comment);
668 /* XXX: we probably should not call it every client exit */
669 /* checking every server quit should suffice --B. */
670 /* check_split(); */
671 return cptr == sptr ? FLUSH_BUFFER : 0;
672 }
673
674 /*
675 ** Exit one client, local or remote. Assuming all dependants have
676 ** been already removed, and socket closed for local client.
677 */
exit_one_client(aClient * cptr,aClient * sptr,aClient * from,const char * comment)678 static void exit_one_client(aClient *cptr, aClient *sptr, aClient *from,
679 const char *comment)
680 {
681 Reg aClient *acptr;
682 Reg int i;
683 Reg Link *lp;
684 invLink *ilp;
685
686 /*
687 ** For a server or user quitting, propagage the information to
688 ** other servers (except to the one where is came from (cptr))
689 */
690 if (IsMe(sptr))
691 {
692 sendto_flag(SCH_ERROR,
693 "ERROR: tried to exit me! : %s", comment);
694 return; /* ...must *never* exit self!! */
695 }
696 else if (IsServer(sptr))
697 {
698 /*
699 ** Old sendto_serv_but_one() call removed because we now
700 ** need to send different names to different servers
701 ** (domain name matching)
702 */
703 if (!IsMasked(sptr))
704 {
705 istat.is_serv--;
706 }
707 if (!IsBursting(sptr))
708 {
709 istat.is_eobservers--;
710 }
711 for (i = fdas.highest; i >= 0; i--)
712 {
713 if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
714 acptr == cptr || IsMe(acptr))
715 {
716 continue;
717 }
718 if (!(sptr->flags & FLAGS_SQUIT))
719 {
720 /* Make sure we only send the last SQUIT
721 ** to a 2.11. */
722 continue;
723 }
724 if ((acptr->flags & FLAGS_HIDDEN) &&
725 !IsMasked(sptr))
726 {
727 /* We need a special SQUIT reason, so
728 ** the remote server can send the
729 ** right quit message. */
730 sendto_one(acptr, ":%s SQUIT %s :%s %s",
731 sptr->serv->up->serv->sid,
732 sptr->serv->sid,
733 sptr->serv->up->name,
734 sptr->name);
735 }
736 else
737 {
738 sendto_one(acptr, ":%s SQUIT %s :%s",
739 sptr->serv->up->serv->sid,
740 sptr->serv->sid, comment);
741 }
742 }
743 #ifdef USE_SERVICES
744 check_services_butone(SERVICE_WANT_SQUIT, sptr->serv, sptr,
745 ":%s SQUIT %s :%s", from->name,
746 sptr->name, comment);
747 #endif
748 del_from_sid_hash_table(sptr->serv);
749 remove_server_from_tree(sptr);
750 /* remove server from svrtop */
751 unregister_server(sptr);
752 }
753 else if (!IsPerson(sptr) && !IsService(sptr))
754 {
755 /* ...this test is *dubious*, would need
756 ** some thougth.. but for now it plugs a
757 ** nasty hole in the server... --msa
758 */
759 ; /* Nothing */
760 }
761 else if (sptr->name[0] && !IsService(sptr)) /* clean with QUIT... */
762 {
763 /*
764 ** If this exit is generated from "m_kill", then there
765 ** is no sense in sending the QUIT--KILL's have been
766 ** sent instead.
767 */
768 if ((sptr->flags & FLAGS_KILLED) == 0)
769 {
770 if ((sptr->flags & FLAGS_SPLIT) == 0)
771 {
772 sendto_serv_butone(cptr, ":%s QUIT :%s",
773 sptr->user->uid, comment);
774 #ifdef USE_SERVICES
775 check_services_butone(SERVICE_WANT_QUIT|
776 SERVICE_WANT_RQUIT,
777 (sptr->user) ?
778 sptr->user->servp
779 : NULL, cptr,
780 ":%s QUIT :%s",
781 sptr->name, comment);
782 #endif
783 }
784 else
785 {
786 if (sptr->flags & FLAGS_HIDDEN)
787 /* joys of hostmasking */
788 for (i = fdas.highest; i >= 0; i--)
789 {
790 if (!(acptr =local[fdas.fd[i]])
791 || acptr == cptr
792 || IsMe(acptr))
793 continue;
794 if (acptr->flags & FLAGS_HIDDEN)
795 sendto_one(acptr,
796 ":%s QUIT :%s",
797 sptr->user->uid,
798 comment);
799 }
800 #ifdef USE_SERVICES
801 check_services_butone(SERVICE_WANT_QUIT,
802 (sptr->user) ? sptr->user->servp
803 : NULL, cptr,
804 ":%s QUIT :%s",
805 sptr->name, comment);
806 #endif
807 }
808 }
809 #ifdef USE_SERVICES
810 else
811 {
812 /* Send QUIT to services which desire such as well.
813 ** Services with both _QUIT and _KILL will get both
814 ** for now --jv
815 */
816 check_services_butone(SERVICE_WANT_QUIT,
817 (sptr->user) ? sptr->user->servp
818 : NULL, cptr,
819 ":%s QUIT :%s",
820 sptr->name, comment);
821
822 }
823 #endif
824 /*
825 ** If a person is on a channel, send a QUIT notice
826 ** to every client (person) on the same channel (so
827 ** that the client can show the "**signoff" message).
828 ** (Note: The notice is to the local clients *only*)
829 */
830 if (sptr->user)
831 {
832 if (IsInvisible(sptr))
833 {
834 istat.is_user[1]--;
835 sptr->user->servp->usercnt[1]--;
836 }
837 else
838 {
839 istat.is_user[0]--;
840 sptr->user->servp->usercnt[0]--;
841 }
842 if (IsAnOper(sptr))
843 {
844 sptr->user->servp->usercnt[2]--;
845 istat.is_oper--;
846 }
847 sendto_common_channels(sptr, ":%s QUIT :%s",
848 sptr->name, comment);
849
850 if (!(acptr = cptr ? cptr : sptr->from))
851 acptr = sptr;
852 while ((lp = sptr->user->channel))
853 {
854 /*
855 ** Mark channels from where remote chop left,
856 ** this will eventually lock the channel.
857 ** close_connection() has already been called,
858 ** it makes MyConnect == False - krys
859 */
860 if (sptr != cptr)
861 {
862 if (*lp->value.chptr->chname == '!')
863 {
864 if (!(sptr->flags &FLAGS_QUIT))
865 lp->value.chptr->history = timeofday + LDELAYCHASETIMELIMIT;
866 }
867 else if (
868 #ifndef BETTER_CDELAY
869 !(sptr->flags & FLAGS_QUIT) &&
870 #endif
871 is_chan_op(sptr, lp->value.chptr))
872 {
873 lp->value.chptr->history = timeofday + DELAYCHASETIMELIMIT;
874 }
875 }
876 if (IsAnonymous(lp->value.chptr) &&
877 !IsQuiet(lp->value.chptr))
878 {
879 sendto_channel_butserv(lp->value.chptr, sptr, ":%s PART %s :None", sptr->name, lp->value.chptr->chname);
880 }
881 remove_user_from_channel(sptr,lp->value.chptr);
882 }
883
884 /* Clean up invitefield */
885 while ((ilp = sptr->user->invited))
886 {
887 del_invite(sptr, ilp->chptr);
888 /* again, this is all that is needed */
889 }
890
891 /* remove from uid hash table */
892 if (sptr->user)
893 {
894 del_from_uid_hash_table(sptr->user->uid, sptr);
895 }
896
897 /* Add user to history */
898 #ifndef BETTER_NDELAY
899 add_history(sptr, (sptr->flags & FLAGS_QUIT) ?
900 &me : NULL);
901 #else
902 add_history(sptr, (sptr == cptr) ? &me : NULL);
903 #endif
904 off_history(sptr);
905 #ifdef USE_HOSTHASH
906 del_from_hostname_hash_table(sptr->user->host,
907 sptr->user);
908 #endif
909 #ifdef USE_IPHASH
910 del_from_ip_hash_table(sptr->user->sip, sptr->user);
911 #endif
912 }
913 }
914 else if (sptr->name[0] && IsService(sptr))
915 {
916 /*
917 ** If this exit is generated from "m_kill", then there
918 ** is no sense in sending the QUIT--KILL's have been
919 ** sent instead.
920 */
921 if ((sptr->flags & FLAGS_KILLED) == 0)
922 {
923 /*
924 ** A service quitting is annoying, It has to be sent
925 ** to connected servers depending on
926 ** sptr->service->dist
927 */
928 for (i = fdas.highest; i >= 0; i--)
929 {
930 if (!(acptr = local[fdas.fd[i]])
931 || !IsServer(acptr) || acptr == cptr
932 || IsMe(acptr))
933 {
934 continue;
935 }
936 if (match(sptr->service->dist, acptr->name) &&
937 match(sptr->service->dist, acptr->serv->sid))
938 {
939 continue;
940 }
941 sendto_one(acptr, ":%s QUIT :%s", sptr->name,
942 comment);
943 }
944 }
945 #ifdef USE_SERVICES
946 check_services_butone(SERVICE_WANT_SERVICE, NULL, NULL,
947 ":%s QUIT :%s", sptr->name, comment);
948 #endif
949 /* MyConnect(sptr) is always FALSE here */
950 if (cptr == sptr)
951 {
952 sendto_flag(SCH_NOTICE, "Service %s disconnected",
953 get_client_name(sptr, TRUE));
954 }
955 sendto_flag(SCH_SERVICE, "Received QUIT %s from %s (%s)",
956 sptr->name, from->name, comment);
957 istat.is_service--;
958 }
959
960 /* Remove sptr from the client list */
961 if (del_from_client_hash_table(sptr->name, sptr) != 1)
962 {
963 Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
964 sptr, sptr->name,
965 sptr->from ? sptr->from->sockhost : "??host",
966 sptr->from, sptr->next, sptr->prev, sptr->fd,
967 sptr->status, sptr->user));
968 }
969 remove_client_from_list(sptr);
970 return;
971 }
972
checklist(void)973 void checklist(void)
974 {
975 Reg aClient *acptr;
976 Reg int i,j;
977
978 if (!(bootopt & BOOT_AUTODIE))
979 return;
980 for (j = i = 0; i <= highest_fd; i++)
981 if (!(acptr = local[i]))
982 continue;
983 else if (IsClient(acptr))
984 j++;
985 if (!j)
986 {
987 #ifdef USE_SYSLOG
988 syslog(LOG_WARNING,"ircd exiting: autodie");
989 #endif
990 exit(0);
991 }
992 return;
993 }
994
initstats(void)995 void initstats(void)
996 {
997 bzero((char *)&istat, sizeof(istat));
998 istat.is_serv = 1;
999 istat.is_localc = 1; /* me */
1000 istat.is_m_users_t = timeofday;
1001 istat.is_m_myclnt_t = timeofday;
1002 istat.is_l_myclnt_t = timeofday;
1003 bzero((char *)&ircst, sizeof(ircst));
1004 }
1005
initruntimeconf(void)1006 void initruntimeconf(void)
1007 {
1008 memset((char *)&iconf, 0, sizeof(iconf));
1009 iconf.aconnect = 1; /* default to ON */
1010 iconf.split = 1; /* ircd starts in split-mode */
1011 iconf.caccept = 2; /* accept clients when no split */
1012
1013 /* Defaults set in config.h */
1014 iconf.split_minservers = DEFAULT_SPLIT_SERVERS;
1015 iconf.split_minusers = DEFAULT_SPLIT_USERS;
1016
1017 if ((bootopt & BOOT_STANDALONE))
1018 {
1019 /* standalone mode */
1020 iconf.split = 3;
1021 }
1022 }
1023
tstats(aClient * cptr,char * name)1024 void tstats(aClient *cptr, char *name)
1025 {
1026 Reg aClient *acptr;
1027 Reg int i;
1028 Reg struct stats *sp;
1029 struct stats tmp;
1030
1031 sp = &tmp;
1032 bcopy((char *)ircstp, (char *)sp, sizeof(*sp));
1033 for (i = 0; i < MAXCONNECTIONS; i++)
1034 {
1035 if (!(acptr = local[i]))
1036 continue;
1037 if (IsServer(acptr))
1038 {
1039 sp->is_sbs += acptr->sendB;
1040 sp->is_sbr += acptr->receiveB;
1041 sp->is_sti += timeofday - acptr->firsttime;
1042 sp->is_sv++;
1043 }
1044 else if (IsClient(acptr))
1045 {
1046 sp->is_cbs += acptr->sendB;
1047 sp->is_cbr += acptr->receiveB;
1048 sp->is_cti += timeofday - acptr->firsttime;
1049 sp->is_cl++;
1050 }
1051 else if (IsUnknown(acptr))
1052 sp->is_ni++;
1053 }
1054
1055 sendto_one(cptr, ":%s %d %s :accepts %lu refused %lu",
1056 ME, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref);
1057 sendto_one(cptr, ":%s %d %s :unknown: commands %lu prefixes %lu",
1058 ME, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf);
1059 sendto_one(cptr, ":%s %d %s :nick collisions %lu saves %lu, unknown closes %lu",
1060 ME, RPL_STATSDEBUG, name, sp->is_kill, sp->is_save, sp->is_ni);
1061 sendto_one(cptr, ":%s %d %s :wrong direction %lu empty %lu",
1062 ME, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt);
1063 sendto_one(cptr, ":%s %d %s :users without servers %lu ghosts N/A",
1064 ME, RPL_STATSDEBUG, name, sp->is_nosrv);
1065 sendto_one(cptr, ":%s %d %s :numerics seen %lu mode fakes %lu",
1066 ME, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake);
1067 sendto_one(cptr, ":%s %d %s :auth: successes %lu fails %lu",
1068 ME, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad);
1069 sendto_one(cptr,":%s %d %s :local connections %lu udp packets %lu",
1070 ME, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udpok);
1071 sendto_one(cptr,":%s %d %s :udp errors %lu udp dropped %lu",
1072 ME, RPL_STATSDEBUG, name, sp->is_udperr, sp->is_udpdrop);
1073 sendto_one(cptr,
1074 ":%s %d %s :link checks %lu passed %lu 15s/%lu 30s dropped %luSq/%luYg/%luFl",
1075 ME, RPL_STATSDEBUG, name, sp->is_ckl, sp->is_cklq,
1076 sp->is_cklok, sp->is_cklQ, sp->is_ckly, sp->is_cklno);
1077 if (sp->is_wwcnt)
1078 sendto_one(cptr, ":%s %d %s :whowas turnover %lu/%lu/%lu [%lu]",
1079 ME, RPL_STATSDEBUG, name, sp->is_wwmt,
1080 (u_int) (sp->is_wwt / sp->is_wwcnt), sp->is_wwMt,
1081 KILLCHASETIMELIMIT);
1082 if (sp->is_lkcnt)
1083 sendto_one(cptr, ":%s %d %s :ndelay turnover %lu/%lu/%lu [%lu]",
1084 ME, RPL_STATSDEBUG, name, sp->is_lkmt,
1085 (u_int) (sp->is_lkt / sp->is_lkcnt), sp->is_lkMt,
1086 DELAYCHASETIMELIMIT);
1087 sendto_one(cptr, ":%s %d %s :abuse protections %u strict %u", ME,
1088 RPL_STATSDEBUG, name, (bootopt & BOOT_PROT) ? 1 : 0,
1089 (bootopt & BOOT_STRICTPROT) ? 1 : 0);
1090 #ifdef DELAY_CLOSE
1091 sendto_one(cptr, ":%s %d %s :delay close %lu total %lu",
1092 ME, RPL_STATSDEBUG, name, istat.is_delayclosewait,
1093 istat.is_delayclose);
1094 #endif
1095 sendto_one(cptr, ":%s %d %s :local channels reops %d remote %d",
1096 ME, RPL_STATSDEBUG, name, sp->is_reop, sp->is_rreop);
1097 sendto_one(cptr, ":%s %d %s :Client - Server",
1098 ME, RPL_STATSDEBUG, name);
1099 sendto_one(cptr, ":%s %d %s :connected %lu %lu",
1100 ME, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv);
1101 sendto_one(cptr, ":%s %d %s :bytes sent %llu %llu",
1102 ME, RPL_STATSDEBUG, name,
1103 sp->is_cbs, sp->is_sbs);
1104 sendto_one(cptr, ":%s %d %s :bytes recv %llu %llu",
1105 ME, RPL_STATSDEBUG, name,
1106 sp->is_cbr, sp->is_sbr);
1107 sendto_one(cptr, ":%s %d %s :time connected %lu %lu",
1108 ME, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti);
1109 #if defined(USE_IAUTH)
1110 report_iauth_stats(cptr, name);
1111 #endif
1112 }
1113
1114 aMotd *motd = NULL;
1115 time_t motd_mtime;
1116
read_motd(char * filename)1117 void read_motd(char *filename)
1118 {
1119 int fd, len;
1120 register aMotd *temp, *last;
1121 struct stat Sb;
1122 char line[80];
1123 register char *tmp;
1124
1125 if ((fd = open(filename, O_RDONLY)) == -1)
1126 return;
1127 if (fstat(fd, &Sb) == -1)
1128 {
1129 close(fd);
1130 return;
1131 }
1132 if (Sb.st_mtime <= motd_mtime)
1133 {
1134 close(fd);
1135 return;
1136 }
1137 motd_mtime = Sb.st_mtime;
1138 for(;motd != NULL;motd=last)
1139 {
1140 last = motd->next;
1141 MyFree(motd->line);
1142 MyFree(motd);
1143 }
1144 (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
1145 last = NULL;
1146 while ((len=dgets(fd, line, sizeof(line)-1)) > 0)
1147 {
1148 if ((tmp = strchr(line, '\n')) != NULL)
1149 *tmp = (char) 0;
1150 else if ((tmp = strchr(line, '\r')) != NULL)
1151 *tmp = (char) 0;
1152 else
1153 line[len] = '\0';
1154 temp = (aMotd *)MyMalloc(sizeof(aMotd));
1155 temp->line = mystrdup(line);
1156 temp->next = NULL;
1157 if (!motd)
1158 motd = temp;
1159 else
1160 last->next = temp;
1161 last = temp;
1162 }
1163 (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
1164 close(fd);
1165 }
1166
check_split(void)1167 void check_split(void)
1168 {
1169 if ((bootopt & BOOT_STANDALONE))
1170 return;
1171
1172 if (istat.is_eobservers < iconf.split_minservers ||
1173 istat.is_user[0] + istat.is_user[1] < iconf.split_minusers)
1174 {
1175 /* Split detected */
1176 if (!IsSplit())
1177 {
1178 sendto_flag(SCH_NOTICE,
1179 "Network split detected, split mode activated");
1180 iconf.split = timeofday;
1181 }
1182 }
1183 else
1184 {
1185 /* End of split */
1186 if (IsSplit())
1187 {
1188 sendto_flag(SCH_NOTICE,
1189 "Network rejoined, split mode deactivated");
1190 iconf.split = 0;
1191 if (!firstrejoindone)
1192 {
1193 firstrejoindone = 1;
1194 activate_delayed_listeners();
1195 #ifdef CACCEPT_DEFAULT
1196 iconf.caccept = CACCEPT_DEFAULT;
1197 #endif
1198 }
1199 }
1200 }
1201 }
1202
1203 /* Some day play with better random functions (configure) etc. --B. */
myrand(void)1204 int myrand(void)
1205 {
1206 return rand();
1207 }
1208
mysrand(unsigned int seed)1209 void mysrand(unsigned int seed)
1210 {
1211 srand(seed);
1212 }
1213