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