source: unix.c @ 4cff28f

Last change on this file since 4cff28f was 6f10697, checked in by dequis <dx@…>, at 2015-01-16T19:50:23Z

Fix incorrect Free Software Foundation address

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