commit 7281b8dd4d917f8b7f7c36460b78b686427ce973 from: Alexander Barton date: Fri May 07 11:19:20 2004 UTC New "chroot" feature (from Benjamin Pineau), introducing new configuration variables "ChrootDir" and "MotdPhrase". commit - 39fc76c4e48e553e9eab007dbfd662060d524679 commit + 7281b8dd4d917f8b7f7c36460b78b686427ce973 blob - 929679a4295c005b2b1e111d87d49fe10f1ff17e blob + 6cca6cb4689e0e00071ce4859a0d522a2446d682 --- AUTHORS +++ AUTHORS @@ -19,6 +19,7 @@ Contributors ~~~~~~~~~~~~ Goetz Hoffart, (goetz) Ilja Osthoff, (ilja) +Benjamin Pineau, Sean Reifschneider, @@ -30,4 +31,4 @@ Andrew Tridgell & Martin Pool: strl{cpy|cat}()-functio -- -$Id: AUTHORS,v 1.8 2004/01/26 02:23:54 alex Exp $ +$Id: AUTHORS,v 1.9 2004/05/07 11:19:20 alex Exp $ blob - 793832bbd8c99f41bb56eff623dd09378ed01192 blob + 3226ece1115d805fb67be038f8eec91a1abb2666 --- ChangeLog +++ ChangeLog @@ -12,6 +12,11 @@ ngIRCd CVSHEAD + - Two new configuration options: "ChrootDir" and "MotdPhrase", thanks to + Benjamin Pineau . Now you can force the daemon to change + its root and working directory to something "safe". MotdPhrase is used + to define an "MOTD string" instead of a whole file, useful if the + "real" MOTD file would be outside the "jail". - INVITE- and BAN-lists become synchronized between IRC+ servers when establishing new connections, if the peer supports this as well. - Reorganized autogen.sh and configure scripts. @@ -516,4 +521,4 @@ ngIRCd 0.0.1, 31.12.2001 -- -$Id: ChangeLog,v 1.233 2004/04/25 15:51:15 alex Exp $ +$Id: ChangeLog,v 1.234 2004/05/07 11:19:20 alex Exp $ blob - e19ea044efe467c018d495b2c5e67636715c90d6 blob + 6df155fdd784e6bc6754d6bbeaf37848a81bcdbf --- INSTALL +++ INSTALL @@ -75,7 +75,12 @@ In addition, you can pass some command line options to and/or disable some features of ngIRCd. All these options are shown using "./configure --help", too. +Compiling a static binary will avoid you the hassle of feeding a chroot dir +(if you want use the chroot feature). Just do something like: + CFLAGS=-static ./configure [--your-options ...] +Then you can use a void directory as ChrootDir (like OpenSSH's /var/empty). + 3): "make" The make command uses the Makefiles produced by configure and compiles the @@ -158,4 +163,4 @@ number. In both cases the server exits after the outpu -- -$Id: INSTALL,v 1.18 2004/02/22 22:12:44 alex Exp $ +$Id: INSTALL,v 1.19 2004/05/07 11:19:20 alex Exp $ blob - b45719549da8913bae1a7405b368df0c1990d910 blob + fdf928d4ec4f237d92febf84fee0c771f82c2540 --- NEWS +++ NEWS @@ -12,6 +12,11 @@ ngIRCd CVSHEAD + - Two new configuration options: "ChrootDir" and "MotdPhrase", thanks to + Benjamin Pineau . Now you can force the daemon to change + its root and working directory to something "safe". MotdPhrase is used + to define an "MOTD string" instead of a whole file, useful if the + "real" MOTD file would be outside the "jail". - INVITE- and BAN-lists become synchronized between IRC+ servers when establishing new connections, if the peer supports this as well. - The type of service (TOS) of all sockets is set to "interactive" now. @@ -184,4 +189,4 @@ ngIRCd 0.0.1, 31.12.2001 -- -$Id: NEWS,v 1.64 2004/04/25 15:51:15 alex Exp $ +$Id: NEWS,v 1.65 2004/05/07 11:19:20 alex Exp $ blob - dd171bf9680cec6b8f3120bf5d0b6db19fdb45a6 blob + ee4ce5cf38838481f13bcd95b1044d5eb22239e7 --- README +++ README @@ -45,7 +45,8 @@ III. Features (or: why use ngIRCd?) - ngIRCd will be developed on in the future. - supported platforms (tested versions): AIX (3.2.5), A/UX (3.0.1), FreeBSD (4.5), HP-UX (10.20), IRIX (6.5), Linux (2.x), Mac OS X (10.x), NetBSD - (1.5.2/i386, 1.5.3/m68k), Solaris (2.5.1, 2.6), and Windows with Cygwin. + (1.5.2/i386, 1.5.3/m68k), Solaris (2.5.1, 2.6), Windows with Cygwin, and + OpenBSD (3.4/i386). IV. Documentation @@ -83,4 +84,4 @@ mail to: or -- -$Id: README,v 1.18 2004/01/26 02:23:54 alex Exp $ +$Id: README,v 1.19 2004/05/07 11:19:20 alex Exp $ blob - f136d27ce4973770dcd6b2c473deb0446412ab16 blob + e8178a5a7483f6c010604d66b1c40b119f4c1992 --- doc/sample-ngircd.conf +++ doc/sample-ngircd.conf @@ -1,4 +1,4 @@ -# $Id: sample-ngircd.conf,v 1.25 2003/12/19 14:32:59 alex Exp $ +# $Id: sample-ngircd.conf,v 1.26 2004/05/07 11:19:20 alex Exp $ # # This is a sample configuration file for the ngIRCd, which must be adepted @@ -45,6 +45,10 @@ # be shown to all users connecting to the server: ;MotdFile = /usr/local/etc/ngircd.motd + # A simple Phrase (<256 chars) if you don't want to use a motd file. + # If it is set no MotdFile will be read at all. + ;MotdPhrase = "Hello world!" + # User ID under which the server should run; you can use the name # of the user or the numerical ID. ATTENTION: For this to work the # server must have been started with root privileges! In addition, @@ -57,6 +61,13 @@ # server must have been started with root privileges! ;ServerGID = 65534 + # A directory to chroot in when everything is initialized. It + # doesn't need to be populated if ngIRCd is compiled as a static + # binary. By default ngIRCd won't use the chroot() feature. + # ATTENTION: For this to work the server must have been started + # with root privileges! + ;ChrootDir = /var/empty + # After seconds of inactivity the server will send a # PING to the peer to test whether it is alive or not. ;PingTimeout = 120 blob - d1cf47e2d60a24a006b0f9d36ee3ea90783a1876 blob + 97d77c6d1b35e8142a08bbcfce34d10a291c95ca --- man/ngircd.conf.5 +++ man/ngircd.conf.5 @@ -1,5 +1,5 @@ .\" -.\" $Id: ngircd.conf.5,v 1.12 2003/11/05 21:41:02 alex Exp $ +.\" $Id: ngircd.conf.5,v 1.13 2004/05/07 11:19:20 alex Exp $ .\" .TH ngircd.conf 5 "Mai 2003" ngircd "ngIRCd Manual" .SH NAME @@ -75,6 +75,10 @@ the server listens on all configured ip addresses and Text file with the "message of the day" (MOTD). This message will be shown to all users connecting to the server. .TP +\fBMotdPhrase\fR +A simple Phrase (<256 chars) if you don't want to use a motd file. +If it is set no MotdFile will be read at all. +.TP \fBServerUID\fR User ID under which the server should run; you can use the name of the user or the numerical ID. @@ -98,6 +102,18 @@ For this to work the server must have been started with root privileges! .RE .TP +\fBChrootDir\fR +A directory to chroot in when everything is initialized. It doesn't need +to be populated if ngIRCd is compiled as a static binary. By default ngIRCd +won't use the chroot() feature. +.PP +.RS +.B Attention: +.br +For this to work the server must have +been started with root privileges! +.RE +.TP \fBPingTimeout\fR After seconds of inactivity the server will send a PING to the peer to test whether it is alive or not. Default: 120. blob - fde37b00948cc1d048273496239c0515f7b5c112 blob + 1ea1fe741ef3397c35a6d151c1bac575c4c1eec7 --- src/ngircd/conf.c +++ src/ngircd/conf.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: conf.c,v 1.63 2004/01/17 03:17:00 alex Exp $"; +static char UNUSED id[] = "$Id: conf.c,v 1.64 2004/05/07 11:19:21 alex Exp $"; #include "imp.h" #include @@ -114,6 +114,8 @@ Conf_Test( VOID ) printf( " AdminInfo2 = %s\n", Conf_ServerAdmin2 ); printf( " AdminEMail = %s\n", Conf_ServerAdminMail ); printf( " MotdFile = %s\n", Conf_MotdFile ); + printf( " MotdPhrase = %s\n", Conf_MotdPhrase ); + printf( " ChrootDir= %s\n", Conf_Chroot ); printf( " Ports = " ); for( i = 0; i < Conf_ListenPorts_Count; i++ ) { @@ -342,6 +344,10 @@ Set_Defaults( BOOLEAN InitServers ) strlcpy( Conf_MotdFile, SYSCONFDIR, sizeof( Conf_MotdFile )); strlcat( Conf_MotdFile, MOTD_FILE, sizeof( Conf_MotdFile )); + + strlcpy( Conf_MotdPhrase, MOTD_PHRASE, sizeof( Conf_MotdPhrase )); + + strlcpy( Conf_Chroot, CHROOT_DIR, sizeof( Conf_Chroot )); Conf_ListenPorts_Count = 0; strcpy( Conf_ListenAddress, "" ); @@ -611,8 +617,20 @@ Handle_GLOBAL( INT Line, CHAR *Var, CHAR *Arg ) { /* "Message of the day" (MOTD) file */ if( strlcpy( Conf_MotdFile, Arg, sizeof( Conf_MotdFile )) >= sizeof( Conf_MotdFile )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MotdFile\" too long!", NGIRCd_ConfFile, Line ); + return; + } + if( strcasecmp( Var, "MotdPhrase" ) == 0 ) + { + /* "Message of the day" phrase (instead of file) */ + if( strlcpy( Conf_MotdPhrase, Arg, sizeof( Conf_MotdPhrase )) >= sizeof( Conf_MotdPhrase )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"MotdPhrase\" too long!", NGIRCd_ConfFile, Line ); return; } + if( strcasecmp( Var, "ChrootDir" ) == 0 ) + { + /* directory for chroot() */ + if( strlcpy( Conf_Chroot, Arg, sizeof( Conf_Chroot )) >= sizeof( Conf_Chroot )) Config_Error( LOG_WARNING, "%s, line %d: Value of \"ChrootDir\" too long!", NGIRCd_ConfFile, Line ); + return; + } if( strcasecmp( Var, "ServerUID" ) == 0 ) { /* UID the daemon should switch to */ blob - b900610b71fa838627e413a3c3bda680cf4ec668 blob + 4fbf2d68597c4d8a69f990d5244570ff69d11104 --- src/ngircd/conf.h +++ src/ngircd/conf.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: conf.h,v 1.28 2003/11/05 21:41:02 alex Exp $ + * $Id: conf.h,v 1.29 2004/05/07 11:19:21 alex Exp $ * * Configuration management (header) */ @@ -72,6 +72,9 @@ GLOBAL CHAR Conf_ServerAdminMail[CLIENT_INFO_LEN]; /* File with MOTD text */ GLOBAL CHAR Conf_MotdFile[FNAME_LEN]; +/* Phrase with MOTD text */ +GLOBAL CHAR Conf_MotdPhrase[LINE_LEN]; + /* Ports the server should listen on */ GLOBAL UINT Conf_ListenPorts[MAX_LISTEN_PORTS]; GLOBAL INT Conf_ListenPorts_Count; @@ -83,6 +86,9 @@ GLOBAL CHAR Conf_ListenAddress[16]; GLOBAL UINT Conf_UID; GLOBAL UINT Conf_GID; +/* A directory to chroot() in */ +GLOBAL CHAR Conf_Chroot[FNAME_LEN]; + /* Timeouts for PING and PONG */ GLOBAL INT Conf_PingTimeout; GLOBAL INT Conf_PongTimeout; blob - e351b236234f64ea48a82f9af043800db5395ef3 blob + 34951aeef8757d41a6837b996cd4ec45ef314714 --- src/ngircd/defines.h +++ src/ngircd/defines.h @@ -8,7 +8,7 @@ * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: defines.h,v 1.45 2004/04/25 15:46:50 alex Exp $ + * $Id: defines.h,v 1.46 2004/05/07 11:19:21 alex Exp $ * * Global defines of ngIRCd. */ @@ -83,6 +83,8 @@ #define CONFIG_FILE "/ngircd.conf" #define MOTD_FILE "/ngircd.motd" +#define MOTD_PHRASE "" +#define CHROOT_DIR "" #define ERROR_DIR "/tmp" blob - 59d04dd1bc6634fe32c872783273fcfb92b2e556 blob + 26306949ed865ecc014d0299770c73e5ee4ab790 --- src/ngircd/irc-info.c +++ src/ngircd/irc-info.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-info.c,v 1.21 2004/01/17 03:17:49 alex Exp $"; +static char UNUSED id[] = "$Id: irc-info.c,v 1.22 2004/05/07 11:19:21 alex Exp $"; #include "imp.h" #include @@ -773,6 +773,13 @@ IRC_Show_MOTD( CLIENT *Client ) assert( Client != NULL ); + if( Conf_MotdPhrase[0] ) + { + if( ! IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return DISCONNECTED; + if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), Conf_MotdPhrase )) return DISCONNECTED; + return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client )); + } + fd = fopen( Conf_MotdFile, "r" ); if( ! fd ) { @@ -780,7 +787,7 @@ IRC_Show_MOTD( CLIENT *Client ) return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) ); } - IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( ))); + if( ! IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return DISCONNECTED; while( TRUE ) { if( ! fgets( line, 126, fd )) break; blob - 1c8d2c7b3e1b52ab37b6b14cb88568d63d434212 blob + cb149939b789db792419481e2c74545ba3897f51 --- src/ngircd/log.c +++ src/ngircd/log.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: log.c,v 1.44 2003/12/26 15:55:07 alex Exp $"; +static char UNUSED id[] = "$Id: log.c,v 1.45 2004/05/07 11:19:21 alex Exp $"; #include "imp.h" #include @@ -85,6 +85,8 @@ Log_Init( VOID ) } #endif if( Init_Txt[0] ) Log( LOG_INFO, "Activating: %s.", Init_Txt ); + + Error_File[0] = '\0'; } /* Log_Init */ @@ -122,8 +124,11 @@ Log_Exit( VOID ) if( NGIRCd_SignalRestart ) Log( LOG_NOTICE, "%s done (restarting).", PACKAGE_NAME ); else Log( LOG_NOTICE, "%s done.", PACKAGE_NAME ); - /* Error-File (stderr) loeschen */ - if( unlink( Error_File ) != 0 ) Log( LOG_ERR, "Can't delete \"%s\": %s", Error_File, strerror( errno )); + if( Error_File[0] ) + { + /* Error-File (stderr) loeschen */ + if( unlink( Error_File ) != 0 ) Log( LOG_ERR, "Can't delete \"%s\": %s", Error_File, strerror( errno )); + } #ifdef SYSLOG /* syslog abmelden */ blob - 8fbdba3f78ab017aa1bdb32848ab1fb2cadc3b1b blob + 8ced6e3f8903c8698e2aa505c8c558a15798b539 --- src/ngircd/ngircd.c +++ src/ngircd/ngircd.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: ngircd.c,v 1.83 2004/01/19 21:54:59 alex Exp $"; +static char UNUSED id[] = "$Id: ngircd.c,v 1.84 2004/05/07 11:19:21 alex Exp $"; #include "imp.h" #include @@ -228,6 +228,38 @@ main( int argc, const char *argv[] ) while( ! NGIRCd_SignalQuit ) { + /* Initialize global variables */ + 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; + + /* Initialize modules, part I */ + Log_Init( ); + Conf_Init( ); + + if( Conf_Chroot[0] ) + { + /* Chroot */ + if( chdir( Conf_Chroot ) != 0 ) Log( LOG_ERR, "Can't chdir() in ChrootDir (%s): %s", Conf_Chroot, strerror( errno )); + + if( chroot( Conf_Chroot ) != 0 ) Log( LOG_ERR, "Can't change root directory to \"%s\": %s", Conf_Chroot, strerror( errno )); + else Log( LOG_INFO, "Changed root and working directory to \"%s\".", Conf_Chroot ); + } + + if( Conf_GID != 0 ) + { + /* Set new group ID */ + if( setgid( Conf_GID ) != 0 ) Log( LOG_ERR, "Can't change group ID to %u: %s", Conf_GID, strerror( errno )); + } + if( Conf_UID != 0 ) + { + /* Set new user ID */ + if( setuid( Conf_UID ) != 0 ) Log( LOG_ERR, "Can't change user ID to %u: %s", Conf_UID, strerror( errno )); + } + /* In der Regel wird ein Sub-Prozess ge-fork()'t, der * nicht mehr mit dem Terminal verbunden ist. Mit der * Option "--nodaemon" kann dies (z.B. zum Debuggen) @@ -252,18 +284,10 @@ main( int argc, const char *argv[] ) (VOID)setsid( ); chdir( "/" ); } - - /* Globale Variablen initialisieren */ - 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; - /* Module initialisieren */ - Log_Init( ); + /* Initialize modules, part II: these functions are eventually + * called with already dropped privileges ... */ Resolve_Init( ); - Conf_Init( ); Lists_Init( ); Channel_Init( ); Client_Init( ); @@ -272,28 +296,15 @@ main( int argc, const char *argv[] ) #endif Conn_Init( ); - /* Wenn als root ausgefuehrt und eine andere UID - * konfiguriert ist, jetzt zu dieser wechseln */ - if( getuid( ) == 0 ) - { - if( Conf_GID != 0 ) - { - /* Neue Group-ID setzen */ - if( setgid( Conf_GID ) != 0 ) Log( LOG_ERR, "Can't change Group-ID to %u: %s", Conf_GID, strerror( errno )); - } - if( Conf_UID != 0 ) - { - /* Neue User-ID setzen */ - if( setuid( Conf_UID ) != 0 ) Log( LOG_ERR, "Can't change User-ID to %u: %s", Conf_UID, strerror( errno )); - } - } - - /* User, Gruppe und Prozess-ID des Daemon ausgeben */ + /* Show user, group, and PID of the running daemon */ pwd = getpwuid( getuid( )); grp = getgrgid( getgid( )); Log( LOG_INFO, "Running as user %s(%ld), group %s(%ld), with PID %ld.", pwd ? pwd->pw_name : "unknown", (LONG)getuid( ), grp ? grp->gr_name : "unknown", (LONG)getgid( ), (LONG)getpid( )); - /* stderr in "Error-File" umlenken */ - Log_InitErrorfile( ); + /* Redirect stderr handle to "error file" for debugging. + * But don't try to write in the chroot jail, since it's more + * secure to have a chroot dir not writable by the daemon. + */ + if( ! Conf_Chroot[0] ) Log_InitErrorfile( ); /* Signal-Handler initialisieren */ Initialize_Signal_Handler( );