source: unix.c @ 0c85c08

Last change on this file since 0c85c08 was be999a5, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-23T23:12:24Z

First step in this merge. Mostly a bzr merge and then a cleanup of conflicts
and parts I want to/have to redo (because of ui-fix).

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