Fix last change
[gnupg.git] / common / simple-pwquery.c
blob3598b3598b4458dd39ed7e59077095ab1122b7f5
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
43 #define JNLIB_NEED_AFLOCAL
44 #include "../jnlib/mischelp.h"
45 #ifdef HAVE_W32_SYSTEM
46 #include "../jnlib/w32-afunix.h"
47 #endif
50 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
51 #include "simple-pwquery.h"
53 #if defined(SPWQ_USE_LOGGING) && !defined(HAVE_JNLIB_LOGGING)
54 # undef SPWQ_USE_LOGGING
55 #endif
57 #ifndef _
58 #define _(a) (a)
59 #endif
61 #if !defined (hexdigitp) && !defined (xtoi_2)
62 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
63 #define hexdigitp(a) (digitp (a) \
64 || (*(a) >= 'A' && *(a) <= 'F') \
65 || (*(a) >= 'a' && *(a) <= 'f'))
66 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
67 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
68 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
69 #endif
72 /* Name of the socket to be used if GPG_AGENT_INFO has not been
73 set. No default socket is used if this is NULL. */
74 static char *default_gpg_agent_info;
81 #ifndef HAVE_STPCPY
82 static char *
83 my_stpcpy(char *a,const char *b)
85 while( *b )
86 *a++ = *b++;
87 *a = 0;
89 return (char*)a;
91 #define stpcpy(a,b) my_stpcpy((a), (b))
92 #endif
96 /* Write NBYTES of BUF to file descriptor FD. */
97 static int
98 writen (int fd, const void *buf, size_t nbytes)
100 size_t nleft = nbytes;
101 int nwritten;
103 while (nleft > 0)
105 #ifdef HAVE_W32_SYSTEM
106 nwritten = send (fd, buf, nleft, 0);
107 #else
108 nwritten = write (fd, buf, nleft);
109 #endif
110 if (nwritten < 0)
112 if (errno == EINTR)
113 nwritten = 0;
114 else {
115 #ifdef SPWQ_USE_LOGGING
116 log_error ("write failed: %s\n", strerror (errno));
117 #endif
118 return SPWQ_IO_ERROR;
121 nleft -= nwritten;
122 buf = (const char*)buf + nwritten;
125 return 0;
129 /* Read an entire line and return number of bytes read. */
130 static int
131 readline (int fd, char *buf, size_t buflen)
133 size_t nleft = buflen;
134 char *p;
135 int nread = 0;
137 while (nleft > 0)
139 #ifdef HAVE_W32_SYSTEM
140 int n = recv (fd, buf, nleft, 0);
141 #else
142 int n = read (fd, buf, nleft);
143 #endif
144 if (n < 0)
146 if (errno == EINTR)
147 continue;
148 return -(SPWQ_IO_ERROR);
150 else if (!n)
152 return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
154 p = buf;
155 nleft -= n;
156 buf += n;
157 nread += n;
159 for (; n && *p != '\n'; n--, p++)
161 if (n)
163 break; /* At least one full line available - that's enough.
164 This function is just a simple implementation, so
165 it is okay to forget about pending bytes. */
169 return nread;
173 /* Send an option to the agent */
174 static int
175 agent_send_option (int fd, const char *name, const char *value)
177 char buf[200];
178 int nread;
179 char *line;
180 int i;
182 line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
183 if (!line)
184 return SPWQ_OUT_OF_CORE;
185 strcpy (stpcpy (stpcpy (stpcpy (
186 stpcpy (line, "OPTION "), name), "="), value), "\n");
187 i = writen (fd, line, strlen (line));
188 spwq_free (line);
189 if (i)
190 return i;
192 /* get response */
193 nread = readline (fd, buf, DIM(buf)-1);
194 if (nread < 0)
195 return -nread;
196 if (nread < 3)
197 return SPWQ_PROTOCOL_ERROR;
199 if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
200 return 0; /* okay */
202 return SPWQ_ERR_RESPONSE;
206 /* Send all available options to the agent. */
207 static int
208 agent_send_all_options (int fd)
210 char *dft_display = NULL;
211 char *dft_ttyname = NULL;
212 char *dft_ttytype = NULL;
213 char *dft_xauthority = NULL;
214 char *dft_pinentry_user_data = NULL;
215 int rc = 0;
217 dft_display = getenv ("DISPLAY");
218 if (dft_display)
220 if ((rc = agent_send_option (fd, "display", dft_display)))
221 return rc;
224 dft_ttyname = getenv ("GPG_TTY");
225 #ifndef HAVE_W32_SYSTEM
226 if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
227 dft_ttyname = ttyname (0);
228 #endif
229 if (dft_ttyname && *dft_ttyname)
231 if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
232 return rc;
235 dft_ttytype = getenv ("TERM");
236 if (dft_ttyname && dft_ttytype)
238 if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
239 return rc;
242 #if defined(HAVE_SETLOCALE)
244 char *old_lc = NULL;
245 char *dft_lc = NULL;
247 #if defined(LC_CTYPE)
248 old_lc = setlocale (LC_CTYPE, NULL);
249 if (old_lc)
251 char *p = spwq_malloc (strlen (old_lc)+1);
252 if (!p)
253 return SPWQ_OUT_OF_CORE;
254 strcpy (p, old_lc);
255 old_lc = p;
257 dft_lc = setlocale (LC_CTYPE, "");
258 if (dft_ttyname && dft_lc)
259 rc = agent_send_option (fd, "lc-ctype", dft_lc);
260 if (old_lc)
262 setlocale (LC_CTYPE, old_lc);
263 spwq_free (old_lc);
265 if (rc)
266 return rc;
267 #endif
269 #if defined(LC_MESSAGES)
270 old_lc = setlocale (LC_MESSAGES, NULL);
271 if (old_lc)
273 char *p = spwq_malloc (strlen (old_lc)+1);
274 if (!p)
275 return SPWQ_OUT_OF_CORE;
276 strcpy (p, old_lc);
277 old_lc = p;
279 dft_lc = setlocale (LC_MESSAGES, "");
280 if (dft_ttyname && dft_lc)
281 rc = agent_send_option (fd, "lc-messages", dft_lc);
282 if (old_lc)
284 setlocale (LC_MESSAGES, old_lc);
285 spwq_free (old_lc);
287 if (rc)
288 return rc;
289 #endif
291 #endif /*HAVE_SETLOCALE*/
293 /* Send the XAUTHORITY variable. */
294 dft_xauthority = getenv ("XAUTHORITY");
295 if (dft_xauthority)
297 /* We ignore errors here because older gpg-agents don't support
298 this option. */
299 agent_send_option (fd, "xauthority", dft_xauthority);
302 /* Send the PINENTRY_USER_DATA variable. */
303 dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
304 if (dft_pinentry_user_data)
306 /* We ignore errors here because older gpg-agents don't support
307 this option. */
308 agent_send_option (fd, "pinentry-user-data", dft_pinentry_user_data);
311 return 0;
316 /* Try to open a connection to the agent, send all options and return
317 the file descriptor for the connection. Return -1 in case of
318 error. */
319 static int
320 agent_open (int *rfd)
322 int rc;
323 int fd;
324 char *infostr, *p;
325 struct sockaddr_un client_addr;
326 size_t len;
327 int prot;
328 char line[200];
329 int nread;
331 *rfd = -1;
332 infostr = getenv ( "GPG_AGENT_INFO" );
333 if ( !infostr || !*infostr )
334 infostr = default_gpg_agent_info;
335 if ( !infostr || !*infostr )
337 #ifdef SPWQ_USE_LOGGING
338 log_error (_("gpg-agent is not available in this session\n"));
339 #endif
340 return SPWQ_NO_AGENT;
342 p = spwq_malloc (strlen (infostr)+1);
343 if (!p)
344 return SPWQ_OUT_OF_CORE;
345 strcpy (p, infostr);
346 infostr = p;
348 if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr
349 || (p-infostr)+1 >= sizeof client_addr.sun_path )
351 #ifdef SPWQ_USE_LOGGING
352 log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
353 #endif
354 return SPWQ_NO_AGENT;
356 *p++ = 0;
358 while (*p && *p != PATHSEP_C)
359 p++;
360 prot = *p? atoi (p+1) : 0;
361 if ( prot != 1)
363 #ifdef SPWQ_USE_LOGGING
364 log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
365 #endif
366 return SPWQ_PROTOCOL_ERROR;
369 #ifdef HAVE_W32_SYSTEM
370 fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
371 #else
372 fd = socket (AF_UNIX, SOCK_STREAM, 0);
373 #endif
374 if (fd == -1)
376 #ifdef SPWQ_USE_LOGGING
377 log_error ("can't create socket: %s\n", strerror(errno) );
378 #endif
379 return SPWQ_SYS_ERROR;
382 memset (&client_addr, 0, sizeof client_addr);
383 client_addr.sun_family = AF_UNIX;
384 strcpy (client_addr.sun_path, infostr);
385 len = SUN_LEN (&client_addr);
387 #ifdef HAVE_W32_SYSTEM
388 rc = _w32_sock_connect (fd, (struct sockaddr*)&client_addr, len );
389 #else
390 rc = connect (fd, (struct sockaddr*)&client_addr, len );
391 #endif
392 if (rc == -1)
394 #ifdef SPWQ_USE_LOGGING
395 log_error ( _("can't connect to `%s': %s\n"), infostr, strerror (errno));
396 #endif
397 close (fd );
398 return SPWQ_IO_ERROR;
401 nread = readline (fd, line, DIM(line));
402 if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
403 && (line[2] == '\n' || line[2] == ' ')) )
405 #ifdef SPWQ_USE_LOGGING
406 log_error ( _("communication problem with gpg-agent\n"));
407 #endif
408 close (fd );
409 return SPWQ_PROTOCOL_ERROR;
412 rc = agent_send_all_options (fd);
413 if (rc)
415 #ifdef SPWQ_USE_LOGGING
416 log_error (_("problem setting the gpg-agent options\n"));
417 #endif
418 close (fd);
419 return rc;
422 *rfd = fd;
423 return 0;
427 /* Copy text to BUFFER and escape as required. Return a pointer to
428 the end of the new buffer. Note that BUFFER must be large enough
429 to keep the entire text; allocataing it 3 times the size of TEXT
430 is sufficient. */
431 static char *
432 copy_and_escape (char *buffer, const char *text)
434 int i;
435 const unsigned char *s = (unsigned char *)text;
436 char *p = buffer;
439 for (i=0; s[i]; i++)
441 if (s[i] < ' ' || s[i] == '+')
443 sprintf (p, "%%%02X", s[i]);
444 p += 3;
446 else if (s[i] == ' ')
447 *p++ = '+';
448 else
449 *p++ = s[i];
451 return p;
455 /* Set the name of the default socket to NAME. */
456 int
457 simple_pw_set_socket (const char *name)
459 spwq_free (default_gpg_agent_info);
460 if (name)
462 default_gpg_agent_info = spwq_malloc (strlen (name) + 4 + 1);
463 if (!default_gpg_agent_info)
464 return SPWQ_OUT_OF_CORE;
465 /* We don't know the PID thus we use 0. */
466 strcpy (stpcpy (default_gpg_agent_info, name),
467 PATHSEP_S "0" PATHSEP_S "1");
469 else
470 default_gpg_agent_info = NULL;
472 return 0;
476 /* Ask the gpg-agent for a passphrase and present the user with a
477 DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
478 If a CACHEID is not NULL it is used to locate the passphrase in in
479 the cache and store it under this ID. If OPT_CHECK is true
480 gpg-agent is asked to apply some checks on the passphrase security.
481 If ERRORCODE is not NULL it should point a variable receiving an
482 errorcode; this error code might be 0 if the user canceled the
483 operation. The function returns NULL to indicate an error. */
484 char *
485 simple_pwquery (const char *cacheid,
486 const char *tryagain,
487 const char *prompt,
488 const char *description,
489 int opt_check,
490 int *errorcode)
492 int fd = -1;
493 int nread;
494 char *result = NULL;
495 char *pw = NULL;
496 char *p;
497 int rc, i;
499 rc = agent_open (&fd);
500 if (rc)
501 goto leave;
503 if (!cacheid)
504 cacheid = "X";
505 if (!tryagain)
506 tryagain = "X";
507 if (!prompt)
508 prompt = "X";
509 if (!description)
510 description = "X";
513 char *line;
514 /* We allocate 3 times the needed space so that there is enough
515 space for escaping. */
516 line = spwq_malloc (15 + 10
517 + 3*strlen (cacheid) + 1
518 + 3*strlen (tryagain) + 1
519 + 3*strlen (prompt) + 1
520 + 3*strlen (description) + 1
521 + 2);
522 if (!line)
524 rc = SPWQ_OUT_OF_CORE;
525 goto leave;
527 strcpy (line, "GET_PASSPHRASE ");
528 p = line+15;
529 if (opt_check)
530 p = stpcpy (p, "--check ");
531 p = copy_and_escape (p, cacheid);
532 *p++ = ' ';
533 p = copy_and_escape (p, tryagain);
534 *p++ = ' ';
535 p = copy_and_escape (p, prompt);
536 *p++ = ' ';
537 p = copy_and_escape (p, description);
538 *p++ = '\n';
539 rc = writen (fd, line, p - line);
540 spwq_free (line);
541 if (rc)
542 goto leave;
545 /* get response */
546 pw = spwq_secure_malloc (500);
547 nread = readline (fd, pw, 499);
548 if (nread < 0)
550 rc = -nread;
551 goto leave;
553 if (nread < 3)
555 rc = SPWQ_PROTOCOL_ERROR;
556 goto leave;
559 if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
560 { /* we got a passphrase - convert it back from hex */
561 size_t pwlen = 0;
563 for (i=3; i < nread && hexdigitp (pw+i); i+=2)
564 pw[pwlen++] = xtoi_2 (pw+i);
565 pw[pwlen] = 0; /* make a C String */
566 result = pw;
567 pw = NULL;
569 else if ((nread > 7 && !memcmp (pw, "ERR 111", 7)
570 && (pw[7] == ' ' || pw[7] == '\n') )
571 || ((nread > 4 && !memcmp (pw, "ERR ", 4)
572 && (strtoul (pw+4, NULL, 0) & 0xffff) == 99)) )
574 /* 111 is the old Assuan code for canceled which might still
575 be in use by old installations. 99 is GPG_ERR_CANCELED as
576 used by modern gpg-agents; 0xffff is used to mask out the
577 error source. */
578 #ifdef SPWQ_USE_LOGGING
579 log_info (_("canceled by user\n") );
580 #endif
581 *errorcode = 0; /* Special error code to indicate Cancel. */
583 else if (nread > 4 && !memcmp (pw, "ERR ", 4))
585 switch ( (strtoul (pw+4, NULL, 0) & 0xffff) )
587 case 85: rc = SPWQ_NO_PIN_ENTRY; break;
588 default: rc = SPWQ_GENERAL_ERROR; break;
591 else
593 #ifdef SPWQ_USE_LOGGING
594 log_error (_("problem with the agent\n"));
595 #endif
596 rc = SPWQ_ERR_RESPONSE;
599 leave:
600 if (errorcode)
601 *errorcode = rc;
602 if (fd != -1)
603 close (fd);
604 if (pw)
605 spwq_secure_free (pw);
606 return result;
610 /* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */
612 simple_pwclear (const char *cacheid)
614 char line[500];
615 char *p;
617 /* We need not more than 50 characters for the command and the
618 terminating nul. */
619 if (strlen (cacheid) * 3 > sizeof (line) - 50)
620 return SPWQ_PROTOCOL_ERROR;
622 strcpy (line, "CLEAR_PASSPHRASE ");
623 p = line + 17;
624 p = copy_and_escape (p, cacheid);
625 *p++ = '\n';
626 *p++ = '\0';
628 return simple_query (line);
632 /* Perform the simple query QUERY (which must be new-line and 0
633 terminated) and return the error code. */
635 simple_query (const char *query)
637 int fd = -1;
638 int nread;
639 char response[500];
640 int rc;
642 rc = agent_open (&fd);
643 if (rc)
644 goto leave;
646 rc = writen (fd, query, strlen (query));
647 if (rc)
648 goto leave;
650 /* get response */
651 nread = readline (fd, response, 499);
652 if (nread < 0)
654 rc = -nread;
655 goto leave;
657 if (nread < 3)
659 rc = SPWQ_PROTOCOL_ERROR;
660 goto leave;
663 if (response[0] == 'O' && response[1] == 'K')
664 /* OK, do nothing. */;
665 else if ((nread > 7 && !memcmp (response, "ERR 111", 7)
666 && (response[7] == ' ' || response[7] == '\n') )
667 || ((nread > 4 && !memcmp (response, "ERR ", 4)
668 && (strtoul (response+4, NULL, 0) & 0xffff) == 99)) )
670 /* 111 is the old Assuan code for canceled which might still
671 be in use by old installations. 99 is GPG_ERR_CANCELED as
672 used by modern gpg-agents; 0xffff is used to mask out the
673 error source. */
674 #ifdef SPWQ_USE_LOGGING
675 log_info (_("canceled by user\n") );
676 #endif
678 else
680 #ifdef SPWQ_USE_LOGGING
681 log_error (_("problem with the agent\n"));
682 #endif
683 rc = SPWQ_ERR_RESPONSE;
686 leave:
687 if (fd != -1)
688 close (fd);
689 return rc;