1 /************************************************************************
2  *   IRC - Internet Relay Chat, ircd/ircd.c
3  *   Copyright (C) 1990 Jarkko Oikarinen and
4  *                      University of Oulu, Computing Center
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 1, or (at your option)
9  *   any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #ifndef lint
22 static const volatile char rcsid[] = "@(#)$Id: ircd.c,v 1.165 2010/08/11 17:39:00 bif Exp $";
23 #endif
24 
25 #include "os.h"
26 #include "s_defines.h"
27 #define IRCD_C
28 #include "s_externs.h"
29 #undef IRCD_C
30 
31 aClient me;			/* That's me */
32 aClient *client = &me;		/* Pointer to beginning of Client list */
33 
34 static	void	open_debugfile(void), setup_signals(void), io_loop(void);
35 
36 #if defined(USE_IAUTH)
37 static	RETSIGTYPE	s_slave(int s);
38 #endif
39 
40 istat_t	istat;
41 iconf_t iconf;
42 char	**myargv;
43 int	rehashed = 0;
44 int	portnum = -1;		    /* Server port number, listening this */
45 char	*configfile = IRCDCONF_PATH;	/* Server configuration file */
46 int	debuglevel = -1;		/* Server debug level */
47 int	bootopt = BOOT_PROT|BOOT_STRICTPROT;	/* Server boot option flags */
48 int	serverbooting = 1;
49 int	firstrejoindone = 0;		/* Server rejoined the network after
50 					   start */
51 char	*debugmode = "";		/*  -"-    -"-   -"-   -"- */
52 char	*sbrk0;				/* initial sbrk(0) */
53 char	*tunefile = IRCDTUNE_PATH;
54 volatile static	int	dorehash = 0,
55 			dorestart = 0,
56 			restart_iauth = 0;
57 
58 #ifdef DELAY_CLOSE
59 time_t	nextdelayclose = 0;	/* time for next delayed close */
60 #endif
61 time_t	nextconnect = 1;	/* time for next try_connections call */
62 time_t	nextgarbage = 1;        /* time for next collect_channel_garbage call*/
63 time_t	nextping = 1;		/* same as above for check_pings() */
64 time_t	nextdnscheck = 0;	/* next time to poll dns to force timeouts */
65 time_t	nextexpire = 1;		/* next expire run on the dns cache */
66 time_t	nextiarestart = 1;	/* next time to check if iauth is alive */
67 time_t	nextpreference = 1;	/* time for next calculate_preference call */
68 #ifdef TKLINE
69 time_t	nexttkexpire = 0;	/* time for next tkline_expire call */
70 #endif
71 
72 aClient *ListenerLL = NULL;	/* Listeners linked list */
73 
s_die(int s)74 RETSIGTYPE s_die(int s)
75 {
76 	sendto_serv_v(NULL, SV_UID, ":%s SDIE", me.serv->sid);
77 #ifdef	USE_SYSLOG
78 	(void)syslog(LOG_CRIT, "Server Killed By SIGTERM");
79 	(void)closelog();
80 #endif
81 	logfiles_close();
82 	ircd_writetune(tunefile);
83 	flush_connections(me.fd);
84 #ifdef  UNIXPORT
85 	{
86 		aClient *acptr;
87 		char unixpath[256];
88 		for (acptr = ListenerLL; acptr; acptr = acptr->next)
89 		{
90 			if (IsUnixSocket(acptr))
91 			{
92 				sprintf(unixpath, "%s/%d",
93 				    acptr->confs->value.aconf->host,
94 				    acptr->confs->value.aconf->port);
95 				(void)unlink(unixpath);
96 			}
97 		}
98 	}
99 #endif
100 	exit(-1);
101 }
102 
103 #if defined(USE_IAUTH)
s_slave(int s)104 static	RETSIGTYPE	s_slave(int s)
105 {
106 # if POSIX_SIGNALS
107 	struct	sigaction act;
108 
109 	act.sa_handler = s_slave;
110 	act.sa_flags = 0;
111 	(void)sigemptyset(&act.sa_mask);
112 	(void)sigaddset(&act.sa_mask, SIGUSR1);
113 	(void)sigaction(SIGUSR1, &act, NULL);
114 # else
115 	(void)signal(SIGUSR1, s_slave);
116 # endif
117 	restart_iauth = 1;
118 }
119 #endif
120 
s_rehash(int s)121 static RETSIGTYPE s_rehash(int s)
122 {
123 #if POSIX_SIGNALS
124 	struct	sigaction act;
125 
126 	act.sa_handler = s_rehash;
127 	act.sa_flags = 0;
128 	(void)sigemptyset(&act.sa_mask);
129 	(void)sigaddset(&act.sa_mask, SIGHUP);
130 	(void)sigaction(SIGHUP, &act, NULL);
131 #else
132 	(void)signal(SIGHUP, s_rehash);	/* sysV -argv */
133 #endif
134 	if (dorehash >= 1)
135 		dorehash = 2;
136 	else
137 		dorehash = 1;
138 }
139 
restart(char * mesg)140 void	restart(char *mesg)
141 {
142 #ifdef	USE_SYSLOG
143 	(void)syslog(LOG_WARNING, "Restarting Server because: %s (%u)", mesg,
144 		     (u_int)((char *)sbrk((size_t)0)-sbrk0));
145 #endif
146 	sendto_flag(SCH_NOTICE, "Restarting server because: %s (%u)", mesg,
147 		    (u_int)((char *)sbrk((size_t)0)-sbrk0));
148 	server_reboot();
149 }
150 
s_restart(int s)151 RETSIGTYPE s_restart(int s)
152 {
153 #if POSIX_SIGNALS
154 	struct	sigaction act;
155 
156 	act.sa_handler = s_restart;
157 	act.sa_flags = 0;
158 	(void)sigemptyset(&act.sa_mask);
159 	(void)sigaddset(&act.sa_mask, SIGINT);
160 	(void)sigaction(SIGINT, &act, NULL);
161 #else
162 
163 	(void)signal(SIGHUP, SIG_DFL);	/* sysV -argv */
164 #endif
165 	if (bootopt & BOOT_TTY)
166 	{
167 		fprintf(stderr, "Caught SIGINT, terminating...\n");
168 		exit(-1);
169 	}
170 
171 	dorestart = 1;
172 }
173 
server_reboot(void)174 void	server_reboot(void)
175 {
176 	Reg	int	i;
177 
178 	sendto_flag(SCH_NOTICE, "Aieeeee!!!  Restarting server... (%u)",
179 		    (u_int)((char *)sbrk((size_t)0)-sbrk0));
180 
181 	Debug((DEBUG_NOTICE,"Restarting server..."));
182 	flush_connections(me.fd);
183 	/*
184 	** fd 0 must be 'preserved' if either the -d or -i options have
185 	** been passed to us before restarting.
186 	*/
187 #ifdef USE_SYSLOG
188 	(void)closelog();
189 #endif
190 	logfiles_close();
191 	for (i = 3; i < MAXCONNECTIONS; i++)
192 		(void)close(i);
193 	if (!(bootopt & (BOOT_TTY|BOOT_DEBUG)))
194 	{
195 		(void)close(2);
196 		(void)close(1);
197 	}
198 	if ((bootopt & BOOT_CONSOLE) || isatty(0))
199 		(void)close(0);
200 	ircd_writetune(tunefile);
201 	if (!(bootopt & BOOT_INETD))
202 	    {
203 		(void)execv(IRCD_PATH, myargv);
204 #ifdef USE_SYSLOG
205 		/* Have to reopen since it has been closed above */
206 
207 		openlog(mybasename(myargv[0]), LOG_PID|LOG_NDELAY, LOG_FACILITY);
208 		syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", IRCD_PATH,
209 		       myargv[0]);
210 		closelog();
211 #endif
212 		Debug((DEBUG_FATAL,"Couldn't restart server: %s",
213 		       strerror(errno)));
214 	    }
215 	exit(-1);
216 }
217 
218 
219 /*
220 ** try_connections
221 **
222 **	Scan through configuration and try new connections.
223 **	Returns the calendar time when the next call to this
224 **	function should be made latest. (No harm done if this
225 **	is called earlier or later...)
226 */
try_connections(time_t currenttime)227 static	time_t	try_connections(time_t currenttime)
228 {
229 	Reg	aConfItem *aconf;
230 	Reg	aClient *cptr;
231 	aConfItem **pconf;
232 	int	confrq;
233 	time_t	next = 0;
234 	aClass	*cltmp;
235 	aConfItem *con_conf = NULL;
236 	int	allheld = 1;
237 #ifdef DISABLE_DOUBLE_CONNECTS
238 	int	i;
239 #endif
240 
241 	if ((bootopt & BOOT_STANDALONE))
242 		return 0;
243 
244 	Debug((DEBUG_NOTICE,"Connection check at   : %s",
245 		myctime(currenttime)));
246 	for (aconf = conf; aconf; aconf = aconf->next )
247 	{
248 		/* not a C-line */
249 		if (!(aconf->status & (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)))
250 			continue;
251 
252 		/* not a candidate for AC */
253 		if (aconf->port <= 0)
254 			continue;
255 
256 		cltmp = Class(aconf);
257 		/* not a candidate for AC */
258 		if (MaxLinks(cltmp) == 0)
259 			continue;
260 
261 		/* minimize next to lowest hold time of all AC-able C-lines */
262 		if (next > aconf->hold || next == 0)
263 			next = aconf->hold;
264 
265 		/* skip conf if the use of it is on hold until future. */
266 		if (aconf->hold > currenttime)
267 			continue;
268 
269 		/* at least one candidate not held for future, good */
270 		allheld = 0;
271 
272 		/* see if another link in this conf is allowed */
273 		if (Links(cltmp) >= MaxLinks(cltmp))
274 			continue;
275 
276 		/* next possible check after connfreq secs for this C-line */
277 		confrq = get_con_freq(cltmp);
278 		aconf->hold = currenttime + confrq;
279 
280 		/* is this server already connected? */
281 		cptr = find_name(aconf->name, (aClient *)NULL);
282 		if (!cptr)
283 			cptr = find_mask(aconf->name, (aClient *)NULL);
284 
285 		/* matching client already exists, no AC to it */
286 		if (cptr)
287 			continue;
288 
289 		/* no such server, check D-lines */
290 		if (find_denied(aconf->name, Class(cltmp)))
291 			continue;
292 
293 #ifdef DISABLE_DOUBLE_CONNECTS
294 		/* Much better would be traversing only unknown
295 		** connections, but this requires another global
296 		** variable, adding and removing from there in
297 		** proper places etc. Some day. --B. */
298 		for (i = highest_fd; i >= 0; i--)
299 		{
300 			if (!(cptr = local[i]) ||
301 				cptr->status > STAT_UNKNOWN)
302 			{
303 				continue;
304 			}
305 			/* an unknown traveller we have */
306 			if (
307 #ifndef INET6
308 				cptr->ip.s_addr == aconf->ipnum.s_addr
309 #else
310 				!memcmp(cptr->ip.s6_addr,
311 					aconf->ipnum.s6_addr, 16)
312 #endif
313 			)
314 			{
315 				/* IP the same. Coincidence? Maybe.
316 				** Do not cause havoc with double connect. */
317 				break;
318 			}
319 			cptr = NULL;
320 		}
321 		if (cptr)
322 		{
323 			sendto_flag(SCH_SERVER, "AC to %s postponed", aconf->name);
324 			continue;
325 		}
326 #endif
327 		/* we have a candidate! */
328 
329 		/* choose the best. */
330 		if (!con_conf ||
331 		     (con_conf->pref > aconf->pref && aconf->pref >= 0) ||
332 		     (con_conf->pref == -1 &&
333 		      Class(cltmp) > ConfClass(con_conf)))
334 		{
335 			con_conf = aconf;
336 		}
337 		/* above is my doubt: if we always choose best connection
338 		** and it always fails connecting, we may never try another,
339 		** even "worse"; what shall we do? --Beeth */
340 	}
341 	if (con_conf)
342 	{
343 		if (con_conf->next)  /* are we already last? */
344 		{
345 			for (pconf = &conf; (aconf = *pconf);
346 			     pconf = &(aconf->next))
347 				/* put the current one at the end and
348 				 * make sure we try all connections
349 				 */
350 				if (aconf == con_conf)
351 					*pconf = aconf->next;
352 			(*pconf = con_conf)->next = 0;
353 		}
354 
355 		/* "Penalty" for being the best, so in next call of
356 		 * try_connections() other servers have chance. --B. */
357 		con_conf->hold += get_con_freq(Class(con_conf));
358 
359 		if (iconf.aconnect == 0 || iconf.aconnect == 2 &&
360 				timeofday - iconf.split > DELAYCHASETIMELIMIT)
361 		{
362 			sendto_flag(SCH_NOTICE,
363 				"Connection to %s deferred. Autoconnect "
364 				"administratively disabled", con_conf->name);
365 		}
366 		else if (connect_server(con_conf, (aClient *)NULL,
367 				   (struct hostent *)NULL) == 0)
368 		{
369 			sendto_flag(SCH_NOTICE,
370 				    "Connection to %s[%s] activated.",
371 				    con_conf->name, con_conf->host);
372 		}
373 	}
374 	else
375 	if (allheld == 0)	/* disable AC only when some C: got checked */
376 	{
377 		/* No suitable conf for AC was found, so why bother checking
378 		** again? If some server quits, it'd get reenabled --B. */
379 		next = 0;
380 	}
381 	Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next)));
382 	return (next);
383 }
384 
385 /*
386  * calculate preference value based on accumulated stats.
387  */
calculate_preference(time_t currenttime)388 time_t calculate_preference(time_t currenttime)
389 {
390 	aConfItem *aconf;
391 	aCPing	*cp;
392 	double	f, f2;
393 
394 	for (aconf = conf; aconf; aconf = aconf->next)
395 	{
396 		/* not a C-line */
397 		if (!(aconf->status & (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)))
398 			continue;
399 
400 		/* not a candidate for AC */
401 		if (aconf->port <= 0)
402 			continue;
403 
404 		/* send (udp) pings for all AC-able C-lines, we'll use it to
405 		** calculate preferences */
406 		send_ping(aconf);
407 
408 		if (!(cp = aconf->ping) || !cp->seq || !cp->recvd)
409 		{
410 			aconf->pref = -1;
411 		}
412 		else
413 		{
414 			f = (double)cp->recvd / (double)cp->seq;
415 			f2 = pow(f, (double)20.0);
416 			if (f2 < (double)0.001)
417 				f = (double)0.001;
418 			else
419 				f = f2;
420 			f2 = (double)cp->ping / (double)cp->recvd;
421 			f = f2 / f;
422 			if (f > 100000.0)
423 				f = 100000.0;
424 			aconf->pref = (u_int) (f * (double)100.0);
425 		}
426 	}
427 	return currenttime + 60;
428 }
429 
430 /* Checks all clients against KILL lines. (And remove them, if found.)
431 ** Only MAXDELAYEDKILLS at a time or all, if not defined.
432 ** Returns 1, if still work to do, 0 if finished.
433 */
delayed_kills(time_t currenttime)434 static	int	delayed_kills(time_t currenttime)
435 {
436 	static	time_t	dk_rehashed = 0;	/* time of last rehash we're processing */
437 	static	int	dk_lastfd;		/* fd we last checked */
438 	static	int	dk_checked;		/* # clients we checked */
439 	static	int	dk_killed;		/* # clients we killed */
440 	Reg	aClient	*cptr;
441 	Reg	int	i, j;
442 
443 	if (dk_rehashed == 0)
444 	{
445 		dk_rehashed = currenttime;
446 		dk_checked = 0;
447 		dk_killed = 0;
448 		dk_lastfd = highest_fd;
449 	}
450 #ifdef MAXDELAYEDKILLS
451 	/* checking only this many clients each time */
452 	j = dk_lastfd - MAXDELAYEDKILLS + 1;
453 	if (j < 0)
454 #endif
455 		j = 0;
456 
457 	for (i = dk_lastfd; i >= j; i--)
458 	{
459 		int	kflag = 0;
460 		char	*reason = NULL;
461 
462 		if (!(cptr = local[i]) || !IsPerson(cptr))
463 		{
464 			/* for K:lines we're interested only in local,
465 			** fully registered clients */
466 			if (j > 0)
467 				j--;
468 			continue;
469 		}
470 
471 		dk_checked++;
472 		kflag = find_kill(cptr, 0, &reason);
473 
474 		/* If the client is a user and a KILL line was found
475 		** to be active, close this connection. */
476 		if (kflag == -1)
477 		{
478 			char buf[100];
479 
480 			dk_killed++;
481 			sendto_flag(SCH_NOTICE,
482 				"Kill line active for %s",
483 				get_client_name(cptr, FALSE));
484 				cptr->exitc = EXITC_KLINE;
485 			if (!BadPtr(reason))
486 				sprintf(buf, "Kill line active: %.80s",
487 						reason);
488 			(void)exit_client(cptr, cptr, &me, (reason) ?
489 					  buf : "Kill line active");
490 		}
491 	}
492 	dk_lastfd = i;	/* from which fd to start next time */
493 	Debug((DEBUG_DEBUG, "DelayedKills killed %d and counting...",
494 		dk_killed));
495 
496 	if (dk_lastfd < 0)
497 	{
498 		sendto_flag(SCH_NOTICE, "DelayedKills checked %d killed %d "
499 			"in %d sec", dk_checked, dk_killed,
500 			currenttime - dk_rehashed);
501 		dk_rehashed = 0;
502 		if (rehashed == 2)
503 		{
504 			/* there was rehash queued, start again */
505 			return 1;
506 		}
507 		return 0;
508 	}
509 	return rehashed;
510 }
511 
check_pings(time_t currenttime)512 static	time_t	check_pings(time_t currenttime)
513 {
514 #ifdef TIMEDKLINES
515 	static	time_t	lkill = 0;
516 #endif
517 	Reg	aClient	*cptr;
518 	Reg	int	kflag = 0;
519 	aClient *bysptr = NULL;
520 	int	ping = 0, i;
521 	time_t	oldest = 0, timeout;
522 	char	*reason = NULL;
523 
524 	for (i = highest_fd; i >= 0; i--)
525 	    {
526 		if (!(cptr = local[i]) || IsListener(cptr))
527 			continue;
528 
529 #ifdef TIMEDKLINES
530 		kflag = 0;
531 		reason = NULL;
532 		/*
533 		** Once per TIMEDKLINES seconds.
534 		** (1 minute is minimum resolution in K-line field)
535 		*/
536 		if ((currenttime - lkill > TIMEDKLINES)
537 			&& IsPerson(cptr) && !IsKlineExempt(cptr))
538 		{
539 			kflag = find_kill(cptr, 1, &reason);
540 		}
541 #endif
542 		ping = IsRegistered(cptr) ? cptr->ping : ACCEPTTIMEOUT;
543 		Debug((DEBUG_DEBUG, "c(%s) %d p %d k %d a %d",
544 			cptr->name, cptr->status, ping, kflag,
545 			currenttime - cptr->lasttime));
546 		/*
547 		 * Ok, so goto's are ugly and can be avoided here but this code
548 		 * is already indented enough so I think its justified. -avalon
549 		 */
550 		if (!kflag && IsRegistered(cptr) &&
551 		    (ping >= currenttime - cptr->lasttime))
552 			goto ping_timeout;
553 		/*
554 		 * If the server hasnt talked to us in 2*ping seconds
555 		 * and it has a ping time, then close its connection.
556 		 * If the client is a user and a KILL line was found
557 		 * to be active, close this connection too.
558 		 */
559 		if (kflag ||
560 		    ((currenttime - cptr->lasttime) >= (2 * ping) &&
561 		     (cptr->flags & FLAGS_PINGSENT)) ||
562 		    (!IsRegistered(cptr) &&
563 		     (currenttime - cptr->firsttime) >= ping))
564 		    {
565 			if (!IsRegistered(cptr) &&
566 			    (DoingDNS(cptr) || DoingAuth(cptr) ||
567 			     DoingXAuth(cptr)))
568 			    {
569 				if (cptr->authfd >= 0)
570 				    {
571 					(void)close(cptr->authfd);
572 					cptr->authfd = -1;
573 					cptr->count = 0;
574 					*cptr->buffer = '\0';
575 				    }
576 				Debug((DEBUG_NOTICE, "%s/%c%s timeout %s",
577 				       (DoingDNS(cptr)) ? "DNS" : "dns",
578 				       (DoingXAuth(cptr)) ? "X" : "x",
579 				       (DoingAuth(cptr)) ? "AUTH" : "auth",
580 				       get_client_name(cptr,TRUE)));
581 				del_queries((char *)cptr);
582 				ClearAuth(cptr);
583 #if defined(USE_IAUTH)
584 				if (DoingDNS(cptr) || DoingXAuth(cptr))
585 				    {
586 					if (DoingDNS(cptr) &&
587 					    (iauth_options & XOPT_EXTWAIT))
588 					    {
589 						/* iauth wants more time */
590 						sendto_iauth("%d d", cptr->fd);
591 						ClearDNS(cptr);
592 						cptr->lasttime = currenttime;
593 						continue;
594 					    }
595 					if (DoingXAuth(cptr) &&
596 					    (iauth_options & XOPT_NOTIMEOUT))
597 					    {
598 						cptr->exitc = EXITC_AUTHTOUT;
599 						sendto_iauth("%d T", cptr->fd);
600 						exit_client(cptr, cptr, &me,
601 						     "Authentication Timeout");
602 						continue;
603 					    }
604 					sendto_iauth("%d T", cptr->fd);
605 					SetDoneXAuth(cptr);
606 				    }
607 #endif
608 				ClearDNS(cptr);
609 				ClearXAuth(cptr);
610 				ClearWXAuth(cptr);
611 				cptr->firsttime = currenttime;
612 				cptr->lasttime = currenttime;
613 				continue;
614 			    }
615 			if (IsServer(cptr) || IsConnecting(cptr) ||
616 			    IsHandshake(cptr))
617 			{
618 				if (cptr->serv && cptr->serv->byuid[0])
619 				{
620 					bysptr = find_uid(cptr->serv->byuid,
621 							NULL);
622 				}
623 				/* we are interested only in *remote* opers */
624 				if (bysptr && !MyConnect(bysptr))
625 				{
626 					sendto_one(bysptr, ":%s NOTICE %s :"
627 						"No response from %s, closing"
628 						" link", ME, bysptr->name,
629 						get_client_name(cptr, FALSE));
630 				}
631 				sendto_flag(SCH_NOTICE,
632 					    "No response from %s closing link",
633 					    get_client_name(cptr, FALSE));
634 			}
635 			/*
636 			 * this is used for KILL lines with time restrictions
637 			 * on them - send a message to the user being killed
638 			 * first.
639 			 */
640 			if (kflag && IsPerson(cptr))
641 			    {
642 				char buf[100];
643 
644 				sendto_flag(SCH_NOTICE,
645 					    "Kill line active for %s",
646 					    get_client_name(cptr, FALSE));
647 				cptr->exitc = EXITC_KLINE;
648 				if (!BadPtr(reason))
649 					sprintf(buf, "Kill line active: %.80s",
650 						reason);
651 				(void)exit_client(cptr, cptr, &me, (reason) ?
652 						  buf : "Kill line active");
653 			    }
654 			else
655 			    {
656 				cptr->exitc = EXITC_PING;
657 				(void)exit_client(cptr, cptr, &me,
658 						  "Ping timeout");
659 			    }
660 			continue;
661 		    }
662 		else if (IsRegistered(cptr) &&
663 			 (cptr->flags & FLAGS_PINGSENT) == 0)
664 		    {
665 			/*
666 			 * if we havent PINGed the connection and we havent
667 			 * heard from it in a while, PING it to make sure
668 			 * it is still alive.
669 			 */
670 			cptr->flags |= FLAGS_PINGSENT;
671 			/* not nice but does the job */
672 			cptr->lasttime = currenttime - ping;
673 			sendto_one(cptr, "PING :%s", me.name);
674 		    }
675 ping_timeout:
676 		timeout = cptr->lasttime + ping;
677 		while (timeout <= currenttime)
678 			timeout += ping;
679 		if (timeout < oldest || !oldest)
680 			oldest = timeout;
681 	    }
682 #ifdef TIMEDKLINES
683 	if (currenttime - lkill > 60)
684 		lkill = currenttime;
685 #endif
686 	if (!oldest || oldest < currenttime)
687 		oldest = currenttime + PINGFREQUENCY;
688 	if (oldest < currenttime + 30)
689 		oldest += 30;
690 	Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
691 		myctime(oldest), ping, oldest, currenttime));
692 	return (oldest);
693 }
694 
695 
setup_me(aClient * mp)696 static	void	setup_me(aClient *mp)
697 {
698 	struct	passwd	*p;
699 
700 	p = getpwuid(getuid());
701 	strncpyzt(mp->username, (p) ? p->pw_name : "unknown",
702 		  sizeof(mp->username));
703 	(void)get_my_name(mp, mp->sockhost, sizeof(mp->sockhost)-1);
704 	/* I think we need no hostp, especially fake one --B.  */
705 	mp->hostp = NULL;
706 	if (mp->serv->namebuf[0] == '\0')
707 		strncpyzt(mp->serv->namebuf, mp->sockhost, sizeof(mp->serv->namebuf));
708 	if (me.info == DefInfo)
709 		me.info = mystrdup("IRCers United");
710 	mp->lasttime = mp->since = mp->firsttime = time(NULL);
711 	mp->hopcount = 0;
712 	mp->authfd = -1;
713 	mp->auth = mp->username;
714 	mp->confs = NULL;
715 	mp->flags = 0;
716 	mp->acpt = mp->from = mp;
717 	mp->next = NULL;
718 	mp->user = NULL;
719 	mp->fd = -1;
720 	SetMe(mp);
721 	mp->serv->snum = find_server_num (ME);
722 	/* we don't fill our own IP -> 0 as ip lenght */
723 	(void) make_user(mp,0);
724 	istat.is_users++;	/* here, cptr->next is NULL, see make_user() */
725 	mp->user->flags |= FLAGS_OPER;
726 	mp->serv->up = mp;
727 	mp->serv->maskedby = mp;
728 	mp->serv->version |= SV_UID;
729 	mp->user->server = find_server_string(mp->serv->snum);
730 	strncpyzt(mp->user->username, (p) ? p->pw_name : "unknown",
731 		  sizeof(mp->user->username));
732 	(void) strcpy(mp->user->host, mp->name);
733 	SetEOB(mp);
734 	istat.is_eobservers = 1;
735 
736 	(void)add_to_client_hash_table(mp->name, mp);
737 	(void)add_to_sid_hash_table(mp->serv->sid, mp);
738 	strncpyzt(mp->serv->verstr, PATCHLEVEL, sizeof(mp->serv->verstr));
739 	setup_server_channels(mp);
740 }
741 
742 /*
743 ** bad_command
744 **	This is called when the commandline is not acceptable.
745 **	Give error message and exit without starting anything.
746 */
bad_command(void)747 static	void	bad_command(void)
748 {
749   (void)printf(
750 	 "Usage: ircd [-a] [-b] [-c]%s [-h servername] [-q] [-i]"
751 	 "[-T [tunefile]] [-p (strict|on|off)] [-s] [-v] [-t] %s\n",
752 #ifdef CMDLINE_CONFIG
753 	 " [-f config]",
754 #else
755 	 "",
756 #endif
757 #ifdef DEBUGMODE
758 	 " [-x loglevel]"
759 #else
760 	 ""
761 #endif
762 	 );
763   (void)printf("Server not started\n\n");
764   exit(-1);
765 }
766 
main(int argc,char * argv[])767 int	main(int argc, char *argv[])
768 {
769 	uid_t	uid, euid;
770 
771 	sbrk0 = (char *)sbrk((size_t)0);
772 	uid = getuid();
773 	euid = geteuid();
774 
775 #ifdef	CHROOTDIR
776 	ircd_res_init();
777 	if (chdir(ROOT_PATH)!=0)
778 	{
779 		perror("chdir");
780 		(void)fprintf(stderr,"%s: Cannot chdir: %s.\n", IRCD_PATH,
781 			ROOT_PATH);
782 		exit(5);
783 	}
784 	if (chroot(ROOT_PATH)!=0)
785 	    {
786 		perror("chroot");
787 		(void)fprintf(stderr,"%s: Cannot chroot: %s.\n", IRCD_PATH,
788 			      ROOT_PATH);
789 		exit(5);
790 	    }
791 #endif /*CHROOTDIR*/
792 
793 #ifdef	ZIP_LINKS
794 	if (zlib_version[0] == '0')
795 	    {
796 		fprintf(stderr, "zlib version 1.0 or higher required\n");
797 		exit(1);
798 	    }
799 	if (zlib_version[0] != ZLIB_VERSION[0])
800 	    {
801         	fprintf(stderr, "incompatible zlib version\n");
802 		exit(1);
803 	    }
804 	if (strcmp(zlib_version, ZLIB_VERSION) != 0)
805 	    {
806 		fprintf(stderr, "warning: different zlib version\n");
807 	    }
808 #endif
809 
810 	myargv = argv;
811 	(void)umask(077);                /* better safe than sorry --SRB */
812 	bzero((char *)&me, sizeof(me));
813 
814 	make_server(&me);
815 	register_server(&me);
816 
817 	version = make_version();	/* Generate readable version string */
818 
819 	/*
820 	** All command line parameters have the syntax "-fstring"
821 	** or "-f string" (e.g. the space is optional). String may
822 	** be empty. Flag characters cannot be concatenated (like
823 	** "-fxyz"), it would conflict with the form "-fstring".
824 	*/
825 	while (--argc > 0 && (*++argv)[0] == '-')
826 	    {
827 		char	*p = argv[0]+1;
828 		int	flag = *p++;
829 
830 		if (flag == '\0' || *p == '\0')
831 		{
832 			if (argc > 1 && argv[1][0] != '-')
833 			{
834 				p = *++argv;
835 				argc -= 1;
836 			}
837 			else
838 			{
839 				p = "";
840 			}
841 		}
842 
843 		switch (flag)
844 		    {
845                     case 'a':
846 			bootopt |= BOOT_AUTODIE;
847 			break;
848 		    case 'b':
849 			bootopt |= BOOT_BADTUNE;
850 			break;
851 		    case 'c':
852 			bootopt |= BOOT_CONSOLE;
853 			break;
854 		    case 'q':
855 			bootopt |= BOOT_QUICK;
856 			break;
857 #ifdef CMDLINE_CONFIG
858 		    case 'f':
859                         (void)setuid((uid_t)uid);
860 			configfile = p;
861 			break;
862 #endif
863 		    case 'h':
864 			if (*p == '\0')
865 				bad_command();
866 			strncpyzt(me.serv->namebuf, p, sizeof(me.serv->namebuf));
867 			break;
868 		    case 'i':
869 			bootopt |= BOOT_INETD|BOOT_AUTODIE;
870 		        break;
871 		    case 'p':
872 			if (!strcmp(p, "strict"))
873 				bootopt |= BOOT_PROT|BOOT_STRICTPROT;
874 			else if (!strcmp(p, "on"))
875 				bootopt |= BOOT_PROT;
876 			else if (!strcmp(p, "off"))
877 				bootopt &= ~(BOOT_PROT|BOOT_STRICTPROT);
878 			else if (!strcmp(p, "standalone"))
879 				bootopt |= BOOT_STANDALONE;
880 			else
881 				bad_command();
882 			break;
883 		    case 's':
884 			bootopt |= BOOT_NOIAUTH;
885 			break;
886 		    case 't':
887 #ifdef DEBUGMODE
888                         (void)setuid((uid_t)uid);
889 #endif
890 			bootopt |= BOOT_TTY;
891 			break;
892 		    case 'T':
893 			tunefile = p;
894 			break;
895 		    case 'v':
896 			(void)printf("ircd %s %s\n\tzlib %s\n\tircd.conf delimiter %c\n\t%s #%s\n",
897 				     version, serveropts,
898 #ifndef	ZIP_LINKS
899 				     "not used",
900 #else
901 				     zlib_version,
902 #endif
903 					IRCDCONF_DELIMITER,
904 				     creation, generation);
905 			  exit(0);
906 		    case 'x':
907 #ifdef	DEBUGMODE
908                         (void)setuid((uid_t)uid);
909 			debuglevel = atoi(p);
910 			debugmode = *p ? p : "0";
911 			bootopt |= BOOT_DEBUG;
912 			break;
913 #else
914 			(void)fprintf(stderr,
915 				"%s: DEBUGMODE must be defined for -x y\n",
916 				myargv[0]);
917 			exit(0);
918 #endif
919 		    default:
920 			bad_command();
921 		    }
922 	    }
923 
924 	if (strlen(tunefile) > 1023 || strlen(mybasename(tunefile)) > 42)
925 	{
926 		fprintf(stderr, "Too long tune filename\n");
927 		exit(-1);
928 	}
929 	if (argc > 0)
930 		bad_command(); /* This exits out */
931 
932 #ifndef IRC_UID
933 	if ((uid != euid) && !euid)
934 	    {
935 		(void)fprintf(stderr,
936 			"ERROR: do not run ircd setuid root. Make it setuid a\
937  normal user.\n");
938 		exit(-1);
939 	    }
940 #endif
941 
942 #if !defined(CHROOTDIR)
943 	(void)setuid((uid_t)euid);
944 # if defined(IRC_UID) && defined(IRC_GID)
945 	if ((int)getuid() == 0)
946 	    {
947 		/* run as a specified user */
948 		(void)fprintf(stderr,"WARNING: running ircd with uid = %d\n",
949 			IRC_UID);
950 		(void)fprintf(stderr,"         changing to gid %d.\n",IRC_GID);
951 		(void)setgid(IRC_GID);
952 		(void)setuid(IRC_UID);
953 	    }
954 # endif
955 #endif /*CHROOTDIR/UID/GID*/
956 
957 #if defined(USE_IAUTH)
958 	/* At this point, we just check whether iauth is there. Real start
959 	 * is done in init_sys(). */
960 	if ((bootopt & BOOT_NOIAUTH) == 0)
961 		switch (vfork())
962 		    {
963 		case -1:
964 			fprintf(stderr, "%s: Unable to fork!", myargv[0]);
965 			exit(-1);
966 		case 0:
967 			close(0); close(1); close(3);
968 			if (execl(IAUTH_PATH, IAUTH, "-X", NULL) < 0)
969 				_exit(-1);
970 		default:
971 		    {
972 			int rc;
973 
974 			(void)wait(&rc);
975 			if (rc != 0)
976 			    {
977 				fprintf(stderr,
978 					"%s: error: unable to find \"%s\".\n",
979 					myargv[0], IAUTH_PATH);
980 				exit(-1);
981 			    }
982 		    }
983 		    }
984 #endif
985 
986 	setup_signals();
987 
988 	/* didn't set debuglevel */
989 	/* but asked for debugging output to tty */
990 #ifdef DEBUGMODE
991 
992 	if ((debuglevel < 0) &&  (bootopt & BOOT_TTY))
993 	    {
994 		(void)fprintf(stderr,
995 			"you specified -t without -x. use -x <n>\n");
996 		exit(-1);
997 	    }
998 
999 #endif
1000 	timeofday = time(NULL);
1001 	initanonymous();
1002 	initstats();
1003 	initruntimeconf();
1004 	ircd_readtune(tunefile);
1005 	motd = NULL;
1006 	read_motd(IRCDMOTD_PATH);
1007 	inithashtables();
1008 	initlists();
1009 	initclass();
1010 	initwhowas();
1011 	timeofday = time(NULL);
1012 	open_debugfile();
1013 	timeofday = time(NULL);
1014 	(void)init_sys();
1015 
1016 #ifdef USE_SYSLOG
1017 	openlog(mybasename(myargv[0]), LOG_PID|LOG_NDELAY, LOG_FACILITY);
1018 #endif
1019 	timeofday = time(NULL);
1020 	if (initconf(bootopt) == -1)
1021 	    {
1022 		Debug((DEBUG_FATAL, "Couldn't open configuration file %s",
1023 			configfile));
1024 		(void)fprintf(stderr,
1025 			"Couldn't open configuration file %s (%s)\n",
1026 			 configfile,strerror(errno));
1027 
1028 		exit(-1);
1029 	    }
1030 	else
1031 	    {
1032 		aClient *acptr = NULL;
1033 		int i;
1034 
1035                 for (i = 0; i <= highest_fd; i++)
1036                     {
1037 			if (!(acptr = local[i]))
1038 				continue;
1039 			if (IsListener(acptr))
1040 				break;
1041 			acptr = NULL;
1042 		    }
1043 		/* exit if there is nothing to listen to */
1044 		if (acptr == NULL && !(bootopt & BOOT_INETD))
1045 		{
1046 			fprintf(stderr,
1047 			"Fatal Error: No working P-line in ircd.conf\n");
1048 			exit(-1);
1049 		}
1050 		/* Is there an M-line? */
1051 		if (!find_me())
1052 		{
1053 			fprintf(stderr,
1054 			"Fatal Error: No M-line in ircd.conf.\n");
1055 			exit(-1);
1056 		}
1057 		if ((i=check_servername(ME)))
1058 		{
1059 			fprintf(stderr,
1060 			"Fatal Error: %s.\n", check_servername_errors[i-1][1]);
1061 			exit(-1);
1062 		}
1063 		if (!me.serv->sid)
1064 		{
1065 			fprintf(stderr,
1066 			"Fatal Error: No SID specified in ircd.conf\n");
1067 			exit(-1);
1068 		}
1069 		if (!sid_valid(me.serv->sid))
1070 		{
1071 			fprintf(stderr,
1072 			"Fatal Error: Invalid sid %s specified in ircd.conf\n",
1073 				me.serv->sid);
1074 			exit(-1);
1075 		}
1076 		if (!networkname)
1077 		{
1078 			fprintf(stderr,
1079 			"Warning: Network name is not set in ircd.conf\n");
1080 		}
1081 		isupport = make_isupport();	/* Generate RPL_ISUPPORT (005) numerics */
1082 	    }
1083 
1084 	setup_me(&me);
1085 	check_class();
1086 	ircd_writetune(tunefile);
1087 	if (bootopt & BOOT_INETD)
1088 	    {
1089 		aClient	*tmp;
1090 		aConfItem *aconf;
1091 
1092 		tmp = make_client(NULL);
1093 		make_server(tmp);
1094 		register_server(tmp);
1095 
1096 		tmp->fd = 0;
1097 		tmp->flags = FLAGS_LISTEN;
1098 		tmp->acpt = tmp;
1099 		tmp->from = tmp;
1100 	        tmp->firsttime = time(NULL);
1101 
1102                 SetMe(tmp);
1103 
1104                 (void)strcpy(tmp->serv->namebuf, "*");
1105 
1106                 if (inetport(tmp, 0, "0.0.0.0", 0, 1))
1107                         tmp->fd = -1;
1108 		if (tmp->fd == 0)
1109 		    {
1110 			aconf = make_conf();
1111 			aconf->status = CONF_LISTEN_PORT;
1112 			aconf->clients++;
1113 	                aconf->next = conf;
1114         	        conf = aconf;
1115 
1116                         tmp->confs = make_link();
1117         	        tmp->confs->next = NULL;
1118 	               	tmp->confs->value.aconf = aconf;
1119 	                add_fd(tmp->fd, &fdas);
1120 	                add_fd(tmp->fd, &fdall);
1121 	                set_non_blocking(tmp->fd, tmp);
1122 		    }
1123 		else
1124 		    exit(5);
1125 	    }
1126 
1127 	Debug((DEBUG_NOTICE,"Server ready..."));
1128 #ifdef USE_SYSLOG
1129 	syslog(LOG_NOTICE, "Server Ready: v%s (%s #%s)", version, creation,
1130 	       generation);
1131 #endif
1132 	printf("Server %s (%s) version %s starting%s%s", ME, me.serv->sid,
1133 		version, (bootopt & BOOT_TTY) ? " in foreground mode." : ".",
1134 #ifdef DEBUGMODE
1135 		"(DEBUGMODE)\n"
1136 #else
1137 		"\n"
1138 #endif
1139 		);
1140 
1141 	timeofday = time(NULL);
1142 	mysrand(timeofday);
1143 
1144 	/* daemonize() closes 0,1,2 -- make sure you don't have any fd open */
1145 	daemonize();
1146 	logfiles_open();
1147 	write_pidfile();
1148 	dbuf_init();
1149 
1150 	serverbooting = 0;
1151 
1152 	while (1)
1153 		io_loop();
1154 }
1155 
1156 
io_loop(void)1157 static	void	io_loop(void)
1158 {
1159 	static	time_t	delay = 0;
1160 	int maxs = 4;
1161 
1162 	if (timeofday >= nextpreference)
1163 		nextpreference = calculate_preference(timeofday);
1164 	/*
1165 	** We only want to connect if a connection is due,
1166 	** not every time through.  Note, if there are no
1167 	** active C lines, this call to Tryconnections is
1168 	** made once only; it will return 0. - avalon
1169 	*/
1170 	if (nextconnect && timeofday >= nextconnect)
1171 		nextconnect = try_connections(timeofday);
1172 #ifdef DELAY_CLOSE
1173 	/* close all overdue delayed fds */
1174 	if (nextdelayclose && timeofday >= nextdelayclose)
1175 		nextdelayclose = delay_close(-1);
1176 #endif
1177 #ifdef TKLINE
1178 	/* expire tklines */
1179 	if (nexttkexpire && timeofday >= nexttkexpire)
1180 		nexttkexpire = tkline_expire(0);
1181 #endif
1182 	/*
1183 	** Every once in a while, hunt channel structures that
1184 	** can be freed. Reop channels while at it, too.
1185 	*/
1186 	if (timeofday >= nextgarbage)
1187 		nextgarbage = collect_channel_garbage(timeofday);
1188 	/*
1189 	** DNS checks. One to timeout queries, one for cache expiries.
1190 	*/
1191 	if (timeofday >= nextdnscheck)
1192 		nextdnscheck = timeout_query_list(timeofday);
1193 	if (timeofday >= nextexpire)
1194 		nextexpire = expire_cache(timeofday);
1195 	/*
1196 	** take the smaller of the two 'timed' event times as
1197 	** the time of next event (stops us being late :) - avalon
1198 	** WARNING - nextconnect can return 0!
1199 	*/
1200 	if (nextconnect)
1201 		delay = MIN(nextping, nextconnect);
1202 	else
1203 		delay = nextping;
1204 #ifdef DELAY_CLOSE
1205 	if (nextdelayclose)
1206 		delay = MIN(nextdelayclose, delay);
1207 #endif
1208 	delay = MIN(nextdnscheck, delay);
1209 	delay = MIN(nextexpire, delay);
1210 	delay = MIN(nextpreference, delay);
1211 	delay -= timeofday;
1212 	/*
1213 	** Adjust delay to something reasonable [ad hoc values]
1214 	** (one might think something more clever here... --msa)
1215 	** We don't really need to check that often and as long
1216 	** as we don't delay too long, everything should be ok.
1217 	** waiting too long can cause things to timeout...
1218 	** i.e. PINGS -> a disconnection :(
1219 	** - avalon
1220 	*/
1221 	if (delay < 1)
1222 		delay = 1;
1223 	else
1224 		delay = MIN(delay, TIMESEC);
1225 
1226 	/*
1227 	** First, try to drain traffic from servers and listening sockets.
1228 	** Give up either if there's no traffic or too many iterations.
1229 	*/
1230 	while (maxs--)
1231 		if (read_message(0, &fdas, 0))
1232 			flush_fdary(&fdas);
1233 		else
1234 			break;
1235 
1236 	Debug((DEBUG_DEBUG, "delay for %d", delay));
1237 	/*
1238 	** Second, deal with _all_ clients but only try to empty sendQ's for
1239 	** servers.  Other clients are dealt with below..
1240 	*/
1241 	if (read_message(1, &fdall, 1) == 0 && delay > 1)
1242 	    {
1243 		/*
1244 		** Timed out (e.g. *NO* traffic at all).
1245 		** Try again but also check to empty sendQ's for all clients.
1246 		*/
1247 		(void)read_message(delay - 1, &fdall, 0);
1248 	    }
1249 	timeofday = time(NULL);
1250 
1251 	Debug((DEBUG_DEBUG ,"Got message(s)"));
1252 	/*
1253 	** ...perhaps should not do these loops every time,
1254 	** but only if there is some chance of something
1255 	** happening (but, note that conf->hold times may
1256 	** be changed elsewhere--so precomputed next event
1257 	** time might be too far away... (similarly with
1258 	** ping times) --msa
1259 	*/
1260 	if (timeofday >= nextping)
1261 	    {
1262 		nextping = check_pings(timeofday);
1263 		if (rehashed > 0)
1264 		{
1265 			rehashed = delayed_kills(timeofday);
1266 		}
1267 	    }
1268 
1269 	if (dorestart)
1270 		restart("Caught SIGINT");
1271 	if (dorehash > 0)
1272 	    {	/* Only on signal, not on oper /rehash */
1273 		ircd_writetune(tunefile);
1274 		(void)rehash(&me, &me, 1);
1275 		dorehash--;
1276 	    }
1277 	if (restart_iauth || timeofday >= nextiarestart)
1278 	    {
1279 		start_iauth(restart_iauth);
1280 		restart_iauth = 0;
1281 		nextiarestart = timeofday + 15;
1282 	    }
1283 	/*
1284 	** Flush output buffers on all connections now if they
1285 	** have data in them (or at least try to flush)
1286 	** -avalon
1287 	*/
1288 	flush_connections(me.fd);
1289 
1290 #ifdef	DEBUGMODE
1291 	checklists();
1292 #endif
1293 
1294 }
1295 
1296 /*
1297  * open_debugfile
1298  *
1299  * If the -t option is not given on the command line when the server is
1300  * started, all debugging output is sent to the file set by IRCDDBG_PATH.
1301  * Here we just open that file and make sure it is opened to fd 2 so that
1302  * any fprintf's to stderr also goto the logfile.  If the debuglevel is not
1303  * set from the command line by -x, use /dev/null as the dummy logfile as long
1304  * as DEBUGMODE has been defined, else don't waste the fd.
1305  */
open_debugfile(void)1306 static	void	open_debugfile(void)
1307 {
1308 #ifdef	DEBUGMODE
1309 	int	fd;
1310 
1311 	if (debuglevel >= 0)
1312 	    {
1313 		(void)printf("isatty = %d ttyname = %#x\n",
1314 			isatty(2), (u_int)ttyname(2));
1315 		if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd 2 */
1316 		    {
1317 			(void)truncate(IRCDDBG_PATH, 0);
1318 			if ((fd = open(IRCDDBG_PATH,O_WRONLY|O_CREAT,0600))<0)
1319 				if ((fd = open("/dev/null", O_WRONLY)) < 0)
1320 					exit(-1);
1321 			if (fd != 2)
1322 			    {
1323 				(void)dup2(fd, 2);
1324 				(void)close(fd);
1325 			    }
1326 		    }
1327 		Debug((DEBUG_FATAL, "Debug: File <%s> Level: %d at %s",
1328 			( (!(bootopt & BOOT_TTY)) ? IRCDDBG_PATH :
1329 			(isatty(2) && ttyname(2)) ? ttyname(2) : "FD2-Pipe"),
1330 			debuglevel, myctime(time(NULL))));
1331 	    }
1332 #endif
1333 	return;
1334 }
1335 
setup_signals(void)1336 static	void	setup_signals(void)
1337 {
1338 #if POSIX_SIGNALS
1339 	struct	sigaction act;
1340 
1341 	act.sa_handler = SIG_IGN;
1342 	act.sa_flags = 0;
1343 	(void)sigemptyset(&act.sa_mask);
1344 	(void)sigaddset(&act.sa_mask, SIGPIPE);
1345 	(void)sigaddset(&act.sa_mask, SIGALRM);
1346 # ifdef	SIGWINCH
1347 	(void)sigaddset(&act.sa_mask, SIGWINCH);
1348 	(void)sigaction(SIGWINCH, &act, NULL);
1349 # endif
1350 	(void)sigaction(SIGPIPE, &act, NULL);
1351 	act.sa_handler = dummy;
1352 	(void)sigaction(SIGALRM, &act, NULL);
1353 	act.sa_handler = s_rehash;
1354 	(void)sigemptyset(&act.sa_mask);
1355 	(void)sigaddset(&act.sa_mask, SIGHUP);
1356 	(void)sigaction(SIGHUP, &act, NULL);
1357 	act.sa_handler = s_restart;
1358 	(void)sigaddset(&act.sa_mask, SIGINT);
1359 	(void)sigaction(SIGINT, &act, NULL);
1360 	act.sa_handler = s_die;
1361 	(void)sigaddset(&act.sa_mask, SIGTERM);
1362 	(void)sigaction(SIGTERM, &act, NULL);
1363 # if defined(USE_IAUTH)
1364 	act.sa_handler = s_slave;
1365 # else
1366 	act.sa_handler = SIG_IGN;
1367 # endif
1368 	(void)sigaddset(&act.sa_mask, SIGUSR1);
1369 	(void)sigaction(SIGUSR1, &act, NULL);
1370 # if defined(USE_IAUTH)
1371 	act.sa_handler = SIG_IGN;
1372 #  ifdef SA_NOCLDWAIT
1373         act.sa_flags = SA_NOCLDWAIT;
1374 #  else
1375         act.sa_flags = 0;
1376 #  endif
1377 	(void)sigaddset(&act.sa_mask, SIGCHLD);
1378 	(void)sigaction(SIGCHLD, &act, NULL);
1379 # endif
1380 
1381 # if defined(__FreeBSD__)
1382 	/* Don't core after detaching from gdb on fbsd */
1383 
1384 	act.sa_handler = SIG_IGN;
1385 	act.sa_flags = 0;
1386 	(void)sigaddset(&act.sa_mask, SIGTRAP);
1387 	(void)sigaction(SIGTRAP,&act,NULL);
1388 # endif /* __FreeBSD__ */
1389 
1390 #else /* POSIX_SIGNALS */
1391 
1392 # ifndef	HAVE_RELIABLE_SIGNALS
1393 	(void)signal(SIGPIPE, dummy);
1394 #  ifdef	SIGWINCH
1395 	(void)signal(SIGWINCH, dummy);
1396 #  endif
1397 # else /* HAVE_RELIABLE_SIGNALS */
1398 #  ifdef	SIGWINCH
1399 	(void)signal(SIGWINCH, SIG_IGN);
1400 #  endif
1401 	(void)signal(SIGPIPE, SIG_IGN);
1402 
1403 # endif /* HAVE_RELIABLE_SIGNALS */
1404 	(void)signal(SIGALRM, dummy);
1405 	(void)signal(SIGHUP, s_rehash);
1406 	(void)signal(SIGTERM, s_die);
1407 	(void)signal(SIGINT, s_restart);
1408 # if defined(USE_IAUTH)
1409 	(void)signal(SIGUSR1, s_slave);
1410 	(void)signal(SIGCHLD, SIG_IGN);
1411 # else
1412 	(void)signal(SIGUSR1, SIG_IGN);
1413 # endif
1414 
1415 # if defined(__FreeBSD__)
1416 	/* don't core after detaching from gdb on fbsd */
1417 	(void)signal(SIGTRAP, SIG_IGN);
1418 # endif /* __FreeBSD__ */
1419 
1420 #endif /* POSIX_SIGNAL */
1421 
1422 #ifdef RESTARTING_SYSTEMCALLS
1423 	/*
1424 	** At least on Apollo sr10.1 it seems continuing system calls
1425 	** after signal is the default. The following 'siginterrupt'
1426 	** should change that default to interrupting calls.
1427 	*/
1428 	(void)siginterrupt(SIGALRM, 1);
1429 #endif
1430 }
1431 
1432 /*
1433  * Called from bigger_hash_table(), s_die(), server_reboot(),
1434  * main(after initializations), grow_history(), rehash(io_loop) signal.
1435  */
ircd_writetune(char * filename)1436 void ircd_writetune(char *filename)
1437 {
1438 	int fd;
1439 	char buf[100];
1440 
1441 	if (!filename || !*filename)
1442 		return;
1443 
1444 	(void)truncate(filename, 0);
1445 	if ((fd = open(filename, O_CREAT|O_WRONLY, 0600)) >= 0)
1446 	    {
1447 		(void)sprintf(buf, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n", ww_size,
1448 			       lk_size, _HASHSIZE, _CHANNELHASHSIZE,
1449 			       _SIDSIZE, poolsize, _UIDSIZE);
1450 		if (write(fd, buf, strlen(buf)) == -1)
1451 			sendto_flag(SCH_ERROR,
1452 				    "Failed (%d) to write tune file: %s.",
1453 				    errno, mybasename(filename));
1454 		else
1455 			sendto_flag(SCH_NOTICE, "Updated %s.",
1456 				    mybasename(filename));
1457 		close(fd);
1458 	    }
1459 	else
1460 		sendto_flag(SCH_ERROR, "Failed (%d) to open tune file: %s.",
1461 			    errno, mybasename(filename));
1462 }
1463 
1464 /*
1465  * Called only from main() at startup.
1466  */
ircd_readtune(char * filename)1467 void ircd_readtune(char *filename)
1468 {
1469 	int fd, t_data[7];
1470 	char buf[100];
1471 
1472 	memset(buf, 0, sizeof(buf));
1473 	if ((fd = open(filename, O_RDONLY)) != -1)
1474 	    {
1475 		read(fd, buf, 100);	/* no panic if this fails.. */
1476 		if (sscanf(buf, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n", &t_data[0],
1477                            &t_data[1], &t_data[2], &t_data[3],
1478                            &t_data[4], &t_data[5], &t_data[6]) != 7)
1479 		    {
1480 			close(fd);
1481 			if (bootopt & BOOT_BADTUNE)
1482 				return;
1483 			else
1484 			    {
1485 				fprintf(stderr,
1486 					"ircd tune file %s: bad format\n",
1487 					filename);
1488 				exit(1);
1489 			    }
1490 		    }
1491 
1492 		/*
1493 		** Initiate the tune-values after successfully
1494 		** reading the tune-file.
1495 		*/
1496 		ww_size = t_data[0];
1497 		lk_size = t_data[1];
1498 		_HASHSIZE = t_data[2];
1499 #ifdef USE_HOSTHASH
1500 		_HOSTNAMEHASHSIZE = t_data[2]; /* hostname has always same size
1501 						  as the client hash */
1502 #endif
1503 #ifdef USE_IPHASH
1504 		_IPHASHSIZE = t_data[2];
1505 #endif
1506 		_CHANNELHASHSIZE = t_data[3];
1507 		_SIDSIZE = t_data[4];
1508 		poolsize = t_data[5];
1509 		_UIDSIZE = t_data[6];
1510 
1511 		/*
1512 		** the lock array only grows if the whowas array grows,
1513 		** I don't think it should be initialized with a lower
1514 		** size since it will never adjust unless whowas array does.
1515 		*/
1516 		if (lk_size < ww_size)
1517 			lk_size = ww_size;
1518 		close(fd);
1519 	    }
1520 }
1521 
1522