Add gpgtar backport
[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_agent_t HANDLE
41 #else
42 # define lock_agent_t DOTLOCK
43 #endif
44
45
46 static gpg_error_t
47 send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
48                  const char *name, const char *value, int use_putenv)
49 {
50   gpg_error_t err;
51   char *optstr;
52
53   (void)errsource;
54
55   if (!value || !*value)
56     err = 0;  /* Avoid sending empty strings.  */
57   else if (asprintf (&optstr, "OPTION %s%s=%s", 
58                      use_putenv? "putenv=":"", name, value) < 0)
59     err = gpg_error_from_syserror ();
60   else
61     {
62       err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
63       xfree (optstr);
64     }
65
66   return err;
67 }
68
69
70 /* Send the assuan commands pertaining to the pinentry environment.  The
71    OPT_* arguments are optional and may be used to override the
72    defaults taken from the current locale. */
73 gpg_error_t
74 send_pinentry_environment (assuan_context_t ctx,
75                            gpg_err_source_t errsource,
76                            const char *opt_lc_ctype,
77                            const char *opt_lc_messages,
78                            session_env_t session_env)
79
80 {
81   gpg_error_t err = 0;
82 #if defined(HAVE_SETLOCALE)
83   char *old_lc = NULL; 
84 #endif
85   char *dft_lc = NULL;
86   const char *dft_ttyname;
87   int iterator;
88   const char *name, *assname, *value;
89   int is_default;
90
91   iterator = 0; 
92   while ((name = session_env_list_stdenvnames (&iterator, &assname)))
93     {
94       value = session_env_getenv_or_default (session_env, name, NULL);
95       if (!value)
96         continue;
97
98       if (assname)
99         err = send_one_option (ctx, errsource, assname, value, 0);
100       else
101         {
102           err = send_one_option (ctx, errsource, name, value, 1);
103           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
104             err = 0;  /* Server too old; can't pass the new envvars.  */
105         }
106       if (err)
107         return err;
108     }
109
110
111   dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY", 
112                                                &is_default);
113   if (dft_ttyname && !is_default)
114     dft_ttyname = NULL;  /* We need the default value.  */
115
116   /* Send the value for LC_CTYPE.  */
117 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
118   old_lc = setlocale (LC_CTYPE, NULL);
119   if (old_lc)
120     {
121       old_lc = xtrystrdup (old_lc);
122       if (!old_lc)
123         return gpg_error_from_syserror ();
124     }
125   dft_lc = setlocale (LC_CTYPE, "");
126 #endif
127   if (opt_lc_ctype || (dft_ttyname && dft_lc))
128     {
129       err = send_one_option (ctx, errsource, "lc-ctype", 
130                              opt_lc_ctype ? opt_lc_ctype : dft_lc, 0);
131     }
132 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
133   if (old_lc)
134     {
135       setlocale (LC_CTYPE, old_lc);
136       xfree (old_lc);
137     }
138 #endif
139   if (err)
140     return err;
141
142   /* Send the value for LC_MESSAGES.  */
143 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
144   old_lc = setlocale (LC_MESSAGES, NULL);
145   if (old_lc)
146     {
147       old_lc = xtrystrdup (old_lc);
148       if (!old_lc)
149         return gpg_error_from_syserror ();
150     }
151   dft_lc = setlocale (LC_MESSAGES, "");
152 #endif
153   if (opt_lc_messages || (dft_ttyname && dft_lc))
154     {
155       err = send_one_option (ctx, errsource, "lc-messages", 
156                              opt_lc_messages ? opt_lc_messages : dft_lc, 0);
157     }
158 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
159   if (old_lc)
160     {
161       setlocale (LC_MESSAGES, old_lc);
162       xfree (old_lc);
163     }
164 #endif
165   if (err)
166     return err;
167
168   return 0;
169 }
170
171
172 /* Lock the agent spawning process.  The caller needs to provide the
173    address of a variable to store the lock information.  */
174 static gpg_error_t
175 lock_agent_spawning (lock_agent_t *lock, const char *homedir)
176 {
177 #ifdef HAVE_W32_SYSTEM
178   int waitrc;
179
180   (void)homedir; /* Not required. */
181
182   *lock = CreateMutex (NULL, FALSE, "GnuPG_spawn_agent_sentinel");
183   if (!*lock)
184     {
185       log_error ("failed to create the spawn_agent mutex: %s\n",
186                  w32_strerror (-1));
187       return gpg_error (GPG_ERR_GENERAL);
188     }
189
190   waitrc = WaitForSingleObject (*lock, 5000);
191   if (waitrc == WAIT_OBJECT_0)
192     return 0;
193
194   if (waitrc == WAIT_TIMEOUT)
195     log_info ("error waiting for the spawn_agent mutex: timeout\n");
196   else
197     log_info ("error waiting for the spawn_agent mutex: "
198               "(code=%d) %s\n", waitrc, w32_strerror (-1));
199   return gpg_error (GPG_ERR_GENERAL);
200 #else /*!HAVE_W32_SYSTEM*/
201   char *fname;
202
203   *lock = NULL;
204
205   fname = make_filename (homedir, "gnupg_spawn_agent_sentinel", NULL);
206   if (!fname)
207     return gpg_error_from_syserror ();
208
209   *lock = create_dotlock (fname);
210   xfree (fname);
211   if (!*lock)
212     return gpg_error_from_syserror ();
213
214   /* FIXME: We should use a timeout of 5000 here - however
215      make_dotlock does not yet support values other than -1 and 0.  */
216   if (make_dotlock (*lock, -1))
217     return gpg_error_from_syserror ();
218
219   return 0;
220 #endif /*!HAVE_W32_SYSTEM*/
221 }
222
223
224 /* Unlock the spawning process.  */
225 static void
226 unlock_agent_spawning (lock_agent_t *lock)
227 {
228   if (*lock)
229     {
230 #ifdef HAVE_W32_SYSTEM
231       if (!ReleaseMutex (*lock))
232         log_error ("failed to release the spawn_agent mutex: %s\n",
233                    w32_strerror (-1));
234       CloseHandle (*lock);
235 #else /*!HAVE_W32_SYSTEM*/
236       destroy_dotlock (*lock);
237 #endif /*!HAVE_W32_SYSTEM*/
238       *lock = NULL;
239     }
240 }
241
242
243 /* Try to connect to the agent via socket or fork it off and work by
244    pipes.  Handle the server's initial greeting.  Returns a new assuan
245    context at R_CTX or an error code. */
246 gpg_error_t
247 start_new_gpg_agent (assuan_context_t *r_ctx,
248                      gpg_err_source_t errsource,
249                      const char *homedir,
250                      const char *agent_program,
251                      const char *opt_lc_ctype,
252                      const char *opt_lc_messages,
253                      session_env_t session_env,
254                      int verbose, int debug,
255                      gpg_error_t (*status_cb)(ctrl_t, int, ...),
256                      ctrl_t status_cb_arg)
257 {
258   /* If we ever failed to connect via a socket we will force the use
259      of the pipe based server for the lifetime of the process.  */
260   static int force_pipe_server = 0;
261
262   gpg_error_t err = 0;
263   char *infostr, *p;
264   assuan_context_t ctx;
265
266   *r_ctx = NULL;
267
268   err = assuan_new (&ctx);
269   if (err)
270     {
271       log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
272       return err;
273     }
274
275  restart:
276   infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
277   if (!infostr || !*infostr)
278     {
279       char *sockname;
280       const char *argv[3];
281       pid_t pid;
282       int excode;
283
284       /* First check whether we can connect at the standard
285          socket.  */
286       sockname = make_filename (homedir, "S.gpg-agent", NULL);
287       err = assuan_socket_connect (ctx, sockname, 0, 0);
288
289       if (err)
290         {
291           /* With no success start a new server.  */
292           if (verbose)
293             log_info (_("no running gpg-agent - starting one\n"));
294           
295           if (status_cb)
296             status_cb (status_cb_arg, STATUS_PROGRESS, 
297                        "starting_agent ? 0 0", NULL);
298           
299           if (fflush (NULL))
300             {
301               gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
302               log_error ("error flushing pending output: %s\n",
303                          strerror (errno));
304               xfree (sockname);
305               assuan_release (ctx);
306               return tmperr;
307             }
308           
309           if (!agent_program || !*agent_program)
310             agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
311
312           argv[0] = "--use-standard-socket-p"; 
313           argv[1] = NULL;  
314           err = gnupg_spawn_process_fd (agent_program, argv, -1, -1, -1, &pid);
315           if (err)
316             log_debug ("starting `%s' for testing failed: %s\n",
317                        agent_program, gpg_strerror (err));
318           else if ((err = gnupg_wait_process (agent_program, pid, &excode)))
319             {
320               if (excode == -1)
321                 log_debug ("running `%s' for testing failed: %s\n",
322                            agent_program, gpg_strerror (err));
323             }          
324
325           if (!err && !excode)
326             {
327               /* If the agent has been configured for use with a
328                  standard socket, an environment variable is not
329                  required and thus we we can savely start the agent
330                  here.  */
331               lock_agent_t lock;
332
333               argv[0] = "--daemon";
334               argv[1] = "--use-standard-socket"; 
335               argv[2] = NULL;  
336
337               if (!(err = lock_agent_spawning (&lock, homedir))
338                   && assuan_socket_connect (ctx, sockname, 0, 0))
339                 {
340                   err = gnupg_spawn_process_detached (agent_program, argv,NULL);
341                   if (err)
342                     log_error ("failed to start agent `%s': %s\n",
343                                agent_program, gpg_strerror (err));
344                   else
345                     {
346                       int i;
347
348                       if (verbose)
349                         log_info (_("waiting %d seconds for the agent "
350                                     "to come up\n"), 5);
351                       for (i=0; i < 5; i++)
352                         {
353                           gnupg_sleep (1);
354                           err = assuan_socket_connect (ctx, sockname, 0, 0);
355                           if (!err)
356                             break;
357                         }
358                     }
359                 }
360
361               unlock_agent_spawning (&lock);
362             }
363           else
364             {
365               /* If using the standard socket is not the default we
366                  start the agent as a pipe server which gives us most
367                  of the required features except for passphrase
368                  caching etc.  */
369               const char *pgmname;
370               int no_close_list[3];
371               int i;
372               
373               if ( !(pgmname = strrchr (agent_program, '/')))
374                 pgmname = agent_program;
375               else
376                 pgmname++;
377               
378               argv[0] = pgmname;
379               argv[1] = "--server";
380               argv[2] = NULL;
381               
382               i=0;
383               if (log_get_fd () != -1)
384                 no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
385               no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
386               no_close_list[i] = -1;
387               
388               /* Connect to the agent and perform initial handshaking. */
389               err = assuan_pipe_connect (ctx, agent_program, argv,
390                                          no_close_list, NULL, NULL, 0);
391             }
392         }
393       xfree (sockname);
394     }
395   else
396     {
397       int prot;
398       int pid;
399
400       infostr = xstrdup (infostr);
401       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
402         {
403           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
404           xfree (infostr);
405           force_pipe_server = 1;
406           goto restart;
407         }
408       *p++ = 0;
409       pid = atoi (p);
410       while (*p && *p != PATHSEP_C)
411         p++;
412       prot = *p? atoi (p+1) : 0;
413       if (prot != 1)
414         {
415           log_error (_("gpg-agent protocol version %d is not supported\n"),
416                      prot);
417           xfree (infostr);
418           force_pipe_server = 1;
419           goto restart;
420         }
421
422       err = assuan_socket_connect (ctx, infostr, pid, 0);
423       xfree (infostr);
424       if (gpg_err_code (err) == GPG_ERR_ASS_CONNECT_FAILED)
425         {
426           log_info (_("can't connect to the agent - trying fall back\n"));
427           force_pipe_server = 1;
428           goto restart;
429         }
430     }
431
432   if (err)
433     {
434       log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
435       assuan_release (ctx);
436       return gpg_error (GPG_ERR_NO_AGENT);
437     }
438
439   if (debug)
440     log_debug ("connection to agent established\n");
441
442   err = assuan_transact (ctx, "RESET",
443                         NULL, NULL, NULL, NULL, NULL, NULL);
444   if (!err)
445     err = send_pinentry_environment (ctx, errsource,
446                                     opt_lc_ctype, opt_lc_messages,
447                                     session_env);
448   if (err)
449     {
450       assuan_release (ctx);
451       return err;
452     }
453
454   *r_ctx = ctx;
455   return 0;
456 }
457