Whole lot of changes to support CE.
[gnupg.git] / common / asshelp.c
1 /* asshelp.c - Helper functions for Assuan
2  * Copyright (C) 2002, 2004, 2007, 2009 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
39 /* A bitfield that specifies the assuan categories to log.  This is
40    identical to the default log handler of libassuan.  We need to do
41    it ourselves because we use a custom log handler and want to use
42    the same assuan variables to select the categories to log. */
43 static int log_cats;
44 #define TEST_LOG_CAT(x) (!! (log_cats & (1 << (x - 1))))
45
46
47 static int
48 my_libassuan_log_handler (assuan_context_t ctx, void *hook,
49                           unsigned int cat, const char *msg)
50 {
51   unsigned int dbgval;
52
53   (void)ctx;
54
55   if (! TEST_LOG_CAT (cat))
56     return 0;
57
58   dbgval = hook? *(unsigned int*)hook : 0;
59   if (!(dbgval & 1024))
60     return 0; /* Assuan debugging is not enabled.  */
61
62   if (msg)
63     log_string (JNLIB_LOG_DEBUG, msg);
64
65   return 1;
66 }
67
68
69 /* Setup libassuan to use our own logging functions.  Should be used
70    early at startup.  */
71 void
72 setup_libassuan_logging (unsigned int *debug_var_address)
73 {
74   char *flagstr;
75
76   flagstr = getenv ("ASSUAN_DEBUG");
77   if (flagstr)
78     log_cats = atoi (flagstr);
79   else /* Default to log the control channel.  */
80     log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
81   assuan_set_log_cb (my_libassuan_log_handler, debug_var_address);
82 }
83
84
85
86 static gpg_error_t
87 send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
88                  const char *name, const char *value, int use_putenv)
89 {
90   gpg_error_t err;
91   char *optstr;
92
93   (void)errsource;
94
95   if (!value || !*value)
96     err = 0;  /* Avoid sending empty strings.  */
97   else if (asprintf (&optstr, "OPTION %s%s=%s", 
98                      use_putenv? "putenv=":"", name, value) < 0)
99     err = gpg_error_from_syserror ();
100   else
101     {
102       err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
103       xfree (optstr);
104     }
105
106   return err;
107 }
108
109
110 /* Send the assuan commands pertaining to the pinentry environment.  The
111    OPT_* arguments are optional and may be used to override the
112    defaults taken from the current locale. */
113 gpg_error_t
114 send_pinentry_environment (assuan_context_t ctx,
115                            gpg_err_source_t errsource,
116                            const char *opt_lc_ctype,
117                            const char *opt_lc_messages,
118                            session_env_t session_env)
119
120 {
121   gpg_error_t err = 0;
122 #if defined(HAVE_SETLOCALE)
123   char *old_lc = NULL; 
124 #endif
125   char *dft_lc = NULL;
126   const char *dft_ttyname;
127   int iterator;
128   const char *name, *assname, *value;
129   int is_default;
130
131   iterator = 0; 
132   while ((name = session_env_list_stdenvnames (&iterator, &assname)))
133     {
134       value = session_env_getenv_or_default (session_env, name, NULL);
135       if (!value)
136         continue;
137
138       if (assname)
139         err = send_one_option (ctx, errsource, assname, value, 0);
140       else
141         {
142           err = send_one_option (ctx, errsource, name, value, 1);
143           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
144             err = 0;  /* Server too old; can't pass the new envvars.  */
145         }
146       if (err)
147         return err;
148     }
149
150
151   dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY", 
152                                                &is_default);
153   if (dft_ttyname && !is_default)
154     dft_ttyname = NULL;  /* We need the default value.  */
155
156   /* Send the value for LC_CTYPE.  */
157 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
158   old_lc = setlocale (LC_CTYPE, NULL);
159   if (old_lc)
160     {
161       old_lc = xtrystrdup (old_lc);
162       if (!old_lc)
163         return gpg_error_from_syserror ();
164     }
165   dft_lc = setlocale (LC_CTYPE, "");
166 #endif
167   if (opt_lc_ctype || (dft_ttyname && dft_lc))
168     {
169       err = send_one_option (ctx, errsource, "lc-ctype", 
170                              opt_lc_ctype ? opt_lc_ctype : dft_lc, 0);
171     }
172 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
173   if (old_lc)
174     {
175       setlocale (LC_CTYPE, old_lc);
176       xfree (old_lc);
177     }
178 #endif
179   if (err)
180     return err;
181
182   /* Send the value for LC_MESSAGES.  */
183 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
184   old_lc = setlocale (LC_MESSAGES, NULL);
185   if (old_lc)
186     {
187       old_lc = xtrystrdup (old_lc);
188       if (!old_lc)
189         return gpg_error_from_syserror ();
190     }
191   dft_lc = setlocale (LC_MESSAGES, "");
192 #endif
193   if (opt_lc_messages || (dft_ttyname && dft_lc))
194     {
195       err = send_one_option (ctx, errsource, "lc-messages", 
196                              opt_lc_messages ? opt_lc_messages : dft_lc, 0);
197     }
198 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
199   if (old_lc)
200     {
201       setlocale (LC_MESSAGES, old_lc);
202       xfree (old_lc);
203     }
204 #endif
205   if (err)
206     return err;
207
208   return 0;
209 }
210
211
212 /* Try to connect to the agent via socket or fork it off and work by
213    pipes.  Handle the server's initial greeting.  Returns a new assuan
214    context at R_CTX or an error code. */
215 gpg_error_t
216 start_new_gpg_agent (assuan_context_t *r_ctx,
217                      gpg_err_source_t errsource,
218                      const char *homedir,
219                      const char *agent_program,
220                      const char *opt_lc_ctype,
221                      const char *opt_lc_messages,
222                      session_env_t session_env,
223                      int verbose, int debug,
224                      gpg_error_t (*status_cb)(ctrl_t, int, ...),
225                      ctrl_t status_cb_arg)
226 {
227   /* If we ever failed to connect via a socket we will force the use
228      of the pipe based server for the lifetime of the process.  */
229   static int force_pipe_server = 0;
230
231   gpg_error_t rc = 0;
232   char *infostr, *p;
233   assuan_context_t ctx;
234
235   *r_ctx = NULL;
236
237   rc = assuan_new (&ctx);
238   if (rc)
239     {
240       log_error ("error allocating assuan context: %s\n", gpg_strerror (rc));
241       return rc;
242     }
243
244  restart:
245   infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
246   if (!infostr || !*infostr)
247     {
248       char *sockname;
249
250       /* First check whether we can connect at the standard
251          socket.  */
252       sockname = make_filename (homedir, "S.gpg-agent", NULL);
253       rc = assuan_socket_connect (ctx, sockname, 0, 0);
254
255       if (rc)
256         {
257           /* With no success start a new server.  */
258           if (verbose)
259             log_info (_("no running gpg-agent - starting one\n"));
260           
261           if (status_cb)
262             status_cb (status_cb_arg, STATUS_PROGRESS, 
263                        "starting_agent ? 0 0", NULL);
264           
265           if (fflush (NULL))
266             {
267               gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
268               log_error ("error flushing pending output: %s\n",
269                          strerror (errno));
270               xfree (sockname);
271               assuan_release (ctx);
272               return tmperr;
273             }
274           
275           if (!agent_program || !*agent_program)
276             agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
277
278 #ifdef HAVE_W32_SYSTEM
279           {
280             /* Under Windows we start the server in daemon mode.  This
281                is because the default is to use the standard socket
282                and thus there is no need for the GPG_AGENT_INFO
283                envvar.  This is possible as we don't have a real unix
284                domain socket but use a plain file and thus there is no
285                need to care about non-local file systems. */
286             const char *argv[3];
287
288             argv[0] = "--daemon";
289             argv[1] = "--use-standard-socket"; 
290             argv[2] = NULL;  
291
292             rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
293             if (rc)
294               log_debug ("failed to start agent `%s': %s\n",
295                          agent_program, gpg_strerror (rc));
296             else
297               {
298                 /* Give the agent some time to prepare itself. */
299                 gnupg_sleep (3);
300                 /* Now try again to connect the agent.  */
301                 rc = assuan_socket_connect (ctx, sockname, 0, 0);
302               }
303           }
304 #else /*!HAVE_W32_SYSTEM*/
305           {
306             const char *pgmname;
307             const char *argv[3];
308             int no_close_list[3];
309             int i;
310
311             if ( !(pgmname = strrchr (agent_program, '/')))
312               pgmname = agent_program;
313             else
314               pgmname++;
315             
316             argv[0] = pgmname;
317             argv[1] = "--server";
318             argv[2] = NULL;
319             
320             i=0;
321             if (log_get_fd () != -1)
322               no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
323             no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
324             no_close_list[i] = -1;
325             
326             /* Connect to the agent and perform initial handshaking. */
327             rc = assuan_pipe_connect (ctx, agent_program, argv,
328                                       no_close_list, NULL, NULL, 0);
329           }
330 #endif /*!HAVE_W32_SYSTEM*/
331         }
332       xfree (sockname);
333     }
334   else
335     {
336       int prot;
337       int pid;
338
339       infostr = xstrdup (infostr);
340       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
341         {
342           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
343           xfree (infostr);
344           force_pipe_server = 1;
345           goto restart;
346         }
347       *p++ = 0;
348       pid = atoi (p);
349       while (*p && *p != PATHSEP_C)
350         p++;
351       prot = *p? atoi (p+1) : 0;
352       if (prot != 1)
353         {
354           log_error (_("gpg-agent protocol version %d is not supported\n"),
355                      prot);
356           xfree (infostr);
357           force_pipe_server = 1;
358           goto restart;
359         }
360
361       rc = assuan_socket_connect (ctx, infostr, pid, 0);
362       xfree (infostr);
363       if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
364         {
365           log_info (_("can't connect to the agent - trying fall back\n"));
366           force_pipe_server = 1;
367           goto restart;
368         }
369     }
370
371   if (rc)
372     {
373       log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
374       assuan_release (ctx);
375       return gpg_error (GPG_ERR_NO_AGENT);
376     }
377
378   if (debug)
379     log_debug ("connection to agent established\n");
380
381   rc = assuan_transact (ctx, "RESET",
382                         NULL, NULL, NULL, NULL, NULL, NULL);
383   if (!rc)
384     rc = send_pinentry_environment (ctx, errsource,
385                                     opt_lc_ctype, opt_lc_messages,
386                                     session_env);
387   if (rc)
388     {
389       assuan_release (ctx);
390       return rc;
391     }
392
393   *r_ctx = ctx;
394   return 0;
395 }
396