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