Reinitialize PINENTRY when the Assuan RESET command is invoke.
[pinentry.git] / pinentry / pinentry.c
1 /* pinentry.c - The PIN entry support library
2    Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015 g10 Code GmbH
3
4    This file is part of PINENTRY.
5
6    PINENTRY is free software; you can redistribute it and/or modify it
7    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    PINENTRY is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    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 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #ifndef HAVE_W32CE_SYSTEM
25 # include <errno.h>
26 #endif
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <assert.h>
31 #ifndef HAVE_W32CE_SYSTEM
32 # include <locale.h>
33 #endif
34 #ifdef HAVE_LANGINFO_H
35 #include <langinfo.h>
36 #endif
37 #include <limits.h>
38 #ifdef HAVE_W32CE_SYSTEM
39 # include <windows.h>
40 #endif
41
42 #if defined FALLBACK_CURSES || defined PINENTRY_CURSES || defined PINENTRY_GTK
43 #include <iconv.h>
44 #endif
45
46 #include "assuan.h"
47 #include "memory.h"
48 #include "secmem-util.h"
49 #include "argparse.h"
50 #include "pinentry.h"
51 #include "password-cache.h"
52
53 #ifdef HAVE_W32CE_SYSTEM
54 #define getpid() GetCurrentProcessId ()
55 #endif
56
57 /* Keep the name of our program here. */
58 static char this_pgmname[50];
59
60 struct pinentry pinentry;
61
62 static void
63 pinentry_reset (ASSUAN_CONTEXT ctx)
64 {
65   /* Free any allocated strings.  */
66   free (pinentry.title);
67   free (pinentry.description);
68   free (pinentry.error);
69   free (pinentry.prompt);
70   free (pinentry.ok);
71   free (pinentry.notok);
72   free (pinentry.cancel);
73   secmem_free (pinentry.pin);
74   free (pinentry.display);
75   free (pinentry.ttyname);
76   free (pinentry.ttytype);
77   free (pinentry.lc_ctype);
78   free (pinentry.lc_messages);
79   free (pinentry.touch_file);
80   free (pinentry.repeat_passphrase);
81   free (pinentry.repeat_error_string);
82   free (pinentry.quality_bar);
83   free (pinentry.quality_bar_tt);
84   free (pinentry.default_ok);
85   free (pinentry.default_cancel);
86   free (pinentry.default_prompt);
87   free (pinentry.default_pwmngr);
88   free (pinentry.keyinfo);
89
90   memset (&pinentry, 0, sizeof (pinentry));
91
92   /* Pinentry timeout in seconds.  */
93   pinentry.timeout = 60;
94
95   /* Global grab.  */
96   pinentry.grab = 1;
97
98   pinentry.color_fg = PINENTRY_COLOR_DEFAULT;
99   pinentry.color_fg_bright = 0;
100   pinentry.color_bg = PINENTRY_COLOR_DEFAULT;
101   pinentry.color_so = PINENTRY_COLOR_DEFAULT;
102   pinentry.color_so_bright = 0;
103 }
104 \f
105 static int lc_ctype_unknown_warning = 0;
106
107 #if defined FALLBACK_CURSES || defined PINENTRY_CURSES || defined PINENTRY_GTK
108 char *
109 pinentry_utf8_to_local (const char *lc_ctype, const char *text)
110 {
111   iconv_t cd;
112   const char *input = text;
113   size_t input_len = strlen (text) + 1;
114   char *output;
115   size_t output_len;
116   char *output_buf;
117   size_t processed;
118   char *old_ctype;
119   char *target_encoding;
120
121   /* If no locale setting could be determined, simply copy the
122      string.  */
123   if (!lc_ctype)
124     {
125       if (! lc_ctype_unknown_warning)
126         {
127           fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n",
128                    this_pgmname);
129           lc_ctype_unknown_warning = 1;
130         }
131       return strdup (text);
132     }
133
134   old_ctype = strdup (setlocale (LC_CTYPE, NULL));
135   if (!old_ctype)
136     return NULL;
137   setlocale (LC_CTYPE, lc_ctype);
138   target_encoding = nl_langinfo (CODESET);
139   if (!target_encoding)
140     target_encoding = "?";
141   setlocale (LC_CTYPE, old_ctype);
142   free (old_ctype);
143
144   /* This is overkill, but simplifies the iconv invocation greatly.  */
145   output_len = input_len * MB_LEN_MAX;
146   output_buf = output = malloc (output_len);
147   if (!output)
148     return NULL;
149
150   cd = iconv_open (target_encoding, "UTF-8");
151   if (cd == (iconv_t) -1)
152     {
153       fprintf (stderr, "%s: can't convert from UTF-8 to %s: %s\n",
154                this_pgmname, target_encoding, strerror (errno));
155       free (output_buf);
156       return NULL;
157     }
158   processed = iconv (cd, (ICONV_CONST char **)&input, &input_len,
159                      &output, &output_len);
160   iconv_close (cd);
161   if (processed == (size_t) -1 || input_len)
162     {
163       fprintf (stderr, "%s: error converting from UTF-8 to %s: %s\n",
164                this_pgmname, target_encoding, strerror (errno));
165       free (output_buf);
166       return NULL;
167     }
168   return output_buf;
169 }
170
171 /* Convert TEXT which is encoded according to LC_CTYPE to UTF-8.  With
172    SECURE set to true, use secure memory for the returned buffer.
173    Return NULL on error. */
174 char *
175 pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure)
176 {
177   char *old_ctype;
178   char *source_encoding;
179   iconv_t cd;
180   const char *input = text;
181   size_t input_len = strlen (text) + 1;
182   char *output;
183   size_t output_len;
184   char *output_buf;
185   size_t processed;
186
187   /* If no locale setting could be determined, simply copy the
188      string.  */
189   if (!lc_ctype)
190     {
191       if (! lc_ctype_unknown_warning)
192         {
193           fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n",
194                    this_pgmname);
195           lc_ctype_unknown_warning = 1;
196         }
197       output_buf = secure? secmem_malloc (input_len) : malloc (input_len);
198       if (output_buf)
199         strcpy (output_buf, input);
200       return output_buf;
201     }
202
203   old_ctype = strdup (setlocale (LC_CTYPE, NULL));
204   if (!old_ctype)
205     return NULL;
206   setlocale (LC_CTYPE, lc_ctype);
207   source_encoding = nl_langinfo (CODESET);
208   setlocale (LC_CTYPE, old_ctype);
209   free (old_ctype);
210
211   /* This is overkill, but simplifies the iconv invocation greatly.  */
212   output_len = input_len * MB_LEN_MAX;
213   output_buf = output = secure? secmem_malloc (output_len):malloc (output_len);
214   if (!output)
215     return NULL;
216
217   cd = iconv_open ("UTF-8", source_encoding);
218   if (cd == (iconv_t) -1)
219     {
220       fprintf (stderr, "%s: can't convert from %s to UTF-8: %s\n",
221                this_pgmname, source_encoding? source_encoding : "?",
222                strerror (errno));
223       if (secure)
224         secmem_free (output_buf);
225       else
226         free (output_buf);
227       return NULL;
228     }
229   processed = iconv (cd, (ICONV_CONST char **)&input, &input_len,
230                      &output, &output_len);
231   iconv_close (cd);
232   if (processed == (size_t) -1 || input_len)
233     {
234       fprintf (stderr, "%s: error converting from %s to UTF-8: %s\n",
235                this_pgmname, source_encoding? source_encoding : "?",
236                strerror (errno));
237       if (secure)
238         secmem_free (output_buf);
239       else
240         free (output_buf);
241       return NULL;
242     }
243   return output_buf;
244 }
245 #endif
246
247
248 /* Copy TEXT or TEXTLEN to BUFFER and escape as required.  Return a
249    pointer to the end of the new buffer.  Note that BUFFER must be
250    large enough to keep the entire text; allocataing it 3 times of
251    TEXTLEN is sufficient.  */
252 static char *
253 copy_and_escape (char *buffer, const void *text, size_t textlen)
254 {
255   int i;
256   const unsigned char *s = (unsigned char *)text;
257   char *p = buffer;
258
259   for (i=0; i < textlen; i++)
260     {
261       if (s[i] < ' ' || s[i] == '+')
262         {
263           snprintf (p, 4, "%%%02X", s[i]);
264           p += 3;
265         }
266       else if (s[i] == ' ')
267         *p++ = '+';
268       else
269         *p++ = s[i];
270     }
271   return p;
272 }
273
274
275
276 /* Run a quality inquiry for PASSPHRASE of LENGTH.  (We need LENGTH
277    because not all backends might be able to return a proper
278    C-string.).  Returns: A value between -100 and 100 to give an
279    estimate of the passphrase's quality.  Negative values are use if
280    the caller won't even accept that passphrase.  Note that we expect
281    just one data line which should not be escaped in any represent a
282    numeric signed decimal value.  Extra data is currently ignored but
283    should not be send at all.  */
284 int
285 pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length)
286 {
287   ASSUAN_CONTEXT ctx = pin->ctx_assuan;
288   const char prefix[] = "INQUIRE QUALITY ";
289   char *command;
290   char *line;
291   size_t linelen;
292   int gotvalue = 0;
293   int value = 0;
294   int rc;
295
296   if (!ctx)
297     return 0; /* Can't run the callback.  */
298
299   if (length > 300)
300     length = 300;  /* Limit so that it definitely fits into an Assuan
301                       line.  */
302
303   command = secmem_malloc (strlen (prefix) + 3*length + 1);
304   if (!command)
305     return 0;
306   strcpy (command, prefix);
307   copy_and_escape (command + strlen(command), passphrase, length);
308   rc = assuan_write_line (ctx, command);
309   secmem_free (command);
310   if (rc)
311     {
312       fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc);
313       return 0;
314     }
315
316   for (;;)
317     {
318       do
319         {
320           rc = assuan_read_line (ctx, &line, &linelen);
321           if (rc)
322             {
323               fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc);
324               return 0;
325             }
326         }
327       while (*line == '#' || !linelen);
328       if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
329           && (!line[3] || line[3] == ' '))
330         break; /* END command received*/
331       if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N'
332           && (!line[3] || line[3] == ' '))
333         break; /* CAN command received*/
334       if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
335           && (!line[3] || line[3] == ' '))
336         break; /* ERR command received*/
337       if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue)
338         continue;
339       gotvalue = 1;
340       value = atoi (line+2);
341     }
342   if (value < -100)
343     value = -100;
344   else if (value > 100)
345     value = 100;
346
347   return value;
348 }
349
350
351
352 /* Try to make room for at least LEN bytes in the pinentry.  Returns
353    new buffer on success and 0 on failure or when the old buffer is
354    sufficient.  */
355 char *
356 pinentry_setbufferlen (pinentry_t pin, int len)
357 {
358   char *newp;
359
360   if (pin->pin_len)
361     assert (pin->pin);
362   else
363     assert (!pin->pin);
364
365   if (len < 2048)
366     len = 2048;
367
368   if (len <= pin->pin_len)
369     return NULL;
370
371   newp = secmem_realloc (pin->pin, len);
372   if (newp)
373     {
374       pin->pin = newp;
375       pin->pin_len = len;
376     }
377   else
378     {
379       secmem_free (pin->pin);
380       pin->pin = 0;
381       pin->pin_len = 0;
382     }
383   return newp;
384 }
385
386 static void
387 pinentry_setbuffer_clear (pinentry_t pin)
388 {
389   if (! pin->pin)
390     {
391       assert (pin->pin_len == 0);
392       return;
393     }
394
395   assert (pin->pin_len > 0);
396
397   secmem_free (pin->pin);
398   pin->pin = NULL;
399   pin->pin_len = 0;
400 }
401
402 static void
403 pinentry_setbuffer_init (pinentry_t pin)
404 {
405   pinentry_setbuffer_clear (pin);
406   pinentry_setbufferlen (pin, 0);
407 }
408
409 /* passphrase better be alloced with secmem_alloc.  */
410 void
411 pinentry_setbuffer_use (pinentry_t pin, char *passphrase, int len)
412 {
413   if (! passphrase)
414     {
415       assert (len == 0);
416       pinentry_setbuffer_clear (pin);
417
418       return;
419     }
420
421   if (passphrase && len == 0)
422     len = strlen (passphrase) + 1;
423
424   if (pin->pin)
425     secmem_free (pin->pin);
426
427   pin->pin = passphrase;
428   pin->pin_len = len;
429 }
430
431 /* Initialize the secure memory subsystem, drop privileges and return.
432    Must be called early. */
433 void
434 pinentry_init (const char *pgmname)
435 {
436   /* Store away our name. */
437   if (strlen (pgmname) > sizeof this_pgmname - 2)
438     abort ();
439   strcpy (this_pgmname, pgmname);
440
441   /* Initialize secure memory.  1 is too small, so the default size
442      will be used.  */
443   secmem_init (1);
444   secmem_set_flags (SECMEM_WARN);
445   drop_privs ();
446
447   if (atexit (secmem_term))
448     /* FIXME: Could not register at-exit function, bail out.  */
449     ;
450
451   assuan_set_malloc_hooks (secmem_malloc, secmem_realloc, secmem_free);
452 }
453
454 /* Simple test to check whether DISPLAY is set or the option --display
455    was given.  Used to decide whether the GUI or curses should be
456    initialized.  */
457 int
458 pinentry_have_display (int argc, char **argv)
459 {
460 #ifndef HAVE_W32CE_SYSTEM
461   const char *s;
462
463   s = getenv ("DISPLAY");
464   if (s && *s)
465     return 1;
466 #endif
467   for (; argc; argc--, argv++)
468     if (!strcmp (*argv, "--display") || !strncmp (*argv, "--display=", 10))
469       return 1;
470   return 0;
471 }
472
473
474 \f
475 /* Print usage information and and provide strings for help. */
476 static const char *
477 my_strusage( int level )
478 {
479   const char *p;
480
481   switch (level)
482     {
483     case 11: p = this_pgmname; break;
484     case 12: p = "pinentry"; break;
485     case 13: p = PACKAGE_VERSION; break;
486     case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break;
487     case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
488     case 1:
489     case 40:
490       {
491         static char *str;
492
493         if (!str)
494           {
495             size_t n = 50 + strlen (this_pgmname);
496             str = malloc (n);
497             if (str)
498               snprintf (str, n, "Usage: %s [options] (-h for help)",
499                         this_pgmname);
500           }
501         p = str;
502       }
503       break;
504     case 41:
505       p = "Ask securely for a secret and print it to stdout.";
506       break;
507
508     case 42:
509       p = "1"; /* Flag print 40 as part of 41. */
510       break;
511
512     default: p = NULL; break;
513     }
514   return p;
515 }
516
517
518 char *
519 parse_color (char *arg, pinentry_color_t *color_p, int *bright_p)
520 {
521   static struct
522   {
523     const char *name;
524     pinentry_color_t color;
525   } colors[] = { { "none", PINENTRY_COLOR_NONE },
526                  { "default", PINENTRY_COLOR_DEFAULT },
527                  { "black", PINENTRY_COLOR_BLACK },
528                  { "red", PINENTRY_COLOR_RED },
529                  { "green", PINENTRY_COLOR_GREEN },
530                  { "yellow", PINENTRY_COLOR_YELLOW },
531                  { "blue", PINENTRY_COLOR_BLUE },
532                  { "magenta", PINENTRY_COLOR_MAGENTA },
533                  { "cyan", PINENTRY_COLOR_CYAN },
534                  { "white", PINENTRY_COLOR_WHITE } };
535
536   int i;
537   char *new_arg;
538   pinentry_color_t color = PINENTRY_COLOR_DEFAULT;
539
540   if (!arg)
541     return NULL;
542
543   new_arg = strchr (arg, ',');
544   if (new_arg)
545     new_arg++;
546
547   if (bright_p)
548     {
549       const char *bname[] = { "bright-", "bright", "bold-", "bold" };
550
551       *bright_p = 0;
552       for (i = 0; i < sizeof (bname) / sizeof (bname[0]); i++)
553         if (!strncasecmp (arg, bname[i], strlen (bname[i])))
554           {
555             *bright_p = 1;
556             arg += strlen (bname[i]);
557           }
558     }
559
560   for (i = 0; i < sizeof (colors) / sizeof (colors[0]); i++)
561     if (!strncasecmp (arg, colors[i].name, strlen (colors[i].name)))
562       color = colors[i].color;
563
564   *color_p = color;
565   return new_arg;
566 }
567
568 /* Parse the command line options.  May exit the program if only help
569    or version output is requested.  */
570 void
571 pinentry_parse_opts (int argc, char *argv[])
572 {
573   static ARGPARSE_OPTS opts[] = {
574     ARGPARSE_s_n('d', "debug",    "Turn on debugging output"),
575     ARGPARSE_s_s('D', "display",  "|DISPLAY|Set the X display"),
576     ARGPARSE_s_s('T', "ttyname",  "|FILE|Set the tty terminal node name"),
577     ARGPARSE_s_s('N', "ttytype",  "|NAME|Set the tty terminal type"),
578     ARGPARSE_s_s('C', "lc-ctype", "|STRING|Set the tty LC_CTYPE value"),
579     ARGPARSE_s_s('M', "lc-messages", "|STRING|Set the tty LC_MESSAGES value"),
580 #ifdef ENABLE_ENHANCED
581     ARGPARSE_s_n('e', "enhanced", "Ask for timeout and insurance, too"),
582 #endif
583     ARGPARSE_s_i('o', "timeout",
584                  "|SECS|Timeout waiting for input after this many seconds"),
585     ARGPARSE_s_n('g', "no-global-grab",
586                  "Grab keyboard only while window is focused"),
587     ARGPARSE_s_u('W', "parent-wid", "Parent window ID (for positioning)"),
588     ARGPARSE_s_s('c', "colors", "|STRING|Set custom colors for ncurses"),
589     ARGPARSE_end()
590   };
591   ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
592
593   set_strusage (my_strusage);
594
595   while (arg_parse  (&pargs, opts))
596     {
597       switch (pargs.r_opt)
598         {
599         case 'd':
600           pinentry.debug = 1;
601           break;
602 #ifdef ENABLE_ENHANCED
603         case 'e':
604           pinentry.enhanced = 1;
605           break;
606 #endif
607         case 'g':
608           pinentry.grab = 0;
609           break;
610
611         case 'D':
612           /* Note, this is currently not used because the GUI engine
613              has already been initialized when parsing these options. */
614           pinentry.display = strdup (pargs.r.ret_str);
615           if (!pinentry.display)
616             {
617 #ifndef HAVE_W32CE_SYSTEM
618               fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
619 #endif
620               exit (EXIT_FAILURE);
621             }
622           break;
623         case 'T':
624           pinentry.ttyname = strdup (pargs.r.ret_str);
625           if (!pinentry.ttyname)
626             {
627 #ifndef HAVE_W32CE_SYSTEM
628               fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
629 #endif
630               exit (EXIT_FAILURE);
631             }
632           break;
633         case 'N':
634           pinentry.ttytype = strdup (pargs.r.ret_str);
635           if (!pinentry.ttytype)
636             {
637 #ifndef HAVE_W32CE_SYSTEM
638               fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
639 #endif
640               exit (EXIT_FAILURE);
641             }
642           break;
643         case 'C':
644           pinentry.lc_ctype = strdup (pargs.r.ret_str);
645           if (!pinentry.lc_ctype)
646             {
647 #ifndef HAVE_W32CE_SYSTEM
648               fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
649 #endif
650               exit (EXIT_FAILURE);
651             }
652           break;
653         case 'M':
654           pinentry.lc_messages = strdup (pargs.r.ret_str);
655           if (!pinentry.lc_messages)
656             {
657 #ifndef HAVE_W32CE_SYSTEM
658               fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
659 #endif
660               exit (EXIT_FAILURE);
661             }
662           break;
663         case 'W':
664           pinentry.parent_wid = pargs.r.ret_ulong;
665           break;
666
667         case 'c':
668           {
669             char *tmpstr = pargs.r.ret_str;
670
671             tmpstr = parse_color (tmpstr, &pinentry.color_fg,
672                                   &pinentry.color_fg_bright);
673             tmpstr = parse_color (tmpstr, &pinentry.color_bg, NULL);
674             tmpstr = parse_color (tmpstr, &pinentry.color_so,
675                                   &pinentry.color_so_bright);
676           }
677           break;
678
679         case 'o':
680           pinentry.timeout = pargs.r.ret_int;
681           break;
682
683         default:
684           pargs.err = ARGPARSE_PRINT_WARNING;
685           break;
686         }
687     }
688 }
689
690 \f
691 static int
692 option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
693 {
694   if (!strcmp (key, "no-grab") && !*value)
695     pinentry.grab = 0;
696   else if (!strcmp (key, "grab") && !*value)
697     pinentry.grab = 1;
698   else if (!strcmp (key, "debug-wait"))
699     {
700 #ifndef HAVE_W32CE_SYSTEM
701       fprintf (stderr, "%s: waiting for debugger - my pid is %u ...\n",
702                this_pgmname, (unsigned int) getpid());
703       sleep (*value?atoi (value):5);
704       fprintf (stderr, "%s: ... okay\n", this_pgmname);
705 #endif
706     }
707   else if (!strcmp (key, "display"))
708     {
709       if (pinentry.display)
710         free (pinentry.display);
711       pinentry.display = strdup (value);
712       if (!pinentry.display)
713         return ASSUAN_Out_Of_Core;
714     }
715   else if (!strcmp (key, "ttyname"))
716     {
717       if (pinentry.ttyname)
718         free (pinentry.ttyname);
719       pinentry.ttyname = strdup (value);
720       if (!pinentry.ttyname)
721         return ASSUAN_Out_Of_Core;
722     }
723   else if (!strcmp (key, "ttytype"))
724     {
725       if (pinentry.ttytype)
726         free (pinentry.ttytype);
727       pinentry.ttytype = strdup (value);
728       if (!pinentry.ttytype)
729         return ASSUAN_Out_Of_Core;
730     }
731   else if (!strcmp (key, "lc-ctype"))
732     {
733       if (pinentry.lc_ctype)
734         free (pinentry.lc_ctype);
735       pinentry.lc_ctype = strdup (value);
736       if (!pinentry.lc_ctype)
737         return ASSUAN_Out_Of_Core;
738     }
739   else if (!strcmp (key, "lc-messages"))
740     {
741       if (pinentry.lc_messages)
742         free (pinentry.lc_messages);
743       pinentry.lc_messages = strdup (value);
744       if (!pinentry.lc_messages)
745         return ASSUAN_Out_Of_Core;
746     }
747   else if (!strcmp (key, "parent-wid"))
748     {
749       pinentry.parent_wid = atoi (value);
750       /* FIXME: Use strtol and add some error handling.  */
751     }
752   else if (!strcmp (key, "touch-file"))
753     {
754       if (pinentry.touch_file)
755         free (pinentry.touch_file);
756       pinentry.touch_file = strdup (value);
757       if (!pinentry.touch_file)
758         return ASSUAN_Out_Of_Core;
759     }
760   else if (!strcmp (key, "default-ok"))
761     {
762       pinentry.default_ok = strdup (value);
763       if (!pinentry.default_ok)
764         return ASSUAN_Out_Of_Core;
765     }
766   else if (!strcmp (key, "default-cancel"))
767     {
768       pinentry.default_cancel = strdup (value);
769       if (!pinentry.default_cancel)
770         return ASSUAN_Out_Of_Core;
771     }
772   else if (!strcmp (key, "default-prompt"))
773     {
774       pinentry.default_prompt = strdup (value);
775       if (!pinentry.default_prompt)
776         return ASSUAN_Out_Of_Core;
777     }
778   else if (!strcmp (key, "default-pwmngr"))
779     {
780       pinentry.default_pwmngr = strdup (value);
781       if (!pinentry.default_pwmngr)
782         return ASSUAN_Out_Of_Core;
783     }
784   else if (!strcmp (key, "allow-external-password-cache") && !*value)
785     {
786       pinentry.allow_external_password_cache = 1;
787       pinentry.tried_password_cache = 0;
788     }
789   else
790     return ASSUAN_Invalid_Option;
791   return 0;
792 }
793
794
795 /* Note, that it is sufficient to allocate the target string D as
796    long as the source string S, i.e.: strlen(s)+1; */
797 static void
798 strcpy_escaped (char *d, const char *s)
799 {
800   while (*s)
801     {
802       if (*s == '%' && s[1] && s[2])
803         {
804           s++;
805           *d++ = xtoi_2 ( s);
806           s += 2;
807         }
808       else
809         *d++ = *s++;
810     }
811   *d = 0;
812 }
813
814
815 static int
816 cmd_setdesc (ASSUAN_CONTEXT ctx, char *line)
817 {
818   char *newd;
819   newd = malloc (strlen (line) + 1);
820
821   if (!newd)
822     return ASSUAN_Out_Of_Core;
823
824   strcpy_escaped (newd, line);
825   if (pinentry.description)
826     free (pinentry.description);
827   pinentry.description = newd;
828   return 0;
829 }
830
831
832 static int
833 cmd_setprompt (ASSUAN_CONTEXT ctx, char *line)
834 {
835   char *newp;
836   newp = malloc (strlen (line) + 1);
837
838   if (!newp)
839     return ASSUAN_Out_Of_Core;
840
841   strcpy_escaped (newp, line);
842   if (pinentry.prompt)
843     free (pinentry.prompt);
844   pinentry.prompt = newp;
845   return 0;
846 }
847
848
849 /* The data provided at LINE may be used by pinentry implementations
850    to identify a key for caching strategies of its own.  The empty
851    string and --clear mean that the key does not have a stable
852    identifier.  */
853 static int
854 cmd_setkeyinfo (ASSUAN_CONTEXT ctx, char *line)
855 {
856   if (pinentry.keyinfo)
857     free (pinentry.keyinfo);
858
859   if (*line && strcmp(line, "--clear") != 0)
860     pinentry.keyinfo = strdup (line);
861   else
862     pinentry.keyinfo = NULL;
863
864   return 0;
865 }
866
867
868 static int
869 cmd_setrepeat (ASSUAN_CONTEXT ctx, char *line)
870 {
871   char *p;
872
873   p = malloc (strlen (line) + 1);
874   if (!p)
875     return ASSUAN_Out_Of_Core;
876
877   strcpy_escaped (p, line);
878   free (pinentry.repeat_passphrase);
879   pinentry.repeat_passphrase = p;
880   return 0;
881 }
882
883
884 static int
885 cmd_setrepeaterror (ASSUAN_CONTEXT ctx, char *line)
886 {
887   char *p;
888
889   p = malloc (strlen (line) + 1);
890   if (!p)
891     return ASSUAN_Out_Of_Core;
892
893   strcpy_escaped (p, line);
894   free (pinentry.repeat_error_string);
895   pinentry.repeat_error_string = p;
896   return 0;
897 }
898
899
900 static int
901 cmd_seterror (ASSUAN_CONTEXT ctx, char *line)
902 {
903   char *newe;
904   newe = malloc (strlen (line) + 1);
905
906   if (!newe)
907     return ASSUAN_Out_Of_Core;
908
909   strcpy_escaped (newe, line);
910   if (pinentry.error)
911     free (pinentry.error);
912   pinentry.error = newe;
913   return 0;
914 }
915
916
917 static int
918 cmd_setok (ASSUAN_CONTEXT ctx, char *line)
919 {
920   char *newo;
921   newo = malloc (strlen (line) + 1);
922
923   if (!newo)
924     return ASSUAN_Out_Of_Core;
925
926   strcpy_escaped (newo, line);
927   if (pinentry.ok)
928     free (pinentry.ok);
929   pinentry.ok = newo;
930   return 0;
931 }
932
933
934 static int
935 cmd_setnotok (ASSUAN_CONTEXT ctx, char *line)
936 {
937   char *newo;
938   newo = malloc (strlen (line) + 1);
939
940   if (!newo)
941     return ASSUAN_Out_Of_Core;
942
943   strcpy_escaped (newo, line);
944   if (pinentry.notok)
945     free (pinentry.notok);
946   pinentry.notok = newo;
947   return 0;
948 }
949
950
951 static int
952 cmd_setcancel (ASSUAN_CONTEXT ctx, char *line)
953 {
954   char *newc;
955   newc = malloc (strlen (line) + 1);
956
957   if (!newc)
958     return ASSUAN_Out_Of_Core;
959
960   strcpy_escaped (newc, line);
961   if (pinentry.cancel)
962     free (pinentry.cancel);
963   pinentry.cancel = newc;
964   return 0;
965 }
966
967
968 static int
969 cmd_settimeout (ASSUAN_CONTEXT ctx, char *line)
970 {
971     if (line && *line)
972         pinentry.timeout = atoi(line);
973
974     return 0;
975 }
976
977 static int
978 cmd_settitle (ASSUAN_CONTEXT ctx, char *line)
979 {
980   char *newt;
981   newt = malloc (strlen (line) + 1);
982
983   if (!newt)
984     return ASSUAN_Out_Of_Core;
985
986   strcpy_escaped (newt, line);
987   if (pinentry.title)
988     free (pinentry.title);
989   pinentry.title = newt;
990   return 0;
991 }
992
993 static int
994 cmd_setqualitybar (ASSUAN_CONTEXT ctx, char *line)
995 {
996   char *newval;
997
998   if (!*line)
999     line = "Quality:";
1000
1001   newval = malloc (strlen (line) + 1);
1002   if (!newval)
1003     return ASSUAN_Out_Of_Core;
1004
1005   strcpy_escaped (newval, line);
1006   if (pinentry.quality_bar)
1007     free (pinentry.quality_bar);
1008   pinentry.quality_bar = newval;
1009   return 0;
1010 }
1011
1012 /* Set the tooltip to be used for a quality bar.  */
1013 static int
1014 cmd_setqualitybar_tt (ASSUAN_CONTEXT ctx, char *line)
1015 {
1016   char *newval;
1017
1018   if (*line)
1019     {
1020       newval = malloc (strlen (line) + 1);
1021       if (!newval)
1022         return ASSUAN_Out_Of_Core;
1023
1024       strcpy_escaped (newval, line);
1025     }
1026   else
1027     newval = NULL;
1028   if (pinentry.quality_bar_tt)
1029     free (pinentry.quality_bar_tt);
1030   pinentry.quality_bar_tt = newval;
1031   return 0;
1032 }
1033
1034
1035 static int
1036 cmd_getpin (ASSUAN_CONTEXT ctx, char *line)
1037 {
1038   int result;
1039   int set_prompt = 0;
1040   int just_read_password_from_cache = 0;
1041
1042   pinentry_setbuffer_init (&pinentry);
1043   if (!pinentry.pin)
1044     return ASSUAN_Out_Of_Core;
1045
1046   /* Try reading from the password cache.  */
1047   if (/* If repeat passphrase is set, then we don't want to read from
1048          the cache.  */
1049       ! pinentry.repeat_passphrase
1050       /* Are we allowed to read from the cache?  */
1051       && pinentry.allow_external_password_cache
1052       && pinentry.keyinfo
1053       /* Only read from the cache if we haven't already tried it.  */
1054       && ! pinentry.tried_password_cache)
1055     {
1056       char *password;
1057
1058       pinentry.tried_password_cache = 1;
1059
1060       password = password_cache_lookup (pinentry.keyinfo);
1061       if (password)
1062         /* There is a cached password.  Try it.  */
1063         {
1064           int len = strlen(password) + 1;
1065           if (len > pinentry.pin_len)
1066             len = pinentry.pin_len;
1067
1068           memcpy (pinentry.pin, password, len);
1069           pinentry.pin[len] = '\0';
1070
1071           secmem_free (password);
1072
1073           pinentry.pin_from_cache = 1;
1074
1075           assuan_write_status (ctx, "PASSWORD_FROM_CACHE", "");
1076
1077           /* Result is the length of the password not including the
1078              NUL terminator.  */
1079           result = len - 1;
1080
1081           just_read_password_from_cache = 1;
1082
1083           goto out;
1084         }
1085     }
1086
1087   /* The password was not cached (or we are not allowed to / cannot
1088      use the cache).  Prompt the user.  */
1089   pinentry.pin_from_cache = 0;
1090
1091   if (!pinentry.prompt)
1092     {
1093       pinentry.prompt = pinentry.default_prompt?pinentry.default_prompt:"PIN:";
1094       set_prompt = 1;
1095     }
1096   pinentry.locale_err = 0;
1097   pinentry.specific_err = 0;
1098   pinentry.close_button = 0;
1099   pinentry.repeat_okay = 0;
1100   pinentry.one_button = 0;
1101   pinentry.ctx_assuan = ctx;
1102   result = (*pinentry_cmd_handler) (&pinentry);
1103   pinentry.ctx_assuan = NULL;
1104   if (pinentry.error)
1105     {
1106       free (pinentry.error);
1107       pinentry.error = NULL;
1108     }
1109   if (pinentry.repeat_passphrase)
1110     {
1111       free (pinentry.repeat_passphrase);
1112       pinentry.repeat_passphrase = NULL;
1113     }
1114   if (set_prompt)
1115     pinentry.prompt = NULL;
1116
1117   pinentry.quality_bar = 0;  /* Reset it after the command.  */
1118
1119   if (pinentry.close_button)
1120     assuan_write_status (ctx, "BUTTON_INFO", "close");
1121
1122   if (result < 0)
1123     {
1124       pinentry_setbuffer_clear (&pinentry);
1125       if (pinentry.specific_err)
1126         return pinentry.specific_err;
1127       return pinentry.locale_err? ASSUAN_Locale_Problem: ASSUAN_Canceled;
1128     }
1129
1130  out:
1131   if (result)
1132     {
1133       if (pinentry.repeat_okay)
1134         assuan_write_status (ctx, "PIN_REPEATED", "");
1135       result = assuan_send_data (ctx, pinentry.pin, strlen(pinentry.pin));
1136       if (!result)
1137         result = assuan_send_data (ctx, NULL, 0);
1138
1139       if (/* GPG Agent says it's okay.  */
1140           pinentry.allow_external_password_cache && pinentry.keyinfo
1141           /* We didn't just read it from the cache.  */
1142           && ! just_read_password_from_cache
1143           /* And the user said it's okay.  */
1144           && pinentry.may_cache_password)
1145         /* Cache the password.  */
1146         password_cache_save (pinentry.keyinfo, pinentry.pin);
1147     }
1148
1149   pinentry_setbuffer_clear (&pinentry);
1150
1151   return result;
1152 }
1153
1154
1155 /* Note that the option --one-button is a hack to allow the use of old
1156    pinentries while the caller is ignoring the result.  Given that
1157    options have never been used or flagged as an error the new option
1158    is an easy way to enable the messsage mode while not requiring to
1159    update pinentry or to have the caller test for the message
1160    command.  New applications which are free to require an updated
1161    pinentry should use MESSAGE instead. */
1162 static int
1163 cmd_confirm (ASSUAN_CONTEXT ctx, char *line)
1164 {
1165   int result;
1166
1167   pinentry.one_button = !!strstr (line, "--one-button");
1168   pinentry.quality_bar = 0;
1169   pinentry.close_button = 0;
1170   pinentry.locale_err = 0;
1171   pinentry.specific_err = 0;
1172   pinentry.canceled = 0;
1173   pinentry_setbuffer_clear (&pinentry);
1174   result = (*pinentry_cmd_handler) (&pinentry);
1175   if (pinentry.error)
1176     {
1177       free (pinentry.error);
1178       pinentry.error = NULL;
1179     }
1180
1181   if (pinentry.close_button)
1182     assuan_write_status (ctx, "BUTTON_INFO", "close");
1183
1184   if (result)
1185     return 0;
1186
1187   if (pinentry.specific_err)
1188     return pinentry.specific_err;
1189
1190   if (pinentry.locale_err)
1191     return ASSUAN_Locale_Problem;
1192
1193   if (pinentry.one_button)
1194     return 0;
1195
1196   if (pinentry.canceled)
1197     return ASSUAN_Canceled;
1198   return ASSUAN_Not_Confirmed;
1199 }
1200
1201
1202 static int
1203 cmd_message (ASSUAN_CONTEXT ctx, char *line)
1204 {
1205   return cmd_confirm (ctx, "--one-button");
1206 }
1207
1208 /* GETINFO <what>
1209
1210    Multipurpose function to return a variety of information.
1211    Supported values for WHAT are:
1212
1213      version     - Return the version of the program.
1214      pid         - Return the process id of the server.
1215  */
1216 static int
1217 cmd_getinfo (assuan_context_t ctx, char *line)
1218 {
1219   int rc;
1220
1221   if (!strcmp (line, "version"))
1222     {
1223       const char *s = VERSION;
1224       rc = assuan_send_data (ctx, s, strlen (s));
1225     }
1226   else if (!strcmp (line, "pid"))
1227     {
1228       char numbuf[50];
1229
1230       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1231       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1232     }
1233   else
1234     rc = ASSUAN_Parameter_Error;
1235   return rc;
1236 }
1237
1238
1239 /* Tell the assuan library about our commands.  */
1240 static int
1241 register_commands (ASSUAN_CONTEXT ctx)
1242 {
1243   static struct
1244   {
1245     const char *name;
1246     int cmd_id;
1247     int (*handler) (ASSUAN_CONTEXT, char *line);
1248   } table[] =
1249     {
1250       { "SETDESC",    0,  cmd_setdesc },
1251       { "SETPROMPT",  0,  cmd_setprompt },
1252       { "SETKEYINFO", 0,  cmd_setkeyinfo },
1253       { "SETREPEAT",  0,  cmd_setrepeat },
1254       { "SETREPEATERROR",0, cmd_setrepeaterror },
1255       { "SETERROR",   0,  cmd_seterror },
1256       { "SETOK",      0,  cmd_setok },
1257       { "SETNOTOK",   0,  cmd_setnotok },
1258       { "SETCANCEL",  0,  cmd_setcancel },
1259       { "GETPIN",     0,  cmd_getpin },
1260       { "CONFIRM",    0,  cmd_confirm },
1261       { "MESSAGE",    0,  cmd_message },
1262       { "SETQUALITYBAR", 0,  cmd_setqualitybar },
1263       { "SETQUALITYBAR_TT", 0,  cmd_setqualitybar_tt },
1264       { "GETINFO",    0,  cmd_getinfo },
1265       { "SETTITLE",   0,  cmd_settitle },
1266       { "SETTIMEOUT",   0,  cmd_settimeout },
1267       { NULL }
1268     };
1269   int i, j, rc;
1270
1271   for (i = j = 0; table[i].name; i++)
1272     {
1273       rc = assuan_register_command (ctx,
1274                                     table[i].cmd_id ? table[i].cmd_id
1275                                                    : (ASSUAN_CMD_USER + j++),
1276                                     table[i].name, table[i].handler);
1277       if (rc)
1278         return rc;
1279     }
1280   return 0;
1281 }
1282
1283
1284 int
1285 pinentry_loop2 (int infd, int outfd)
1286 {
1287   int rc;
1288   int filedes[2];
1289   ASSUAN_CONTEXT ctx;
1290
1291   /* Extra check to make sure we have dropped privs. */
1292 #ifndef HAVE_DOSISH_SYSTEM
1293   if (getuid() != geteuid())
1294     abort ();
1295 #endif
1296
1297   /* For now we use a simple pipe based server so that we can work
1298      from scripts.  We will later add options to run as a daemon and
1299      wait for requests on a Unix domain socket.  */
1300   filedes[0] = infd;
1301   filedes[1] = outfd;
1302   rc = assuan_init_pipe_server (&ctx, filedes);
1303   if (rc)
1304     {
1305       fprintf (stderr, "%s: failed to initialize the server: %s\n",
1306                this_pgmname, assuan_strerror(rc));
1307       return -1;
1308     }
1309   rc = register_commands (ctx);
1310   if (rc)
1311     {
1312       fprintf (stderr, "%s: failed to the register commands with Assuan: %s\n",
1313                this_pgmname, assuan_strerror(rc));
1314       return -1;
1315     }
1316
1317   assuan_register_option_handler (ctx, option_handler);
1318 #if 0
1319   assuan_set_log_stream (ctx, stderr);
1320 #endif
1321   assuan_register_reset_notify (ctx, pinentry_reset);
1322   pinentry_reset (NULL);
1323
1324   for (;;)
1325     {
1326       rc = assuan_accept (ctx);
1327       if (rc == -1)
1328           break;
1329       else if (rc)
1330         {
1331           fprintf (stderr, "%s: Assuan accept problem: %s\n",
1332                    this_pgmname, assuan_strerror (rc));
1333           break;
1334         }
1335
1336       rc = assuan_process (ctx);
1337       if (rc)
1338         {
1339           fprintf (stderr, "%s: Assuan processing failed: %s\n",
1340                    this_pgmname, assuan_strerror (rc));
1341           continue;
1342         }
1343     }
1344
1345   assuan_deinit_server (ctx);
1346   return 0;
1347 }
1348
1349
1350 /* Start the pinentry event loop.  The program will start to process
1351    Assuan commands until it is finished or an error occurs.  If an
1352    error occurs, -1 is returned.  Otherwise, 0 is returned.  */
1353 int
1354 pinentry_loop (void)
1355 {
1356   return pinentry_loop2 (STDIN_FILENO, STDOUT_FILENO);
1357 }