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