source: unix.c @ 5f8ab6a9

Last change on this file since 5f8ab6a9 was 5f8ab6a9, checked in by Sven Moritz Hallberg <pesco@…>, at 2010-06-03T10:41:03Z

merge in bitlbee 1.2.5

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