b8be103fc72cf51bf9f31b81d43009c7203d2ace
[gnupg.git] / common / asshelp.c
1 /* asshelp.c - Helper functions for Assuan
2  * Copyright (C) 2002, 2004, 2007, 2009, 2010 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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #ifdef HAVE_LOCALE_H
27 #include <locale.h>
28 #endif
29
30 #define JNLIB_NEED_LOG_LOGV
31 #include "i18n.h"
32 #include "util.h"
33 #include "exechelp.h"
34 #include "sysutils.h"
35 #include "status.h" 
36 #include "asshelp.h"
37
38 /* The type we use for lock_agent_spawning.  */
39 #ifdef HAVE_W32_SYSTEM
40 # define lock_spawn_t HANDLE
41 #else
42 # define lock_spawn_t dotlock_t
43 #endif
44
45 /* The time we wait until the agent or the dirmngr are ready for
46    operation after we started them before giving up.  */ 
47 #ifdef HAVE_W32CE_SYSTEM
48 # define SECS_TO_WAIT_FOR_AGENT 30
49 # define SECS_TO_WAIT_FOR_DIRMNGR 30
50 #else
51 # define SECS_TO_WAIT_FOR_AGENT 5
52 # define SECS_TO_WAIT_FOR_DIRMNGR 5
53 #endif
54
55 /* A bitfield that specifies the assuan categories to log.  This is
56    identical to the default log handler of libassuan.  We need to do
57    it ourselves because we use a custom log handler and want to use
58    the same assuan variables to select the categories to log. */
59 static int log_cats;
60 #define TEST_LOG_CAT(x) (!! (log_cats & (1 << (x - 1))))
61
62
63 static int
64 my_libassuan_log_handler (assuan_context_t ctx, void *hook,
65                           unsigned int cat, const char *msg)
66 {
67   unsigned int dbgval;
68
69   (void)ctx;
70
71   if (! TEST_LOG_CAT (cat))
72     return 0;
73
74   dbgval = hook? *(unsigned int*)hook : 0;
75   if (!(dbgval & 1024))
76     return 0; /* Assuan debugging is not enabled.  */
77
78   if (msg)
79     log_string (JNLIB_LOG_DEBUG, msg);
80
81   return 1;
82 }
83
84
85 /* Setup libassuan to use our own logging functions.  Should be used
86    early at startup.  */
87 void
88 setup_libassuan_logging (unsigned int *debug_var_address)
89 {
90   char *flagstr;
91
92   flagstr = getenv ("ASSUAN_DEBUG");
93   if (flagstr)
94     log_cats = atoi (flagstr);
95   else /* Default to log the control channel.  */
96     log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
97   assuan_set_log_cb (my_libassuan_log_handler, debug_var_address);
98 }
99
100
101
102 static gpg_error_t
103 send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
104                  const char *name, const char *value, int use_putenv)
105 {
106   gpg_error_t err;
107   char *optstr;
108
109   (void)errsource;
110
111   if (!value || !*value)
112     err = 0;  /* Avoid sending empty strings.  */
113   else if (asprintf (&optstr, "OPTION %s%s=%s", 
114                      use_putenv? "putenv=":"", name, value) < 0)
115     err = gpg_error_from_syserror ();
116   else
117     {
118       err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
119       xfree (optstr);
120     }
121
122   return err;
123 }
124
125
126 /* Send the assuan commands pertaining to the pinentry environment.  The
127    OPT_* arguments are optional and may be used to override the
128    defaults taken from the current locale. */
129 gpg_error_t
130 send_pinentry_environment (assuan_context_t ctx,
131                            gpg_err_source_t errsource,
132                            const char *opt_lc_ctype,
133                            const char *opt_lc_messages,
134                            session_env_t session_env)
135
136 {
137   gpg_error_t err = 0;
138 #if defined(HAVE_SETLOCALE)
139   char *old_lc = NULL; 
140 #endif
141   char *dft_lc = NULL;
142   const char *dft_ttyname;
143   int iterator;
144   const char *name, *assname, *value;
145   int is_default;
146
147   iterator = 0; 
148   while ((name = session_env_list_stdenvnames (&iterator, &assname)))
149     {
150       value = session_env_getenv_or_default (session_env, name, NULL);
151       if (!value)
152         continue;
153
154       if (assname)
155         err = send_one_option (ctx, errsource, assname, value, 0);
156       else
157         {
158           err = send_one_option (ctx, errsource, name, value, 1);
159           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
160             err = 0;  /* Server too old; can't pass the new envvars.  */
161         }
162       if (err)
163         return err;
164     }
165
166
167   dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY", 
168                                                &is_default);
169   if (dft_ttyname && !is_default)
170     dft_ttyname = NULL;  /* We need the default value.  */
171
172   /* Send the value for LC_CTYPE.  */
173 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
174   old_lc = setlocale (LC_CTYPE, NULL);
175   if (old_lc)
176     {
177       old_lc = xtrystrdup (old_lc);
178       if (!old_lc)
179         return gpg_error_from_syserror ();
180     }
181   dft_lc = setlocale (LC_CTYPE, "");
182 #endif
183   if (opt_lc_ctype || (dft_ttyname && dft_lc))
184     {
185       err = send_one_option (ctx, errsource, "lc-ctype", 
186                              opt_lc_ctype ? opt_lc_ctype : dft_lc, 0);
187     }
188 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
189   if (old_lc)
190     {
191       setlocale (LC_CTYPE, old_lc);
192       xfree (old_lc);
193     }
194 #endif
195   if (err)
196     return err;
197
198   /* Send the value for LC_MESSAGES.  */
199 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
200   old_lc = setlocale (LC_MESSAGES, NULL);
201   if (old_lc)
202     {
203       old_lc = xtrystrdup (old_lc);
204       if (!old_lc)
205         return gpg_error_from_syserror ();
206     }
207   dft_lc = setlocale (LC_MESSAGES, "");
208 #endif
209   if (opt_lc_messages || (dft_ttyname && dft_lc))
210     {
211       err = send_one_option (ctx, errsource, "lc-messages", 
212                              opt_lc_messages ? opt_lc_messages : dft_lc, 0);
213     }
214 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
215   if (old_lc)
216     {
217       setlocale (LC_MESSAGES, old_lc);
218       xfree (old_lc);
219     }
220 #endif
221   if (err)
222     return err;
223
224   return 0;
225 }
226
227
228 /* Lock a spawning process.  The caller needs to provide the address
229    of a variable to store the lock information and the name or the
230    process.  */
231 static gpg_error_t
232 lock_spawning (lock_spawn_t *lock, const char *homedir, const char *name,
233                int verbose)
234 {
235 #ifdef HAVE_W32_SYSTEM
236   int waitrc;
237   int timeout = (!strcmp (name, "agent")
238                  ? SECS_TO_WAIT_FOR_AGENT
239                  : SECS_TO_WAIT_FOR_DIRMNGR);
240
241   (void)homedir; /* Not required. */
242
243   *lock = CreateMutexW 
244     (NULL, FALSE,
245      !strcmp (name, "agent")?   L"GnuPG_spawn_agent_sentinel":
246      !strcmp (name, "dirmngr")? L"GnuPG_spawn_dirmngr_sentinel":
247      /*                    */   L"GnuPG_spawn_unknown_sentinel");
248   if (!*lock)
249     {
250       log_error ("failed to create the spawn_%s mutex: %s\n",
251                  name, w32_strerror (-1));
252       return gpg_error (GPG_ERR_GENERAL);
253     }
254
255  retry:
256   waitrc = WaitForSingleObject (*lock, 1000);
257   if (waitrc == WAIT_OBJECT_0)
258     return 0;
259   
260   if (waitrc == WAIT_TIMEOUT && timeout)
261     {
262       timeout--;
263       if (verbose)
264         log_info ("another process is trying to start the %s ... (%ds)\n",
265                   name, timeout);
266       goto retry;
267     }
268   if (waitrc == WAIT_TIMEOUT)
269     log_info ("error waiting for the spawn_%s mutex: timeout\n", name);
270   else
271     log_info ("error waiting for the spawn_%s mutex: (code=%d) %s\n", 
272               name, waitrc, w32_strerror (-1));
273   return gpg_error (GPG_ERR_GENERAL);
274 #else /*!HAVE_W32_SYSTEM*/
275   char *fname;
276
277   (void)verbose;
278
279   *lock = NULL;
280
281   fname = make_filename
282     (homedir,
283      !strcmp (name, "agent")?   "gnupg_spawn_agent_sentinel":
284      !strcmp (name, "dirmngr")? "gnupg_spawn_dirmngr_sentinel":
285      /*                    */   "gnupg_spawn_unknown_sentinel",
286      NULL);
287   if (!fname)
288     return gpg_error_from_syserror ();
289
290   *lock = create_dotlock (fname);
291   xfree (fname);
292   if (!*lock)
293     return gpg_error_from_syserror ();
294
295   /* FIXME: We should use a timeout of 5000 here - however
296      make_dotlock does not yet support values other than -1 and 0.  */
297   if (make_dotlock (*lock, -1))
298     return gpg_error_from_syserror ();
299
300   return 0;
301 #endif /*!HAVE_W32_SYSTEM*/
302 }
303
304
305 /* Unlock the spawning process.  */
306 static void
307 unlock_spawning (lock_spawn_t *lock, const char *name)
308 {
309   if (*lock)
310     {
311 #ifdef HAVE_W32_SYSTEM
312       if (!ReleaseMutex (*lock))
313         log_error ("failed to release the spawn_%s mutex: %s\n",
314                    name, w32_strerror (-1));
315       CloseHandle (*lock);
316 #else /*!HAVE_W32_SYSTEM*/
317       (void)name;
318       destroy_dotlock (*lock);
319 #endif /*!HAVE_W32_SYSTEM*/
320       *lock = NULL;
321     }
322 }
323
324 /* Try to connect to the agent via socket or fork it off and work by
325    pipes.  Handle the server's initial greeting.  Returns a new assuan
326    context at R_CTX or an error code. */
327 gpg_error_t
328 start_new_gpg_agent (assuan_context_t *r_ctx,
329                      gpg_err_source_t errsource,
330                      const char *homedir,
331                      const char *agent_program,
332                      const char *opt_lc_ctype,
333                      const char *opt_lc_messages,
334                      session_env_t session_env,
335                      int verbose, int debug,
336                      gpg_error_t (*status_cb)(ctrl_t, int, ...),
337                      ctrl_t status_cb_arg)
338 {
339   /* If we ever failed to connect via a socket we will force the use
340      of the pipe based server for the lifetime of the process.  */
341   static int force_pipe_server = 0;
342
343   gpg_error_t err = 0;
344   char *infostr, *p;
345   assuan_context_t ctx;
346   int did_success_msg = 0;
347
348   *r_ctx = NULL;
349
350   err = assuan_new (&ctx);
351   if (err)
352     {
353       log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
354       return err;
355     }
356
357  restart:
358   infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
359   if (!infostr || !*infostr)
360     {
361       char *sockname;
362       const char *argv[3];
363       pid_t pid;
364       int excode;
365
366       /* First check whether we can connect at the standard
367          socket.  */
368       sockname = make_filename (homedir, "S.gpg-agent", NULL);
369       err = assuan_socket_connect (ctx, sockname, 0, 0);
370
371       if (err)
372         {
373           /* With no success start a new server.  */
374           if (!agent_program || !*agent_program)
375             agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
376
377           if (verbose)
378             log_info (_("no running gpg-agent - starting `%s'\n"),
379                       agent_program);
380           
381           if (status_cb)
382             status_cb (status_cb_arg, STATUS_PROGRESS, 
383                        "starting_agent ? 0 0", NULL);
384           
385           if (fflush (NULL))
386             {
387               gpg_error_t tmperr = gpg_err_make (errsource,
388                                                  gpg_err_code_from_syserror ());
389               log_error ("error flushing pending output: %s\n",
390                          strerror (errno));
391               xfree (sockname);
392               assuan_release (ctx);
393               return tmperr;
394             }
395           
396           argv[0] = "--use-standard-socket-p"; 
397           argv[1] = NULL;  
398           err = gnupg_spawn_process_fd (agent_program, argv, -1, -1, -1, &pid);
399           if (err)
400             log_debug ("starting `%s' for testing failed: %s\n",
401                        agent_program, gpg_strerror (err));
402           else if ((err = gnupg_wait_process (agent_program, pid, 1, &excode)))
403             {
404               if (excode == -1)
405                 log_debug ("running `%s' for testing failed (wait): %s\n",
406                            agent_program, gpg_strerror (err));
407             }          
408           gnupg_release_process (pid);
409
410           if (!err && !excode)
411             {
412               /* If the agent has been configured for use with a
413                  standard socket, an environment variable is not
414                  required and thus we we can savely start the agent
415                  here.  */
416               lock_spawn_t lock;
417
418               argv[0] = "--daemon";
419               argv[1] = "--use-standard-socket"; 
420               argv[2] = NULL;  
421
422               if (!(err = lock_spawning (&lock, homedir, "agent", verbose))
423                   && assuan_socket_connect (ctx, sockname, 0, 0))
424                 {
425                   err = gnupg_spawn_process_detached (agent_program, argv,NULL);
426                   if (err)
427                     log_error ("failed to start agent `%s': %s\n",
428                                agent_program, gpg_strerror (err));
429                   else
430                     {
431                       int i;
432
433                       for (i=0; i < SECS_TO_WAIT_FOR_AGENT; i++)
434                         {
435                           if (verbose)
436                             log_info (_("waiting for the agent "
437                                         "to come up ... (%ds)\n"),
438                                       SECS_TO_WAIT_FOR_AGENT - i);
439                           gnupg_sleep (1);
440                           err = assuan_socket_connect (ctx, sockname, 0, 0);
441                           if (!err)
442                             {
443                               if (verbose)
444                                 {
445                                   log_info (_("connection to agent "
446                                               "established\n"));
447                                   did_success_msg = 1;
448                                 }
449                               break;
450                             }
451                         }
452                     }
453                 }
454
455               unlock_spawning (&lock, "agent");
456             }
457           else
458             {
459               /* If using the standard socket is not the default we
460                  start the agent as a pipe server which gives us most
461                  of the required features except for passphrase
462                  caching etc.  */
463               const char *pgmname;
464               int no_close_list[3];
465               int i;
466               
467               if ( !(pgmname = strrchr (agent_program, '/')))
468                 pgmname = agent_program;
469               else
470                 pgmname++;
471               
472               argv[0] = pgmname;
473               argv[1] = "--server";
474               argv[2] = NULL;
475               
476               i=0;
477               if (log_get_fd () != -1)
478                 no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
479               no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
480               no_close_list[i] = -1;
481               
482               /* Connect to the agent and perform initial handshaking. */
483               err = assuan_pipe_connect (ctx, agent_program, argv,
484                                          no_close_list, NULL, NULL, 0);
485             }
486         }
487       xfree (sockname);
488     }
489   else
490     {
491       int prot;
492       int pid;
493
494       infostr = xstrdup (infostr);
495       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
496         {
497           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
498           xfree (infostr);
499           force_pipe_server = 1;
500           goto restart;
501         }
502       *p++ = 0;
503       pid = atoi (p);
504       while (*p && *p != PATHSEP_C)
505         p++;
506       prot = *p? atoi (p+1) : 0;
507       if (prot != 1)
508         {
509           log_error (_("gpg-agent protocol version %d is not supported\n"),
510                      prot);
511           xfree (infostr);
512           force_pipe_server = 1;
513           goto restart;
514         }
515
516       err = assuan_socket_connect (ctx, infostr, pid, 0);
517       xfree (infostr);
518       if (gpg_err_code (err) == GPG_ERR_ASS_CONNECT_FAILED)
519         {
520           log_info (_("can't connect to the agent - trying fall back\n"));
521           force_pipe_server = 1;
522           goto restart;
523         }
524     }
525
526   if (err)
527     {
528       log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
529       assuan_release (ctx);
530       return gpg_err_make (errsource, GPG_ERR_NO_AGENT);
531     }
532
533   if (debug && !did_success_msg)
534     log_debug (_("connection to agent established\n"));
535
536   err = assuan_transact (ctx, "RESET",
537                         NULL, NULL, NULL, NULL, NULL, NULL);
538   if (!err)
539     err = send_pinentry_environment (ctx, errsource,
540                                     opt_lc_ctype, opt_lc_messages,
541                                     session_env);
542   if (err)
543     {
544       assuan_release (ctx);
545       return err;
546     }
547
548   *r_ctx = ctx;
549   return 0;
550 }
551
552
553 /* Try to connect to the dirmngr via a socket.  On platforms
554    supporting it, start it up if needed.  Returns a new assuan context
555    at R_CTX or an error code. */
556 gpg_error_t
557 start_new_dirmngr (assuan_context_t *r_ctx,
558                    gpg_err_source_t errsource,
559                    const char *homedir,
560                    const char *dirmngr_program,
561                    int verbose, int debug,
562                    gpg_error_t (*status_cb)(ctrl_t, int, ...),
563                    ctrl_t status_cb_arg)
564 {
565   gpg_error_t err;
566   assuan_context_t ctx;
567   const char *sockname;
568   int did_success_msg = 0;
569       
570   *r_ctx = NULL;
571
572   err = assuan_new (&ctx);
573   if (err)
574     {
575       log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
576       return err;
577     }
578
579   sockname = dirmngr_socket_name ();
580   err = assuan_socket_connect (ctx, sockname, 0, 0);
581 #ifdef USE_DIRMNGR_AUTO_START
582   if (err)
583     {
584       lock_spawn_t lock;
585       const char *argv[2];
586
587       /* With no success try start a new Dirmngr.  On most systems
588          this will fail because the Dirmngr is expected to be a system
589          service.  However on Wince we don't distinguish users and
590          thus we can start it.  A future extension might be to use the
591          userv system to start the Dirmngr as a system service.  */
592       if (!dirmngr_program || !*dirmngr_program)
593         dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
594
595       if (verbose)
596         log_info (_("no running Dirmngr - starting `%s'\n"),
597                   dirmngr_program);
598           
599       if (status_cb)
600         status_cb (status_cb_arg, STATUS_PROGRESS, 
601                    "starting_dirmngr ? 0 0", NULL);
602           
603       if (fflush (NULL))
604         {
605           gpg_error_t tmperr = gpg_err_make (errsource,
606                                              gpg_err_code_from_syserror ());
607           log_error ("error flushing pending output: %s\n",
608                      strerror (errno));
609           assuan_release (ctx);
610           return tmperr;
611         }
612           
613       argv[0] = "--daemon";
614       argv[1] = NULL;  
615       
616       if (!(err = lock_spawning (&lock, homedir, "dirmngr", verbose))
617           && assuan_socket_connect (ctx, sockname, 0, 0))
618         {
619           err = gnupg_spawn_process_detached (dirmngr_program, argv,NULL);
620           if (err)
621             log_error ("failed to start the dirmngr `%s': %s\n",
622                        dirmngr_program, gpg_strerror (err));
623           else
624             {
625               int i;
626               
627               for (i=0; i < SECS_TO_WAIT_FOR_DIRMNGR; i++)
628                 {
629                   if (verbose)
630                     log_info (_("waiting for the dirmngr "
631                                 "to come up ... (%ds)\n"),
632                               SECS_TO_WAIT_FOR_DIRMNGR - i);
633                   gnupg_sleep (1);
634                   err = assuan_socket_connect (ctx, sockname, 0, 0);
635                   if (!err)
636                     {
637                       if (verbose)
638                         {
639                           log_info (_("connection to the dirmngr"
640                                       " established\n"));
641                           did_success_msg = 1;
642                         }
643                       break;
644                     }
645                 }
646             }
647         }
648       
649       unlock_spawning (&lock, "dirmngr");
650     }
651 #else
652   (void)homedir;
653   (void)dirmngr_program;
654   (void)verbose;
655   (void)status_cb;
656   (void)status_cb_arg;
657 #endif /*USE_DIRMNGR_AUTO_START*/
658  
659   if (err)
660     {
661       log_error ("connecting dirmngr at `%s' failed: %s\n",
662                  sockname, gpg_strerror (err));
663       assuan_release (ctx);
664       return gpg_err_make (errsource, GPG_ERR_NO_DIRMNGR);
665     }
666
667   if (debug && !did_success_msg)
668     log_debug (_("connection to the dirmngr established\n"));
669
670   *r_ctx = ctx;
671   return 0;
672 }
673