diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2005-12-26 15:02:47 +0100 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2005-12-26 15:02:47 +0100 |
commit | d25f6fcbe8e291dd858bf734fa85cde176dc8415 (patch) | |
tree | 58fffb8b1dd8cc0a3cf3583c0daf7c10271af871 | |
parent | ffea9b950b183dd54952b56703506508b0984d4b (diff) |
Added OperPassword and RunMode = ForkDaemon settings. Oper stuff is
*INSECURE* because users can just do /mode +o to become operator.
-rw-r--r-- | bitlbee.c | 40 | ||||
-rw-r--r-- | bitlbee.conf | 9 | ||||
-rw-r--r-- | bitlbee.h | 1 | ||||
-rw-r--r-- | conf.c | 16 | ||||
-rw-r--r-- | conf.h | 5 | ||||
-rw-r--r-- | irc.c | 13 | ||||
-rw-r--r-- | irc.h | 2 | ||||
-rw-r--r-- | storage_text.c | 2 | ||||
-rw-r--r-- | unix.c | 27 |
9 files changed, 92 insertions, 23 deletions
@@ -36,12 +36,30 @@ gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpoi { size_t size = sizeof( struct sockaddr_in ); struct sockaddr_in conn_info; - int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, - &size ); + int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size ); + pid_t client_pid = 0; + + if( global.conf->runmode == RUNMODE_FORKDAEMON ) + client_pid = fork(); + + if( client_pid == 0 ) + { + log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket ); + irc_new( new_socket ); + + if( global.conf->runmode == RUNMODE_FORKDAEMON ) + { + /* Close the listening socket, we're a client. */ + close( global.listen_socket ); + g_source_remove( global.listen_watch_source_id ); + } + } + else + { + /* We don't need this one, only the client does. */ + close( new_socket ); + } - log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket ); - irc_new( new_socket ); - return TRUE; } @@ -65,24 +83,24 @@ int bitlbee_daemon_init() listen_addr.sin_family = AF_INET; listen_addr.sin_port = htons( global.conf->port ); listen_addr.sin_addr.s_addr = inet_addr( global.conf->iface ); - + i = bind( global.listen_socket, (struct sockaddr *) &listen_addr, sizeof( struct sockaddr ) ); if( i == -1 ) { log_error( "bind" ); return( -1 ); } - + i = listen( global.listen_socket, 10 ); if( i == -1 ) { log_error( "listen" ); return( -1 ); } - + ch = g_io_channel_unix_new( global.listen_socket ); - g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL ); - + global.listen_watch_source_id = g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL ); + #ifndef _WIN32 if( !global.conf->nofork ) { @@ -164,6 +182,8 @@ gboolean bitlbee_io_current_client_read( GIOChannel *source, GIOCondition condit return FALSE; } + return TRUE; + /* Very naughty, go read the RFCs! >:) */ if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) ) { diff --git a/bitlbee.conf b/bitlbee.conf index b0de328d..919cee9d 100644 --- a/bitlbee.conf +++ b/bitlbee.conf @@ -13,6 +13,9 @@ ## stable enough to serve lots of users from one process. Because of this ## and other reasons, the use of daemon-mode is *STRONGLY* discouraged, ## don't even *think* of reporting bugs when you use this. +## ForkDaemon -- Run as a stand-alone daemon, but keep all clients in separate +## child processes. This should be pretty safe and reliable to use instead +## of inetd mode. ## # RunMode = Inetd @@ -41,6 +44,12 @@ ## # AuthPassword = ItllBeBitlBee ## Heh.. Our slogan. ;-) +## OperPassword +## +## Password that unlocks access to special operator commands. +## +# OperPassword = ChangeMe! + ## HostName ## ## Normally, BitlBee gets a hostname using getsockname(). If you have a nicer @@ -113,6 +113,7 @@ extern char *CONF_FILE; typedef struct global_t { int listen_socket; + gint listen_watch_source_id; help_t *help; conf_t *conf; GList *storage; /* The first backend in the list will be used for saving */ @@ -52,7 +52,8 @@ conf_t *conf_load( int argc, char *argv[] ) conf->primary_storage = "text"; conf->runmode = RUNMODE_INETD; conf->authmode = AUTHMODE_OPEN; - conf->password = NULL; + conf->auth_pass = NULL; + conf->oper_pass = NULL; conf->configdir = g_strdup( CONFIG ); conf->plugindir = g_strdup( PLUGINDIR ); conf->motdfile = g_strdup( ETCDIR "/motd.txt" ); @@ -70,7 +71,7 @@ conf_t *conf_load( int argc, char *argv[] ) fprintf( stderr, "Warning: Unable to read configuration file `%s'.\n", CONF_FILE ); } - while( ( opt = getopt( argc, argv, "i:p:nvIDc:d:h" ) ) >= 0 ) + while( ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 ) { if( opt == 'i' ) { @@ -93,6 +94,8 @@ conf_t *conf_load( int argc, char *argv[] ) conf->runmode=RUNMODE_INETD; else if( opt == 'D' ) conf->runmode=RUNMODE_DAEMON; + else if( opt == 'F' ) + conf->runmode=RUNMODE_FORKDAEMON; else if( opt == 'c' ) { if( strcmp( CONF_FILE, optarg ) != 0 ) @@ -117,6 +120,7 @@ conf_t *conf_load( int argc, char *argv[] ) "\n" " -I Classic/InetD mode. (Default)\n" " -D Daemon mode. (Still EXPERIMENTAL!)\n" + " -F Forking daemon. (one process per client)\n" " -i Specify the interface (by IP address) to listen on.\n" " (Default: 0.0.0.0 (any interface))\n" " -p Port number to listen on. (Default: 6667)\n" @@ -156,6 +160,8 @@ static int conf_loadini( conf_t *conf, char *file ) { if( g_strcasecmp( ini->value, "daemon" ) == 0 ) conf->runmode = RUNMODE_DAEMON; + else if( g_strcasecmp( ini->value, "forkdaemon" ) == 0 ) + conf->runmode = RUNMODE_FORKDAEMON; else conf->runmode = RUNMODE_INETD; } @@ -183,7 +189,11 @@ static int conf_loadini( conf_t *conf, char *file ) } else if( g_strcasecmp( ini->key, "authpassword" ) == 0 ) { - conf->password = g_strdup( ini->value ); + conf->auth_pass = g_strdup( ini->value ); + } + else if( g_strcasecmp( ini->key, "operpassword" ) == 0 ) + { + conf->oper_pass = g_strdup( ini->value ); } else if( g_strcasecmp( ini->key, "hostname" ) == 0 ) { @@ -26,7 +26,7 @@ #ifndef __CONF_H #define __CONF_H -typedef enum runmode { RUNMODE_DAEMON, RUNMODE_INETD } runmode_t; +typedef enum runmode { RUNMODE_DAEMON, RUNMODE_FORKDAEMON, RUNMODE_INETD } runmode_t; typedef enum authmode { AUTHMODE_OPEN, AUTHMODE_CLOSED, AUTHMODE_REGISTERED } authmode_t; typedef struct conf @@ -37,7 +37,8 @@ typedef struct conf int verbose; runmode_t runmode; authmode_t authmode; - char *password; + char *auth_pass; + char *oper_pass; char *hostname; char *configdir; char *plugindir; @@ -263,7 +263,7 @@ void irc_free(irc_t * irc) } g_free(irc); - if( global.conf->runmode == RUNMODE_INETD ) + if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) g_main_quit( global.loop ); } @@ -421,7 +421,7 @@ int irc_exec( irc_t *irc, char **cmd ) { irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); } - else if( strcmp( cmd[1], (global.conf)->password ) == 0 ) + else if( strcmp( cmd[1], (global.conf)->auth_pass ) == 0 ) { irc->status = USTATUS_AUTHORIZED; } @@ -500,6 +500,15 @@ int irc_exec( irc_t *irc, char **cmd ) { irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost ); } + else if( g_strcasecmp( cmd[0], "OPER" ) == 0 ) + { + if( !cmd[2] ) + irc_reply( irc, 461, "%s :Need more parameters", cmd[0] ); + else if( strcmp( cmd[2], global.conf->oper_pass ) == 0 ) + irc_umode_set( irc, irc->nick, "+o" ); + // else + /* FIXME/TODO: Find out which reply to send now. */ + } else if( g_strcasecmp( cmd[0], "MODE" ) == 0 ) { if( !cmd[1] ) @@ -39,7 +39,7 @@ #define FLOOD_SEND_BYTES (1024*10) #define FLOOD_SEND_MAXBUFFER (1024*20) -#define UMODES "ais" +#define UMODES "aiso" #define CMODES "nt" #define CMODE "t" #define UMODE "s" diff --git a/storage_text.c b/storage_text.c index 1bf2dcf3..f807cb3e 100644 --- a/storage_text.c +++ b/storage_text.c @@ -70,7 +70,7 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i FILE *fp; user_t *ru = user_find( irc, ROOT_NICK ); - if( irc->status == USTATUS_IDENTIFIED ) + if( irc->status >= USTATUS_IDENTIFIED ) return( 1 ); g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" ); @@ -31,6 +31,7 @@ #include <signal.h> #include <unistd.h> #include <sys/time.h> +#include <sys/wait.h> global_t global; /* Against global namespace pollution */ @@ -45,7 +46,7 @@ int main( int argc, char *argv[] ) global.loop = g_main_new( FALSE ); - log_init( ); + log_init(); nogaim_init(); @@ -69,11 +70,15 @@ int main( int argc, char *argv[] ) i = bitlbee_daemon_init(); log_message( LOGLVL_INFO, "Bitlbee %s starting in daemon mode.", BITLBEE_VERSION ); } + else if( global.conf->runmode == RUNMODE_FORKDAEMON ) + { + i = bitlbee_daemon_init(); + log_message( LOGLVL_INFO, "Bitlbee %s starting in forking daemon mode.", BITLBEE_VERSION ); + } if( i != 0 ) return( i ); - global.storage = storage_init( global.conf->primary_storage, - global.conf->migrate_storage ); + global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage ); if ( global.storage == NULL) { log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage ); return( 1 ); @@ -83,6 +88,7 @@ int main( int argc, char *argv[] ) /* Catch some signals to tell the user what's happening before quitting */ memset( &sig, 0, sizeof( sig ) ); sig.sa_handler = sighandler; + sigaction( SIGCHLD, &sig, &old ); sigaction( SIGPIPE, &sig, &old ); sig.sa_flags = SA_RESETHAND; sigaction( SIGINT, &sig, &old ); @@ -106,7 +112,7 @@ int main( int argc, char *argv[] ) static void sighandler( int signal ) { - /* FIXME: In fact, calling log_message() here can be dangerous. But well, let's take the risk for now. */ + /* FIXME: Calling log_message() here is not a very good idea! */ if( signal == SIGTERM ) { @@ -132,6 +138,19 @@ static void sighandler( int signal ) raise( signal ); } } + else if( signal == SIGCHLD ) + { + pid_t pid; + int st; + + while( ( pid = waitpid( 0, &st, WNOHANG ) ) > 0 ) + { + if( WIFSIGNALED( st ) ) + log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", pid, WEXITSTATUS( st ) ); + else if( WIFEXITED( st ) ) + log_message( LOGLVL_INFO, "Client %d killed by signal %d.", pid, WTERMSIG( st ) ); + } + } else if( signal != SIGPIPE ) { log_message( LOGLVL_ERROR, "Fatal signal received: %d. That's probably a bug.", signal ); |