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"));
331 return SPWQ_NO_AGENT
;
335 while (*p
&& *p
!= PATHSEP_C
)
337 prot
= *p
? atoi (p
+1) : 0;
340 #ifdef SPWQ_USE_LOGGING
341 log_error (_("gpg-agent protocol version %d is not supported\n"),prot
);
343 return SPWQ_PROTOCOL_ERROR
;
346 #ifdef HAVE_W32_SYSTEM
347 fd
= _w32_sock_new (AF_UNIX
, SOCK_STREAM
, 0);
349 fd
= socket (AF_UNIX
, SOCK_STREAM
, 0);
353 #ifdef SPWQ_USE_LOGGING
354 log_error ("can't create socket: %s\n", strerror(errno
) );
356 return SPWQ_SYS_ERROR
;
359 memset (&client_addr
, 0, sizeof client_addr
);
360 client_addr
.sun_family
= AF_UNIX
;
361 strcpy (client_addr
.sun_path
, infostr
);
362 len
= (offsetof (struct sockaddr_un
, sun_path
)
363 + strlen(client_addr
.sun_path
) + 1);
365 #ifdef HAVE_W32_SYSTEM
366 rc
= _w32_sock_connect (fd
, (struct sockaddr
*)&client_addr
, len
);
368 rc
= connect (fd
, (struct sockaddr
*)&client_addr
, len
);
372 #ifdef SPWQ_USE_LOGGING
373 log_error ( _("can't connect to `%s': %s\n"), infostr
, strerror (errno
));
376 return SPWQ_IO_ERROR
;
379 nread
= readline (fd
, line
, DIM(line
));
380 if (nread
< 3 || !(line
[0] == 'O' && line
[1] == 'K'
381 && (line
[2] == '\n' || line
[2] == ' ')) )
383 #ifdef SPWQ_USE_LOGGING
384 log_error ( _("communication problem with gpg-agent\n"));
387 return SPWQ_PROTOCOL_ERROR
;
390 rc
= agent_send_all_options (fd
);
393 #ifdef SPWQ_USE_LOGGING
394 log_error (_("problem setting the gpg-agent options\n"));
405 /* Copy text to BUFFER and escape as required. Return a pointer to
406 the end of the new buffer. Note that BUFFER must be large enough
407 to keep the entire text; allocataing it 3 times the size of TEXT
410 copy_and_escape (char *buffer
, const char *text
)
413 const unsigned char *s
= (unsigned char *)text
;
419 if (s
[i
] < ' ' || s
[i
] == '+')
421 sprintf (p
, "%%%02X", s
[i
]);
424 else if (s
[i
] == ' ')
433 /* Set the name of the default socket to NAME. */
435 simple_pw_set_socket (const char *name
)
437 spwq_free (default_gpg_agent_info
);
440 default_gpg_agent_info
= spwq_malloc (strlen (name
) + 4 + 1);
441 if (!default_gpg_agent_info
)
442 return SPWQ_OUT_OF_CORE
;
443 /* We don't know the PID thus we use 0. */
444 strcpy (stpcpy (default_gpg_agent_info
, name
),
445 PATHSEP_S
"0" PATHSEP_S
"1");
448 default_gpg_agent_info
= NULL
;
454 /* Ask the gpg-agent for a passphrase and present the user with a
455 DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
456 If a CACHEID is not NULL it is used to locate the passphrase in in
457 the cache and store it under this ID. If OPT_CHECK is true
458 gpg-agent is asked to apply some checks on the passphrase security.
459 If ERRORCODE is not NULL it should point a variable receiving an
460 errorcode; this error code might be 0 if the user canceled the
461 operation. The function returns NULL to indicate an error. */
463 simple_pwquery (const char *cacheid
,
464 const char *tryagain
,
466 const char *description
,
477 rc
= agent_open (&fd
);
492 /* We allocate 3 times the needed space so that there is enough
493 space for escaping. */
494 line
= spwq_malloc (15 + 10
495 + 3*strlen (cacheid
) + 1
496 + 3*strlen (tryagain
) + 1
497 + 3*strlen (prompt
) + 1
498 + 3*strlen (description
) + 1
502 rc
= SPWQ_OUT_OF_CORE
;
505 strcpy (line
, "GET_PASSPHRASE ");
508 p
= stpcpy (p
, "--check ");
509 p
= copy_and_escape (p
, cacheid
);
511 p
= copy_and_escape (p
, tryagain
);
513 p
= copy_and_escape (p
, prompt
);
515 p
= copy_and_escape (p
, description
);
517 rc
= writen (fd
, line
, p
- line
);
524 pw
= spwq_secure_malloc (500);
525 nread
= readline (fd
, pw
, 499);
533 rc
= SPWQ_PROTOCOL_ERROR
;
537 if (pw
[0] == 'O' && pw
[1] == 'K' && pw
[2] == ' ')
538 { /* we got a passphrase - convert it back from hex */
541 for (i
=3; i
< nread
&& hexdigitp (pw
+i
); i
+=2)
542 pw
[pwlen
++] = xtoi_2 (pw
+i
);
543 pw
[pwlen
] = 0; /* make a C String */
547 else if ((nread
> 7 && !memcmp (pw
, "ERR 111", 7)
548 && (pw
[7] == ' ' || pw
[7] == '\n') )
549 || ((nread
> 4 && !memcmp (pw
, "ERR ", 4)
550 && (strtoul (pw
+4, NULL
, 0) & 0xffff) == 99)) )
552 /* 111 is the old Assuan code for canceled which might still
553 be in use by old installations. 99 is GPG_ERR_CANCELED as
554 used by modern gpg-agents; 0xffff is used to mask out the
556 #ifdef SPWQ_USE_LOGGING
557 log_info (_("canceled by user\n") );
559 *errorcode
= 0; /* Special error code to indicate Cancel. */
561 else if (nread
> 4 && !memcmp (pw
, "ERR ", 4))
563 switch ( (strtoul (pw
+4, NULL
, 0) & 0xffff) )
565 case 85: rc
= SPWQ_NO_PIN_ENTRY
; break;
566 default: rc
= SPWQ_GENERAL_ERROR
; break;
571 #ifdef SPWQ_USE_LOGGING
572 log_error (_("problem with the agent\n"));
574 rc
= SPWQ_ERR_RESPONSE
;
583 spwq_secure_free (pw
);
588 /* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */
590 simple_pwclear (const char *cacheid
)
595 /* We need not more than 50 characters for the command and the
597 if (strlen (cacheid
) * 3 > sizeof (line
) - 50)
598 return SPWQ_PROTOCOL_ERROR
;
600 strcpy (line
, "CLEAR_PASSPHRASE ");
602 p
= copy_and_escape (p
, cacheid
);
606 return simple_query (line
);
610 /* Perform the simple query QUERY (which must be new-line and 0
611 terminated) and return the error code. */
613 simple_query (const char *query
)
620 rc
= agent_open (&fd
);
624 rc
= writen (fd
, query
, strlen (query
));
629 nread
= readline (fd
, response
, 499);
637 rc
= SPWQ_PROTOCOL_ERROR
;
641 if (response
[0] == 'O' && response
[1] == 'K')
642 /* OK, do nothing. */;
643 else if ((nread
> 7 && !memcmp (response
, "ERR 111", 7)
644 && (response
[7] == ' ' || response
[7] == '\n') )
645 || ((nread
> 4 && !memcmp (response
, "ERR ", 4)
646 && (strtoul (response
+4, NULL
, 0) & 0xffff) == 99)) )
648 /* 111 is the old Assuan code for canceled which might still
649 be in use by old installations. 99 is GPG_ERR_CANCELED as
650 used by modern gpg-agents; 0xffff is used to mask out the
652 #ifdef SPWQ_USE_LOGGING
653 log_info (_("canceled by user\n") );
658 #ifdef SPWQ_USE_LOGGING
659 log_error (_("problem with the agent\n"));
661 rc
= SPWQ_ERR_RESPONSE
;