Re-indented
[gnupg.git] / common / asshelp.c
blob47b86ee1c5b9466cb248f890336c432f4c52da95
1 /* asshelp.c - Helper functions for Assuan
2 * Copyright (C) 2002, 2004, 2007, 2009 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"
37 static gpg_error_t
38 send_one_option (assuan_context_t ctx, gpg_err_source_t errsource,
39 const char *name, const char *value, int use_putenv)
41 gpg_error_t err;
42 char *optstr;
44 (void)errsource;
46 if (!value || !*value)
47 err = 0; /* Avoid sending empty strings. */
48 else if (asprintf (&optstr, "OPTION %s%s=%s",
49 use_putenv? "putenv=":"", 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_lc_ctype,
68 const char *opt_lc_messages,
69 session_env_t session_env)
72 gpg_error_t err = 0;
73 char *old_lc = NULL;
74 char *dft_lc = NULL;
75 const char *dft_ttyname;
76 int iterator;
77 const char *name, *assname, *value;
78 int is_default;
80 iterator = 0;
81 while ((name = session_env_list_stdenvnames (&iterator, &assname)))
83 value = session_env_getenv_or_default (session_env, name, NULL);
84 if (!value)
85 continue;
87 if (assname)
88 err = send_one_option (ctx, errsource, assname, value, 0);
89 else
91 err = send_one_option (ctx, errsource, name, value, 1);
92 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
93 err = 0; /* Server too old; can't pass the new envvars. */
95 if (err)
96 return err;
100 dft_ttyname = session_env_getenv_or_default (session_env, "GPG_TTY",
101 &is_default);
102 if (dft_ttyname && !is_default)
103 dft_ttyname = NULL; /* We need the default value. */
105 /* Send the value for LC_CTYPE. */
106 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
107 old_lc = setlocale (LC_CTYPE, NULL);
108 if (old_lc)
110 old_lc = xtrystrdup (old_lc);
111 if (!old_lc)
112 return gpg_error_from_syserror ();
114 dft_lc = setlocale (LC_CTYPE, "");
115 #endif
116 if (opt_lc_ctype || (dft_ttyname && dft_lc))
118 err = send_one_option (ctx, errsource, "lc-ctype",
119 opt_lc_ctype ? opt_lc_ctype : dft_lc, 0);
121 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
122 if (old_lc)
124 setlocale (LC_CTYPE, old_lc);
125 xfree (old_lc);
127 #endif
128 if (err)
129 return err;
131 /* Send the value for LC_MESSAGES. */
132 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
133 old_lc = setlocale (LC_MESSAGES, NULL);
134 if (old_lc)
136 old_lc = xtrystrdup (old_lc);
137 if (!old_lc)
138 return gpg_error_from_syserror ();
140 dft_lc = setlocale (LC_MESSAGES, "");
141 #endif
142 if (opt_lc_messages || (dft_ttyname && dft_lc))
144 err = send_one_option (ctx, errsource, "lc-messages",
145 opt_lc_messages ? opt_lc_messages : dft_lc, 0);
147 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
148 if (old_lc)
150 setlocale (LC_MESSAGES, old_lc);
151 xfree (old_lc);
153 #endif
154 if (err)
155 return err;
157 return 0;
161 /* Try to connect to the agent via socket or fork it off and work by
162 pipes. Handle the server's initial greeting. Returns a new assuan
163 context at R_CTX or an error code. */
164 gpg_error_t
165 start_new_gpg_agent (assuan_context_t *r_ctx,
166 gpg_err_source_t errsource,
167 const char *homedir,
168 const char *agent_program,
169 const char *opt_lc_ctype,
170 const char *opt_lc_messages,
171 session_env_t session_env,
172 int verbose, int debug,
173 gpg_error_t (*status_cb)(ctrl_t, int, ...),
174 ctrl_t status_cb_arg)
176 /* If we ever failed to connect via a socket we will force the use
177 of the pipe based server for the lifetime of the process. */
178 static int force_pipe_server = 0;
180 gpg_error_t rc = 0;
181 char *infostr, *p;
182 assuan_context_t ctx;
184 *r_ctx = NULL;
186 rc = assuan_new (&ctx);
187 if (rc)
189 log_error ("error allocating assuan context: %s\n", gpg_strerror (rc));
190 return rc;
193 restart:
194 infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
195 if (!infostr || !*infostr)
197 char *sockname;
199 /* First check whether we can connect at the standard
200 socket. */
201 sockname = make_filename (homedir, "S.gpg-agent", NULL);
202 rc = assuan_socket_connect (ctx, sockname, 0);
204 if (rc)
206 /* With no success start a new server. */
207 if (verbose)
208 log_info (_("no running gpg-agent - starting one\n"));
210 if (status_cb)
211 status_cb (status_cb_arg, STATUS_PROGRESS,
212 "starting_agent ? 0 0", NULL);
214 if (fflush (NULL))
216 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
217 log_error ("error flushing pending output: %s\n",
218 strerror (errno));
219 xfree (sockname);
220 assuan_release (ctx);
221 return tmperr;
224 if (!agent_program || !*agent_program)
225 agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
227 #ifdef HAVE_W32_SYSTEM
229 /* Under Windows we start the server in daemon mode. This
230 is because the default is to use the standard socket
231 and thus there is no need for the GPG_AGENT_INFO
232 envvar. This is possible as we don't have a real unix
233 domain socket but use a plain file and thus there is no
234 need to care about non-local file systems. */
235 const char *argv[3];
237 argv[0] = "--daemon";
238 argv[1] = "--use-standard-socket";
239 argv[2] = NULL;
241 rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
242 if (rc)
243 log_debug ("failed to start agent `%s': %s\n",
244 agent_program, gpg_strerror (rc));
245 else
247 /* Give the agent some time to prepare itself. */
248 gnupg_sleep (3);
249 /* Now try again to connect the agent. */
250 rc = assuan_socket_connect (ctx, sockname, 0);
253 #else /*!HAVE_W32_SYSTEM*/
255 const char *pgmname;
256 const char *argv[3];
257 int no_close_list[3];
258 int i;
260 if ( !(pgmname = strrchr (agent_program, '/')))
261 pgmname = agent_program;
262 else
263 pgmname++;
265 argv[0] = pgmname;
266 argv[1] = "--server";
267 argv[2] = NULL;
269 i=0;
270 if (log_get_fd () != -1)
271 no_close_list[i++] = log_get_fd ();
272 no_close_list[i++] = fileno (stderr);
273 no_close_list[i] = -1;
275 /* Connect to the agent and perform initial handshaking. */
276 rc = assuan_pipe_connect (ctx, agent_program, argv,
277 no_close_list);
279 #endif /*!HAVE_W32_SYSTEM*/
281 xfree (sockname);
283 else
285 int prot;
286 int pid;
288 infostr = xstrdup (infostr);
289 if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
291 log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
292 xfree (infostr);
293 force_pipe_server = 1;
294 goto restart;
296 *p++ = 0;
297 pid = atoi (p);
298 while (*p && *p != PATHSEP_C)
299 p++;
300 prot = *p? atoi (p+1) : 0;
301 if (prot != 1)
303 log_error (_("gpg-agent protocol version %d is not supported\n"),
304 prot);
305 xfree (infostr);
306 force_pipe_server = 1;
307 goto restart;
310 rc = assuan_socket_connect (ctx, infostr, pid);
311 xfree (infostr);
312 if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
314 log_info (_("can't connect to the agent - trying fall back\n"));
315 force_pipe_server = 1;
316 goto restart;
320 if (rc)
322 log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
323 assuan_release (ctx);
324 return gpg_error (GPG_ERR_NO_AGENT);
327 if (debug)
328 log_debug ("connection to agent established\n");
330 rc = assuan_transact (ctx, "RESET",
331 NULL, NULL, NULL, NULL, NULL, NULL);
332 if (!rc)
333 rc = send_pinentry_environment (ctx, errsource,
334 opt_lc_ctype, opt_lc_messages,
335 session_env);
336 if (rc)
338 assuan_release (ctx);
339 return rc;
342 *r_ctx = ctx;
343 return 0;