1 /* simple-pwquery.c - A simple password query client for gpg-agent
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 <https://www.gnu.org/licenses/>.
20 /* This module is intended as a simple client implementation to
21 gpg-agent's GET_PASSPHRASE command. It can only cope with an
22 already running gpg-agent. Some stuff is configurable in the
34 #ifdef HAVE_W32_SYSTEM
37 #include <sys/socket.h>
44 #define GNUPG_COMMON_NEED_AFLOCAL
45 #include "../common/mischelp.h"
50 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
51 #include "simple-pwquery.h"
53 #define SPWQ_OUT_OF_CORE gpg_error_from_errno (ENOMEM)
54 #define SPWQ_IO_ERROR gpg_error_from_errno (EIO)
55 #define SPWQ_PROTOCOL_ERROR gpg_error (GPG_ERR_PROTOCOL_VIOLATION)
56 #define SPWQ_ERR_RESPONSE gpg_error (GPG_ERR_INV_RESPONSE)
57 #define SPWQ_NO_AGENT gpg_error (GPG_ERR_NO_AGENT)
58 #define SPWQ_SYS_ERROR gpg_error_from_syserror ()
59 #define SPWQ_GENERAL_ERROR gpg_error (GPG_ERR_GENERAL)
60 #define SPWQ_NO_PIN_ENTRY gpg_error (GPG_ERR_NO_PIN_ENTRY)
66 #if !defined (hexdigitp) && !defined (xtoi_2)
67 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
68 #define hexdigitp(a) (digitp (a) \
69 || (*(a) >= 'A' && *(a) <= 'F') \
70 || (*(a) >= 'a' && *(a) <= 'f'))
71 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
72 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
73 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
77 /* Name of the socket to be used. This is a kludge to keep on using
78 the existsing code despite that we only support a standard socket. */
79 static char *default_gpg_agent_info;
87 my_stpcpy(char *a,const char *b)
95 #define stpcpy(a,b) my_stpcpy((a), (b))
99 /* Send an option to the agent */
101 agent_send_option (assuan_context_t ctx, const char *name, const char *value)
106 line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
108 return SPWQ_OUT_OF_CORE;
109 strcpy (stpcpy (stpcpy (stpcpy (
110 stpcpy (line, "OPTION "), name), "="), value), "\n");
112 err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
119 /* Send all available options to the agent. */
121 agent_send_all_options (assuan_context_t ctx)
123 char *dft_display = NULL;
124 char *dft_ttyname = NULL;
125 char *dft_ttytype = NULL;
126 char *dft_xauthority = NULL;
127 char *dft_pinentry_user_data = NULL;
130 dft_display = getenv ("DISPLAY");
133 if ((rc = agent_send_option (ctx, "display", dft_display)))
137 dft_ttyname = getenv ("GPG_TTY");
138 #if !defined(HAVE_W32_SYSTEM) && !defined(HAVE_BROKEN_TTYNAME)
139 if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
140 dft_ttyname = ttyname (0);
142 if (dft_ttyname && *dft_ttyname)
144 if ((rc=agent_send_option (ctx, "ttyname", dft_ttyname)))
148 dft_ttytype = getenv ("TERM");
149 if (dft_ttyname && dft_ttytype)
151 if ((rc = agent_send_option (ctx, "ttytype", dft_ttytype)))
155 #if defined(HAVE_SETLOCALE)
160 #if defined(LC_CTYPE)
161 old_lc = setlocale (LC_CTYPE, NULL);
164 char *p = spwq_malloc (strlen (old_lc)+1);
166 return SPWQ_OUT_OF_CORE;
170 dft_lc = setlocale (LC_CTYPE, "");
171 if (dft_ttyname && dft_lc)
172 rc = agent_send_option (ctx, "lc-ctype", dft_lc);
175 setlocale (LC_CTYPE, old_lc);
182 #if defined(LC_MESSAGES)
183 old_lc = setlocale (LC_MESSAGES, NULL);
186 char *p = spwq_malloc (strlen (old_lc)+1);
188 return SPWQ_OUT_OF_CORE;
192 dft_lc = setlocale (LC_MESSAGES, "");
193 if (dft_ttyname && dft_lc)
194 rc = agent_send_option (ctx, "lc-messages", dft_lc);
197 setlocale (LC_MESSAGES, old_lc);
204 #endif /*HAVE_SETLOCALE*/
206 /* Send the XAUTHORITY variable. */
207 dft_xauthority = getenv ("XAUTHORITY");
210 /* We ignore errors here because older gpg-agents don't support
212 agent_send_option (ctx, "xauthority", dft_xauthority);
215 /* Send the PINENTRY_USER_DATA variable. */
216 dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
217 if (dft_pinentry_user_data)
219 /* We ignore errors here because older gpg-agents don't support
221 agent_send_option (ctx, "pinentry-user-data", dft_pinentry_user_data);
224 /* Tell the agent that we support Pinentry notifications. No
225 error checking so that it will work with older agents. */
226 assuan_transact (ctx, "OPTION allow-pinentry-notify",
227 NULL, NULL, NULL, NULL, NULL, NULL);
234 /* Try to open a connection to the agent, send all options and return
235 the file descriptor for the connection. Return -1 in case of
238 agent_open (assuan_context_t *ctx)
243 infostr = default_gpg_agent_info;
244 if ( !infostr || !*infostr )
246 #ifdef SPWQ_USE_LOGGING
247 log_error (_("no gpg-agent running in this session\n"));
249 return SPWQ_NO_AGENT;
252 rc = assuan_new (ctx);
256 rc = assuan_socket_connect (*ctx, infostr, 0, 0);
259 #ifdef SPWQ_USE_LOGGING
260 log_error (_("can't connect to '%s': %s\n"),
261 infostr, gpg_strerror (rc));
266 rc = agent_send_all_options (*ctx);
269 #ifdef SPWQ_USE_LOGGING
270 log_error (_("problem setting the gpg-agent options\n"));
278 assuan_release (*ctx);
284 /* Copy text to BUFFER and escape as required. Return a pointer to
285 the end of the new buffer. Note that BUFFER must be large enough
286 to keep the entire text; allocataing it 3 times the size of TEXT
289 copy_and_escape (char *buffer, const char *text)
292 const unsigned char *s = (unsigned char *)text;
298 if (s[i] < ' ' || s[i] == '+')
300 sprintf (p, "%%%02X", s[i]);
303 else if (s[i] == ' ')
312 /* Set the name of the default socket to NAME. */
314 simple_pw_set_socket (const char *name)
316 spwq_free (default_gpg_agent_info);
317 default_gpg_agent_info = NULL;
320 default_gpg_agent_info = spwq_malloc (strlen (name) + 1);
321 if (!default_gpg_agent_info)
322 return SPWQ_OUT_OF_CORE;
323 strcpy (default_gpg_agent_info, name);
330 /* This is the default inquiry callback. It merely handles the
331 Pinentry notification. */
333 default_inq_cb (void *opaque, const char *line)
337 if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
339 gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
340 /* We do not return errors to avoid breaking other code. */
344 #ifdef SPWQ_USE_LOGGING
345 log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
353 /* Ask the gpg-agent for a passphrase and present the user with a
354 DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
355 If a CACHEID is not NULL it is used to locate the passphrase in in
356 the cache and store it under this ID. If OPT_CHECK is true
357 gpg-agent is asked to apply some checks on the passphrase security.
358 If ERRORCODE is not NULL it should point a variable receiving an
359 errorcode; this error code might be 0 if the user canceled the
360 operation. The function returns NULL to indicate an error. */
362 simple_pwquery (const char *cacheid,
363 const char *tryagain,
365 const char *description,
370 assuan_context_t ctx;
378 rc = agent_open (&ctx);
393 /* We allocate 3 times the needed space so that there is enough
394 space for escaping. */
395 line = spwq_malloc (15 + 10
396 + 3*strlen (cacheid) + 1
397 + 3*strlen (tryagain) + 1
398 + 3*strlen (prompt) + 1
399 + 3*strlen (description) + 1
403 rc = SPWQ_OUT_OF_CORE;
406 strcpy (line, "GET_PASSPHRASE ");
409 p = stpcpy (p, "--check ");
410 p = copy_and_escape (p, cacheid);
412 p = copy_and_escape (p, tryagain);
414 p = copy_and_escape (p, prompt);
416 p = copy_and_escape (p, description);
419 init_membuf_secure (&data, 64);
421 rc = assuan_transact (ctx, line, put_membuf_cb, &data,
422 default_inq_cb, NULL, NULL, NULL);
425 /* Older Pinentries return the old assuan error code for canceled
426 which gets translated by libassuan to GPG_ERR_ASS_CANCELED and
427 not to the code for a user cancel. Fix this here. */
428 if (rc && gpg_err_source (rc)
429 && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
430 rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
434 p = get_membuf (&data, &n);
441 put_membuf (&data, "", 1);
442 result = get_membuf (&data, NULL);
444 rc = gpg_error_from_syserror ();
451 assuan_release (ctx);
456 /* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */
458 simple_pwclear (const char *cacheid)
463 /* We need not more than 50 characters for the command and the
465 if (strlen (cacheid) * 3 > sizeof (line) - 50)
466 return SPWQ_PROTOCOL_ERROR;
468 strcpy (line, "CLEAR_PASSPHRASE ");
470 p = copy_and_escape (p, cacheid);
474 return simple_query (line);
478 /* Perform the simple query QUERY (which must be new-line and 0
479 terminated) and return the error code. */
481 simple_query (const char *query)
483 assuan_context_t ctx;
486 rc = agent_open (&ctx);
490 rc = assuan_transact (ctx, query, NULL, NULL, NULL, NULL, NULL, NULL);
492 assuan_release (ctx);