2005-07-04 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / simple-pwquery.c
1 /* simple-pwquery.c - A simple password query client for gpg-agent
2  *      Copyright (C) 2002, 2004 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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 2 of the License, or
9  * (at your option) any later version.
10  *
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.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 /* This module is intended as a standalone client implementation to
22    gpg-agent's GET_PASSPHRASE command.  In particular it does not use
23    the Assuan library and can only cope with an already running
24    gpg-agent.  Some stuff is configurable in the header file. */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #ifdef HAVE_W32_SYSTEM
35 #include <winsock2.h>
36 #else
37 #include <sys/socket.h>
38 #include <sys/un.h>
39 #endif
40 #ifdef HAVE_LOCALE_H
41 #include <locale.h>
42 #endif
43 #ifdef HAVE_W32_SYSTEM
44 #include "../jnlib/w32-afunix.h"
45 #endif
46
47
48 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
49 #include "simple-pwquery.h"
50
51 #if defined(SPWQ_USE_LOGGING) && !defined(HAVE_JNLIB_LOGGING)
52 # undef SPWQ_USE_LOGGING
53 #endif
54
55 #ifndef _
56 #define _(a) (a)
57 #endif
58
59 #if !defined (hexdigitp) && !defined (xtoi_2)
60 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
61 #define hexdigitp(a) (digitp (a)                     \
62                       || (*(a) >= 'A' && *(a) <= 'F')  \
63                       || (*(a) >= 'a' && *(a) <= 'f'))
64 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
65                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
66 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
67 #endif
68
69
70
71
72 \f
73
74 #ifndef HAVE_STPCPY
75 static char *
76 my_stpcpy(char *a,const char *b)
77 {
78     while( *b )
79         *a++ = *b++;
80     *a = 0;
81
82     return (char*)a;
83 }
84 #define stpcpy(a,b)  my_stpcpy((a), (b))
85 #endif
86
87
88
89 /* Write NBYTES of BUF to file descriptor FD. */
90 static int
91 writen (int fd, const void *buf, size_t nbytes)
92 {
93   size_t nleft = nbytes;
94   int nwritten;
95   
96   while (nleft > 0)
97     {
98 #ifdef HAVE_W32_SYSTEM
99       nwritten = send (fd, buf, nleft, 0);
100 #else
101       nwritten = write (fd, buf, nleft);
102 #endif
103       if (nwritten < 0)
104         {
105           if (errno == EINTR)
106             nwritten = 0;
107           else {
108 #ifdef SPWQ_USE_LOGGING
109             log_error ("write failed: %s\n", strerror (errno));
110 #endif
111             return SPWQ_IO_ERROR;
112           }
113         }
114       nleft -= nwritten;
115       buf = (const char*)buf + nwritten;
116     }
117     
118   return 0;
119 }
120
121
122 /* Read an entire line and return number of bytes read. */
123 static int
124 readline (int fd, char *buf, size_t buflen)
125 {
126   size_t nleft = buflen;
127   char *p;
128   int nread = 0;
129
130   while (nleft > 0)
131     {
132 #ifdef HAVE_W32_SYSTEM
133       int n = recv (fd, buf, nleft, 0);
134 #else
135       int n = read (fd, buf, nleft);
136 #endif
137       if (n < 0)
138         {
139           if (errno == EINTR)
140             continue;
141           return -(SPWQ_IO_ERROR);
142         }
143       else if (!n)
144         {
145           return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
146         }
147       p = buf;
148       nleft -= n;
149       buf += n;
150       nread += n;
151       
152       for (; n && *p != '\n'; n--, p++)
153         ;
154       if (n)
155         {
156           break; /* at least one full line available - that's enough.
157                     This function is just a simple implementation, so
158                     it is okay to forget about pending bytes */
159         }
160     }
161
162   return nread; 
163 }
164
165
166 /* Send an option to the agent */
167 static int
168 agent_send_option (int fd, const char *name, const char *value)
169 {
170   char buf[200];
171   int nread;
172   char *line;
173   int i; 
174   
175   line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
176   if (!line)
177     return SPWQ_OUT_OF_CORE;
178   strcpy (stpcpy (stpcpy (stpcpy (
179                      stpcpy (line, "OPTION "), name), "="), value), "\n");
180   i = writen (fd, line, strlen (line));
181   spwq_free (line);
182   if (i)
183     return i;
184   
185   /* get response */
186   nread = readline (fd, buf, DIM(buf)-1);
187   if (nread < 0)
188     return -nread;
189   if (nread < 3)
190     return SPWQ_PROTOCOL_ERROR;
191   
192   if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n')) 
193     return 0; /* okay */
194
195   return SPWQ_ERR_RESPONSE;
196 }
197
198
199 /* Send all available options to the agent. */
200 static int 
201 agent_send_all_options (int fd)
202 {
203   char *dft_display = NULL;
204   char *dft_ttyname = NULL;
205   char *dft_ttytype = NULL;
206   int rc = 0;
207
208   dft_display = getenv ("DISPLAY");
209   if (dft_display)
210     {
211       if ((rc = agent_send_option (fd, "display", dft_display)))
212         return rc;
213     }
214
215   dft_ttyname = getenv ("GPG_TTY");
216 #ifndef HAVE_W32_SYSTEM
217   if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
218     dft_ttyname = ttyname (0);
219 #endif
220   if (dft_ttyname && *dft_ttyname)
221     {
222       if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
223         return rc;
224     }
225
226   dft_ttytype = getenv ("TERM");
227   if (dft_ttyname && dft_ttytype)
228     {
229       if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
230         return rc;
231     }
232
233 #if defined(HAVE_SETLOCALE) 
234   {
235     char *old_lc = NULL;
236     char *dft_lc = NULL;
237
238 #if defined(LC_CTYPE)
239     old_lc = setlocale (LC_CTYPE, NULL);
240     if (old_lc)
241       {
242         char *p = spwq_malloc (strlen (old_lc)+1);
243         if (!p)
244           return SPWQ_OUT_OF_CORE;
245         strcpy (p, old_lc);
246         old_lc = p;
247       }
248     dft_lc = setlocale (LC_CTYPE, "");
249     if (dft_ttyname && dft_lc)
250       rc = agent_send_option (fd, "lc-ctype", dft_lc);
251     if (old_lc)
252       {
253         setlocale (LC_CTYPE, old_lc);
254         spwq_free (old_lc);
255       }
256     if (rc)
257       return rc;
258 #endif
259
260 #if defined(LC_MESSAGES)
261     old_lc = setlocale (LC_MESSAGES, NULL);
262     if (old_lc)
263       {
264         char *p = spwq_malloc (strlen (old_lc)+1);
265         if (!p)
266           return SPWQ_OUT_OF_CORE;
267         strcpy (p, old_lc);
268         old_lc = p;
269       }
270     dft_lc = setlocale (LC_MESSAGES, "");
271     if (dft_ttyname && dft_lc)
272       rc = agent_send_option (fd, "lc-messages", dft_lc);
273     if (old_lc)
274       {
275         setlocale (LC_MESSAGES, old_lc);
276         spwq_free (old_lc);
277       }
278     if (rc)
279       return rc;
280 #endif
281   }
282 #endif /*HAVE_SETLOCALE*/
283
284   return 0;
285 }
286
287
288
289 /* Try to open a connection to the agent, send all options and return
290    the file descriptor for the connection.  Return -1 in case of
291    error. */
292 static int
293 agent_open (int *rfd)
294 {
295   int rc;
296   int fd;
297   char *infostr, *p;
298   struct sockaddr_un client_addr;
299   size_t len;
300   int prot;
301   char line[200];
302   int nread;
303
304   *rfd = -1;
305   infostr = getenv ( "GPG_AGENT_INFO" );
306   if ( !infostr || !*infostr ) 
307     {
308 #ifdef SPWQ_USE_LOGGING
309       log_error (_("gpg-agent is not available in this session\n"));
310 #endif
311       return SPWQ_NO_AGENT;
312     }
313   p = spwq_malloc (strlen (infostr)+1);
314   if (!p)
315     return SPWQ_OUT_OF_CORE;
316   strcpy (p, infostr);
317   infostr = p;
318
319   if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr
320        || (p-infostr)+1 >= sizeof client_addr.sun_path ) 
321     {
322 #ifdef SPWQ_USE_LOGGING
323       log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
324 #endif
325       return SPWQ_NO_AGENT;
326     }
327   *p++ = 0;
328
329   while (*p && *p != PATHSEP_C)
330     p++;
331   prot = *p? atoi (p+1) : 0;
332   if ( prot != 1)
333     {
334 #ifdef SPWQ_USE_LOGGING
335       log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
336 #endif
337       return SPWQ_PROTOCOL_ERROR;
338     }
339
340 #ifdef HAVE_W32_SYSTEM       
341   fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
342 #else
343   fd = socket (AF_UNIX, SOCK_STREAM, 0);
344 #endif
345   if (fd == -1) 
346     {
347 #ifdef SPWQ_USE_LOGGING
348       log_error ("can't create socket: %s\n", strerror(errno) );
349 #endif
350       return SPWQ_SYS_ERROR;
351     }
352     
353   memset (&client_addr, 0, sizeof client_addr);
354   client_addr.sun_family = AF_UNIX;
355   strcpy (client_addr.sun_path, infostr);
356   len = (offsetof (struct sockaddr_un, sun_path)
357          + strlen(client_addr.sun_path) + 1);
358     
359 #ifdef HAVE_W32_SYSTEM       
360   rc = _w32_sock_connect (fd, (struct sockaddr*)&client_addr, len );
361 #else
362   rc = connect (fd, (struct sockaddr*)&client_addr, len );
363 #endif
364   if (rc == -1)
365     {
366 #ifdef SPWQ_USE_LOGGING
367       log_error ( _("can't connect to `%s': %s\n"), infostr, strerror (errno));
368 #endif
369       close (fd );
370       return SPWQ_IO_ERROR;
371     }
372
373   nread = readline (fd, line, DIM(line));
374   if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
375                      && (line[2] == '\n' || line[2] == ' ')) ) 
376     {
377 #ifdef SPWQ_USE_LOGGING
378       log_error ( _("communication problem with gpg-agent\n"));
379 #endif
380       close (fd );
381       return SPWQ_PROTOCOL_ERROR;
382     }
383
384   rc = agent_send_all_options (fd);
385   if (rc)
386     {
387 #ifdef SPWQ_USE_LOGGING
388       log_error (_("problem setting the gpg-agent options\n"));
389 #endif
390       close (fd);
391       return rc;
392     }
393
394   *rfd = fd;
395   return 0;
396 }
397
398
399 /* Copy text to BUFFER and escape as required.  Return a pointer to
400    the end of the new buffer.  Note that BUFFER must be large enough
401    to keep the entire text; allocataing it 3 times the size of TEXT
402    is sufficient. */
403 static char *
404 copy_and_escape (char *buffer, const char *text)
405 {
406   int i;
407   const unsigned char *s = (unsigned char *)text;
408   char *p = buffer;
409   
410
411   for (i=0; s[i]; i++)
412     {
413       if (s[i] < ' ' || s[i] == '+')
414         {
415           sprintf (p, "%%%02X", s[i]);
416           p += 3;
417         }
418       else if (s[i] == ' ')
419         *p++ = '+';
420       else
421         *p++ = s[i];
422     }
423   return p;
424 }
425
426
427 /* Ask the gpg-agent for a passphrase and present the user with a
428    DESCRIPTION, a PROMPT and optiaonlly with a TRYAGAIN extra text.
429    If a CACHEID is not NULL it is used to locate the passphrase in in
430    the cache and store it under this ID.  If ERRORCODE is not NULL it
431    should point a variable receiving an errorcode; thsi errocode might
432    be 0 if the user canceled the operation.  The function returns NULL
433    to indicate an error. */
434 char *
435 simple_pwquery (const char *cacheid, 
436                 const char *tryagain,
437                 const char *prompt,
438                 const char *description,
439                 int *errorcode)
440 {
441   int fd = -1;
442   int nread;
443   char *result = NULL;
444   char *pw = NULL;
445   char *p;
446   int rc, i; 
447
448   rc = agent_open (&fd);
449   if (rc)
450     goto leave;
451
452   if (!cacheid)
453     cacheid = "X";
454   if (!tryagain)
455     tryagain = "X";
456   if (!prompt)
457     prompt = "X";
458   if (!description)
459     description = "X";
460
461   {
462     char *line;
463     /* We allocate 3 times the needed space so that there is enough
464        space for escaping. */
465     line = spwq_malloc (15
466                         + 3*strlen (cacheid) + 1
467                         + 3*strlen (tryagain) + 1
468                         + 3*strlen (prompt) + 1
469                         + 3*strlen (description) + 1
470                         + 2);
471     if (!line)
472       {
473         rc = SPWQ_OUT_OF_CORE;
474         goto leave;
475       }
476     strcpy (line, "GET_PASSPHRASE ");
477     p = line+15;
478     p = copy_and_escape (p, cacheid);
479     *p++ = ' ';
480     p = copy_and_escape (p, tryagain);
481     *p++ = ' ';
482     p = copy_and_escape (p, prompt);
483     *p++ = ' ';
484     p = copy_and_escape (p, description);
485     *p++ = '\n';
486     rc = writen (fd, line, p - line);
487     spwq_free (line);
488     if (rc)
489       goto leave;
490   }
491
492   /* get response */
493   pw = spwq_secure_malloc (500);
494   nread = readline (fd, pw, 499);
495   if (nread < 0)
496     {
497       rc = -nread;
498       goto leave;
499     }
500   if (nread < 3)
501     {
502       rc = SPWQ_PROTOCOL_ERROR;
503       goto leave;
504     }
505       
506   if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ') 
507     { /* we got a passphrase - convert it back from hex */
508       size_t pwlen = 0;
509       
510       for (i=3; i < nread && hexdigitp (pw+i); i+=2)
511         pw[pwlen++] = xtoi_2 (pw+i);
512       pw[pwlen] = 0; /* make a C String */
513       result = pw;
514       pw = NULL;
515     }
516   else if ((nread > 7 && !memcmp (pw, "ERR 111", 7)
517             && (pw[7] == ' ' || pw[7] == '\n') )
518            || ((nread > 4 && !memcmp (pw, "ERR ", 4)
519                 && (strtoul (pw+4, NULL, 0) & 0xffff) == 99)) ) 
520     {
521       /* 111 is the old Assuan code for canceled which might still
522          be in use by old installations. 99 is GPG_ERR_CANCELED as
523          used by modern gpg-agents; 0xffff is used to mask out the
524          error source.  */
525 #ifdef SPWQ_USE_LOGGING
526       log_info (_("canceled by user\n") );
527 #endif
528       *errorcode = 0; /* canceled */
529     }
530   else 
531     {
532 #ifdef SPWQ_USE_LOGGING
533       log_error (_("problem with the agent\n"));
534 #endif
535       rc = SPWQ_ERR_RESPONSE;
536     }
537         
538  leave:
539   if (errorcode)
540     *errorcode = rc;
541   if (fd != -1)
542     close (fd);
543   if (pw)
544     spwq_secure_free (pw);
545   return result;
546 }
547
548
549 /* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID.  */
550 int
551 simple_pwclear (const char *cacheid)
552 {
553   char line[500];
554   char *p;
555
556   /* We need not more than 50 characters for the command and the
557      terminating nul.  */
558   if (strlen (cacheid) * 3 > sizeof (line) - 50)
559     return SPWQ_PROTOCOL_ERROR;
560
561   strcpy (line, "CLEAR_PASSPHRASE ");
562   p = line + 17;
563   p = copy_and_escape (p, cacheid);
564   *p++ = '\n';
565   *p++ = '\0';
566
567   return simple_query (line);
568 }
569
570
571 /* Perform the simple query QUERY (which must be new-line and 0
572    terminated) and return the error code.  */
573 int
574 simple_query (const char *query)
575 {
576   int fd = -1;
577   int nread;
578   char response[500];
579   int rc;
580
581   rc = agent_open (&fd);
582   if (rc)
583     goto leave;
584
585   rc = writen (fd, query, strlen (query));
586   if (rc)
587     goto leave;
588
589   /* get response */
590   nread = readline (fd, response, 499);
591   if (nread < 0)
592     {
593       rc = -nread;
594       goto leave;
595     }
596   if (nread < 3)
597     {
598       rc = SPWQ_PROTOCOL_ERROR;
599       goto leave;
600     }
601   
602   if (response[0] == 'O' && response[1] == 'K') 
603     /* OK, do nothing.  */;
604   else if ((nread > 7 && !memcmp (response, "ERR 111", 7)
605             && (response[7] == ' ' || response[7] == '\n') )
606            || ((nread > 4 && !memcmp (response, "ERR ", 4)
607                 && (strtoul (response+4, NULL, 0) & 0xffff) == 99)) ) 
608     {
609       /* 111 is the old Assuan code for canceled which might still
610          be in use by old installations. 99 is GPG_ERR_CANCELED as
611          used by modern gpg-agents; 0xffff is used to mask out the
612          error source.  */
613 #ifdef SPWQ_USE_LOGGING
614       log_info (_("canceled by user\n") );
615 #endif
616     }
617   else 
618     {
619 #ifdef SPWQ_USE_LOGGING
620       log_error (_("problem with the agent\n"));
621 #endif
622       rc = SPWQ_ERR_RESPONSE;
623     }
624         
625  leave:
626   if (fd != -1)
627     close (fd);
628   return rc;
629 }