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