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. */
33 #ifdef HAVE_W32_SYSTEM
36 #include <sys/socket.h>
42 #ifdef HAVE_W32_SYSTEM
43 #include "../jnlib/w32-afunix.h"
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
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))
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
;
80 my_stpcpy(char *a
,const char *b
)
88 #define stpcpy(a,b) my_stpcpy((a), (b))
93 /* Write NBYTES of BUF to file descriptor FD. */
95 writen (int fd
, const void *buf
, size_t nbytes
)
97 size_t nleft
= nbytes
;
102 #ifdef HAVE_W32_SYSTEM
103 nwritten
= send (fd
, buf
, nleft
, 0);
105 nwritten
= write (fd
, buf
, nleft
);
112 #ifdef SPWQ_USE_LOGGING
113 log_error ("write failed: %s\n", strerror (errno
));
115 return SPWQ_IO_ERROR
;
119 buf
= (const char*)buf
+ nwritten
;
126 /* Read an entire line and return number of bytes read. */
128 readline (int fd
, char *buf
, size_t buflen
)
130 size_t nleft
= buflen
;
136 #ifdef HAVE_W32_SYSTEM
137 int n
= recv (fd
, buf
, nleft
, 0);
139 int n
= read (fd
, buf
, nleft
);
145 return -(SPWQ_IO_ERROR
);
149 return -(SPWQ_PROTOCOL_ERROR
); /* incomplete line */
156 for (; n
&& *p
!= '\n'; n
--, p
++)
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. */
170 /* Send an option to the agent */
172 agent_send_option (int fd
, const char *name
, const char *value
)
179 line
= spwq_malloc (7 + strlen (name
) + 1 + strlen (value
) + 2);
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
));
190 nread
= readline (fd
, buf
, DIM(buf
)-1);
194 return SPWQ_PROTOCOL_ERROR
;
196 if (buf
[0] == 'O' && buf
[1] == 'K' && (buf
[2] == ' ' || buf
[2] == '\n'))
199 return SPWQ_ERR_RESPONSE
;
203 /* Send all available options to the agent. */
205 agent_send_all_options (int fd
)
207 char *dft_display
= NULL
;
208 char *dft_ttyname
= NULL
;
209 char *dft_ttytype
= NULL
;
212 dft_display
= getenv ("DISPLAY");
215 if ((rc
= agent_send_option (fd
, "display", dft_display
)))
219 dft_ttyname
= getenv ("GPG_TTY");
220 #ifndef HAVE_W32_SYSTEM
221 if ((!dft_ttyname
|| !*dft_ttyname
) && ttyname (0))
222 dft_ttyname
= ttyname (0);
224 if (dft_ttyname
&& *dft_ttyname
)
226 if ((rc
=agent_send_option (fd
, "ttyname", dft_ttyname
)))
230 dft_ttytype
= getenv ("TERM");
231 if (dft_ttyname
&& dft_ttytype
)
233 if ((rc
= agent_send_option (fd
, "ttytype", dft_ttytype
)))
237 #if defined(HAVE_SETLOCALE)
242 #if defined(LC_CTYPE)
243 old_lc
= setlocale (LC_CTYPE
, NULL
);
246 char *p
= spwq_malloc (strlen (old_lc
)+1);
248 return SPWQ_OUT_OF_CORE
;
252 dft_lc
= setlocale (LC_CTYPE
, "");
253 if (dft_ttyname
&& dft_lc
)
254 rc
= agent_send_option (fd
, "lc-ctype", dft_lc
);
257 setlocale (LC_CTYPE
, old_lc
);
264 #if defined(LC_MESSAGES)
265 old_lc
= setlocale (LC_MESSAGES
, NULL
);
268 char *p
= spwq_malloc (strlen (old_lc
)+1);
270 return SPWQ_OUT_OF_CORE
;
274 dft_lc
= setlocale (LC_MESSAGES
, "");
275 if (dft_ttyname
&& dft_lc
)
276 rc
= agent_send_option (fd
, "lc-messages", dft_lc
);
279 setlocale (LC_MESSAGES
, old_lc
);
286 #endif /*HAVE_SETLOCALE*/
293 /* Try to open a connection to the agent, send all options and return
294 the file descriptor for the connection. Return -1 in case of
297 agent_open (int *rfd
)
302 struct sockaddr_un client_addr
;
309 infostr
= getenv ( "GPG_AGENT_INFO" );
310 if ( !infostr
|| !*infostr
)
311 infostr
= default_gpg_agent_info
;
312 if ( !infostr
|| !*infostr
)
314 #ifdef SPWQ_USE_LOGGING
315 log_error (_("gpg-agent is not available in this session\n"));
317 return SPWQ_NO_AGENT
;
319 p
= spwq_malloc (strlen (infostr
)+1);
321 return SPWQ_OUT_OF_CORE
;
325 if ( !(p
= strchr ( infostr
, PATHSEP_C
)) || p
== infostr
326 || (p
-infostr
)+1 >= sizeof client_addr
.sun_path
)
328 #ifdef SPWQ_USE_LOGGING
329 log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
330 log_debug ( "a='%s'\n", infostr
);
331 log_debug ( "a='%s'\n", strchr ( infostr
, PATHSEP_C
));
332 log_debug ( "a=%td\n", (p
-infostr
));
334 return SPWQ_NO_AGENT
;
338 while (*p
&& *p
!= PATHSEP_C
)
340 prot
= *p
? atoi (p
+1) : 0;
343 #ifdef SPWQ_USE_LOGGING
344 log_error (_("gpg-agent protocol version %d is not supported\n"),prot
);
346 return SPWQ_PROTOCOL_ERROR
;
349 #ifdef HAVE_W32_SYSTEM
350 fd
= _w32_sock_new (AF_UNIX
, SOCK_STREAM
, 0);
352 fd
= socket (AF_UNIX
, SOCK_STREAM
, 0);
356 #ifdef SPWQ_USE_LOGGING
357 log_error ("can't create socket: %s\n", strerror(errno
) );
359 return SPWQ_SYS_ERROR
;
362 memset (&client_addr
, 0, sizeof client_addr
);
363 client_addr
.sun_family
= AF_UNIX
;
364 strcpy (client_addr
.sun_path
, infostr
);
365 len
= (offsetof (struct sockaddr_un
, sun_path
)
366 + strlen(client_addr
.sun_path
) + 1);
368 #ifdef HAVE_W32_SYSTEM
369 rc
= _w32_sock_connect (fd
, (struct sockaddr
*)&client_addr
, len
);
371 rc
= connect (fd
, (struct sockaddr
*)&client_addr
, len
);
375 #ifdef SPWQ_USE_LOGGING
376 log_error ( _("can't connect to `%s': %s\n"), infostr
, strerror (errno
));
379 return SPWQ_IO_ERROR
;
382 nread
= readline (fd
, line
, DIM(line
));
383 if (nread
< 3 || !(line
[0] == 'O' && line
[1] == 'K'
384 && (line
[2] == '\n' || line
[2] == ' ')) )
386 #ifdef SPWQ_USE_LOGGING
387 log_error ( _("communication problem with gpg-agent\n"));
390 return SPWQ_PROTOCOL_ERROR
;
393 rc
= agent_send_all_options (fd
);
396 #ifdef SPWQ_USE_LOGGING
397 log_error (_("problem setting the gpg-agent options\n"));
408 /* Copy text to BUFFER and escape as required. Return a pointer to
409 the end of the new buffer. Note that BUFFER must be large enough
410 to keep the entire text; allocataing it 3 times the size of TEXT
413 copy_and_escape (char *buffer
, const char *text
)
416 const unsigned char *s
= (unsigned char *)text
;
422 if (s
[i
] < ' ' || s
[i
] == '+')
424 sprintf (p
, "%%%02X", s
[i
]);
427 else if (s
[i
] == ' ')
436 /* Set the name of the default socket to NAME. */
438 simple_pw_set_socket (const char *name
)
440 spwq_free (default_gpg_agent_info
);
443 default_gpg_agent_info
= spwq_malloc (strlen (name
) + 4 + 1);
444 if (!default_gpg_agent_info
)
445 return SPWQ_OUT_OF_CORE
;
446 /* We don't know the PID thus we use 0. */
447 strcpy (stpcpy (default_gpg_agent_info
, name
),
448 PATHSEP_S
"0" PATHSEP_S
"1");
451 default_gpg_agent_info
= NULL
;
457 /* Ask the gpg-agent for a passphrase and present the user with a
458 DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
459 If a CACHEID is not NULL it is used to locate the passphrase in in
460 the cache and store it under this ID. If OPT_CHECK is true
461 gpg-agent is asked to apply some checks on the passphrase security.
462 If ERRORCODE is not NULL it should point a variable receiving an
463 errorcode; this error code might be 0 if the user canceled the
464 operation. The function returns NULL to indicate an error. */
466 simple_pwquery (const char *cacheid
,
467 const char *tryagain
,
469 const char *description
,
480 rc
= agent_open (&fd
);
495 /* We allocate 3 times the needed space so that there is enough
496 space for escaping. */
497 line
= spwq_malloc (15 + 10
498 + 3*strlen (cacheid
) + 1
499 + 3*strlen (tryagain
) + 1
500 + 3*strlen (prompt
) + 1
501 + 3*strlen (description
) + 1
505 rc
= SPWQ_OUT_OF_CORE
;
508 strcpy (line
, "GET_PASSPHRASE ");
511 p
= stpcpy (p
, "--check ");
512 p
= copy_and_escape (p
, cacheid
);
514 p
= copy_and_escape (p
, tryagain
);
516 p
= copy_and_escape (p
, prompt
);
518 p
= copy_and_escape (p
, description
);
520 rc
= writen (fd
, line
, p
- line
);
527 pw
= spwq_secure_malloc (500);
528 nread
= readline (fd
, pw
, 499);
536 rc
= SPWQ_PROTOCOL_ERROR
;
540 if (pw
[0] == 'O' && pw
[1] == 'K' && pw
[2] == ' ')
541 { /* we got a passphrase - convert it back from hex */
544 for (i
=3; i
< nread
&& hexdigitp (pw
+i
); i
+=2)
545 pw
[pwlen
++] = xtoi_2 (pw
+i
);
546 pw
[pwlen
] = 0; /* make a C String */
550 else if ((nread
> 7 && !memcmp (pw
, "ERR 111", 7)
551 && (pw
[7] == ' ' || pw
[7] == '\n') )
552 || ((nread
> 4 && !memcmp (pw
, "ERR ", 4)
553 && (strtoul (pw
+4, NULL
, 0) & 0xffff) == 99)) )
555 /* 111 is the old Assuan code for canceled which might still
556 be in use by old installations. 99 is GPG_ERR_CANCELED as
557 used by modern gpg-agents; 0xffff is used to mask out the
559 #ifdef SPWQ_USE_LOGGING
560 log_info (_("canceled by user\n") );
562 *errorcode
= 0; /* Special error code to indicate Cancel. */
564 else if (nread
> 4 && !memcmp (pw
, "ERR ", 4))
566 switch ( (strtoul (pw
+4, NULL
, 0) & 0xffff) )
568 case 85: rc
= SPWQ_NO_PIN_ENTRY
; break;
569 default: rc
= SPWQ_GENERAL_ERROR
; break;
574 #ifdef SPWQ_USE_LOGGING
575 log_error (_("problem with the agent\n"));
577 rc
= SPWQ_ERR_RESPONSE
;
586 spwq_secure_free (pw
);
591 /* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */
593 simple_pwclear (const char *cacheid
)
598 /* We need not more than 50 characters for the command and the
600 if (strlen (cacheid
) * 3 > sizeof (line
) - 50)
601 return SPWQ_PROTOCOL_ERROR
;
603 strcpy (line
, "CLEAR_PASSPHRASE ");
605 p
= copy_and_escape (p
, cacheid
);
609 return simple_query (line
);
613 /* Perform the simple query QUERY (which must be new-line and 0
614 terminated) and return the error code. */
616 simple_query (const char *query
)
623 rc
= agent_open (&fd
);
627 rc
= writen (fd
, query
, strlen (query
));
632 nread
= readline (fd
, response
, 499);
640 rc
= SPWQ_PROTOCOL_ERROR
;
644 if (response
[0] == 'O' && response
[1] == 'K')
645 /* OK, do nothing. */;
646 else if ((nread
> 7 && !memcmp (response
, "ERR 111", 7)
647 && (response
[7] == ' ' || response
[7] == '\n') )
648 || ((nread
> 4 && !memcmp (response
, "ERR ", 4)
649 && (strtoul (response
+4, NULL
, 0) & 0xffff) == 99)) )
651 /* 111 is the old Assuan code for canceled which might still
652 be in use by old installations. 99 is GPG_ERR_CANCELED as
653 used by modern gpg-agents; 0xffff is used to mask out the
655 #ifdef SPWQ_USE_LOGGING
656 log_info (_("canceled by user\n") );
661 #ifdef SPWQ_USE_LOGGING
662 log_error (_("problem with the agent\n"));
664 rc
= SPWQ_ERR_RESPONSE
;