2009-05-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / asshelp.c
blob6663241ae766983ec3c84f829e23b2342fde94f1
1 /* asshelp.c - Helper functions for Assuan
2 * Copyright (C) 2002, 2004, 2007 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
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
30 #include "i18n.h"
31 #include "util.h"
32 #include "exechelp.h"
33 #include "sysutils.h"
34 #include "status.h"
35 #include "asshelp.h"
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)
42 gpg_error_t err;
43 char *optstr;
45 (void)errsource;
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
53 err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
54 xfree (optstr);
57 return err;
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)
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;
84 /* Send the DISPLAY variable. */
85 dft_display = getenv ("DISPLAY");
86 if (opt_display || dft_display)
88 err = send_one_option (ctx, errsource, "display",
89 opt_display ? opt_display : dft_display);
90 if (err)
91 return err;
94 /* Send the name of the TTY. */
95 if (!opt_ttyname)
97 dft_ttyname = getenv ("GPG_TTY");
98 if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
99 dft_ttyname = ttyname (0);
101 if (opt_ttyname || dft_ttyname)
103 err = send_one_option (ctx, errsource, "ttyname",
104 opt_ttyname ? opt_ttyname : dft_ttyname);
105 if (err)
106 return err;
109 /* Send the type of the TTY. */
110 dft_ttytype = getenv ("TERM");
111 if (opt_ttytype || (dft_ttyname && dft_ttytype))
113 err = send_one_option (ctx, errsource, "ttytype",
114 opt_ttyname ? opt_ttytype : dft_ttytype);
115 if (err)
116 return err;
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)
124 old_lc = xtrystrdup (old_lc);
125 if (!old_lc)
126 return gpg_error_from_syserror ();
128 dft_lc = setlocale (LC_CTYPE, "");
129 #endif
130 if (opt_lc_ctype || (dft_ttyname && dft_lc))
132 err = send_one_option (ctx, errsource, "lc-ctype",
133 opt_lc_ctype ? opt_lc_ctype : dft_lc);
135 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
136 if (old_lc)
138 setlocale (LC_CTYPE, old_lc);
139 xfree (old_lc);
141 #endif
142 if (err)
143 return err;
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)
150 old_lc = xtrystrdup (old_lc);
151 if (!old_lc)
152 return gpg_error_from_syserror ();
154 dft_lc = setlocale (LC_MESSAGES, "");
155 #endif
156 if (opt_lc_messages || (dft_ttyname && dft_lc))
158 err = send_one_option (ctx, errsource, "lc-messages",
159 opt_lc_messages ? opt_lc_messages : dft_lc);
161 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
162 if (old_lc)
164 setlocale (LC_MESSAGES, old_lc);
165 xfree (old_lc);
167 #endif
168 if (err)
169 return err;
171 /* Send the XAUTHORITY variable. */
172 dft_xauthority = getenv ("XAUTHORITY");
173 if (opt_xauthority || dft_xauthority)
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;
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)
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;
196 return 0;
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)
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;
223 gpg_error_t rc = 0;
224 char *infostr, *p;
225 assuan_context_t ctx;
227 *r_ctx = NULL;
229 restart:
230 infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
231 if (!infostr || !*infostr)
233 char *sockname;
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);
240 if (rc)
242 /* With no success start a new server. */
243 if (verbose)
244 log_info (_("no running gpg-agent - starting one\n"));
246 if (status_cb)
247 status_cb (status_cb_arg, STATUS_PROGRESS,
248 "starting_agent ? 0 0", NULL);
250 if (fflush (NULL))
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;
259 if (!agent_program || !*agent_program)
260 agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
262 #ifdef HAVE_W32_SYSTEM
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];
272 argv[0] = "--daemon";
273 argv[1] = "--use-standard-socket";
274 argv[2] = NULL;
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
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);
288 #else /*!HAVE_W32_SYSTEM*/
290 const char *pgmname;
291 const char *argv[3];
292 int no_close_list[3];
293 int i;
295 if ( !(pgmname = strrchr (agent_program, '/')))
296 pgmname = agent_program;
297 else
298 pgmname++;
300 argv[0] = pgmname;
301 argv[1] = "--server";
302 argv[2] = NULL;
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;
310 /* Connect to the agent and perform initial handshaking. */
311 rc = assuan_pipe_connect (&ctx, agent_program, argv,
312 no_close_list);
314 #endif /*!HAVE_W32_SYSTEM*/
316 xfree (sockname);
318 else
320 int prot;
321 int pid;
323 infostr = xstrdup (infostr);
324 if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
326 log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
327 xfree (infostr);
328 force_pipe_server = 1;
329 goto restart;
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)
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;
345 rc = assuan_socket_connect (&ctx, infostr, pid);
346 xfree (infostr);
347 if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
349 log_info (_("can't connect to the agent - trying fall back\n"));
350 force_pipe_server = 1;
351 goto restart;
355 if (rc)
357 log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
358 return gpg_error (GPG_ERR_NO_AGENT);
361 if (debug)
362 log_debug ("connection to agent established\n");
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)
374 assuan_disconnect (ctx);
375 return rc;
378 *r_ctx = ctx;
379 return 0;