From b6a2373c2c9a98594a87c54a4644f3c0e985e420 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 28 Nov 2007 23:24:26 +0000 Subject: Fixed the epoll+ForkDaemon combination. The libevent event handling didn't work very well on Linux 2.6 (and possibly others) in ForkDaemon mode. --- bitlbee.c | 2 ++ lib/events_libevent.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index 3d8a0310..3f488b46 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -292,6 +292,8 @@ static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition get the same random numbers as the parent/siblings. */ srand( time( NULL ) ^ getpid() ); + b_main_init(); + /* Close the listening socket, we're a client. */ close( global.listen_socket ); b_event_remove( global.listen_watch_source_id ); diff --git a/lib/events_libevent.c b/lib/events_libevent.c index f2b4d15c..d02ad6a6 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -36,7 +36,9 @@ #include #include -static guint id_next; +static void b_main_restart(); + +static guint id_next = 1; static GHashTable *id_hash; static int quitting = 0; @@ -47,6 +49,9 @@ static int quitting = 0; static GHashTable *read_hash; static GHashTable *write_hash; +struct event_base *leh; +struct event_base *old_leh; + struct b_event_data { guint id; @@ -58,9 +63,16 @@ struct b_event_data void b_main_init() { - event_init(); + if( leh != NULL ) + { + /* Clean up the hash tables? */ + + b_main_restart(); + old_leh = leh; + } + + leh = event_init(); - id_next = 1; id_hash = g_hash_table_new( g_int_hash, g_int_equal ); read_hash = g_hash_table_new( g_int_hash, g_int_equal ); write_hash = g_hash_table_new( g_int_hash, g_int_equal ); @@ -68,19 +80,40 @@ void b_main_init() void b_main_run() { - event_dispatch(); + /* This while loop is necessary to exit the event loop and start a + different one (necessary for ForkDaemon mode). */ + while( event_base_dispatch( leh ) == 0 && !quitting ) + { + if( old_leh != NULL ) + { + /* For some reason this just isn't allowed... + Possibly a bug in older versions, will see later. + event_base_free( old_leh ); */ + old_leh = NULL; + } + + printf( "New event loop.\n" ); + } } -void b_main_quit() +static void b_main_restart() { struct timeval tv; - /* libevent sometimes generates events before really quitting, + memset( &tv, 0, sizeof( struct timeval ) ); + event_base_loopexit( leh, &tv ); + + printf( "b_main_restart()\n" ); +} + +void b_main_quit() +{ + /* Tell b_main_run() that it shouldn't restart the loop. Also, + libevent sometimes generates events before really quitting, we want to stop them. */ quitting = 1; - memset( &tv, 0, sizeof( struct timeval ) ); - event_loopexit( &tv ); + b_main_restart(); } static void b_event_passthrough( int fd, short event, void *data ) -- cgit v1.2.3 From 9ff5737ec53cca2ba295b58fb74a8b97f496cd19 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 29 Nov 2007 21:55:14 +0000 Subject: printf() in daemons considered harmful. --- lib/events.h | 4 ++-- lib/events_libevent.c | 8 +++----- protocols/oscar/msgcookie.c | 15 --------------- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/lib/events.h b/lib/events.h index 0588547f..4baea7b6 100644 --- a/lib/events.h +++ b/lib/events.h @@ -44,7 +44,7 @@ #include #include -/* The conditions you can pass to gaim_input_add()/that will be passed to +/* The conditions you can pass to b_input_add()/that will be passed to the given callback function. */ typedef enum { GAIM_INPUT_READ = 1 << 1, @@ -57,7 +57,7 @@ typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition co #define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) #define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) -// #define event_debug( x... ) printf( x ) +/* #define event_debug( x... ) printf( x ) */ #define event_debug( x... ) /* Call this once when the program starts. It'll initialize the event handler diff --git a/lib/events_libevent.c b/lib/events_libevent.c index d02ad6a6..d3403152 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -31,13 +31,11 @@ #include #include #include -#include "proxy.h" - #include #include +#include "proxy.h" static void b_main_restart(); - static guint id_next = 1; static GHashTable *id_hash; static int quitting = 0; @@ -92,7 +90,7 @@ void b_main_run() old_leh = NULL; } - printf( "New event loop.\n" ); + event_debug( "New event loop.\n" ); } } @@ -103,7 +101,7 @@ static void b_main_restart() memset( &tv, 0, sizeof( struct timeval ) ); event_base_loopexit( leh, &tv ); - printf( "b_main_restart()\n" ); + event_debug( "b_main_restart()\n" ); } void b_main_quit() diff --git a/protocols/oscar/msgcookie.c b/protocols/oscar/msgcookie.c index d3c91a94..efeb8cbf 100644 --- a/protocols/oscar/msgcookie.c +++ b/protocols/oscar/msgcookie.c @@ -130,21 +130,6 @@ aim_msgcookie_t *aim_checkcookie(aim_session_t *sess, const guint8 *cookie, int return NULL; } -#if 0 /* debugging feature */ -int aim_dumpcookie(aim_msgcookie_t *cookie) -{ - - if (!cookie) - return -EINVAL; - - printf("\tCookie at %p: %d/%s with %p, next %p\n", - cookie, cookie->type, cookie->cookie, - cookie->data, cookie->next); - - return 0; -} -#endif - /** * aim_cookie_free - free an aim_msgcookie_t struct * @sess: session to remove the cookie from -- cgit v1.2.3 From 94d52d64c1ad3d55f210e1fc8e6345d54c4e46d5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Dec 2007 11:00:15 +0000 Subject: Added charset checks on incoming msgs (from the IRC side) to prevent possible crashes/other odd behaviour in IM modules (or a GLib function that crashes on non-UTF-8 strings). --- irc.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/irc.c b/irc.c index 5531addb..01d4c47e 100644 --- a/irc.c +++ b/irc.c @@ -319,11 +319,22 @@ void irc_process( irc_t *irc ) break; } - if( ( cs = set_getstr( &irc->set, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) + if( ( cs = set_getstr( &irc->set, "charset" ) ) ) { conv[IRC_MAX_LINE] = 0; - if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) != -1 ) - lines[i] = conv; + if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 ) + { + if( irc->status & USTATUS_LOGGED_IN ) + irc_usermsg( irc, "ERROR: Charset mismatch detected. The charset " + "setting is currently set to %s, so please make " + "sure your IRC client will send and accept text in " + "that charset, or tell BitlBee which charset to " + "expect by changing the charset setting. See " + "`help set charset' for more information. Your " + "message was ignored.", cs ); + *conv = 0; + } + lines[i] = conv; } if( ( cmd = irc_parse_line( lines[i] ) ) == NULL ) -- cgit v1.2.3 From 4306d8b066d335cb6667414bdd6c5b2e78ccbfd5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Dec 2007 16:43:57 +0000 Subject: Removed retarded printf() (ARGH) and moved the event handling handling of IQ packets to jabber_util so I can reuse it for certain presence packets. --- protocols/jabber/iq.c | 19 +------------------ protocols/jabber/jabber.c | 2 -- protocols/jabber/jabber.h | 1 + protocols/jabber/jabber_util.c | 30 ++++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 595718fb..3dae39f6 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -30,7 +30,6 @@ static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_no xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) { struct im_connection *ic = data; - struct jabber_data *jd = ic->proto_data; struct xt_node *c, *reply = NULL; char *type, *s; int st, pack = 1; @@ -46,23 +45,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) { - struct jabber_cache_entry *entry; - - if( ( s = xt_find_attr( node, "id" ) ) == NULL || - strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 ) - { - /* Silently ignore it, without an ID (or a non-cache - ID) we don't know how to handle the packet and we - probably don't have to. */ - return XT_HANDLED; - } - - entry = g_hash_table_lookup( jd->node_cache, s ); - - if( entry == NULL ) - imcb_log( ic, "WARNING: Received IQ-%s packet with unknown/expired ID %s!", type, s ); - else if( entry->func ) - return entry->func( ic, node, entry->node ); + return jabber_cache_handle_packet( ic, node ); } else if( strcmp( type, "get" ) == 0 ) { diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index b0651a59..6ee10a38 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -225,8 +225,6 @@ static void jabber_generate_id_hash( struct jabber_data *jd ) s = base64_encode( binbuf, 9 ); jd->cached_id_prefix = g_strdup_printf( "%s%s", JABBER_CACHED_ID, s ); g_free( s ); - - printf( "%s\n", jd->cached_id_prefix ); } static void jabber_logout( struct im_connection *ic ) diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index fc9d2fc4..bee5cb73 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -184,6 +184,7 @@ void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_ca struct xt_node *jabber_cache_get( struct im_connection *ic, char *id ); void jabber_cache_entry_free( gpointer entry ); void jabber_cache_clean( struct im_connection *ic ); +xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node ); const struct jabber_away_state *jabber_away_state_by_code( char *code ); const struct jabber_away_state *jabber_away_state_by_name( char *name ); void jabber_buddy_ask( struct im_connection *ic, char *handle ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 43b91fe3..453e5930 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -180,6 +180,36 @@ gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer nullp } } +xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node ) +{ + struct jabber_data *jd = ic->proto_data; + struct jabber_cache_entry *entry; + char *s; + + if( ( s = xt_find_attr( node, "id" ) ) == NULL || + strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 ) + { + /* Silently ignore it, without an ID (or a non-cache + ID) we don't know how to handle the packet and we + probably don't have to. */ + return XT_HANDLED; + } + + entry = g_hash_table_lookup( jd->node_cache, s ); + + if( entry == NULL ) + { + imcb_log( ic, "WARNING: Received %s-%s packet with unknown/expired ID %s!", + node->name, xt_find_attr( node, "type" ) ? : "(no type)", s ); + } + else if( entry->func ) + { + return entry->func( ic, node, entry->node ); + } + + return XT_HANDLED; +} + const struct jabber_away_state jabber_away_state_list[] = { { "away", "Away" }, -- cgit v1.2.3 From 911cc4f16e96c1ea9027bb12b024531a4b588038 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Dec 2007 17:24:46 +0000 Subject: Defining DEBUG via CFLAGS so that it'll always be there, even when a file doesn't include config.h. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index b84f3947..15e22623 100755 --- a/configure +++ b/configure @@ -134,7 +134,7 @@ EOF if [ "$debug" = "1" ]; then [ -z "$CFLAGS" ] && CFLAGS=-g echo 'DEBUG=1' >> Makefile.settings - echo '#define DEBUG' >> config.h + CFLAGS="$CFLAGS -DDEBUG" else [ -z "$CFLAGS" ] && CFLAGS="-O2 -fno-strict-aliasing" fi -- cgit v1.2.3 From 5bd21df87b195af211c2280ca00391493a669895 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Dec 2007 17:25:57 +0000 Subject: Handling of presence-error packets (only useful for groupchats now), moved jabber_chat_by_jid() (with the right name) to conference.c, I don't know what it was doing in jabber_util.c. --- protocols/jabber/conference.c | 48 ++++++++++++++++++++++++++++++++++++++---- protocols/jabber/jabber.c | 4 ++-- protocols/jabber/jabber.h | 2 +- protocols/jabber/jabber_util.c | 23 +++++--------------- protocols/jabber/presence.c | 9 ++++---- 5 files changed, 57 insertions(+), 29 deletions(-) diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 008bbe63..72d7b5d8 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -23,6 +23,8 @@ #include "jabber.h" +static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); + struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ) { struct jabber_chat *jc; @@ -34,14 +36,13 @@ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char * node = xt_new_node( "x", NULL, NULL ); xt_add_attr( node, "xmlns", XMLNS_MUC ); node = jabber_make_packet( "presence", NULL, roomjid, node ); + jabber_cache_add( ic, node, jabber_chat_join_failed ); if( !jabber_write_packet( ic, node ) ) { g_free( roomjid ); - xt_free_node( node ); return NULL; } - xt_free_node( node ); jc = g_new0( struct jabber_chat, 1 ); jc->name = jabber_normalize( room ); @@ -64,6 +65,45 @@ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char * return c; } +static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ + struct jabber_error *err; + struct jabber_buddy *bud; + char *room; + + room = xt_find_attr( orig, "to" ); + bud = jabber_buddy_by_jid( ic, room, 0 ); + + err = jabber_error_parse( xt_find_node( node->children, "error" ), XMLNS_STANZA_ERROR ); + if( err ) + { + imcb_error( ic, "Error joining groupchat %s: %s%s%s", + bud->bare_jid, err->code, err->text ? ": " : "", + err->text ? err->text : "" ); + jabber_error_free( err ); + } + + if( bud ) + jabber_chat_free( jabber_chat_by_jid( ic, bud->bare_jid ) ); +} + +struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ) +{ + char *normalized = jabber_normalize( name ); + struct groupchat *ret; + struct jabber_chat *jc; + + for( ret = ic->groupchats; ret; ret = ret->next ) + { + jc = ret->data; + if( strcmp( normalized, jc->name ) == 0 ) + break; + } + g_free( normalized ); + + return ret; +} + void jabber_chat_free( struct groupchat *c ) { struct jabber_chat *jc = c->data; @@ -147,7 +187,7 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu struct jabber_chat *jc; char *s; - if( ( chat = jabber_chat_by_name( ic, bud->bare_jid ) ) == NULL ) + if( ( chat = jabber_chat_by_jid( ic, bud->bare_jid ) ) == NULL ) { /* How could this happen?? We could do kill( self, 11 ) now or just wait for the OS to do it. :-) */ @@ -249,7 +289,7 @@ void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud return; } - else if( ( chat = jabber_chat_by_name( ic, bud->bare_jid ) ) == NULL ) + else if( ( chat = jabber_chat_by_jid( ic, bud->bare_jid ) ) == NULL ) { /* How could this happen?? We could do kill( self, 11 ) now or just wait for the OS to do it. :-) */ diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 6ee10a38..817d1487 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -269,7 +269,7 @@ static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) return jabber_write( ic, message, strlen( message ) ); - if( ( s = strchr( who, '=' ) ) && jabber_chat_by_name( ic, s + 1 ) ) + if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) ) bud = jabber_buddy_by_ext_jid( ic, who, 0 ); else bud = jabber_buddy_by_jid( ic, who, 0 ); @@ -396,7 +396,7 @@ static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room { if( strchr( room, '@' ) == NULL ) imcb_error( ic, "Invalid room name: %s", room ); - else if( jabber_chat_by_name( ic, room ) ) + else if( jabber_chat_by_jid( ic, room ) ) imcb_error( ic, "Already present in chat `%s'", room ); else return jabber_chat_join( ic, room, nick, password ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index bee5cb73..94d017d6 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -207,7 +207,6 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, g struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); -struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ); time_t jabber_get_timestamp( struct xt_node *xt ); struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ); void jabber_error_free( struct jabber_error *err ); @@ -230,6 +229,7 @@ gboolean sasl_supported( struct im_connection *ic ); /* conference.c */ struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); +struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ); void jabber_chat_free( struct groupchat *c ); int jabber_chat_msg( struct groupchat *ic, char *message, int flags ); int jabber_chat_topic( struct groupchat *c, char *topic ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 453e5930..9d84e099 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -613,23 +613,6 @@ int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ) } } -struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name ) -{ - char *normalized = jabber_normalize( name ); - struct groupchat *ret; - struct jabber_chat *jc; - - for( ret = ic->groupchats; ret; ret = ret->next ) - { - jc = ret->data; - if( strcmp( normalized, jc->name ) == 0 ) - break; - } - g_free( normalized ); - - return ret; -} - time_t jabber_get_timestamp( struct xt_node *xt ) { struct tm tp, utc; @@ -681,10 +664,14 @@ time_t jabber_get_timestamp( struct xt_node *xt ) struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ) { - struct jabber_error *err = g_new0( struct jabber_error, 1 ); + struct jabber_error *err; struct xt_node *c; char *s; + if( node == NULL ) + return NULL; + + err = g_new0( struct jabber_error, 1 ); err->type = xt_find_attr( node, "type" ); for( c = node->children; c; c = c->next ) diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index 5abdc449..c3d7dced 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -39,7 +39,7 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) if( ( s = strchr( from, '/' ) ) ) { *s = 0; - if( jabber_chat_by_name( ic, from ) ) + if( jabber_chat_by_jid( ic, from ) ) is_chat = 1; *s = '/'; } @@ -163,8 +163,10 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) } else if( strcmp( type, "error" ) == 0 ) { - struct jabber_error *err; + return jabber_cache_handle_packet( ic, node ); + /* + struct jabber_error *err; if( ( c = xt_find_node( node->children, "error" ) ) ) { err = jabber_error_parse( c, XMLNS_STANZA_ERROR ); @@ -172,8 +174,7 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) err->code, err->text ? ": " : "", err->text ? err->text : "" ); jabber_error_free( err ); - } - /* What else to do with it? */ + } */ } return XT_HANDLED; -- cgit v1.2.3 From 80e9db97776bfd6c6192135d65027abd8f50887c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Dec 2007 23:14:49 +0000 Subject: Forgot to return something in jabber_chat_join_failed(). --- protocols/jabber/conference.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 72d7b5d8..c5bc0e68 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -72,7 +72,8 @@ static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_no char *room; room = xt_find_attr( orig, "to" ); - bud = jabber_buddy_by_jid( ic, room, 0 ); + if( ( bud = jabber_buddy_by_jid( ic, room, 0 ) ) ) + jabber_chat_free( jabber_chat_by_jid( ic, bud->bare_jid ) ); err = jabber_error_parse( xt_find_node( node->children, "error" ), XMLNS_STANZA_ERROR ); if( err ) @@ -83,8 +84,7 @@ static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_no jabber_error_free( err ); } - if( bud ) - jabber_chat_free( jabber_chat_by_jid( ic, bud->bare_jid ) ); + return XT_HANDLED; } struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ) -- cgit v1.2.3 From aaf92a9eb64327892e39fdbd7113d797d1d68cec Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Dec 2007 23:18:25 +0000 Subject: Imported setuid() patch from Simo Leone with some modifications. Also adding some missing g_free()s to conf.c. --- bitlbee.conf | 7 +++++++ conf.c | 19 ++++++++++++++++++- conf.h | 1 + unix.c | 21 +++++++++++++++++---- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/bitlbee.conf b/bitlbee.conf index e5e0f7de..d9f878c8 100644 --- a/bitlbee.conf +++ b/bitlbee.conf @@ -19,6 +19,13 @@ ## # RunMode = Inetd +## User: +## +## If BitlBee is started by root as a daemon, it can drop root privileges, +## and change to the specified user. +## +# User = bitlbee + ## DaemonPort/DaemonInterface: ## ## For daemon mode, you can specify on what interface and port the daemon diff --git a/conf.c b/conf.c index 82487ddf..94c673cc 100644 --- a/conf.c +++ b/conf.c @@ -62,6 +62,7 @@ conf_t *conf_load( int argc, char *argv[] ) conf->motdfile = g_strdup( ETCDIR "/motd.txt" ); conf->ping_interval = 180; conf->ping_timeout = 300; + conf->user = NULL; proxytype = 0; i = conf_loadini( conf, CONF_FILE ); @@ -75,7 +76,7 @@ conf_t *conf_load( int argc, char *argv[] ) fprintf( stderr, "Warning: Unable to read configuration file `%s'.\n", CONF_FILE ); } - while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:" ) ) >= 0 ) + while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:u:" ) ) >= 0 ) /* ^^^^ Just to make sure we skip this step from the REHASH handler. */ { if( opt == 'i' ) @@ -131,6 +132,7 @@ conf_t *conf_load( int argc, char *argv[] ) " -I Classic/InetD mode. (Default)\n" " -D Daemon mode. (Still EXPERIMENTAL!)\n" " -F Forking daemon. (one process per client)\n" + " -u Run daemon as specified user.\n" " -P Specify PID-file (not for inetd mode)\n" " -i Specify the interface (by IP address) to listen on.\n" " (Default: 0.0.0.0 (any interface))\n" @@ -150,6 +152,11 @@ conf_t *conf_load( int argc, char *argv[] ) mode anyway!) */ ipc_master_set_statefile( optarg ); } + else if( opt == 'u' ) + { + g_free( conf->user ); + conf->user = g_strdup( optarg ); + } } if( conf->configdir[strlen(conf->configdir)-1] != '/' ) @@ -191,10 +198,12 @@ static int conf_loadini( conf_t *conf, char *file ) } else if( g_strcasecmp( ini->key, "daemoninterface" ) == 0 ) { + g_free( conf->iface ); conf->iface = g_strdup( ini->value ); } else if( g_strcasecmp( ini->key, "daemonport" ) == 0 ) { + g_free( conf->port ); conf->port = g_strdup( ini->value ); } else if( g_strcasecmp( ini->key, "authmode" ) == 0 ) @@ -208,14 +217,17 @@ static int conf_loadini( conf_t *conf, char *file ) } else if( g_strcasecmp( ini->key, "authpassword" ) == 0 ) { + g_free( conf->auth_pass ); conf->auth_pass = g_strdup( ini->value ); } else if( g_strcasecmp( ini->key, "operpassword" ) == 0 ) { + g_free( conf->oper_pass ); conf->oper_pass = g_strdup( ini->value ); } else if( g_strcasecmp( ini->key, "hostname" ) == 0 ) { + g_free( conf->hostname ); conf->hostname = g_strdup( ini->value ); } else if( g_strcasecmp( ini->key, "configdir" ) == 0 ) @@ -280,6 +292,11 @@ static int conf_loadini( conf_t *conf, char *file ) g_free( url ); } + else if( g_strcasecmp( ini->key, "user" ) == 0 ) + { + g_free( conf->user ); + conf->user = g_strdup( ini->value ); + } else { fprintf( stderr, "Error: Unknown setting `%s` in configuration file.\n", ini->key ); diff --git a/conf.h b/conf.h index 5138ce11..d21ec577 100644 --- a/conf.h +++ b/conf.h @@ -48,6 +48,7 @@ typedef struct conf char **migrate_storage; int ping_interval; int ping_timeout; + char *user; } conf_t; G_GNUC_MALLOC conf_t *conf_load( int argc, char *argv[] ); diff --git a/unix.c b/unix.c index 0abf43ea..75ffcf95 100644 --- a/unix.c +++ b/unix.c @@ -33,6 +33,7 @@ #include #include #include +#include global_t global; /* Against global namespace pollution */ @@ -44,8 +45,6 @@ int main( int argc, char *argv[], char **envp ) char *old_cwd = NULL; struct sigaction sig, old; - memset( &global, 0, sizeof( global_t ) ); - log_init(); CONF_FILE = g_strdup( CONF_FILE_DEF ); global.conf = conf_load( argc, argv ); @@ -86,12 +85,26 @@ int main( int argc, char *argv[], char **envp ) if( i != 0 ) return( i ); + if( ( global.conf->user && *global.conf->user ) && + ( global.conf->runmode == RUNMODE_DAEMON || + global.conf->runmode == RUNMODE_FORKDAEMON ) && + ( !getuid() || !geteuid() ) ) + { + struct passwd *pw = NULL; + pw = getpwnam( global.conf->user ); + if( pw ) + { + setgid( pw->pw_gid ); + setuid( pw->pw_uid ); + } + } + global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage ); - if ( global.storage == NULL) { + if( global.storage == NULL ) + { log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage ); return( 1 ); } - /* Catch some signals to tell the user what's happening before quitting */ memset( &sig, 0, sizeof( sig ) ); -- cgit v1.2.3