source: unix.c @ 9c9a29c

Last change on this file since 9c9a29c was d150a9d, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-10-10T18:40:06Z

Alas, commit 700 becomes a boring "Oops, --otr=0 still doesn't build without
libotr installed". Also, it appears that this code needs libotr 3.2.0 or
higher, but I'm not adding a build-dep since that'll cause troubles on the
build bot, people can just build with BITLBEE_OTR=0.

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