source: unix.c @ 03e5fb7

Last change on this file since 03e5fb7 was 858ea01, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-09-30T05:50:43Z

Allow building OTR support as a plugin. Fairly simple, let's hope I can get
away with doing this without libtool (eep).

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