intermediate release
[gnupg.git] / g10 / gpgd.c
1 /* ggpd.c - The GNUPG daemon (keyserver)
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #include "util.h"
32 #include "cipher.h"
33 #include "options.h"
34 #include "main.h"
35
36
37 static ARGPARSE_OPTS opts[] = {
38     { 'v', "verbose",   0, "verbose" },
39     { 501, "options"   ,2, "read options from file"},
40     { 502, "no-daemon", 0, "do not operate as a daemon" },
41     { 510, "debug"     ,4|16, "set debugging flags"},
42     { 511, "debug-all" ,0, "enable full debugging"},
43 {0} };
44
45
46
47 static char *build_list( const char *text,
48                          const char * (*mapf)(int), int (*chkf)(int) );
49 static void become_daemon(void);
50
51 const char *
52 strusage( int level )
53 {
54   static char *digests, *pubkeys, *ciphers;
55     const char *p;
56     switch( level ) {
57       case 11: p = "gpgd (GNUPG)"; break;
58       case 13: p = VERSION; break;
59       case 17: p = PRINTABLE_OS_NAME; break;
60       case 19: p =
61             "Please report bugs to <gnupg-bugs@gnu.org>.\n";
62         break;
63       case 1:
64       case 40:  p = "Usage: gpgd [options] (-h for help)";
65         break;
66       case 41:  p = "Syntax: gpgd [options] [files]\n"
67                     "GNUPG keyserver\n";
68         break;
69       case 31: p = "\n"; break;
70       case 32:
71         if( !ciphers )
72             ciphers = build_list("Supported ciphers: ", cipher_algo_to_string,
73                                                         check_cipher_algo );
74         p = ciphers;
75         break;
76       case 33:
77         if( !pubkeys )
78             pubkeys = build_list("Supported pubkeys: ", pubkey_algo_to_string,
79                                                         check_pubkey_algo );
80         p = pubkeys;
81         break;
82       case 34:
83         if( !digests )
84             digests = build_list("Supported digests: ", digest_algo_to_string,
85                                                         check_digest_algo );
86         p = digests;
87         break;
88
89       default:  p = default_strusage(level);
90     }
91     return p;
92 }
93
94
95 static char *
96 build_list( const char *text, const char * (*mapf)(int), int (*chkf)(int) )
97 {
98     int i;
99     const char *s;
100     size_t n=strlen(text)+2;
101     char *list, *p;
102
103     for(i=1; i < 100; i++ )
104         if( !chkf(i) && (s=mapf(i)) )
105             n += strlen(s) + 2;
106     list = m_alloc( 21 + n ); *list = 0;
107     for(p=NULL, i=1; i < 100; i++ ) {
108         if( !chkf(i) && (s=mapf(i)) ) {
109             if( !p )
110                 p = stpcpy( list, text );
111             else
112                 p = stpcpy( p, ", ");
113             p = stpcpy(p, s );
114         }
115     }
116     if( p )
117         p = stpcpy(p, "\n" );
118     return list;
119 }
120
121
122 static void
123 set_debug(void)
124 {
125     if( opt.debug & DBG_MEMORY_VALUE )
126         memory_debug_mode = 1;
127     if( opt.debug & DBG_MEMSTAT_VALUE )
128         memory_stat_debug_mode = 1;
129     if( opt.debug & DBG_MPI_VALUE )
130         mpi_debug_mode = 1;
131     if( opt.debug & DBG_CIPHER_VALUE )
132         g10c_debug_mode = 1;
133     if( opt.debug & DBG_IOBUF_VALUE )
134         iobuf_debug_mode = 1;
135 }
136
137
138 int
139 main( int argc, char **argv )
140 {
141     ARGPARSE_ARGS pargs;
142     int orig_argc;
143     char **orig_argv;
144     FILE *configfp = NULL;
145     char *configname = NULL;
146     unsigned configlineno;
147     int parse_debug = 0;
148     int default_config =1;
149     int daemon = 1;
150
151     secmem_init( 0 );      /* disable use of secmem */
152     log_set_name("gpgd");
153     log_set_pid( getpid() );
154     opt.compress = -1; /* defaults to standard compress level */
155     opt.batch = 1;
156
157     /* check whether we have a config file on the commandline */
158     orig_argc = argc;
159     orig_argv = argv;
160     pargs.argc = &argc;
161     pargs.argv = &argv;
162     pargs.flags=  1;  /* do not remove the args */
163     while( arg_parse( &pargs, opts) ) {
164         if( pargs.r_opt == 510 || pargs.r_opt == 511 )
165             parse_debug++;
166         else if( pargs.r_opt == 501 ) {
167             /* yes there is one, so we do not try the default one, but
168              * read the option file when it is encountered at the commandline
169              */
170             default_config = 0;
171         }
172     }
173
174     if( default_config )
175         configname = make_filename("/etc/gpgd.conf", NULL );
176
177     argc = orig_argc;
178     argv = orig_argv;
179     pargs.argc = &argc;
180     pargs.argv = &argv;
181     pargs.flags=  1;  /* do not remove the args */
182   next_pass:
183     if( configname ) {
184         configlineno = 0;
185         configfp = fopen( configname, "r" );
186         if( !configfp ) {
187             if( default_config ) {
188                 if( parse_debug )
189                     log_info("note: no default option file '%s'\n",
190                                                             configname );
191             }
192             else {
193                 log_error("option file '%s': %s\n",
194                                     configname, strerror(errno) );
195                 g10_exit(1);
196             }
197             m_free(configname); configname = NULL;
198         }
199         if( parse_debug && configname )
200             log_info("reading options from '%s'\n", configname );
201         default_config = 0;
202     }
203
204     while( optfile_parse( configfp, configname, &configlineno,
205                                                 &pargs, opts) ) {
206         switch( pargs.r_opt ) {
207           case 'v': opt.verbose++; break;
208           case 501:
209             if( !configfp ) {
210                 m_free(configname);
211                 configname = m_strdup(pargs.r.ret_str);
212                 goto next_pass;
213             }
214             break;
215           case 502: daemon = 0; break;
216           case 510: opt.debug |= pargs.r.ret_ulong; break;
217           case 511: opt.debug = ~0; break;
218           default : pargs.err = configfp? 1:2; break;
219         }
220     }
221     if( configfp ) {
222         fclose( configfp );
223         configfp = NULL;
224         m_free(configname); configname = NULL;
225         goto next_pass;
226     }
227     m_free( configname ); configname = NULL;
228     if( log_get_errorcount(0) )
229         g10_exit(2);
230
231     fprintf(stderr, "%s %s; %s\n", strusage(11), strusage(13), strusage(14) );
232     fprintf(stderr, "%s\n", strusage(15) );
233
234     set_debug();
235     if( daemon )
236         become_daemon();
237
238
239     g10_exit(0);
240     return 8; /*NEVER REACHED*/
241 }
242
243
244 void
245 g10_exit( int rc )
246 {
247     secmem_term();
248     rc = rc? rc : log_get_errorcount(0)? 2:0;
249     exit(rc );
250 }
251
252 void
253 do_not_use_RSA()
254 {
255     static int did_rsa_note = 0;
256
257     if( !did_rsa_note ) {
258         did_rsa_note = 1;
259         log_info("RSA keys are depreciated; please consider "
260                  "creating a new key and use this key in the future\n");
261     }
262 }
263
264
265 static void
266 become_daemon()
267 {
268     long nfile;
269     int i, n;
270     int childpid;
271
272     if( opt.verbose )
273         log_info("becoming a daemon ...\n");
274     fflush(NULL);
275
276     /* FIXME: handle the TTY signals */
277
278     if( (childpid = fork()) == -1 )
279         log_fatal("can't fork first child: %s\n", strerror(errno));
280     else if( childpid > 0 )
281         exit(0); /* terminate parent */
282
283     /* Disassociate from controlling terminal etc. */
284     if( setsid() == -1 )
285         log_fatal("setsid() failed: %s\n", strerror(errno) );
286
287     log_set_pid( getpid() );
288     /* close all files but not the log files */
289     if( (nfile=sysconf( _SC_OPEN_MAX )) < 0 )
290       #ifdef _POSIX_OPEN_MAX
291         nfile = _POSIX_OPEN_MAX;
292       #else
293         nfile = 20; /* assume a common value */
294       #endif
295     n = fileno( stderr );
296     for(i=0; i < nfile; i++ )
297         if( i != n )
298             close(i);
299     errno = 0;
300
301     if( chdir("/") )
302         log_fatal("chdir to root failed: %s\n", strerror(errno) );
303     umask(0);
304
305     /* do not let possible children become zombies */
306     signal(SIGCHLD, SIG_IGN);
307     if( opt.verbose )
308         log_info("now running as daemon\n");
309 }
310
311
312