1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
4 * Copyright 2002-2004 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* Main file (Unix specific part) */
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License with
21 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22 if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23 Suite 330, Boston, MA 02111-1307 USA
31 #include "protocols/nogaim.h"
34 #include "lib/ssl_client.h"
45 #if defined(OTR_BI) || defined(OTR_PI)
49 global_t global
; /* Against global namespace pollution */
51 static void sighandler( int signal
);
53 static int crypt_main( int argc
, char *argv
[] );
55 int main( int argc
, char *argv
[] )
59 struct sigaction sig
, old
;
61 /* Required to make iconv to ASCII//TRANSLIT work. This makes BitlBee
62 system-locale-sensitive. :-( */
63 setlocale( LC_CTYPE
, "" );
65 if( argc
> 1 && strcmp( argv
[1], "-x" ) == 0 )
66 return crypt_main( argc
, argv
);
70 global
.conf_file
= g_strdup( CONF_FILE_DEF
);
71 global
.conf
= conf_load( argc
, argv
);
72 if( global
.conf
== NULL
)
77 /* libpurple doesn't like fork()s after initializing itself, so if
78 we use it, do this init a little later (in case we're running in
84 /* Ugly Note: libotr and gnutls both use libgcrypt. libgcrypt
85 has a process-global config state whose initialization happpens
86 twice if libotr and gnutls are used together. libotr installs custom
87 memory management functions for libgcrypt while our gnutls module
88 uses the defaults. Therefore we initialize OTR after SSL. *sigh* */
93 /* And in case OTR is loaded as a plugin, it'll also get loaded after
96 srand( time( NULL
) ^ getpid() );
98 global
.helpfile
= g_strdup( HELP_FILE
);
99 if( help_init( &global
.help
, global
.helpfile
) == NULL
)
100 log_message( LOGLVL_WARNING
, "Error opening helpfile %s.", HELP_FILE
);
102 global
.storage
= storage_init( global
.conf
->primary_storage
, global
.conf
->migrate_storage
);
103 if( global
.storage
== NULL
)
105 log_message( LOGLVL_ERROR
, "Unable to load storage backend '%s'", global
.conf
->primary_storage
);
109 if( global
.conf
->runmode
== RUNMODE_INETD
)
111 log_link( LOGLVL_ERROR
, LOGOUTPUT_IRC
);
112 log_link( LOGLVL_WARNING
, LOGOUTPUT_IRC
);
114 i
= bitlbee_inetd_init();
115 log_message( LOGLVL_INFO
, "%s %s starting in inetd mode.", PACKAGE
, BITLBEE_VERSION
);
118 else if( global
.conf
->runmode
== RUNMODE_DAEMON
)
120 log_link( LOGLVL_ERROR
, LOGOUTPUT_CONSOLE
);
121 log_link( LOGLVL_WARNING
, LOGOUTPUT_CONSOLE
);
123 i
= bitlbee_daemon_init();
124 log_message( LOGLVL_INFO
, "%s %s starting in daemon mode.", PACKAGE
, BITLBEE_VERSION
);
126 else if( global
.conf
->runmode
== RUNMODE_FORKDAEMON
)
128 log_link( LOGLVL_ERROR
, LOGOUTPUT_CONSOLE
);
129 log_link( LOGLVL_WARNING
, LOGOUTPUT_CONSOLE
);
131 /* In case the operator requests a restart, we need this. */
132 old_cwd
= g_malloc( 256 );
133 if( getcwd( old_cwd
, 255 ) == NULL
)
135 log_message( LOGLVL_WARNING
, "Could not save current directory: %s", strerror( errno
) );
140 i
= bitlbee_daemon_init();
141 log_message( LOGLVL_INFO
, "%s %s starting in forking daemon mode.", PACKAGE
, BITLBEE_VERSION
);
146 if( ( global
.conf
->user
&& *global
.conf
->user
) &&
147 ( global
.conf
->runmode
== RUNMODE_DAEMON
||
148 global
.conf
->runmode
== RUNMODE_FORKDAEMON
) &&
149 ( !getuid() || !geteuid() ) )
151 struct passwd
*pw
= NULL
;
152 pw
= getpwnam( global
.conf
->user
);
155 initgroups( global
.conf
->user
, pw
->pw_gid
);
156 setgid( pw
->pw_gid
);
157 setuid( pw
->pw_uid
);
161 log_message( LOGLVL_WARNING
, "Failed to look up user %s.", global
.conf
->user
);
165 /* Catch some signals to tell the user what's happening before quitting */
166 memset( &sig
, 0, sizeof( sig
) );
167 sig
.sa_handler
= sighandler
;
168 sigaction( SIGCHLD
, &sig
, &old
);
169 sigaction( SIGPIPE
, &sig
, &old
);
170 sig
.sa_flags
= SA_RESETHAND
;
171 sigaction( SIGINT
, &sig
, &old
);
172 sigaction( SIGILL
, &sig
, &old
);
173 sigaction( SIGBUS
, &sig
, &old
);
174 sigaction( SIGFPE
, &sig
, &old
);
175 sigaction( SIGSEGV
, &sig
, &old
);
176 sigaction( SIGTERM
, &sig
, &old
);
177 sigaction( SIGQUIT
, &sig
, &old
);
178 sigaction( SIGXCPU
, &sig
, &old
);
180 if( !getuid() || !geteuid() )
181 log_message( LOGLVL_WARNING
, "BitlBee is running with root privileges. Why?" );
185 /* Mainly good for restarting, to make sure we close the help.txt fd. */
186 help_free( &global
.help
);
190 char *fn
= ipc_master_save_state();
193 env
= g_strdup_printf( "_BITLBEE_RESTART_STATE=%s", fn
);
196 /* Looks like env should *not* be freed here as putenv
197 doesn't make a copy. Odd. */
199 i
= chdir( old_cwd
);
200 close( global
.listen_socket
);
202 if( execv( argv
[0], argv
) == -1 )
203 /* Apparently the execve() failed, so let's just
204 jump back into our own/current main(). */
205 /* Need more cleanup code to make this work. */
206 return 1; /* main( argc, argv ); */
212 static int crypt_main( int argc
, char *argv
[] )
215 unsigned char *pass_cr
, *pass_cl
;
217 if( argc
< 4 || ( strcmp( argv
[2], "hash" ) != 0 &&
218 strcmp( argv
[2], "unhash" ) != 0 && argc
< 5 ) )
220 printf( "Supported:\n"
221 " %s -x enc <key> <cleartext password>\n"
222 " %s -x dec <key> <encrypted password>\n"
223 " %s -x hash <cleartext password>\n"
224 " %s -x unhash <hashed password>\n"
225 " %s -x chkhash <hashed password> <cleartext password>\n",
226 argv
[0], argv
[0], argv
[0], argv
[0], argv
[0] );
228 else if( strcmp( argv
[2], "enc" ) == 0 )
230 pass_len
= arc_encode( argv
[4], strlen( argv
[4] ), (unsigned char**) &pass_cr
, argv
[3], 12 );
231 printf( "%s\n", base64_encode( pass_cr
, pass_len
) );
233 else if( strcmp( argv
[2], "dec" ) == 0 )
235 pass_len
= base64_decode( argv
[4], (unsigned char**) &pass_cr
);
236 arc_decode( pass_cr
, pass_len
, (char**) &pass_cl
, argv
[3] );
237 printf( "%s\n", pass_cl
);
239 else if( strcmp( argv
[2], "hash" ) == 0 )
241 md5_byte_t pass_md5
[21];
242 md5_state_t md5_state
;
244 random_bytes( pass_md5
+ 16, 5 );
245 md5_init( &md5_state
);
246 md5_append( &md5_state
, (md5_byte_t
*) argv
[3], strlen( argv
[3] ) );
247 md5_append( &md5_state
, pass_md5
+ 16, 5 ); /* Add the salt. */
248 md5_finish( &md5_state
, pass_md5
);
250 printf( "%s\n", base64_encode( pass_md5
, 21 ) );
252 else if( strcmp( argv
[2], "unhash" ) == 0 )
254 printf( "Hash %s submitted to a massive Beowulf cluster of\n"
255 "overclocked 486s. Expect your answer next year somewhere around this time. :-)\n", argv
[3] );
257 else if( strcmp( argv
[2], "chkhash" ) == 0 )
259 char *hash
= strncmp( argv
[3], "md5:", 4 ) == 0 ? argv
[3] + 4 : argv
[3];
260 int st
= md5_verify_password( argv
[4], hash
);
262 printf( "Hash %s given password.\n", st
== 0 ? "matches" : "does not match" );
270 static void sighandler( int signal
)
272 /* FIXME: Calling log_message() here is not a very good idea! */
274 if( signal
== SIGTERM
|| signal
== SIGQUIT
|| signal
== SIGINT
)
276 static int first
= 1;
280 /* We don't know what we were doing when this signal came in. It's not safe to touch
281 the user data now (not to mention writing them to disk), so add a timer. */
283 log_message( LOGLVL_ERROR
, "SIGTERM received, cleaning up process." );
284 b_timeout_add( 1, (b_event_handler
) bitlbee_shutdown
, NULL
);
290 /* Well, actually, for now we'll never need this part because this signal handler
291 will never be called more than once in a session for a non-SIGPIPE signal...
292 But just in case we decide to change that: */
294 log_message( LOGLVL_ERROR
, "SIGTERM received twice, so long for a clean shutdown." );
298 else if( signal
== SIGCHLD
)
303 while( ( pid
= waitpid( 0, &st
, WNOHANG
) ) > 0 )
305 if( WIFSIGNALED( st
) )
306 log_message( LOGLVL_INFO
, "Client %d terminated normally. (status = %d)", (int) pid
, WEXITSTATUS( st
) );
307 else if( WIFEXITED( st
) )
308 log_message( LOGLVL_INFO
, "Client %d killed by signal %d.", (int) pid
, WTERMSIG( st
) );
311 else if( signal
!= SIGPIPE
)
313 log_message( LOGLVL_ERROR
, "Fatal signal received: %d. That's probably a bug.", signal
);
320 struct timeval time
[1];
322 gettimeofday( time
, 0 );
323 return( (double) time
->tv_sec
+ (double) time
->tv_usec
/ 1000000 );