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