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