source: unix.c @ 5eab298f

Last change on this file since 5eab298f was 5eab298f, checked in by dequis <dx@…>, at 2015-01-26T03:27:24Z

random_bytes: Use /dev/urandom only, don't bother trying /dev/random

Also abort() if there's no /dev/urandom

See http://www.2uo.de/myths-about-urandom/ for details.

  • 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-2012 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., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  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 "md5.h"
35#include "misc.h"
36#include <signal.h>
37#include <unistd.h>
38#include <sys/time.h>
39#include <sys/wait.h>
40#include <pwd.h>
41#include <locale.h>
42#include <grp.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 int signal_shutdown_pipe[2] = { -1, -1 };
51static void sighandler_shutdown( int signal );
52static void sighandler_crash( int signal );
53
54static int crypt_main( int argc, char *argv[] );
55
56int main( int argc, char *argv[] )
57{
58        int i = 0;
59        char *old_cwd = NULL;
60        struct sigaction sig, old;
61       
62        /* Required to make iconv to ASCII//TRANSLIT work. This makes BitlBee
63           system-locale-sensitive. :-( */
64        setlocale( LC_CTYPE, "" );
65       
66        if( argc > 1 && strcmp( argv[1], "-x" ) == 0 )
67                return crypt_main( argc, argv );
68       
69        log_init();
70       
71        global.conf_file = g_strdup( CONF_FILE_DEF );
72        global.conf = conf_load( argc, argv );
73        if( global.conf == NULL )
74                return( 1 );
75       
76        b_main_init();
77       
78        /* libpurple doesn't like fork()s after initializing itself, so if
79           we use it, do this init a little later (in case we're running in
80           ForkDaemon mode). */
81#ifndef WITH_PURPLE
82        nogaim_init();
83#endif
84       
85#ifdef OTR_BI
86        otr_init();
87#endif
88       
89        global.helpfile = g_strdup( HELP_FILE );
90        if( help_init( &global.help, global.helpfile ) == NULL )
91                log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE );
92
93        global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
94        if( global.storage == NULL )
95        {
96                log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
97                return( 1 );
98        }
99       
100        if( global.conf->runmode == RUNMODE_INETD )
101        {
102                log_link( LOGLVL_ERROR, LOGOUTPUT_IRC );
103                log_link( LOGLVL_WARNING, LOGOUTPUT_IRC );
104       
105                i = bitlbee_inetd_init();
106                log_message( LOGLVL_INFO, "%s %s starting in inetd mode.", PACKAGE, BITLBEE_VERSION );
107
108        }
109        else if( global.conf->runmode == RUNMODE_DAEMON )
110        {
111                log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE );
112                log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE );
113
114                i = bitlbee_daemon_init();
115                log_message( LOGLVL_INFO, "%s %s starting in daemon mode.", PACKAGE, BITLBEE_VERSION );
116        }
117        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
118        {
119                log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE );
120                log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE );
121
122                /* In case the operator requests a restart, we need this. */
123                old_cwd = g_malloc( 256 );
124                if( getcwd( old_cwd, 255 ) == NULL )
125                {
126                        log_message( LOGLVL_WARNING, "Could not save current directory: %s", strerror( errno ) );
127                        g_free( old_cwd );
128                        old_cwd = NULL;
129                }
130               
131                i = bitlbee_daemon_init();
132                log_message( LOGLVL_INFO, "%s %s starting in forking daemon mode.", PACKAGE, BITLBEE_VERSION );
133        }
134        if( i != 0 )
135                return( i );
136       
137        if( ( global.conf->user && *global.conf->user ) &&
138            ( global.conf->runmode == RUNMODE_DAEMON || 
139              global.conf->runmode == RUNMODE_FORKDAEMON ) &&
140            ( !getuid() || !geteuid() ) )
141        {
142                struct passwd *pw = NULL;
143                pw = getpwnam( global.conf->user );
144                if( pw )
145                {
146                        initgroups( global.conf->user, pw->pw_gid );
147                        setgid( pw->pw_gid );
148                        setuid( pw->pw_uid );
149                }
150                else
151                {
152                        log_message( LOGLVL_WARNING, "Failed to look up user %s.", global.conf->user );
153                }
154        }
155       
156        /* Catch some signals to tell the user what's happening before quitting */
157        memset( &sig, 0, sizeof( sig ) );
158        sig.sa_handler = SIG_IGN;
159        sigaction( SIGCHLD, &sig, &old );
160        sigaction( SIGPIPE, &sig, &old );
161        sig.sa_flags = SA_RESETHAND;
162        sig.sa_handler = sighandler_crash;
163        sigaction( SIGSEGV, &sig, &old );
164
165        /* Use a pipe for SIGTERM/SIGINT so the actual signal handler doesn't do anything unsafe */
166        if ( pipe( signal_shutdown_pipe ) == 0 ) {
167                b_input_add( signal_shutdown_pipe[0], B_EV_IO_READ, bitlbee_shutdown, NULL );
168                sig.sa_handler = sighandler_shutdown;
169                sigaction( SIGINT, &sig, &old );
170                sigaction( SIGTERM, &sig, &old );
171        }
172       
173        if( !getuid() || !geteuid() )
174                log_message( LOGLVL_WARNING, "BitlBee is running with root privileges. Why?" );
175       
176        b_main_run();
177       
178        /* Mainly good for restarting, to make sure we close the help.txt fd. */
179        help_free( &global.help );
180       
181        if( global.restart )
182        {
183                char *fn = ipc_master_save_state();
184                char *env;
185               
186                env = g_strdup_printf( "_BITLBEE_RESTART_STATE=%s", fn );
187                putenv( env );
188                g_free( fn );
189                /* Looks like env should *not* be freed here as putenv
190                   doesn't make a copy. Odd. */
191               
192                i = chdir( old_cwd );
193                close( global.listen_socket );
194               
195                if( execv( argv[0], argv ) == -1 )
196                        /* Apparently the execve() failed, so let's just
197                           jump back into our own/current main(). */
198                        /* Need more cleanup code to make this work. */
199                        return 1; /* main( argc, argv ); */
200        }
201       
202        return( 0 );
203}
204
205static int crypt_main( int argc, char *argv[] )
206{
207        int pass_len;
208        unsigned char *pass_cr, *pass_cl;
209       
210        if( argc < 4 || ( strcmp( argv[2], "hash" ) != 0 &&
211                          strcmp( argv[2], "unhash" ) != 0 && argc < 5 ) )
212        {
213                printf( "Supported:\n"
214                        "  %s -x enc <key> <cleartext password>\n"
215                        "  %s -x dec <key> <encrypted password>\n"
216                        "  %s -x hash <cleartext password>\n"
217                        "  %s -x unhash <hashed password>\n"
218                        "  %s -x chkhash <hashed password> <cleartext password>\n",
219                        argv[0], argv[0], argv[0], argv[0], argv[0] );
220        }
221        else if( strcmp( argv[2], "enc" ) == 0 )
222        {
223                pass_len = arc_encode( argv[4], strlen( argv[4] ), (unsigned char**) &pass_cr, argv[3], 12 );
224                printf( "%s\n", base64_encode( pass_cr, pass_len ) );
225        }
226        else if( strcmp( argv[2], "dec" ) == 0 )
227        {
228                pass_len = base64_decode( argv[4], (unsigned char**) &pass_cr );
229                arc_decode( pass_cr, pass_len, (char**) &pass_cl, argv[3] );
230                printf( "%s\n", pass_cl );
231        }
232        else if( strcmp( argv[2], "hash" ) == 0 )
233        {
234                md5_byte_t pass_md5[21];
235                md5_state_t md5_state;
236               
237                random_bytes( pass_md5 + 16, 5 );
238                md5_init( &md5_state );
239                md5_append( &md5_state, (md5_byte_t*) argv[3], strlen( argv[3] ) );
240                md5_append( &md5_state, pass_md5 + 16, 5 ); /* Add the salt. */
241                md5_finish( &md5_state, pass_md5 );
242               
243                printf( "%s\n", base64_encode( pass_md5, 21 ) );
244        }
245        else if( strcmp( argv[2], "unhash" ) == 0 )
246        {
247                printf( "Hash %s submitted to a massive Beowulf cluster of\n"
248                        "overclocked 486s. Expect your answer next year somewhere around this time. :-)\n", argv[3] );
249        }
250        else if( strcmp( argv[2], "chkhash" ) == 0 )
251        {
252                char *hash = strncmp( argv[3], "md5:", 4 ) == 0 ? argv[3] + 4 : argv[3];
253                int st = md5_verify_password( argv[4], hash );
254               
255                printf( "Hash %s given password.\n", st == 0 ? "matches" : "does not match" );
256               
257                return st;
258        }
259       
260        return 0;
261}
262
263/* Signal handler for SIGTERM and SIGINT */
264static void sighandler_shutdown( int signal )
265{
266        /* Write a single null byte to the pipe, just to send a message to the main loop.
267         * This gets handled by bitlbee_shutdown (the b_input_add callback for this pipe) */
268        write( signal_shutdown_pipe[1], "", 1 );
269}
270
271/* Signal handler for SIGSEGV
272 * A desperate attempt to tell the user that everything is wrong in the world.
273 * Avoids using irc_abort() because it has several unsafe calls to malloc */
274static void sighandler_crash( int signal )
275{
276        GSList *l;
277        const char *message = "ERROR :BitlBee crashed! (SIGSEGV received)\r\n";
278        int len = strlen(message);
279
280        for (l = irc_connection_list; l; l = l->next ) {
281                irc_t *irc = l->data;
282                write( irc->fd, message, len );
283        }
284
285        raise( signal );
286}
287
288double gettime()
289{
290        struct timeval time[1];
291
292        gettimeofday( time, 0 );
293        return( (double) time->tv_sec + (double) time->tv_usec / 1000000 );
294}
Note: See TracBrowser for help on using the repository browser.