X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fngircd.c;h=74a998800f364376a87efb290cd2d0dc030a2ab4;hp=ec42b2370a0deb858667a872610eee045eb4bbfb;hb=162433398e320c45f3c8a523814518aa6b78372e;hpb=761b2284b953de0d5c2f847e55e3fbc030243178 diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c index ec42b237..74a99880 100644 --- a/src/ngircd/ngircd.c +++ b/src/ngircd/ngircd.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2010 Alexander Barton (alex@barton.de). + * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -9,7 +9,6 @@ * Please read the file COPYING, README and AUTHORS for more information. */ - #include "portab.h" /** @@ -29,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -46,19 +44,14 @@ #include "lists.h" #include "log.h" #include "parse.h" +#include "sighandlers.h" +#include "io.h" #include "irc.h" -#ifdef ZEROCONF -#include "rendezvous.h" -#endif - #include "exp.h" #include "ngircd.h" -static void Initialize_Signal_Handler PARAMS(( void )); -static void Signal_Handler PARAMS(( int Signal )); - static void Show_Version PARAMS(( void )); static void Show_Help PARAMS(( void )); @@ -67,17 +60,20 @@ static void Pidfile_Delete PARAMS(( void )); static void Fill_Version PARAMS(( void )); -static void Setup_FDStreams PARAMS(( void )); +static void Setup_FDStreams PARAMS(( int fd )); static bool NGIRCd_Init PARAMS(( bool )); + /** * The main() function of ngIRCd. + * * Here all starts: this function is called by the operating system loader, * it is the first portion of code executed of ngIRCd. - * @param argc The number of arguments passed to ngIRCd on the command line. - * @param argv An array containing all the arguments passed to ngIRCd. - * @return Global exit code of ngIRCd, zero on success. + * + * @param argc The number of arguments passed to ngIRCd on the command line. + * @param argv An array containing all the arguments passed to ngIRCd. + * @return Global exit code of ngIRCd, zero on success. */ GLOBAL int main( int argc, const char *argv[] ) @@ -95,7 +91,7 @@ main( int argc, const char *argv[] ) umask( 0077 ); - NGIRCd_SignalQuit = NGIRCd_SignalRestart = NGIRCd_SignalRehash = false; + NGIRCd_SignalQuit = NGIRCd_SignalRestart = false; NGIRCd_Passive = false; #ifdef DEBUG NGIRCd_Debug = false; @@ -238,7 +234,7 @@ main( int argc, const char *argv[] ) } } - /* Debug-Level (for IRCs "VERSION" command) */ + /* Debug level for "VERSION" command */ NGIRCd_DebugLevel[0] = '\0'; #ifdef DEBUG if( NGIRCd_Debug ) strcpy( NGIRCd_DebugLevel, "1" ); @@ -263,7 +259,6 @@ main( int argc, const char *argv[] ) NGIRCd_Start = time( NULL ); (void)strftime( NGIRCd_StartStr, 64, "%a %b %d %Y at %H:%M:%S (%Z)", localtime( &NGIRCd_Start )); - NGIRCd_SignalRehash = false; NGIRCd_SignalRestart = false; NGIRCd_SignalQuit = false; @@ -282,24 +277,23 @@ main( int argc, const char *argv[] ) * called with already dropped privileges ... */ Channel_Init( ); Client_Init( ); -#ifdef ZEROCONF - Rendezvous_Init( ); -#endif Conn_Init( ); -#ifdef DEBUG - /* Redirect stderr handle to "error file" for debugging - * when not running in "no daemon" mode: */ - if( ! NGIRCd_NoDaemon ) Log_InitErrorfile( ); -#endif + if (!io_library_init(CONNECTION_POOL)) { + Log(LOG_ALERT, "Fatal: Cannot initialize IO routines: %s", strerror(errno)); + exit(1); + } + + if (!Signals_Init()) { + Log(LOG_ALERT, "Fatal: Could not set up signal handlers: %s", strerror(errno)); + exit(1); + } - Initialize_Signal_Handler( ); + srandom(getpid()); - /* - * create protocol and server identification. - * The syntax used by ngIRCd in PASS commands and the extended flags - * are described in doc/Protocol.txt - */ + /* Create protocol and server identification. The syntax + * used by ngIRCd in PASS commands and the known "extended + * flags" are described in doc/Protocol.txt. */ #ifdef IRCPLUS snprintf( NGIRCd_ProtoID, sizeof NGIRCd_ProtoID, "%s%s %s|%s:%s", PROTOVER, PROTOIRCPLUS, PACKAGE_NAME, PACKAGE_VERSION, IRCPLUSFLAGS ); #ifdef ZLIB @@ -324,15 +318,11 @@ main( int argc, const char *argv[] ) Pidfile_Delete( ); exit( 1 ); } - - /* Hauptschleife */ + + /* Main Run Loop */ Conn_Handler( ); - /* Alles abmelden */ Conn_Exit( ); -#ifdef ZEROCONF - Rendezvous_Exit( ); -#endif Client_Exit( ); Channel_Exit( ); Log_Exit( ); @@ -344,10 +334,12 @@ main( int argc, const char *argv[] ) /** - * Generate ngIRCd "version string". - * This string is generated once and then stored in NGIRCd_Version for - * further usage, for example by the IRC command VERSION and the --version - * command line switch. + * Generate ngIRCd "version strings". + * + * The ngIRCd version information is generated once and then stored in the + * NGIRCd_Version and NGIRCd_VersionAddition string variables for further + * usage, for example by the IRC command "VERSION" and the --version command + * line switch. */ static void Fill_Version( void ) @@ -371,11 +363,6 @@ Fill_Version( void ) strlcat( NGIRCd_VersionAddition, "+", sizeof NGIRCd_VersionAddition ); strlcat( NGIRCd_VersionAddition, "TCPWRAP", sizeof NGIRCd_VersionAddition ); #endif -#ifdef ZEROCONF - if( NGIRCd_VersionAddition[0] ) - strlcat( NGIRCd_VersionAddition, "+", sizeof NGIRCd_VersionAddition ); - strlcat( NGIRCd_VersionAddition, "ZEROCONF", sizeof NGIRCd_VersionAddition ); -#endif #ifdef IDENTAUTH if( NGIRCd_VersionAddition[0] ) strlcat( NGIRCd_VersionAddition, "+", sizeof NGIRCd_VersionAddition ); @@ -422,131 +409,7 @@ Fill_Version( void ) snprintf(NGIRCd_Version, sizeof NGIRCd_Version, "%s %s-%s", PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_VersionAddition); - } /* Fill_Version */ - - -/** - * Reload the server configuration file. - */ -GLOBAL void -NGIRCd_Rehash( void ) -{ - char old_name[CLIENT_ID_LEN]; - unsigned old_nicklen; - - Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" ); - NGIRCd_SignalRehash = false; - - /* Remember old server name and nick name length */ - strlcpy( old_name, Conf_ServerName, sizeof old_name ); - old_nicklen = Conf_MaxNickLength; - - /* Re-read configuration ... */ - if (!Conf_Rehash( )) - return; - - /* Close down all listening sockets */ - Conn_ExitListeners( ); - - /* Recover old server name and nick name length: these values can't - * be changed during run-time */ - if (strcmp(old_name, Conf_ServerName) != 0 ) { - strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName); - Log(LOG_ERR, "Can't change \"ServerName\" on runtime! Ignored new name."); - } - if (old_nicklen != Conf_MaxNickLength) { - Conf_MaxNickLength = old_nicklen; - Log(LOG_ERR, "Can't change \"MaxNickLength\" on runtime! Ignored new value."); - } - - /* Create new pre-defined channels */ - Channel_InitPredefined( ); - - if (!ConnSSL_InitLibrary()) - Log(LOG_WARNING, "Re-Initializing SSL failed, using old keys"); - - /* Start listening on sockets */ - Conn_InitListeners( ); - - /* Sync configuration with established connections */ - Conn_SyncServerStruct( ); - - Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." ); -} /* NGIRCd_Rehash */ - - -/** - * Initialize the signal handler. - */ -static void -Initialize_Signal_Handler( void ) -{ -#ifdef HAVE_SIGACTION - struct sigaction saction; - - memset( &saction, 0, sizeof( saction )); - saction.sa_handler = Signal_Handler; -#ifdef SA_RESTART - saction.sa_flags |= SA_RESTART; -#endif -#ifdef SA_NOCLDWAIT - saction.sa_flags |= SA_NOCLDWAIT; -#endif - - sigaction(SIGINT, &saction, NULL); - sigaction(SIGQUIT, &saction, NULL); - sigaction(SIGTERM, &saction, NULL); - sigaction(SIGHUP, &saction, NULL); - sigaction(SIGCHLD, &saction, NULL); - - /* we handle write errors properly; ignore SIGPIPE */ - saction.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &saction, NULL); -#else - signal(SIGINT, Signal_Handler); - signal(SIGQUIT, Signal_Handler); - signal(SIGTERM, Signal_Handler); - signal(SIGHUP, Signal_Handler); - signal(SIGCHLD, Signal_Handler); - - signal(SIGPIPE, SIG_IGN); -#endif -} /* Initialize_Signal_Handler */ - - -/** - * Signal handler of ngIRCd. - * This function is called whenever ngIRCd catches a signal sent by the - * user and/or the system to it. For example SIGTERM and SIGHUP. - * @param Signal Number of the signal to handle. - */ -static void -Signal_Handler( int Signal ) -{ - switch( Signal ) - { - case SIGTERM: - case SIGINT: - case SIGQUIT: - /* shut down sever */ - NGIRCd_SignalQuit = true; - break; - case SIGHUP: - /* re-read configuration */ - NGIRCd_SignalRehash = true; - break; - case SIGCHLD: - /* child-process exited, avoid zombies */ - while (waitpid( -1, NULL, WNOHANG) > 0) - ; - break; -#ifdef DEBUG - default: - /* unbekanntes bzw. unbehandeltes Signal */ - Log( LOG_DEBUG, "Got signal %d! Ignored.", Signal ); -#endif - } -} /* Signal_Handler */ +} /* Fill_Version */ /** @@ -556,7 +419,7 @@ static void Show_Version( void ) { puts( NGIRCd_Version ); - puts( "Copyright (c)2001-2010 Alexander Barton () and Contributors." ); + puts( "Copyright (c)2001-2011 Alexander Barton () and Contributors." ); puts( "Homepage: \n" ); puts( "This is free software; see the source for copying conditions. There is NO" ); puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." ); @@ -606,7 +469,8 @@ Pidfile_Delete( void ) /** * Create the file containing the process ID of ngIRCd ("PID file"). - * @param pid The process ID to be stored in this file. + * + * @param pid The process ID to be stored in this file. */ static void Pidfile_Create(pid_t pid) @@ -644,32 +508,30 @@ Pidfile_Create(pid_t pid) /** * Redirect stdin, stdout and stderr to apropriate file handles. + * + * @param fd The file handle stdin, stdout and stderr should be redirected to. */ static void -Setup_FDStreams( void ) +Setup_FDStreams(int fd) { - int fd; - - /* Test if we can open /dev/null for reading and writing. If not - * we are most probably chrooted already and the server has been - * restarted. So we simply don't try to redirect stdXXX ... */ - fd = open( "/dev/null", O_RDWR ); - if ( fd < 0 ) { - Log(LOG_WARNING, "Could not open /dev/null: %s", strerror(errno)); + if (fd < 0) return; - } fflush(stdout); fflush(stderr); /* Create new stdin(0), stdout(1) and stderr(2) descriptors */ dup2( fd, 0 ); dup2( fd, 1 ); dup2( fd, 2 ); - - /* Close newly opened file descriptor if not stdin/out/err */ - if( fd > 2 ) close( fd ); } /* Setup_FDStreams */ +/** + * Get user and group ID of unprivileged "nobody" user. + * + * @param uid User ID + * @param gid Group ID + * @return true on success. + */ static bool NGIRCd_getNobodyID(uid_t *uid, gid_t *gid ) { @@ -694,14 +556,21 @@ NGIRCd_getNobodyID(uid_t *uid, gid_t *gid ) if ( !pwd->pw_uid || !pwd->pw_gid) return false; - *uid = pwd->pw_uid; + *uid = pwd->pw_uid; *gid = pwd->pw_gid; endpwent(); - return true; -} + return true; +} /* NGIRCd_getNobodyID */ +/** + * Initialize ngIRCd daemon. + * + * @param NGIRCd_NoDaemon Set to true if ngIRCd should run in the + * foreground and not as a daemon. + * @return true on success. + */ static bool NGIRCd_Init( bool NGIRCd_NoDaemon ) { @@ -709,12 +578,19 @@ NGIRCd_Init( bool NGIRCd_NoDaemon ) bool chrooted = false; struct passwd *pwd; struct group *grp; - int real_errno; + int real_errno, fd = -1; pid_t pid; if (initialized) return true; + if (!NGIRCd_NoDaemon) { + /* open /dev/null before chroot() */ + fd = open( "/dev/null", O_RDWR); + if (fd < 0) + Log(LOG_WARNING, "Could not open /dev/null: %s", strerror(errno)); + } + if (!ConnSSL_InitLibrary()) Log(LOG_WARNING, "Warning: Error during SSL initialization, continuing ..."); @@ -722,15 +598,14 @@ NGIRCd_Init( bool NGIRCd_NoDaemon ) if( Conf_Chroot[0] ) { if( chdir( Conf_Chroot ) != 0 ) { Log( LOG_ERR, "Can't chdir() in ChrootDir (%s): %s", Conf_Chroot, strerror( errno )); - return false; + goto out; } if( chroot( Conf_Chroot ) != 0 ) { if (errno != EPERM) { Log( LOG_ERR, "Can't change root directory to \"%s\": %s", Conf_Chroot, strerror( errno )); - - return false; + goto out; } } else { chrooted = true; @@ -744,7 +619,7 @@ NGIRCd_Init( bool NGIRCd_NoDaemon ) if (! NGIRCd_getNobodyID(&Conf_UID, &Conf_GID)) { Log(LOG_WARNING, "Could not get user/group ID of user \"nobody\": %s", errno ? strerror(errno) : "not found" ); - return false; + goto out; } } @@ -754,7 +629,7 @@ NGIRCd_Init( bool NGIRCd_NoDaemon ) real_errno = errno; Log( LOG_ERR, "Can't change group ID to %u: %s", Conf_GID, strerror( errno )); if (real_errno != EPERM) - return false; + goto out; } } @@ -764,7 +639,7 @@ NGIRCd_Init( bool NGIRCd_NoDaemon ) real_errno = errno; Log(LOG_ERR, "Can't change user ID to %u: %s", Conf_UID, strerror(errno)); if (real_errno != EPERM) - return false; + goto out; } } @@ -797,7 +672,11 @@ NGIRCd_Init( bool NGIRCd_NoDaemon ) strerror(errno)); /* Detach stdin, stdout and stderr */ - Setup_FDStreams( ); + Setup_FDStreams(fd); + if (fd > 2) { + close(fd); + fd = -1; + } } pid = getpid(); @@ -824,8 +703,8 @@ NGIRCd_Init( bool NGIRCd_NoDaemon ) /* Change working directory to home directory of the user * we are running as (only when running in daemon mode and not in chroot) */ - - if ( pwd ) { + + if (pwd) { if (!NGIRCd_NoDaemon ) { if( chdir( pwd->pw_dir ) == 0 ) Log( LOG_DEBUG, "Changed working directory to \"%s\" ...", pwd->pw_dir ); @@ -837,7 +716,12 @@ NGIRCd_Init( bool NGIRCd_NoDaemon ) Log( LOG_ERR, "Can't get user informaton for UID %d!?", Conf_UID ); } -return true; -} + return true; + out: + if (fd > 2) + close(fd); + return false; +} /* NGIRCd_Init */ + /* -eof- */