2008-05-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / simple-pwquery.c
blob3a1f0365f327f5a0c78230783ad5c12d9544be99
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 <http://www.gnu.org/licenses/>.
20 /* This module is intended as a standalone client implementation to
21 gpg-agent's GET_PASSPHRASE command. In particular it does not use
22 the Assuan library and can only cope with an already running
23 gpg-agent. Some stuff is configurable in the header file. */
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <stdlib.h>
29 #include <stddef.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #ifdef HAVE_W32_SYSTEM
34 #include <winsock2.h>
35 #else
36 #include <sys/socket.h>
37 #include <sys/un.h>
38 #endif
39 #ifdef HAVE_LOCALE_H
40 #include <locale.h>
41 #endif
42 #ifdef HAVE_W32_SYSTEM
43 #include "../jnlib/w32-afunix.h"
44 #endif
47 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
48 #include "simple-pwquery.h"
50 #if defined(SPWQ_USE_LOGGING) && !defined(HAVE_JNLIB_LOGGING)
51 # undef SPWQ_USE_LOGGING
52 #endif
54 #ifndef _
55 #define _(a) (a)
56 #endif
58 #if !defined (hexdigitp) && !defined (xtoi_2)
59 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
60 #define hexdigitp(a) (digitp (a) \
61 || (*(a) >= 'A' && *(a) <= 'F') \
62 || (*(a) >= 'a' && *(a) <= 'f'))
63 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
64 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
65 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
66 #endif
69 /* Name of the socket to be used if GPG_AGENT_INFO has not been
70 set. No default socket is used if this is NULL. */
71 static char *default_gpg_agent_info;
78 #ifndef HAVE_STPCPY
79 static char *
80 my_stpcpy(char *a,const char *b)
82 while( *b )
83 *a++ = *b++;
84 *a = 0;
86 return (char*)a;
88 #define stpcpy(a,b) my_stpcpy((a), (b))
89 #endif
93 /* Write NBYTES of BUF to file descriptor FD. */
94 static int
95 writen (int fd, const void *buf, size_t nbytes)
97 size_t nleft = nbytes;
98 int nwritten;
100 while (nleft > 0)
102 #ifdef HAVE_W32_SYSTEM
103 nwritten = send (fd, buf, nleft, 0);
104 #else
105 nwritten = write (fd, buf, nleft);
106 #endif
107 if (nwritten < 0)
109 if (errno == EINTR)
110 nwritten = 0;
111 else {
112 #ifdef SPWQ_USE_LOGGING
113 log_error ("write failed: %s\n", strerror (errno));
114 #endif
115 return SPWQ_IO_ERROR;
118 nleft -= nwritten;
119 buf = (const char*)buf + nwritten;
122 return 0;
126 /* Read an entire line and return number of bytes read. */
127 static int
128 readline (int fd, char *buf, size_t buflen)
130 size_t nleft = buflen;
131 char *p;
132 int nread = 0;
134 while (nleft > 0)
136 #ifdef HAVE_W32_SYSTEM
137 int n = recv (fd, buf, nleft, 0);
138 #else
139 int n = read (fd, buf, nleft);
140 #endif
141 if (n < 0)
143 if (errno == EINTR)
144 continue;
145 return -(SPWQ_IO_ERROR);
147 else if (!n)
149 return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
151 p = buf;
152 nleft -= n;
153 buf += n;
154 nread += n;
156 for (; n && *p != '\n'; n--, p++)
158 if (n)
160 break; /* At least one full line available - that's enough.
161 This function is just a simple implementation, so
162 it is okay to forget about pending bytes. */
166 return nread;
170 /* Send an option to the agent */
171 static int
172 agent_send_option (int fd, const char *name, const char *value)
174 char buf[200];
175 int nread;
176 char *line;
177 int i;
179 line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
180 if (!line)
181 return SPWQ_OUT_OF_CORE;
182 strcpy (stpcpy (stpcpy (stpcpy (
183 stpcpy (line, "OPTION "), name), "="), value), "\n");
184 i = writen (fd, line, strlen (line));
185 spwq_free (line);
186 if (i)
187 return i;
189 /* get response */
190 nread = readline (fd, buf, DIM(buf)-1);
191 if (nread < 0)
192 return -nread;
193 if (nread < 3)
194 return SPWQ_PROTOCOL_ERROR;
196 if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
197 return 0; /* okay */
199 return SPWQ_ERR_RESPONSE;
203 /* Send all available options to the agent. */
204 static int
205 agent_send_all_options (int fd)
207 char *dft_display = NULL;
208 char *dft_ttyname = NULL;
209 char *dft_ttytype = NULL;
210 char *dft_xauthority = NULL;
211 char *dft_pinentry_user_data = NULL;
212 int rc = 0;
214 dft_display = getenv ("DISPLAY");
215 if (dft_display)
217 if ((rc = agent_send_option (fd, "display", dft_display)))
218 return rc;
221 dft_ttyname = getenv ("GPG_TTY");
222 #ifndef HAVE_W32_SYSTEM
223 if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
224 dft_ttyname = ttyname (0);
225 #endif
226 if (dft_ttyname && *dft_ttyname)
228 if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
229 return rc;
232 dft_ttytype = getenv ("TERM");
233 if (dft_ttyname && dft_ttytype)
235 if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
236 return rc;
239 #if defined(HAVE_SETLOCALE)
241 char *old_lc = NULL;
242 char *dft_lc = NULL;
244 #if defined(LC_CTYPE)
245 old_lc = setlocale (LC_CTYPE, NULL);
246 if (old_lc)
248 char *p = spwq_malloc (strlen (old_lc)+1);
249 if (!p)
250 return SPWQ_OUT_OF_CORE;
251 strcpy (p, old_lc);
252 old_lc = p;
254 dft_lc = setlocale (LC_CTYPE, "");
255 if (dft_ttyname && dft_lc)
256 rc = agent_send_option (fd, "lc-ctype", dft_lc);
257 if (old_lc)
259 setlocale (LC_CTYPE, old_lc);
260 spwq_free (old_lc);
262 if (rc)
263 return rc;
264 #endif
266 #if defined(LC_MESSAGES)
267 old_lc = setlocale (LC_MESSAGES, NULL);
268 if (old_lc)
270 char *p = spwq_malloc (strlen (old_lc)+1);
271 if (!p)
272 return SPWQ_OUT_OF_CORE;
273 strcpy (p, old_lc);
274 old_lc = p;
276 dft_lc = setlocale (LC_MESSAGES, "");
277 if (dft_ttyname && dft_lc)
278 rc = agent_send_option (fd, "lc-messages", dft_lc);
279 if (old_lc)
281 setlocale (LC_MESSAGES, old_lc);
282 spwq_free (old_lc);
284 if (rc)
285 return rc;
286 #endif
288 #endif /*HAVE_SETLOCALE*/
290 /* Send the XAUTHORITY variable. */
291 dft_xauthority = getenv ("XAUTHORITY");
292 if (dft_xauthority)
294 /* We ignore errors here because older gpg-agents don't support
295 this option. */
296 agent_send_option (fd, "xauthority", dft_xauthority);
299 /* Send the PINENTRY_USER_DATA variable. */
300 dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
301 if (dft_pinentry_user_data)
303 /* We ignore errors here because older gpg-agents don't support
304 this option. */
305 agent_send_option (fd, "pinentry-user-data", dft_pinentry_user_data);
308 return 0;
313 /* Try to open a connection to the agent, send all options and return
314 the file descriptor for the connection. Return -1 in case of
315 error. */
316 static int
317 agent_open (int *rfd)
319 int rc;
320 int fd;
321 char *infostr, *p;
322 struct sockaddr_un client_addr;
323 size_t len;
324 int prot;
325 char line[200];
326 int nread;
328 *rfd = -1;
329 infostr = getenv ( "GPG_AGENT_INFO" );
330 if ( !infostr || !*infostr )
331 infostr = default_gpg_agent_info;
332 if ( !infostr || !*infostr )
334 #ifdef SPWQ_USE_LOGGING
335 log_error (_("gpg-agent is not available in this session\n"));
336 #endif
337 return SPWQ_NO_AGENT;
339 p = spwq_malloc (strlen (infostr)+1);
340 if (!p)
341 return SPWQ_OUT_OF_CORE;
342 strcpy (p, infostr);
343 infostr = p;
345 if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr
346 || (p-infostr)+1 >= sizeof client_addr.sun_path )
348 #ifdef SPWQ_USE_LOGGING
349 log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
350 #endif
351 return SPWQ_NO_AGENT;
353 *p++ = 0;
355 while (*p && *p != PATHSEP_C)
356 p++;
357 prot = *p? atoi (p+1) : 0;
358 if ( prot != 1)
360 #ifdef SPWQ_USE_LOGGING
361 log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
362 #endif
363 return SPWQ_PROTOCOL_ERROR;
366 #ifdef HAVE_W32_SYSTEM
367 fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
368 #else
369 fd = socket (AF_UNIX, SOCK_STREAM, 0);
370 #endif
371 if (fd == -1)
373 #ifdef SPWQ_USE_LOGGING
374 log_error ("can't create socket: %s\n", strerror(errno) );
375 #endif
376 return SPWQ_SYS_ERROR;
379 memset (&client_addr, 0, sizeof client_addr);
380 client_addr.sun_family = AF_UNIX;
381 strcpy (client_addr.sun_path, infostr);
382 len = (offsetof (struct sockaddr_un, sun_path)
383 + strlen(client_addr.sun_path) + 1);
385 #ifdef HAVE_W32_SYSTEM
386 rc = _w32_sock_connect (fd, (struct sockaddr*)&client_addr, len );
387 #else
388 rc = connect (fd, (struct sockaddr*)&client_addr, len );
389 #endif
390 if (rc == -1)
392 #ifdef SPWQ_USE_LOGGING
393 log_error ( _("can't connect to `%s': %s\n"), infostr, strerror (errno));
394 #endif
395 close (fd );
396 return SPWQ_IO_ERROR;
399 nread = readline (fd, line, DIM(line));
400 if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
401 && (line[2] == '\n' || line[2] == ' ')) )
403 #ifdef SPWQ_USE_LOGGING
404 log_error ( _("communication problem with gpg-agent\n"));
405 #endif
406 close (fd );
407 return SPWQ_PROTOCOL_ERROR;
410 rc = agent_send_all_options (fd);
411 if (rc)
413 #ifdef SPWQ_USE_LOGGING
414 log_error (_("problem setting the gpg-agent options\n"));
415 #endif
416 close (fd);
417 return rc;
420 *rfd = fd;
421 return 0;
425 /* Copy text to BUFFER and escape as required. Return a pointer to
426 the end of the new buffer. Note that BUFFER must be large enough
427 to keep the entire text; allocataing it 3 times the size of TEXT
428 is sufficient. */
429 static char *
430 copy_and_escape (char *buffer, const char *text)
432 int i;
433 const unsigned char *s = (unsigned char *)text;
434 char *p = buffer;
437 for (i=0; s[i]; i++)
439 if (s[i] < ' ' || s[i] == '+')
441 sprintf (p, "%%%02X", s[i]);
442 p += 3;
444 else if (s[i] == ' ')
445 *p++ = '+';
446 else
447 *p++ = s[i];
449 return p;
453 /* Set the name of the default socket to NAME. */
454 int
455 simple_pw_set_socket (const char *name)
457 spwq_free (default_gpg_agent_info);
458 if (name)
460 default_gpg_agent_info = spwq_malloc (strlen (name) + 4 + 1);
461 if (!default_gpg_agent_info)
462 return SPWQ_OUT_OF_CORE;
463 /* We don't know the PID thus we use 0. */
464 strcpy (stpcpy (default_gpg_agent_info, name),
465 PATHSEP_S "0" PATHSEP_S "1");
467 else
468 default_gpg_agent_info = NULL;
470 return 0;
474 /* Ask the gpg-agent for a passphrase and present the user with a
475 DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
476 If a CACHEID is not NULL it is used to locate the passphrase in in
477 the cache and store it under this ID. If OPT_CHECK is true
478 gpg-agent is asked to apply some checks on the passphrase security.
479 If ERRORCODE is not NULL it should point a variable receiving an
480 errorcode; this error code might be 0 if the user canceled the
481 operation. The function returns NULL to indicate an error. */
482 char *
483 simple_pwquery (const char *cacheid,
484 const char *tryagain,
485 const char *prompt,
486 const char *description,
487 int opt_check,
488 int *errorcode)
490 int fd = -1;
491 int nread;
492 char *result = NULL;
493 char *pw = NULL;
494 char *p;
495 int rc, i;
497 rc = agent_open (&fd);
498 if (rc)
499 goto leave;
501 if (!cacheid)
502 cacheid = "X";
503 if (!tryagain)
504 tryagain = "X";
505 if (!prompt)
506 prompt = "X";
507 if (!description)
508 description = "X";
511 char *line;
512 /* We allocate 3 times the needed space so that there is enough
513 space for escaping. */
514 line = spwq_malloc (15 + 10
515 + 3*strlen (cacheid) + 1
516 + 3*strlen (tryagain) + 1
517 + 3*strlen (prompt) + 1
518 + 3*strlen (description) + 1
519 + 2);
520 if (!line)
522 rc = SPWQ_OUT_OF_CORE;
523 goto leave;
525 strcpy (line, "GET_PASSPHRASE ");
526 p = line+15;
527 if (opt_check)
528 p = stpcpy (p, "--check ");
529 p = copy_and_escape (p, cacheid);
530 *p++ = ' ';
531 p = copy_and_escape (p, tryagain);
532 *p++ = ' ';
533 p = copy_and_escape (p, prompt);
534 *p++ = ' ';
535 p = copy_and_escape (p, description);
536 *p++ = '\n';
537 rc = writen (fd, line, p - line);
538 spwq_free (line);
539 if (rc)
540 goto leave;
543 /* get response */
544 pw = spwq_secure_malloc (500);
545 nread = readline (fd, pw, 499);
546 if (nread < 0)
548 rc = -nread;
549 goto leave;
551 if (nread < 3)
553 rc = SPWQ_PROTOCOL_ERROR;
554 goto leave;
557 if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
558 { /* we got a passphrase - convert it back from hex */
559 size_t pwlen = 0;
561 for (i=3; i < nread && hexdigitp (pw+i); i+=2)
562 pw[pwlen++] = xtoi_2 (pw+i);
563 pw[pwlen] = 0; /* make a C String */
564 result = pw;
565 pw = NULL;
567 else if ((nread > 7 && !memcmp (pw, "ERR 111", 7)
568 && (pw[7] == ' ' || pw[7] == '\n') )
569 || ((nread > 4 && !memcmp (pw, "ERR ", 4)
570 && (strtoul (pw+4, NULL, 0) & 0xffff) == 99)) )
572 /* 111 is the old Assuan code for canceled which might still
573 be in use by old installations. 99 is GPG_ERR_CANCELED as
574 used by modern gpg-agents; 0xffff is used to mask out the
575 error source. */
576 #ifdef SPWQ_USE_LOGGING
577 log_info (_("canceled by user\n") );
578 #endif
579 *errorcode = 0; /* Special error code to indicate Cancel. */
581 else if (nread > 4 && !memcmp (pw, "ERR ", 4))
583 switch ( (strtoul (pw+4, NULL, 0) & 0xffff) )
585 case 85: rc = SPWQ_NO_PIN_ENTRY; break;
586 default: rc = SPWQ_GENERAL_ERROR; break;
589 else
591 #ifdef SPWQ_USE_LOGGING
592 log_error (_("problem with the agent\n"));
593 #endif
594 rc = SPWQ_ERR_RESPONSE;
597 leave:
598 if (errorcode)
599 *errorcode = rc;
600 if (fd != -1)
601 close (fd);
602 if (pw)
603 spwq_secure_free (pw);
604 return result;
608 /* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */
610 simple_pwclear (const char *cacheid)
612 char line[500];
613 char *p;
615 /* We need not more than 50 characters for the command and the
616 terminating nul. */
617 if (strlen (cacheid) * 3 > sizeof (line) - 50)
618 return SPWQ_PROTOCOL_ERROR;
620 strcpy (line, "CLEAR_PASSPHRASE ");
621 p = line + 17;
622 p = copy_and_escape (p, cacheid);
623 *p++ = '\n';
624 *p++ = '\0';
626 return simple_query (line);
630 /* Perform the simple query QUERY (which must be new-line and 0
631 terminated) and return the error code. */
633 simple_query (const char *query)
635 int fd = -1;
636 int nread;
637 char response[500];
638 int rc;
640 rc = agent_open (&fd);
641 if (rc)
642 goto leave;
644 rc = writen (fd, query, strlen (query));
645 if (rc)
646 goto leave;
648 /* get response */
649 nread = readline (fd, response, 499);
650 if (nread < 0)
652 rc = -nread;
653 goto leave;
655 if (nread < 3)
657 rc = SPWQ_PROTOCOL_ERROR;
658 goto leave;
661 if (response[0] == 'O' && response[1] == 'K')
662 /* OK, do nothing. */;
663 else if ((nread > 7 && !memcmp (response, "ERR 111", 7)
664 && (response[7] == ' ' || response[7] == '\n') )
665 || ((nread > 4 && !memcmp (response, "ERR ", 4)
666 && (strtoul (response+4, NULL, 0) & 0xffff) == 99)) )
668 /* 111 is the old Assuan code for canceled which might still
669 be in use by old installations. 99 is GPG_ERR_CANCELED as
670 used by modern gpg-agents; 0xffff is used to mask out the
671 error source. */
672 #ifdef SPWQ_USE_LOGGING
673 log_info (_("canceled by user\n") );
674 #endif
676 else
678 #ifdef SPWQ_USE_LOGGING
679 log_error (_("problem with the agent\n"));
680 #endif
681 rc = SPWQ_ERR_RESPONSE;
684 leave:
685 if (fd != -1)
686 close (fd);
687 return rc;