2002-04-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / agent / gpg-agent.c
1 /* gpg-agent.c  -  The GnuPG Agent
2  *      Copyright (C) 2000, 2001, 2002 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
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <time.h>
31 #include <fcntl.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include <unistd.h>
35 #include <signal.h>
36
37 #include <gcrypt.h>
38
39 #define JNLIB_NEED_LOG_LOGV
40 #include "agent.h"
41 #include "../assuan/assuan.h" /* malloc hooks */
42
43 #include "sysutils.h"
44
45
46 #define N_(a) a
47 #define _(a) a
48
49
50 enum cmd_and_opt_values 
51 { aNull = 0,
52   oCsh            = 'c',
53   oQuiet          = 'q',
54   oSh             = 's',
55   oVerbose        = 'v',
56   
57   oNoVerbose = 500,
58   oOptions,
59   oDebug,
60   oDebugAll,
61   oDebugWait,
62   oNoGreeting,
63   oNoOptions,
64   oHomedir,
65   oNoDetach,
66   oNoGrab,
67   oLogFile,
68   oServer,
69   oBatch,
70
71   oPinentryProgram,
72   oDisplay,
73   oTTYname,
74   oTTYtype,
75   oLCctype,
76   oLCmessages,
77   oScdaemonProgram,
78   oDefCacheTTL,
79
80 aTest };
81
82
83
84 static ARGPARSE_OPTS opts[] = {
85   
86   { 301, NULL, 0, N_("@Options:\n ") },
87
88   { oServer,   "server",     0, N_("run in server mode") },
89   { oVerbose, "verbose",   0, N_("verbose") },
90   { oQuiet,     "quiet",     0, N_("be somewhat more quiet") },
91   { oSh,        "sh",        0, N_("sh-style command output") },
92   { oCsh,       "csh",       0, N_("csh-style command output") },
93   { oOptions, "options"  , 2, N_("read options from file")},
94   { oDebug,     "debug"     ,4|16, N_("set debugging flags")},
95   { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
96   { oDebugWait,"debug-wait",1, "@"},
97   { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
98   { oNoGrab, "no-grab"     ,0, N_("do not grab keyboard and mouse")},
99   { oLogFile, "log-file"   ,2, N_("use a log file for the server")},
100
101   { oPinentryProgram, "pinentry-program", 2 , "path to PIN Entry program" },
102   { oDisplay,    "display",     2, "set the display" },
103   { oTTYname,    "ttyname",     2, "set the tty terminal node name" },
104   { oTTYtype,    "ttytype",     2, "set the tty terminal type" },
105   { oLCctype,    "lc-ctype",    2, "set the tty LC_CTYPE value" },
106   { oLCmessages, "lc-messages", 2, "set the tty LC_MESSAGES value" },
107
108   { oScdaemonProgram, "scdaemon-program", 2 , "path to SCdaemon program" },
109   { oDefCacheTTL, "default-cache-ttl", 4,
110                                  "|N|expire cached PINs after N seconds"},
111
112   {0}
113 };
114
115
116 static volatile int caught_fatal_sig = 0;
117
118 /* It is possible that we are currently running under setuid permissions */
119 static int maybe_setuid = 1;
120
121 /* Name of the communication socket */
122 static char socket_name[128];
123
124
125
126 static const char *
127 my_strusage (int level)
128 {
129   const char *p;
130   switch (level)
131     {
132     case 11: p = "gpg-agent (GnuPG)";
133       break;
134     case 13: p = VERSION; break;
135     case 17: p = PRINTABLE_OS_NAME; break;
136     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
137       break;
138     case 1:
139     case 40: p =  _("Usage: gpg-agent [options] (-h for help)");
140       break;
141     case 41: p =  _("Syntax: gpg-agent [options] [command [args]]\n"
142                     "Secret key management for GnuPG\n");
143     break;
144     
145     default: p = NULL;
146     }
147   return p;
148 }
149
150
151
152 static void
153 i18n_init (void)
154 {
155 #ifdef USE_SIMPLE_GETTEXT
156     set_gettext_file( PACKAGE );
157 #else
158 #ifdef ENABLE_NLS
159     /* gtk_set_locale (); HMMM: We have not yet called gtk_init */
160     bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
161     textdomain( PACKAGE );
162 #endif
163 #endif
164 }
165
166
167
168 /* Use by gcry for logging */
169 static void
170 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
171 {
172   /* translate the log levels */
173   switch (level)
174     {
175     case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
176     case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
177     case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
178     case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
179     case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
180     case GCRY_LOG_BUG:  level = JNLIB_LOG_BUG; break;
181     case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
182     default:            level = JNLIB_LOG_ERROR; break;  
183     }
184   log_logv (level, fmt, arg_ptr);
185 }
186
187
188 static void
189 cleanup (void)
190 {
191   if (*socket_name)
192     {
193       char *p;
194
195       remove (socket_name);
196       p = strrchr (socket_name, '/');
197       if (p)
198         {
199           *p = 0;
200           rmdir (socket_name);
201           *p = '/';
202         }
203       *socket_name = 0;
204     }
205 }
206
207
208 static RETSIGTYPE
209 cleanup_sh (int sig)
210 {
211   if (caught_fatal_sig)
212     raise (sig);
213   caught_fatal_sig = 1;
214
215   /* gcry_control( GCRYCTL_TERM_SECMEM );*/
216   cleanup ();
217
218 #ifndef HAVE_DOSISH_SYSTEM
219   {     /* reset action to default action and raise signal again */
220     struct sigaction nact;
221     nact.sa_handler = SIG_DFL;
222     sigemptyset( &nact.sa_mask );
223     nact.sa_flags = 0;
224     sigaction( sig, &nact, NULL);
225   }
226 #endif
227   raise( sig );
228 }
229
230 int
231 main (int argc, char **argv )
232 {
233   ARGPARSE_ARGS pargs;
234   int orig_argc;
235   int may_coredump;
236   char **orig_argv;
237   FILE *configfp = NULL;
238   char *configname = NULL;
239   const char *shell;
240   unsigned configlineno;
241   int parse_debug = 0;
242   int default_config =1;
243   int greeting = 0;
244   int nogreeting = 0;
245   int pipe_server = 0;
246   int nodetach = 0;
247   int csh_style = 0;
248   char *logfile = NULL;
249   int debug_wait = 0;
250
251   set_strusage (my_strusage);
252   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
253   /* Please note that we may running SUID(ROOT), so be very CAREFUL
254      when adding any stuff between here and the call to INIT_SECMEM()
255      somewhere after the option parsing */
256   log_set_prefix ("gpg-agent", 1|4); 
257   i18n_init ();
258
259   /* check that the libraries are suitable.  Do it here because
260      the option parsing may need services of the library */
261   if (!gcry_check_version ( "1.1.5" ) )
262     {
263       log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
264                  "1.1.5", gcry_check_version (NULL) );
265     }
266
267   assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
268   gcry_set_log_handler (my_gcry_logger, NULL);
269   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
270
271   may_coredump = disable_core_dumps ();
272
273   shell = getenv ("SHELL");
274   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
275     csh_style = 1;
276   
277   opt.homedir = getenv("GNUPGHOME");
278   if (!opt.homedir || !*opt.homedir)
279     {
280 #ifdef HAVE_DRIVE_LETTERS
281       opt.homedir = "c:/gnupg-test";
282 #else
283       opt.homedir = "~/.gnupg-test";
284 #endif
285     }
286   opt.def_cache_ttl = 10*60; /* default to 10 minutes */
287
288
289   /* check whether we have a config file on the commandline */
290   orig_argc = argc;
291   orig_argv = argv;
292   pargs.argc = &argc;
293   pargs.argv = &argv;
294   pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
295   while (arg_parse( &pargs, opts))
296     {
297       if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
298         parse_debug++;
299       else if (pargs.r_opt == oOptions)
300         { /* yes there is one, so we do not try the default one, but
301              read the option file when it is encountered at the
302              commandline */
303           default_config = 0;
304         }
305         else if (pargs.r_opt == oNoOptions)
306           default_config = 0; /* --no-options */
307         else if (pargs.r_opt == oHomedir)
308           opt.homedir = pargs.r.ret_str;
309     }
310
311   /* initialize the secure memory. */
312   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
313   maybe_setuid = 0;
314
315   /* 
316      Now we are now working under our real uid 
317   */
318
319
320   if (default_config)
321     configname = make_filename (opt.homedir, "gpg-agent.conf", NULL );
322   
323   argc = orig_argc;
324   argv = orig_argv;
325   pargs.argc = &argc;
326   pargs.argv = &argv;
327   pargs.flags=  1;  /* do not remove the args */
328  next_pass:
329   if (configname)
330     {
331       configlineno = 0;
332       configfp = fopen (configname, "r");
333       if (!configfp)
334         {
335           if (default_config)
336             {
337               if( parse_debug )
338                 log_info (_("NOTE: no default option file `%s'\n"),
339                           configname );
340             }
341           else
342             {
343               log_error (_("option file `%s': %s\n"),
344                          configname, strerror(errno) );
345               exit(2);
346             }
347           xfree (configname); 
348           configname = NULL;
349         }
350       if (parse_debug && configname )
351         log_info (_("reading options from `%s'\n"), configname );
352       default_config = 0;
353     }
354
355   while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
356     {
357       switch (pargs.r_opt)
358         {
359         case oQuiet: opt.quiet = 1; break;
360         case oVerbose: opt.verbose++; break;
361         case oBatch: opt.batch=1; break;
362
363         case oDebug: opt.debug |= pargs.r.ret_ulong; break;
364         case oDebugAll: opt.debug = ~0; break;
365         case oDebugWait: debug_wait = pargs.r.ret_int; break;
366
367         case oOptions:
368           /* config files may not be nested (silently ignore them) */
369           if (!configfp)
370             {
371                 xfree(configname);
372                 configname = xstrdup(pargs.r.ret_str);
373                 goto next_pass;
374             }
375           break;
376         case oNoGreeting: nogreeting = 1; break;
377         case oNoVerbose: opt.verbose = 0; break;
378         case oNoOptions: break; /* no-options */
379         case oHomedir: opt.homedir = pargs.r.ret_str; break;
380         case oNoDetach: nodetach = 1; break;
381         case oNoGrab: opt.no_grab = 1; break;
382         case oLogFile: logfile = pargs.r.ret_str; break;
383         case oCsh: csh_style = 1; break;
384         case oSh: csh_style = 0; break;
385         case oServer: pipe_server = 1; break;
386
387         case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break;
388         case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break;
389         case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break;
390         case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break;
391         case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break;
392         case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break;
393         case oScdaemonProgram: opt.scdaemon_program = pargs.r.ret_str; break;
394         case oDefCacheTTL: opt.def_cache_ttl = pargs.r.ret_ulong; break;
395
396         default : pargs.err = configfp? 1:2; break;
397         }
398     }
399   if (configfp)
400     {
401       fclose( configfp );
402       configfp = NULL;
403       xfree(configname);
404       configname = NULL;
405       goto next_pass;
406     }
407   xfree (configname);
408   configname = NULL;
409   if (log_get_errorcount(0))
410     exit(2);
411   if (nogreeting )
412     greeting = 0;
413
414   if (greeting)
415     {
416       fprintf (stderr, "%s %s; %s\n",
417                  strusage(11), strusage(13), strusage(14) );
418       fprintf (stderr, "%s\n", strusage(15) );
419     }
420 #ifdef IS_DEVELOPMENT_VERSION
421   log_info ("NOTE: this is a development version!\n");
422 #endif
423
424   
425   if (atexit (cleanup))
426     {
427       log_error ("atexit failed\n");
428       cleanup ();
429       exit (1);
430     }
431
432   if (debug_wait && pipe_server)
433     {
434       log_debug ("waiting for debugger - my pid is %u .....\n",
435                  (unsigned int)getpid());
436       sleep (debug_wait);
437       log_debug ("... okay\n");
438     }
439   
440   /* now start with logging to a file if this is desired */
441   if (logfile)
442     {
443       log_set_file (logfile);
444       log_set_prefix (NULL, 1|2|4);
445     }
446
447
448   if (pipe_server)
449     { /* this is the simple pipe based server */
450       start_command_handler (-1);
451     }
452   else
453     { /* regular server mode */
454       int fd;
455       pid_t pid;
456       int i;
457       int len;
458       struct sockaddr_un serv_addr;
459       char *p;
460
461       *socket_name = 0;
462       snprintf (socket_name, DIM(socket_name)-1,
463                 "/tmp/gpg-XXXXXX/S.gpg-agent");
464       socket_name[DIM(socket_name)-1] = 0;
465       p = strrchr (socket_name, '/');
466       if (!p)
467         BUG ();
468       *p = 0;;
469       if (!mkdtemp(socket_name))
470         {
471           log_error ("can't create directory `%s': %s\n",
472                      socket_name, strerror(errno) );
473           exit (1);
474         }
475       *p = '/';
476
477       if (strchr (socket_name, ':') )
478         {
479           log_error ("colons are not allowed in the socket name\n");
480           exit (1);
481         }
482       if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path ) 
483         {
484           log_error ("name of socket too long\n");
485           exit (1);
486         }
487    
488
489       fd = socket (AF_UNIX, SOCK_STREAM, 0);
490       if (fd == -1)
491         {
492           log_error ("can't create socket: %s\n", strerror(errno) );
493           exit (1);
494         }
495
496       memset (&serv_addr, 0, sizeof serv_addr);
497       serv_addr.sun_family = AF_UNIX;
498       strcpy (serv_addr.sun_path, socket_name);
499       len = (offsetof (struct sockaddr_un, sun_path)
500              + strlen(serv_addr.sun_path) + 1);
501
502       if (bind (fd, (struct sockaddr*)&serv_addr, len) == -1)
503         {
504           log_error ("error binding socket to `%s': %s\n",
505                      serv_addr.sun_path, strerror (errno) );
506           close (fd);
507           exit (1);
508         }
509   
510       if (listen (fd, 5 ) == -1)
511         {
512           log_error ("listen() failed: %s\n", strerror (errno));
513           close (fd);
514           exit (1);
515         }
516
517       if (opt.verbose)
518         log_info ("listening on socket `%s'\n", socket_name );
519
520
521       fflush (NULL);
522       pid = fork ();
523       if (pid == (pid_t)-1) 
524         {
525           log_fatal ("fork failed: %s\n", strerror (errno) );
526           exit (1);
527         }
528       else if (pid) 
529         { /* we are the parent */
530           char *infostr;
531           
532           close (fd);
533           
534           /* create the info string: <name>:<pid>:<protocol_version> */
535           if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
536                         socket_name, (ulong)pid ) < 0)
537             {
538               log_error ("out of core\n");
539               kill (pid, SIGTERM);
540               exit (1);
541             }
542           *socket_name = 0; /* don't let cleanup() remove the socket -
543                                the child should do this from now on */
544           if (argc) 
545             { /* run the program given on the commandline */
546               if (putenv (infostr))
547                 {
548                   log_error ("failed to set environment: %s\n",
549                              strerror (errno) );
550                   kill (pid, SIGTERM );
551                   exit (1);
552                 }
553               execvp (argv[0], argv);
554               log_error ("failed to run the command: %s\n", strerror (errno));
555               kill (pid, SIGTERM);
556               exit (1);
557             }
558           else
559             {
560               /* print the environment string, so that the caller can use
561                  shell's eval to set it */
562               if (csh_style)
563                 {
564                   *strchr (infostr, '=') = ' ';
565                   printf ( "setenv %s\n", infostr);
566                 }
567               else
568                 {
569                   printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
570                 }
571               free (infostr);
572               exit (0); 
573             }
574           /*NEVER REACHED*/
575         } /* end parent */
576       
577       /* this is the child */
578
579       /* detach from tty and put process into a new session */
580       if (!nodetach )
581         {  /* close stdin, stdout and stderr unless it is the log stream */
582           for (i=0; i <= 2; i++) 
583             {
584               if ( log_get_fd () != i)
585                 close (i);
586             }
587           if (setsid() == -1)
588             {
589               log_error ("setsid() failed: %s\n", strerror(errno) );
590               cleanup ();
591               exit (1);
592             }
593         }
594
595       /* setup signals */
596       {
597         struct sigaction oact, nact;
598         
599         nact.sa_handler = cleanup_sh;
600         sigemptyset (&nact.sa_mask);
601         nact.sa_flags = 0;
602         
603         sigaction (SIGHUP, NULL, &oact);
604         if (oact.sa_handler != SIG_IGN)
605           sigaction (SIGHUP, &nact, NULL);
606         sigaction( SIGTERM, NULL, &oact );
607         if (oact.sa_handler != SIG_IGN)
608           sigaction (SIGTERM, &nact, NULL);
609         nact.sa_handler = SIG_IGN;
610         sigaction (SIGPIPE, &nact, NULL);
611         sigaction (SIGINT, &nact, NULL);
612       }
613
614       if (chdir("/"))
615         {
616           log_error ("chdir to / failed: %s\n", strerror (errno));
617           exit (1);
618         }
619
620       start_command_handler (fd);
621
622       close (fd);
623     }
624   
625   return 0;
626 }
627
628 void
629 agent_exit (int rc)
630 {
631   #if 0
632 #warning no update_random_seed_file
633   update_random_seed_file();
634   #endif
635 #if 0
636   /* at this time a bit annoying */
637   if (opt.debug & DBG_MEMSTAT_VALUE)
638     {
639       gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
640       gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
641     }
642   if (opt.debug)
643     gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
644 #endif
645   gcry_control (GCRYCTL_TERM_SECMEM );
646   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
647   exit (rc);
648 }
649