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