2007-07-16 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / asshelp.c
blob269e897db5cc9b0662e924506b3511bbba874ece
1 /* asshelp.c - Helper functions for Assuan
2 * Copyright (C) 2002, 2004 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 "errors.h" /* FIXME: This one conatisn only status code - rename it*/
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 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
51 err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
52 free (optstr);
55 return err;
59 /* Send the assuan commands pertaining to the pinenry 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)
71 gpg_error_t err = 0;
72 char *dft_display = NULL;
73 char *dft_ttyname = NULL;
74 char *dft_ttytype = NULL;
75 char *old_lc = NULL;
76 char *dft_lc = NULL;
78 /* Send the DISPLAY variable. */
79 dft_display = getenv ("DISPLAY");
80 if (opt_display || dft_display)
82 err = send_one_option (ctx, errsource, "display",
83 opt_display ? opt_display : dft_display);
84 if (err)
85 return err;
88 /* Send the name of the TTY. */
89 if (!opt_ttyname)
91 dft_ttyname = getenv ("GPG_TTY");
92 if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
93 dft_ttyname = ttyname (0);
95 if (opt_ttyname || dft_ttyname)
97 err = send_one_option (ctx, errsource, "ttyname",
98 opt_ttyname ? opt_ttyname : dft_ttyname);
99 if (err)
100 return err;
103 /* Send the type of the TTY. */
104 dft_ttytype = getenv ("TERM");
105 if (opt_ttytype || (dft_ttyname && dft_ttytype))
107 err = send_one_option (ctx, errsource, "ttytype",
108 opt_ttyname ? opt_ttytype : dft_ttytype);
109 if (err)
110 return err;
113 /* Send the value for LC_CTYPE. */
114 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
115 old_lc = setlocale (LC_CTYPE, NULL);
116 if (old_lc)
118 old_lc = strdup (old_lc);
119 if (!old_lc)
120 return gpg_error_from_syserror ();
122 dft_lc = setlocale (LC_CTYPE, "");
123 #endif
124 if (opt_lc_ctype || (dft_ttyname && dft_lc))
126 err = send_one_option (ctx, errsource, "lc-ctype",
127 opt_lc_ctype ? opt_lc_ctype : dft_lc);
129 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
130 if (old_lc)
132 setlocale (LC_CTYPE, old_lc);
133 free (old_lc);
135 #endif
136 if (err)
137 return err;
139 /* Send the value for LC_MESSAGES. */
140 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
141 old_lc = setlocale (LC_MESSAGES, NULL);
142 if (old_lc)
144 old_lc = strdup (old_lc);
145 if (!old_lc)
146 return gpg_error_from_syserror ();
148 dft_lc = setlocale (LC_MESSAGES, "");
149 #endif
150 if (opt_lc_messages || (dft_ttyname && dft_lc))
152 err = send_one_option (ctx, errsource, "lc-messages",
153 opt_lc_messages ? opt_lc_messages : dft_lc);
155 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
156 if (old_lc)
158 setlocale (LC_MESSAGES, old_lc);
159 free (old_lc);
161 #endif
162 if (err)
163 return err;
165 return 0;
169 /* Try to connect to the agent via socket or fork it off and work by
170 pipes. Handle the server's initial greeting. Returns a new assuan
171 context at R_CTX or an error code. */
172 gpg_error_t
173 start_new_gpg_agent (assuan_context_t *r_ctx,
174 gpg_err_source_t errsource,
175 const char *homedir,
176 const char *agent_program,
177 const char *opt_display,
178 const char *opt_ttyname,
179 const char *opt_ttytype,
180 const char *opt_lc_ctype,
181 const char *opt_lc_messages,
182 int verbose, int debug,
183 gpg_error_t (*status_cb)(ctrl_t, int, ...),
184 ctrl_t status_cb_arg)
186 /* If we ever failed to connect via a socket we will force the use
187 of the pipe based server for the lifetime of the process. */
188 static int force_pipe_server = 0;
190 gpg_error_t rc = 0;
191 char *infostr, *p;
192 assuan_context_t ctx;
194 *r_ctx = NULL;
196 restart:
197 infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
198 if (!infostr || !*infostr)
200 char *sockname;
202 /* First check whether we can connect at the standard
203 socket. */
204 sockname = make_filename (homedir, "S.gpg-agent", NULL);
205 rc = assuan_socket_connect (&ctx, sockname, 0);
207 if (rc)
209 /* With no success start a new server. */
210 if (verbose)
211 log_info (_("no running gpg-agent - starting one\n"));
213 if (status_cb)
214 status_cb (status_cb_arg, STATUS_PROGRESS,
215 "starting_agent ? 0 0", NULL);
217 if (fflush (NULL))
219 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
220 log_error ("error flushing pending output: %s\n",
221 strerror (errno));
222 xfree (sockname);
223 return tmperr;
226 if (!agent_program || !*agent_program)
227 agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
229 #ifdef HAVE_W32_SYSTEM
231 /* Under Windows we start the server in daemon mode. This
232 is because the default is to use the standard socket
233 and thus there is no need for the GPG_AGENT_INFO
234 envvar. This is possible as we don't have a real unix
235 domain socket but use a plain file and thus there is no
236 need to care about non-local file systems. */
237 const char *argv[3];
239 argv[0] = "--daemon";
240 argv[1] = "--use-standard-socket";
241 argv[2] = NULL;
243 rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
244 if (rc)
245 log_debug ("failed to start agent `%s': %s\n",
246 agent_program, gpg_strerror (rc));
247 else
249 /* Give the agent some time to prepare itself. */
250 gnupg_sleep (3);
251 /* Now try again to connect the agent. */
252 rc = assuan_socket_connect (&ctx, sockname, 0);
255 #else /*!HAVE_W32_SYSTEM*/
257 const char *pgmname;
258 const char *argv[3];
259 int no_close_list[3];
260 int i;
262 if ( !(pgmname = strrchr (agent_program, '/')))
263 pgmname = agent_program;
264 else
265 pgmname++;
267 argv[0] = pgmname;
268 argv[1] = "--server";
269 argv[2] = NULL;
271 i=0;
272 if (log_get_fd () != -1)
273 no_close_list[i++] = log_get_fd ();
274 no_close_list[i++] = fileno (stderr);
275 no_close_list[i] = -1;
277 /* Connect to the agent and perform initial handshaking. */
278 rc = assuan_pipe_connect (&ctx, agent_program, argv,
279 no_close_list);
281 #endif /*!HAVE_W32_SYSTEM*/
283 xfree (sockname);
285 else
287 int prot;
288 int pid;
290 infostr = xstrdup (infostr);
291 if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
293 log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
294 xfree (infostr);
295 force_pipe_server = 1;
296 goto restart;
298 *p++ = 0;
299 pid = atoi (p);
300 while (*p && *p != PATHSEP_C)
301 p++;
302 prot = *p? atoi (p+1) : 0;
303 if (prot != 1)
305 log_error (_("gpg-agent protocol version %d is not supported\n"),
306 prot);
307 xfree (infostr);
308 force_pipe_server = 1;
309 goto restart;
312 rc = assuan_socket_connect (&ctx, infostr, pid);
313 xfree (infostr);
314 if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
316 log_info (_("can't connect to the agent - trying fall back\n"));
317 force_pipe_server = 1;
318 goto restart;
322 if (rc)
324 log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
325 return gpg_error (GPG_ERR_NO_AGENT);
328 if (debug)
329 log_debug ("connection to agent established\n");
331 rc = assuan_transact (ctx, "RESET",
332 NULL, NULL, NULL, NULL, NULL, NULL);
333 if (!rc)
334 rc = send_pinentry_environment (ctx, errsource,
335 opt_display, opt_ttyname, opt_ttytype,
336 opt_lc_ctype, opt_lc_messages);
337 if (rc)
339 assuan_disconnect (ctx);
340 return rc;
343 *r_ctx = ctx;
344 return 0;