source: unix.c @ 1dd3470

Last change on this file since 1dd3470 was 814aa52, checked in by Sven Moritz Hallberg <pesco@…>, at 2010-06-03T11:00:45Z

merge in bitlbee 1.2.6

  • Property mode set to 100644
File size: 8.8 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* Main file (Unix specific part)                                       */
8
9/*
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.
14
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.
19
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
24*/
25
26#include "bitlbee.h"
[7c9db24]27
28#include "arc.h"
29#include "base64.h"
[b7d3cc34]30#include "commands.h"
31#include "crypting.h"
[764c7d1]32#include "otr.h"
[b7d3cc34]33#include "protocols/nogaim.h"
34#include "help.h"
[54879ab]35#include "ipc.h"
[ba5add7]36#include "lib/ssl_client.h"
[7c9db24]37#include "md5.h"
38#include "misc.h"
[b7d3cc34]39#include <signal.h>
40#include <unistd.h>
41#include <sys/time.h>
[d25f6fc]42#include <sys/wait.h>
[aaf92a9]43#include <pwd.h>
[b7d3cc34]44
45global_t global;        /* Against global namespace pollution */
46
47static void sighandler( int signal );
48
[7c9db24]49static int crypt_main( int argc, char *argv[] );
50
[cd63d58]51int main( int argc, char *argv[] )
[b7d3cc34]52{
53        int i = 0;
[58bc4e6]54        char *old_cwd = NULL;
[b7d3cc34]55        struct sigaction sig, old;
56       
[7c9db24]57        if( argc > 1 && strcmp( argv[1], "-x" ) == 0 )
58                return crypt_main( argc, argv );
59       
[d25f6fc]60        log_init();
[eeb85a8]61        global.conf_file = g_strdup( CONF_FILE_DEF );
[b7d3cc34]62        global.conf = conf_load( argc, argv );
63        if( global.conf == NULL )
64                return( 1 );
[6e1fed7]65       
[60c1a4e]66        b_main_init();
67        nogaim_init();
[823de9d]68        /* Ugly Note: libotr and gnutls both use libgcrypt. libgcrypt
69           has a process-global config state whose initialization happpens
70           twice if libotr and gnutls are used together. libotr installs custom
71           memory management functions for libgcrypt while our gnutls module
72           uses the defaults. Therefore we initialize OTR after SSL. *sigh* */
73        ssl_init();
74        otr_init();
[60c1a4e]75       
76        srand( time( NULL ) ^ getpid() );
77        global.helpfile = g_strdup( HELP_FILE );
78       
[b7d3cc34]79        if( global.conf->runmode == RUNMODE_INETD )
80        {
[99318ad]81                log_link( LOGLVL_ERROR, LOGOUTPUT_IRC );
82                log_link( LOGLVL_WARNING, LOGOUTPUT_IRC );
83       
[b7d3cc34]84                i = bitlbee_inetd_init();
[156bbd7]85                log_message( LOGLVL_INFO, "BitlBee %s starting in inetd mode.", BITLBEE_VERSION );
[b7d3cc34]86
87        }
88        else if( global.conf->runmode == RUNMODE_DAEMON )
89        {
[156bbd7]90                log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE );
91                log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE );
[99318ad]92
[b7d3cc34]93                i = bitlbee_daemon_init();
[156bbd7]94                log_message( LOGLVL_INFO, "BitlBee %s starting in daemon mode.", BITLBEE_VERSION );
[b7d3cc34]95        }
[d25f6fc]96        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
97        {
[156bbd7]98                log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE );
99                log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE );
100
[54879ab]101                /* In case the operator requests a restart, we need this. */
102                old_cwd = g_malloc( 256 );
103                if( getcwd( old_cwd, 255 ) == NULL )
104                {
105                        log_message( LOGLVL_WARNING, "Could not save current directory: %s", strerror( errno ) );
106                        g_free( old_cwd );
107                        old_cwd = NULL;
108                }
109               
[d25f6fc]110                i = bitlbee_daemon_init();
[156bbd7]111                log_message( LOGLVL_INFO, "BitlBee %s starting in forking daemon mode.", BITLBEE_VERSION );
[d25f6fc]112        }
[b7d3cc34]113        if( i != 0 )
114                return( i );
[6e1fed7]115       
[aaf92a9]116        if( ( global.conf->user && *global.conf->user ) &&
117            ( global.conf->runmode == RUNMODE_DAEMON || 
118              global.conf->runmode == RUNMODE_FORKDAEMON ) &&
119            ( !getuid() || !geteuid() ) )
120        {
121                struct passwd *pw = NULL;
122                pw = getpwnam( global.conf->user );
123                if( pw )
124                {
125                        setgid( pw->pw_gid );
126                        setuid( pw->pw_uid );
127                }
128        }
129
[d25f6fc]130        global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
[aaf92a9]131        if( global.storage == NULL )
132        {
[b73ac9c]133                log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
[1ee6c18]134                return( 1 );
135        }
[b7d3cc34]136       
137        /* Catch some signals to tell the user what's happening before quitting */
138        memset( &sig, 0, sizeof( sig ) );
139        sig.sa_handler = sighandler;
[d25f6fc]140        sigaction( SIGCHLD, &sig, &old );
[b7d3cc34]141        sigaction( SIGPIPE, &sig, &old );
142        sig.sa_flags = SA_RESETHAND;
143        sigaction( SIGINT,  &sig, &old );
144        sigaction( SIGILL,  &sig, &old );
145        sigaction( SIGBUS,  &sig, &old );
146        sigaction( SIGFPE,  &sig, &old );
147        sigaction( SIGSEGV, &sig, &old );
148        sigaction( SIGTERM, &sig, &old );
149        sigaction( SIGQUIT, &sig, &old );
150        sigaction( SIGXCPU, &sig, &old );
151       
152        if( !getuid() || !geteuid() )
153                log_message( LOGLVL_WARNING, "BitlBee is running with root privileges. Why?" );
[0fbda193]154        if( help_init( &global.help, global.helpfile ) == NULL )
[b7d3cc34]155                log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE );
156       
[ba9edaa]157        b_main_run();
[b7d3cc34]158       
[0fbda193]159        /* Mainly good for restarting, to make sure we close the help.txt fd. */
160        help_free( &global.help );
161       
[54879ab]162        if( global.restart )
163        {
164                char *fn = ipc_master_save_state();
165               
166                chdir( old_cwd );
167               
[cd63d58]168                setenv( "_BITLBEE_RESTART_STATE", fn, 1 );
169                g_free( fn );
[54879ab]170               
171                close( global.listen_socket );
172               
[cd63d58]173                if( execv( argv[0], argv ) == -1 )
174                        /* Apparently the execve() failed, so let's just
175                           jump back into our own/current main(). */
176                        /* Need more cleanup code to make this work. */
177                        return 1; /* main( argc, argv ); */
[54879ab]178        }
179       
[b7d3cc34]180        return( 0 );
181}
182
[7c9db24]183static int crypt_main( int argc, char *argv[] )
184{
185        int pass_len;
186        unsigned char *pass_cr, *pass_cl;
187       
[8b6b740]188        if( argc < 4 || ( strcmp( argv[2], "hash" ) != 0 &&
189                          strcmp( argv[2], "unhash" ) != 0 && argc < 5 ) )
[7c9db24]190        {
191                printf( "Supported:\n"
192                        "  %s -x enc <key> <cleartext password>\n"
193                        "  %s -x dec <key> <encrypted password>\n"
194                        "  %s -x hash <cleartext password>\n"
195                        "  %s -x unhash <hashed password>\n"
196                        "  %s -x chkhash <hashed password> <cleartext password>\n",
197                        argv[0], argv[0], argv[0], argv[0], argv[0] );
198        }
199        else if( strcmp( argv[2], "enc" ) == 0 )
200        {
201                pass_len = arc_encode( argv[4], strlen( argv[4] ), (unsigned char**) &pass_cr, argv[3], 12 );
202                printf( "%s\n", base64_encode( pass_cr, pass_len ) );
203        }
204        else if( strcmp( argv[2], "dec" ) == 0 )
205        {
206                pass_len = base64_decode( argv[4], (unsigned char**) &pass_cr );
207                arc_decode( pass_cr, pass_len, (char**) &pass_cl, argv[3] );
208                printf( "%s\n", pass_cl );
209        }
210        else if( strcmp( argv[2], "hash" ) == 0 )
211        {
212                md5_byte_t pass_md5[21];
213                md5_state_t md5_state;
214               
215                random_bytes( pass_md5 + 16, 5 );
216                md5_init( &md5_state );
217                md5_append( &md5_state, (md5_byte_t*) argv[3], strlen( argv[3] ) );
218                md5_append( &md5_state, pass_md5 + 16, 5 ); /* Add the salt. */
219                md5_finish( &md5_state, pass_md5 );
220               
221                printf( "%s\n", base64_encode( pass_md5, 21 ) );
222        }
223        else if( strcmp( argv[2], "unhash" ) == 0 )
224        {
225                printf( "Hash %s submitted to a massive Beowulf cluster of\n"
226                        "overclocked 486s. Expect your answer next year somewhere around this time. :-)\n", argv[3] );
227        }
228        else if( strcmp( argv[2], "chkhash" ) == 0 )
229        {
[8b6b740]230                char *hash = strncmp( argv[3], "md5:", 4 ) == 0 ? argv[3] + 4 : argv[3];
231                int st = md5_verify_password( argv[4], hash );
[7c9db24]232               
233                printf( "Hash %s given password.\n", st == 0 ? "matches" : "does not match" );
234               
235                return st;
236        }
237       
238        return 0;
239}
240
[b7d3cc34]241static void sighandler( int signal )
242{
[d25f6fc]243        /* FIXME: Calling log_message() here is not a very good idea! */
[b7d3cc34]244       
245        if( signal == SIGTERM )
246        {
247                static int first = 1;
248               
249                if( first )
250                {
251                        /* We don't know what we were doing when this signal came in. It's not safe to touch
252                           the user data now (not to mention writing them to disk), so add a timer. */
253                       
254                        log_message( LOGLVL_ERROR, "SIGTERM received, cleaning up process." );
[ba9edaa]255                        b_timeout_add( 1, (b_event_handler) bitlbee_shutdown, NULL );
[b7d3cc34]256                       
257                        first = 0;
258                }
259                else
260                {
261                        /* Well, actually, for now we'll never need this part because this signal handler
262                           will never be called more than once in a session for a non-SIGPIPE signal...
263                           But just in case we decide to change that: */
264                       
265                        log_message( LOGLVL_ERROR, "SIGTERM received twice, so long for a clean shutdown." );
266                        raise( signal );
267                }
268        }
[d25f6fc]269        else if( signal == SIGCHLD )
270        {
271                pid_t pid;
272                int st;
273               
274                while( ( pid = waitpid( 0, &st, WNOHANG ) ) > 0 )
275                {
276                        if( WIFSIGNALED( st ) )
[52744f8]277                                log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", (int) pid, WEXITSTATUS( st ) );
[d25f6fc]278                        else if( WIFEXITED( st ) )
[52744f8]279                                log_message( LOGLVL_INFO, "Client %d killed by signal %d.", (int) pid, WTERMSIG( st ) );
[d25f6fc]280                }
281        }
[b7d3cc34]282        else if( signal != SIGPIPE )
283        {
284                log_message( LOGLVL_ERROR, "Fatal signal received: %d. That's probably a bug.", signal );
285                raise( signal );
286        }
287}
288
289double gettime()
290{
291        struct timeval time[1];
292
293        gettimeofday( time, 0 );
294        return( (double) time->tv_sec + (double) time->tv_usec / 1000000 );
295}
Note: See TracBrowser for help on using the repository browser.