From 467acf9f87becdc34893655e086baf9e64c1337e Mon Sep 17 00:00:00 2001 From: Perry Lorier Date: Sun, 30 Apr 2000 06:44:27 +0000 Subject: [PATCH] Author: ZenShadow Log message: Cleanup for ircd.c and CHROOTDIR configuration stuff. Testing Required: * Configuration * CHROOT (enabled/disabled) * running as root * /restart and associated startup stuff. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@219 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 8 +- config/config-sh.in | 11 +- ircd/ircd.c | 914 +++++++++++++++++++------------------------- 3 files changed, 399 insertions(+), 534 deletions(-) diff --git a/ChangeLog b/ChangeLog index 95760af..a782980 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ -2000-04-29 Perry Lorier +2000-04-30 Steven M. Doyle + * config/config-sh.in: Fix for CHROOT + * ircd/ircd.c: General Cleanup + +2000-04-30 Perry Lorier * ircd/s_bsd.c: Sigh. :) * ircd/m_mode.c: fix for modeless channels by poptix. @@ -996,7 +1000,7 @@ # # ChangeLog for ircu2.10.11 # -# $Id: ChangeLog,v 1.116 2000-04-30 06:37:52 isomer Exp $ +# $Id: ChangeLog,v 1.117 2000-04-30 06:44:27 isomer Exp $ # # Insert new changes at beginning of the change list. # diff --git a/config/config-sh.in b/config/config-sh.in index 6cd8cf1..f2bc5e9 100644 --- a/config/config-sh.in +++ b/config/config-sh.in @@ -171,12 +171,13 @@ endmenu mainmenu_option next_comment comment 'General defines' - bool 'Change root ('/') after start of daemon' CHROOTDIR - bool 'Do you want the daemon set its own uid/gid' CONFIG_SETUGID + bool 'Do you want the daemon set its own uid/gid (say yes for chroot!)' CONFIG_SETUGID if [ "$CONFIG_SETUGID" = "y" ]; then int ' UID of irc daemon' IRC_UID int ' GID of irc daemon' IRC_GID + bool ' Change root ('/') after start of daemon' CHROOTDIR else + define_bool CHROOTDIR n define_int IRC_UID $IRC_UID define_int IRC_GID $IRC_GID bool 'Allow to specify configuration file on command line' CMDLINE_CONFIG @@ -197,7 +198,11 @@ mainmenu_option next_comment comment 'Paths and files' eval DPATH_DEFAULT="${prefix}/lib/ircd" string 'Directory where all ircd stuff resides' DPATH $DPATH_DEFAULT - define_string SPATH "$BINDIR/$SYMLINK" + if [ "$CHROOTDIR" = "y" ] ; then + define_string SPATH "/$SYMLINK" + else + define_string SPATH "$BINDIR/$SYMLINK" + fi echo "The following filenames are either full paths or files within DPATH" string 'Server configuration file' CPATH 'ircd.conf' string 'Server MOTD file' MPATH 'ircd.motd' diff --git a/ircd/ircd.c b/ircd/ircd.c index 47ea5c6..ad4ba77 100644 --- a/ircd/ircd.c +++ b/ircd/ircd.c @@ -19,21 +19,44 @@ * * $Id$ */ -#include "ircd.h" + + +/*---------------------------------------------------------------------------- + * Platform Includes + *--------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/*---------------------------------------------------------------------------- + * ircu Includes + *--------------------------------------------------------------------------*/ +#include "config.h" + #include "IPcheck.h" #include "class.h" #include "client.h" #include "crule.h" #include "hash.h" -#include "ircd_alloc.h" /* set_nomem_handler */ +#include "ircd.h" +#include "ircd_alloc.h" #include "ircd_log.h" #include "ircd_reply.h" #include "ircd_signal.h" #include "ircd_string.h" #include "jupe.h" #include "list.h" -#include "listener.h" #include "match.h" +#include "msg.h" #include "numeric.h" #include "numnicks.h" #include "parse.h" @@ -44,58 +67,76 @@ #include "s_debug.h" #include "s_misc.h" #include "send.h" -#include "struct.h" #include "sys.h" #include "uping.h" #include "userload.h" #include "version.h" #include "whowas.h" -#include "msg.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +/*---------------------------------------------------------------------------- + * External stuff + *--------------------------------------------------------------------------*/ extern void init_counters(void); +#ifdef PROFIL +extern etext(void); +#endif + + +/*---------------------------------------------------------------------------- + * Constants / Enums + *--------------------------------------------------------------------------*/ enum { BOOT_DEBUG = 1, BOOT_TTY = 2 }; -struct Client me; /* That's me */ -struct Client* GlobalClientList = &me; /* Pointer to beginning of Client list */ -time_t TSoffset = 0; /* Offset of timestamps to system clock */ -int GlobalRehashFlag = 0; /* do a rehash if set */ -int GlobalRestartFlag = 0; /* do a restart if set */ -time_t CurrentTime; /* Updated every time we leave select() */ -static struct Daemon thisServer = { 0 }; /* server process info */ +/*---------------------------------------------------------------------------- + * Global data (YUCK!) + *--------------------------------------------------------------------------*/ +struct Client me; // That's me +struct Client *GlobalClientList = &me; // Pointer to beginning of Client list +time_t TSoffset = 0; // Offset of timestamps to system clock +int GlobalRehashFlag = 0; // do a rehash if set +int GlobalRestartFlag = 0; // do a restart if set +time_t CurrentTime; // Updated every time we leave select() -char *configfile = CPATH; /* Server configuration file */ -int debuglevel = -1; /* Server debug level */ -char *debugmode = ""; /* -"- -"- -"- */ -static char *dpath = DPATH; +char *configfile = CPATH; // Server configuration file +int debuglevel = -1; // Server debug level +char *debugmode = ""; // Server debug level +static char *dpath = DPATH; -time_t nextconnect = 1; /* time for next try_connections call */ -time_t nextping = 1; /* same as above for check_pings() */ -time_t nextdnscheck = 0; /* next time to poll dns to force timeouts */ -time_t nextexpire = 1; /* next expire run on the dns cache */ +time_t nextconnect = 1; // time for next try_connections call +time_t nextping = 1; // same as above for check_pings() -#ifdef PROFIL -extern etext(void); -#endif +static struct Daemon thisServer = { 0 }; // server process info + + + +/*---------------------------------------------------------------------------- + * API: server_die + *--------------------------------------------------------------------------*/ +void server_die(const char* message) { + ircd_log(L_CRIT, "Server terminating: %s", message); + sendto_opmask_butone(0, SNO_OLDSNO, "Server terminating: %s", message); + flush_connections(0); + close_connections(1); + thisServer.running = 0; +} + + +/*---------------------------------------------------------------------------- + * API: server_restart + *--------------------------------------------------------------------------*/ +void server_restart(const char* message) { + static int restarting = 0; + + ircd_log(L_WARNING, "Restarting Server: %s", message); + if (restarting) + return; -static void server_reboot(const char* message) -{ sendto_opmask_butone(0, SNO_OLDSNO, "Restarting server: %s", message); Debug((DEBUG_NOTICE, "Restarting server...")); flush_connections(0); @@ -105,62 +146,45 @@ static void server_reboot(const char* message) execv(SPATH, thisServer.argv); - /* - * Have to reopen since it has been closed above - */ + /* Have to reopen since it has been closed above */ open_log(*thisServer.argv); ircd_log(L_CRIT, "execv(%s,%s) failed: %m\n", SPATH, *thisServer.argv); Debug((DEBUG_FATAL, "Couldn't restart server \"%s\": %s", SPATH, (strerror(errno)) ? strerror(errno) : "")); - exit(2); + exit(8); } -void server_die(const char* message) -{ - ircd_log(L_CRIT, "Server terminating: %s", message); - sendto_opmask_butone(0, SNO_OLDSNO, "Server terminating: %s", message); - flush_connections(0); - close_connections(1); - thisServer.running = 0; -} - -void server_restart(const char* message) -{ - static int restarting = 0; - ircd_log(L_WARNING, "Restarting Server: %s", message); - if (restarting == 0) { - restarting = 1; - server_reboot(message); - } -} - -static void outofmemory(void) -{ +/*---------------------------------------------------------------------------- + * outofmemory: Handler for out of memory conditions... + *--------------------------------------------------------------------------*/ +static void outofmemory(void) { Debug((DEBUG_FATAL, "Out of memory: restarting server...")); server_restart("Out of Memory"); } -static void write_pidfile(void) -{ -#ifdef PPATH - int fd; - char buff[20]; - if ((fd = open(PPATH, O_CREAT | O_WRONLY, 0600)) == -1) { - Debug((DEBUG_NOTICE, "Error opening pid file \"%s\": %s", - PPATH, strerror(errno))); + +/*---------------------------------------------------------------------------- + * write_pidfile + *--------------------------------------------------------------------------*/ +static void write_pidfile(void) { + FILE *pidf; + + if (!(pidf = fopen(PPATH, "w+"))) { + Debug((DEBUG_NOTICE, + "Error opening pid file \"%s\": %s", PPATH, strerror(errno))); return; } - memset(buff, 0, sizeof(buff)); - sprintf(buff, "%5d\n", getpid()); - if (write(fd, buff, strlen(buff)) == -1) + + if (fprintf(pidf, "%5d\n", getpid()) < 5) Debug((DEBUG_NOTICE, "Error writing to pid file %s", PPATH)); - close(fd); -#endif + + fclose(pidf); } -/* + +/*---------------------------------------------------------------------------- * try_connections * * Scan through configuration and try new connections. @@ -168,25 +192,23 @@ static void write_pidfile(void) * Returns the calendar time when the next call to this * function should be made latest. (No harm done if this * is called earlier or later...) - */ -static time_t try_connections(void) -{ - struct ConfItem* aconf; - struct Client* cptr; - struct ConfItem** pconf; - int connecting; - int confrq; - time_t next = 0; - struct ConfClass* cltmp; - struct ConfItem* cconf; - struct ConfItem* con_conf = NULL; - struct Jupe* ajupe; - unsigned int con_class = 0; + *--------------------------------------------------------------------------*/ +static time_t try_connections(void) { + struct ConfItem *aconf; + struct Client *cptr; + struct ConfItem **pconf; + int connecting; + int confrq; + time_t next = 0; + struct ConfClass *cltmp; + struct ConfItem *cconf; + struct ConfItem *con_conf = NULL; + struct Jupe *ajupe; + unsigned int con_class = 0; connecting = FALSE; Debug((DEBUG_NOTICE, "Connection check at : %s", myctime(CurrentTime))); - for (aconf = GlobalConfList; aconf; aconf = aconf->next) - { + for (aconf = GlobalConfList; aconf; aconf = aconf->next) { /* Also when already connecting! (update holdtimes) --SRB */ if (!(aconf->status & CONF_SERVER) || aconf->port == 0) continue; @@ -195,41 +217,34 @@ static time_t try_connections(void) if ((ajupe = jupe_find(aconf->name)) && JupeIsActive(ajupe)) continue; - cltmp = aconf->confClass; - /* - * Skip this entry if the use of it is still on hold until - * future. Otherwise handle this entry (and set it on hold - * until next time). Will reset only hold times, if already - * made one successfull connection... [this algorithm is - * a bit fuzzy... -- msa >;) ] + /* Skip this entry if the use of it is still on hold until + * future. Otherwise handle this entry (and set it on hold until next + * time). Will reset only hold times, if already made one successfull + * connection... [this algorithm is a bit fuzzy... -- msa >;) ] */ - - if ((aconf->hold > CurrentTime)) - { - if ((next > aconf->hold) || (next == 0)) - next = aconf->hold; + if (aconf->hold > CurrentTime && (next > aconf->hold || next == 0)) { + next = aconf->hold; continue; } + cltmp = aconf->confClass; confrq = get_con_freq(cltmp); aconf->hold = CurrentTime + confrq; - /* - * Found a CONNECT config with port specified, scan clients - * and see if this server is already connected? + + /* Found a CONNECT config with port specified, scan clients and see if + * this server is already connected? */ cptr = FindServer(aconf->name); if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) && - (!connecting || (ConClass(cltmp) > con_class))) - { + (!connecting || (ConClass(cltmp) > con_class))) { /* Check connect rules to see if we're allowed to try */ - for (cconf = GlobalConfList; cconf; cconf = cconf->next) - if ((cconf->status & CONF_CRULE) && - (match(cconf->host, aconf->name) == 0)) + for (cconf = GlobalConfList; cconf; cconf = cconf->next) { + if ((cconf->status & CONF_CRULE) && !match(cconf->host, aconf->name)) if (crule_eval(cconf->passwd)) break; - if (!cconf) - { + } + if (!cconf) { con_class = ConClass(cltmp); con_conf = aconf; /* We connect only one at time... */ @@ -239,96 +254,80 @@ static time_t try_connections(void) if ((next > aconf->hold) || (next == 0)) next = aconf->hold; } - if (connecting) - { - if (con_conf->next) /* are we already last? */ - { + if (connecting) { + if (con_conf->next) { /* are we already last? */ /* Put the current one at the end and make sure we try all connections */ for (pconf = &GlobalConfList; (aconf = *pconf); pconf = &(aconf->next)) if (aconf == con_conf) *pconf = aconf->next; (*pconf = con_conf)->next = 0; } + if (connect_server(con_conf, 0, 0)) sendto_opmask_butone(0, SNO_OLDSNO, "Connection to %s activated.", con_conf->name); } + Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next))); - return (next); + return(next); } -static time_t check_pings(void) -{ - int expire=0; - /* Temp to figure out what time this connection will next need - * to be checked. - */ - int next_check = CurrentTime + PINGFREQUENCY; - /* - * The current lowest expire time - ie: the time that check_pings - * needs to be called next. - */ - int max_ping = 0; - /* - * The time you've got before a ping is sent/your connection is - * terminated. - */ - - int i=0; /* loop counter */ + +/*---------------------------------------------------------------------------- + * check_pings + * + * TODO: This should be moved out of ircd.c. It's protocol-specific when you + * get right down to it. Can't really be done until the server is more + * modular, however... + *--------------------------------------------------------------------------*/ +static time_t check_pings(void) { + int expire = 0; + int next_check = CurrentTime + PINGFREQUENCY; + int max_ping = 0; + int i; - /* Scan through the client table */ - for (i=0; i <= HighestFd; i++) { - struct Client *cptr; - - cptr = LocalClientArray[i]; + /* Scan through the client table */ + for (i=0; i <= HighestFd; i++) { + struct Client *cptr = LocalClientArray[i]; - /* Skip empty entries */ - if (!cptr) - continue; + if (!cptr) + continue; - assert(&me != cptr); /* I should never be in the local client array, - * so if I am, dying is a good thing(tm). - */ + assert(&me != cptr); /* I should never be in the local client array! */ - /* Remove dead clients. - * We will have sent opers a message when we set the dead flag, - * so don't bother to send one now. - */ - if (IsDead(cptr)) { - exit_client(cptr, cptr, &me, cptr->info); - continue; - } - - /* Should we concider adding a class 0 for 'unregistered clients', - * where we can specify their 'ping timeout' etc? - */ - max_ping = IsRegistered(cptr) ? get_client_ping(cptr) : CONNECTTIMEOUT; + + /* Remove dead clients. */ + if (IsDead(cptr)) { + exit_client(cptr, cptr, &me, cptr->info); + continue; + } + + max_ping = IsRegistered(cptr) ? get_client_ping(cptr) : CONNECTTIMEOUT; - Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d", - cptr->name, (cptr->flags & FLAGS_PINGSENT) ? "[Ping Sent]" : "[]", - max_ping, (int)(CurrentTime - cptr->lasttime))); + Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d", + cptr->name, (cptr->flags & FLAGS_PINGSENT) ? "[Ping Sent]" : "[]", + max_ping, (int)(CurrentTime - cptr->lasttime))); - /* Ok, the thing that will happen most frequently, is that someone will - * have sent something recently. Cover this first for speed. - */ - if (CurrentTime-cptr->lasttime < max_ping) { - expire=cptr->lasttime + max_ping; - if (expirelasttime >= (max_ping*2) ) { - + + /* Ok, the thing that will happen most frequently, is that someone will + * have sent something recently. Cover this first for speed. + */ + if (CurrentTime-cptr->lasttime < max_ping) { + expire = cptr->lasttime + max_ping; + if (expire < next_check) + next_check = expire; + continue; + } + + /* Quit the client after max_ping*2 - they should have answered by now */ + if (CurrentTime-cptr->lasttime >= (max_ping*2) ) { /* If it was a server, then tell ops about it. */ if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) sendto_opmask_butone(0, SNO_OLDSNO, "No response from %s, closing link", cptr->name); - exit_client_msg(cptr, cptr, &me, "Ping timeout"); continue; - } /* of testing to see if ping has been sent */ + } /* Unregistered clients pingout after max_ping seconds, they don't * get given a second chance - if they were then people could not quite @@ -348,247 +347,91 @@ static time_t check_pings(void) } exit_client_msg(cptr,cptr,&me, "Ping Timeout"); continue; - } /* of not registered */ + } - if (0 == (cptr->flags & FLAGS_PINGSENT)) { - /* - * If we havent PINGed the connection and we havent heard from it in a + if (!(cptr->flags & FLAGS_PINGSENT)) { + /* If we havent PINGed the connection and we havent heard from it in a * while, PING it to make sure it is still alive. */ cptr->flags |= FLAGS_PINGSENT; - /* - * If we're late in noticing don't hold it against them :) - */ + /* If we're late in noticing don't hold it against them :) */ cptr->lasttime = CurrentTime - max_ping; if (IsUser(cptr)) sendrawto_one(cptr, MSG_PING " :%s", me.name); else sendcmdto_one(&me, CMD_PING, cptr, ":%s", me.name); - } /* of if not ping sent... */ - - expire=cptr->lasttime+max_ping*2; + } - if (expirelasttime + max_ping * 2; + if (expire < next_check) + next_check=expire; + } - assert(next_check>=CurrentTime); + assert(next_check >= CurrentTime); - Debug((DEBUG_DEBUG, "[%i] check_pings() again in %is",CurrentTime,next_check-CurrentTime)); + Debug((DEBUG_DEBUG, "[%i] check_pings() again in %is", + CurrentTime, next_check-CurrentTime)); return next_check; } -#if 0 -static time_t check_pings(void) -{ - struct Client *cptr; - int max_ping = 0; - int i; - time_t oldest = CurrentTime + PINGFREQUENCY; - time_t timeout; - - /* For each client... */ - for (i = 0; i <= HighestFd; i++) { - if (!(cptr = LocalClientArray[i])) /* oops! not a client... */ - continue; - /* - * me is never in the local client array - */ - assert(cptr != &me); - /* - * Note: No need to notify opers here. - * It's already done when "FLAGS_DEADSOCKET" is set. - */ - if (IsDead(cptr)) { - exit_client(cptr, cptr, &me, cptr->info); - continue; - } - - max_ping = IsRegistered(cptr) ? get_client_ping(cptr) : CONNECTTIMEOUT; - - Debug((DEBUG_DEBUG, "check_pings(%s)=status:%d ping: %d current: %d", - cptr->name, cptr->status, max_ping, - (int)(CurrentTime - cptr->lasttime))); - - /* - * Ok, so goto's are ugly and can be avoided here but this code - * is already indented enough so I think its justified. -avalon - */ - /* - * If this is a registered client that we've heard of in a reasonable - * time, then skip them. - */ - if (IsRegistered(cptr) && (max_ping >= CurrentTime - cptr->lasttime)) - goto ping_timeout; - /* - * If the server hasnt talked to us in 2 * ping seconds - * and it has a ping time, then close its connection. - * If the client is a user and a KILL line was found - * to be active, close this connection too. - */ - if (((CurrentTime - cptr->lasttime) >= (2 * ping) && (cptr->flags & FLAGS_PINGSENT)) || - (!IsRegistered(cptr) && !IsHandshake(cptr) && (CurrentTime - cptr->firsttime) >= ping)) - { - if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) - { - sendto_ops("No response from %s, closing link", cptr->name); /* XXX DEAD */ - exit_client(cptr, cptr, &me, "Ping timeout"); - continue; - } - else { - if (!IsRegistered(cptr) && *cptr->name && *cptr->user->username) { - sendto_one(cptr, /* XXX DEAD */ - ":%s %d %s :Your client may not be compatible with this server.", - me.name, ERR_BADPING, cptr->name); - sendto_one(cptr, /* XXX DEAD */ - ":%s %d %s :Compatible clients are available at " - "ftp://ftp.undernet.org/pub/irc/clients", - me.name, ERR_BADPING, cptr->name); - } - exit_client_msg(cptr, cptr, &me, "Ping timeout"); - } - continue; - } - else if (IsRegistered(cptr) && 0 == (cptr->flags & FLAGS_PINGSENT)) { - /* - * If we havent PINGed the connection and we havent - * heard from it in a while, PING it to make sure - * it is still alive. - */ - cptr->flags |= FLAGS_PINGSENT; - /* - * not nice but does the job - */ - cptr->lasttime = CurrentTime - ping; - if (IsUser(cptr)) - sendto_one(cptr, "PING :%s", me.name); /* XXX DEAD */ - else - sendto_one(cptr, "%s " TOK_PING " :%s", NumServ(&me), me.name); /* XXX DEAD */ - } -ping_timeout: - timeout = cptr->lasttime + max_ping; - while (timeout <= CurrentTime) - timeout += max_ping; - if (timeout < oldest) - oldest = timeout; - } - if (oldest < CurrentTime) - oldest = CurrentTime + PINGFREQUENCY; - Debug((DEBUG_NOTICE, - "Next check_ping() call at: %s, %d " TIME_T_FMT " " TIME_T_FMT, - myctime(oldest), ping, oldest, CurrentTime)); - - return (oldest); -} -#endif - -/* - * bad_command - * - * This is called when the commandline is not acceptable. - * Give error message and exit without starting anything. - */ -static void print_usage(void) -{ - printf("Usage: ircd [-f config] [-h servername] [-x loglevel] [-ntv]\n"); - printf("\n -n -t\t Don't detach\n -v\t display version\n\n"); - printf("Server not started\n"); -} - -/* - * for getopt - * ZZZ this is going to need confirmation on other OS's - * - * #include - * Solaris has getopt.h, you should too... hopefully - * BSD declares them in stdlib.h - * extern char *optarg; - * - * for FreeBSD the following are defined: - * - * extern char *optarg; - * extern int optind; - * extern in optopt; - * extern int opterr; - * extern in optreset; - * - * - * All command line parameters have the syntax "-f string" or "-fstring" - * OPTIONS: - * -d filename - specify d:line file - * -f filename - specify config file - * -h hostname - specify server name - * -k filename - specify k:line file (hybrid) - * -l filename - specify log file - * -n - do not fork, run in foreground - * -t - do not fork send debugging info to tty - * -v - print version and exit - * -x - set debug level, if compiled for debug logging - */ -static void parse_command_line(int argc, char** argv) -{ - const char* options = "d:f:h:ntvx:"; +/*---------------------------------------------------------------------------- + * parse_command_line + *--------------------------------------------------------------------------*/ +static void parse_command_line(int argc, char** argv) { + const char *options = "d:f:h:ntvx:"; int opt; if (thisServer.euid != thisServer.uid) setuid(thisServer.uid); - while ((opt = getopt(argc, argv, options)) != EOF) { + /* Do we really need to santiy check the non-NULLness of optarg? That's + * getopt()'s job... Removing those... -zs + */ + while ((opt = getopt(argc, argv, options)) != EOF) switch (opt) { - case 'd': - if (optarg) - dpath = optarg; - break; - case 'f': - if (optarg) - configfile = optarg; - break; - case 'h': - if (optarg) - ircd_strncpy(me.name, optarg, HOSTLEN); - break; case 'n': - case 't': - thisServer.bootopt |= BOOT_TTY; - break; - case 'v': - printf("ircd %s\n", version); - exit(0); + case 't': thisServer.bootopt |= BOOT_TTY; break; + case 'd': dpath = optarg; break; + case 'f': configfile = optarg; break; + case 'h': ircd_strncpy(me.name, optarg, HOSTLEN); break; + case 'v': printf("ircd %s\n", version); exit(0); + case 'x': - if (optarg) { - debuglevel = atoi(optarg); - if (debuglevel < 0) - debuglevel = 0; - debugmode = optarg; - thisServer.bootopt |= BOOT_DEBUG; - } + debuglevel = atoi(optarg); + if (debuglevel < 0) + debuglevel = 0; + debugmode = optarg; + thisServer.bootopt |= BOOT_DEBUG; break; + default: - print_usage(); + printf("Usage: ircd [-f config] [-h servername] [-x loglevel] [-ntv]\n"); + printf("\n -n -t\t Don't detach\n -v\t display version\n\n"); + printf("Server not started.\n"); exit(1); } - } } -/* + +/*---------------------------------------------------------------------------- * daemon_init - */ -static void daemon_init(int no_fork) -{ + *--------------------------------------------------------------------------*/ +static void daemon_init(int no_fork) { if (!init_connection_limits()) - exit(2); + exit(9); close_connections(!(thisServer.bootopt & (BOOT_DEBUG | BOOT_TTY))); + if (no_fork) return; if (fork()) exit(0); + #ifdef TIOCNOTTY { int fd; @@ -598,116 +441,194 @@ static void daemon_init(int no_fork) } } #endif + setsid(); } -static void event_loop(void) -{ - time_t delay = 0; +/*---------------------------------------------------------------------------- + * event_loop + *--------------------------------------------------------------------------*/ +static void event_loop(void) { + time_t nextdnscheck = 0; + time_t delay = 0; + thisServer.running = 1; while (thisServer.running) { - /* - * We only want to connect if a connection is due, - * not every time through. Note, if there are no - * active C lines, this call to Tryconnections is + /* We only want to connect if a connection is due, not every time through. + * Note, if there are no active C lines, this call to Tryconnections is * made once only; it will return 0. - avalon */ if (nextconnect && CurrentTime >= nextconnect) nextconnect = try_connections(); - /* - * DNS checks. One to timeout queries, one for cache expiries. - */ + + /* DNS checks. One to timeout queries, one for cache expiries. */ nextdnscheck = timeout_resolver(CurrentTime); - /* - * Take the smaller of the two 'timed' event times as - * the time of next event (stops us being late :) - avalon + + /* Take the smaller of the two 'timed' event times as the time of next + * event (stops us being late :) - avalon * WARNING - nextconnect can return 0! */ if (nextconnect) delay = IRCD_MIN(nextping, nextconnect); else delay = nextping; - delay = IRCD_MIN(nextdnscheck, delay); - delay -= CurrentTime; - /* - * Adjust delay to something reasonable [ad hoc values] - * (one might think something more clever here... --msa) - * We don't really need to check that often and as long - * as we don't delay too long, everything should be ok. - * waiting too long can cause things to timeout... - * i.e. PINGS -> a disconnection :( - * - avalon + + delay = IRCD_MIN(nextdnscheck, delay) - CurrentTime; + + /* Adjust delay to something reasonable [ad hoc values] (one might think + * something more clever here... --msa) We don't really need to check that + * often and as long as we don't delay too long, everything should be ok. + * waiting too long can cause things to timeout... i.e. PINGS -> a + * disconnection :( - avalon */ if (delay < 1) - delay = 1; + read_message(1); else - delay = IRCD_MIN(delay, TIMESEC); - read_message(delay); + read_message(IRCD_MIN(delay, TIMESEC)); Debug((DEBUG_DEBUG, "Got message(s)")); - /* - * ...perhaps should not do these loops every time, - * but only if there is some chance of something - * happening (but, note that conf->hold times may - * be changed elsewhere--so precomputed next event - * time might be too far away... (similarly with - * ping times) --msa + /* ...perhaps should not do these loops every time, but only if there is + * some chance of something happening (but, note that conf->hold times may + * be changed elsewhere--so precomputed next event time might be too far + * away... (similarly with ping times) --msa */ if (CurrentTime >= nextping) nextping = check_pings(); - /* - * timeout pending queries that haven't been responded to - */ + /* timeout pending queries that haven't been responded to */ timeout_auth_queries(CurrentTime); IPcheck_expire(); + if (GlobalRehashFlag) { rehash(&me, 1); GlobalRehashFlag = 0; } + if (GlobalRestartFlag) server_restart("caught signal: SIGINT"); } } -int main(int argc, char *argv[]) -{ + +/*---------------------------------------------------------------------------- + * check_file_access: random helper function to make sure that a file is + * accessible in a certain way, and complain if not. + *--------------------------------------------------------------------------*/ +static char check_file_access(const char *path, char which, int mode) { + if (!access(path, mode)) + return 1; + + fprintf(stderr, + "Check on %cPATH (%s) failed: %s\n" + "Please create file and/or rerun `make config' and " + "recompile to correct this.\n", + which, path, strerror(errno)); + +#ifdef CHROOTDIR + fprintf(stderr, "Keep in mind that paths are relative to CHROOTDIR.\n"); +#endif + + return 0; +} + + +/*---------------------------------------------------------------------------- + * set_core_limit + *--------------------------------------------------------------------------*/ #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE) +static void set_core_limit(void) { struct rlimit corelim; -#endif - CurrentTime = time(NULL); - /* - * sanity check - */ - if (MAXCONNECTIONS < 64 || MAXCONNECTIONS > 256000) { - fprintf(stderr, "%s: MAXCONNECTIONS insane: %d\n", *argv, MAXCONNECTIONS); - return 2; + if (getrlimit(RLIMIT_CORE, &corelim)) { + fprintf(stderr, "Read of rlimit core size failed: %s\n", strerror(errno)); + corelim.rlim_max = RLIM_INFINITY; /* Try to recover */ } - thisServer.argc = argc; - thisServer.argv = argv; - thisServer.uid = getuid(); - thisServer.euid = geteuid(); -#ifdef PROFIL - monstartup(0, etext); - moncontrol(1); - signal(SIGUSR1, s_monitor); + + corelim.rlim_cur = corelim.rlim_max; + if (setrlimit(RLIMIT_CORE, &corelim)) + fprintf(stderr, "Setting rlimit core size failed: %s\n", strerror(errno)); +} #endif + + +/*---------------------------------------------------------------------------- + * set_chroot_environment + *--------------------------------------------------------------------------*/ #ifdef CHROOTDIR +static char set_chroot_environment(void) { + /* Must be root to chroot! Silly if you ask me... */ + if (geteuid()) + seteuid(0); + if (chdir(DPATH)) { fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", DPATH, strerror(errno)); - exit(2); + return 0; } if (chroot(DPATH)) { fprintf(stderr, "Fail: Cannot chroot(%s): %s\n", DPATH, strerror(errno)); - exit(5); + return 0; } dpath = "/"; -#endif /*CHROOTDIR */ + return 1; +} +#endif + + +/*---------------------------------------------------------------------------- + * set_userid_if_needed() + *--------------------------------------------------------------------------*/ +static int set_userid_if_needed(void) { + /* TODO: Drop privs correctly! */ +#if defined(IRC_GID) && defined(IRC_UID) + setgid (IRC_GID); + setegid(IRC_GID); + setuid (IRC_UID); + seteuid(IRC_UID); +#endif + + if (getuid() == 0 || geteuid() == 0 || + getgid() == 0 || getegid() == 0) { + fprintf(stderr, "ERROR: This server will not run as superuser.\n"); + return 0; + } + + return 1; +} + + +/*---------------------------------------------------------------------------- + * main - entrypoint + * + * TODO: This should set the basic environment up and start the main loop. + * we're doing waaaaaaaaay too much server initialization here. I hate + * long and ugly control paths... -smd + *--------------------------------------------------------------------------*/ +int main(int argc, char **argv) { +#ifdef PROFIL + monstartup(0, etext); + moncontrol(1); + signal(SIGUSR1, s_monitor); +#endif + + CurrentTime = time(NULL); + + thisServer.argc = argc; + thisServer.argv = argv; + thisServer.uid = getuid(); + thisServer.euid = geteuid(); + +#ifdef CHROOTDIR + if (!set_chroot_environment()) + exit(1); +#endif + +#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE) + set_core_limit(); +#endif umask(077); /* better safe than sorry --SRB */ memset(&me, 0, sizeof(me)); @@ -716,16 +637,6 @@ int main(int argc, char *argv[]) setup_signals(); initload(); -#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE) - if (getrlimit(RLIMIT_CORE, &corelim)) - { - fprintf(stderr, "Read of rlimit core size failed: %s\n", strerror(errno)); - corelim.rlim_max = RLIM_INFINITY; /* Try to recover */ - } - corelim.rlim_cur = corelim.rlim_max; - if (setrlimit(RLIMIT_CORE, &corelim)) - fprintf(stderr, "Setting rlimit core size failed: %s\n", strerror(errno)); -#endif parse_command_line(argc, argv); if (chdir(dpath)) { @@ -733,76 +644,20 @@ int main(int argc, char *argv[]) exit(2); } -#ifndef IRC_UID - if ((thisServer.uid != thisServer.euid) && !thisServer.euid) { - fprintf(stderr, - "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n"); - exit(2); - } -#endif - -#if !defined(CHROOTDIR) || (defined(IRC_UID) && defined(IRC_GID)) - if (thisServer.euid != thisServer.uid) { - setuid(thisServer.uid); - setuid(thisServer.euid); - } - - if (0 == getuid()) { -#if defined(IRC_UID) && defined(IRC_GID) - - /* run as a specified user */ - fprintf(stderr, "WARNING: running ircd with uid = %d\n", IRC_UID); - fprintf(stderr, " changing to gid %d.\n", IRC_GID); - setuid(IRC_UID); - setgid(IRC_GID); -#else - /* check for setuid root as usual */ - fprintf(stderr, - "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n"); - exit(2); -#endif - } -#endif /*CHROOTDIR/UID/GID */ + if (!set_userid_if_needed()) + exit(3); - /* Sanity checks */ - { - char c; - char *path; - - c = 'S'; - path = SPATH; - if (access(path, X_OK) == 0) { - c = 'C'; - path = CPATH; - if (access(path, R_OK) == 0) { - c = 'M'; - path = MPATH; - if (access(path, R_OK) == 0) { - c = 'R'; - path = RPATH; - if (access(path, R_OK) == 0) { -#ifndef DEBUG - c = 0; -#else - c = 'L'; - path = LPATH; - if (access(path, W_OK) == 0) - c = 0; -#endif - } - } - } - } - if (c) { - fprintf(stderr, "Check on %cPATH (%s) failed: %s\n", c, path, strerror(errno)); - fprintf(stderr, - "Please create file and/or rerun `make config' and recompile to correct this.\n"); -#ifdef CHROOTDIR - fprintf(stderr, "Keep in mind that all paths are relative to CHROOTDIR.\n"); + /* Check paths for accessibility */ + if (!check_file_access(SPATH, 'S', X_OK) || + !check_file_access(CPATH, 'C', R_OK) || + !check_file_access(MPATH, 'M', R_OK) || + !check_file_access(RPATH, 'R', R_OK)) + exit(4); + +#ifdef DEBUG + if (!check_file_access(LPATH, 'L', W_OK)) + exit(5); #endif - exit(2); - } - } init_list(); hash_init(); @@ -820,47 +675,48 @@ int main(int argc, char *argv[]) open_log(*argv); if (!conf_init()) { - Debug((DEBUG_FATAL, "Failed in reading configuration file %s", configfile)); + Debug((DEBUG_FATAL, "Failed to read configuration file %s", configfile)); printf("Couldn't open configuration file %s\n", configfile); - exit(2); + exit(6); } + if (!init_server_identity()) { Debug((DEBUG_FATAL, "Failed to initialize server identity")); - exit(2); + exit(7); } + uping_init(); read_tlines(); - rmotd = read_motd(RPATH); - motd = read_motd(MPATH); + + rmotd = read_motd(RPATH); + motd = read_motd(MPATH); CurrentTime = time(NULL); - me.from = &me; + me.from = &me; + SetMe(&me); make_server(&me); - /* - * Abuse own link timestamp as start timestamp: - */ - me.serv->timestamp = TStime(); - me.serv->prot = atoi(MAJOR_PROTOCOL); - me.serv->up = &me; - me.serv->down = NULL; - me.handler = SERVER_HANDLER; + + me.serv->timestamp = TStime(); /* Abuse own link timestamp as start TS */ + me.serv->prot = atoi(MAJOR_PROTOCOL); + me.serv->up = &me; + me.serv->down = NULL; + me.handler = SERVER_HANDLER; SetYXXCapacity(&me, MAXCLIENTS); me.lasttime = me.since = me.firsttime = CurrentTime; + hAddClient(&me); check_class(); write_pidfile(); - init_counters(); Debug((DEBUG_NOTICE, "Server ready...")); ircd_log(L_NOTICE, "Server Ready"); - thisServer.running = 1; event_loop(); + return 0; } - -- 2.20.1