1 /* pinentry.c - The PIN entry support library
2  * Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015, 2016 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 <https://www.gnu.org/licenses/>.
18  * SPDX-License-Identifier: GPL-2.0+
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #ifndef HAVE_W32CE_SYSTEM
26 # include <errno.h>
27 #endif
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <assert.h>
34 #ifndef HAVE_W32_SYSTEM
35 # include <sys/utsname.h>
36 #endif
37 #ifndef HAVE_W32CE_SYSTEM
38 # include <locale.h>
39 #endif
40 #ifdef HAVE_LANGINFO_H
41 #include <langinfo.h>
42 #endif
43 #include <limits.h>
44 #ifdef HAVE_W32CE_SYSTEM
45 # include <windows.h>
46 #endif
47 
48 #undef WITH_UTF8_CONVERSION
49 #if defined FALLBACK_CURSES || defined PINENTRY_CURSES || defined PINENTRY_GTK
50 # include <iconv.h>
51 # define WITH_UTF8_CONVERSION 1
52 #endif
53 
54 #include <assuan.h>
55 
56 #include "memory.h"
57 #include "secmem-util.h"
58 #include "argparse.h"
59 #include "pinentry.h"
60 #include "password-cache.h"
61 
62 #ifdef INSIDE_EMACS
63 # include "pinentry-emacs.h"
64 #endif
65 #ifdef FALLBACK_CURSES
66 # include "pinentry-curses.h"
67 #endif
68 
69 #ifdef HAVE_W32CE_SYSTEM
70 #define getpid() GetCurrentProcessId ()
71 #endif
72 
73 /* Keep the name of our program here. */
74 static char this_pgmname[50];
75 
76 struct pinentry pinentry;
77 
78 
79 static const char *flavor_flag;
80 
81 /* Because gtk_init removes the --display arg from the command lines
82  * and our command line parser is called after gtk_init (so that it
83  * does not see gtk specific options) we don't have a way to get hold
84  * of the --display option.  Our solution is to remember --disable in
85  * the call to pinentry_have_display and set it then in our
86  * parser.  */
87 static char *remember_display;
88 
89 /* Flag to remember whether a warning has been printed.  */
90 #ifdef WITH_UTF8_CONVERSION
91 static int lc_ctype_unknown_warning;
92 #endif
93 
94 
95 static void
pinentry_reset(int use_defaults)96 pinentry_reset (int use_defaults)
97 {
98   /* GPG Agent sets these options once when it starts the pinentry.
99      Don't reset them.  */
100   int grab = pinentry.grab;
101   char *ttyname = pinentry.ttyname;
102   char *ttytype = pinentry.ttytype_l;
103   char *ttyalert = pinentry.ttyalert;
104   char *lc_ctype = pinentry.lc_ctype;
105   char *lc_messages = pinentry.lc_messages;
106   int allow_external_password_cache = pinentry.allow_external_password_cache;
107   char *default_ok = pinentry.default_ok;
108   char *default_cancel = pinentry.default_cancel;
109   char *default_prompt = pinentry.default_prompt;
110   char *default_pwmngr = pinentry.default_pwmngr;
111   char *default_cf_visi = pinentry.default_cf_visi;
112   char *default_tt_visi = pinentry.default_tt_visi;
113   char *default_tt_hide = pinentry.default_tt_hide;
114   char *touch_file = pinentry.touch_file;
115   unsigned long owner_pid = pinentry.owner_pid;
116   int owner_uid = pinentry.owner_uid;
117   char *owner_host = pinentry.owner_host;
118 
119   /* These options are set from the command line.  Don't reset
120      them.  */
121   int debug = pinentry.debug;
122   char *display = pinentry.display;
123   int parent_wid = pinentry.parent_wid;
124 
125   pinentry_color_t color_fg = pinentry.color_fg;
126   int color_fg_bright = pinentry.color_fg_bright;
127   pinentry_color_t color_bg = pinentry.color_bg;
128   pinentry_color_t color_so = pinentry.color_so;
129   int color_so_bright = pinentry.color_so_bright;
130 
131   int timeout = pinentry.timeout;
132 
133   char *invisible_char = pinentry.invisible_char;
134 
135 
136   /* Free any allocated memory.  */
137   if (use_defaults)
138     {
139       free (pinentry.ttyname);
140       free (pinentry.ttytype_l);
141       free (pinentry.ttyalert);
142       free (pinentry.lc_ctype);
143       free (pinentry.lc_messages);
144       free (pinentry.default_ok);
145       free (pinentry.default_cancel);
146       free (pinentry.default_prompt);
147       free (pinentry.default_pwmngr);
148       free (pinentry.default_cf_visi);
149       free (pinentry.default_tt_visi);
150       free (pinentry.default_tt_hide);
151       free (pinentry.touch_file);
152       free (pinentry.owner_host);
153       free (pinentry.display);
154     }
155 
156   free (pinentry.title);
157   free (pinentry.description);
158   free (pinentry.error);
159   free (pinentry.prompt);
160   free (pinentry.ok);
161   free (pinentry.notok);
162   free (pinentry.cancel);
163   secmem_free (pinentry.pin);
164   free (pinentry.repeat_passphrase);
165   free (pinentry.repeat_error_string);
166   free (pinentry.quality_bar);
167   free (pinentry.quality_bar_tt);
168   free (pinentry.keyinfo);
169   free (pinentry.specific_err_info);
170 
171   /* Reset the pinentry structure.  */
172   memset (&pinentry, 0, sizeof (pinentry));
173 
174   /* Restore options without a default we want to preserve.  */
175   pinentry.invisible_char = invisible_char;
176 
177   /* Restore other options or set defaults.  */
178 
179   if (use_defaults)
180     {
181       /* Pinentry timeout in seconds.  */
182       pinentry.timeout = 60;
183 
184       /* Global grab.  */
185       pinentry.grab = 1;
186 
187       pinentry.color_fg = PINENTRY_COLOR_DEFAULT;
188       pinentry.color_fg_bright = 0;
189       pinentry.color_bg = PINENTRY_COLOR_DEFAULT;
190       pinentry.color_so = PINENTRY_COLOR_DEFAULT;
191       pinentry.color_so_bright = 0;
192 
193       pinentry.owner_uid = -1;
194     }
195   else /* Restore the options.  */
196     {
197       pinentry.grab = grab;
198       pinentry.ttyname = ttyname;
199       pinentry.ttytype_l = ttytype;
200       pinentry.ttyalert = ttyalert;
201       pinentry.lc_ctype = lc_ctype;
202       pinentry.lc_messages = lc_messages;
203       pinentry.allow_external_password_cache = allow_external_password_cache;
204       pinentry.default_ok = default_ok;
205       pinentry.default_cancel = default_cancel;
206       pinentry.default_prompt = default_prompt;
207       pinentry.default_pwmngr = default_pwmngr;
208       pinentry.default_cf_visi = default_cf_visi;
209       pinentry.default_tt_visi = default_tt_visi;
210       pinentry.default_tt_hide = default_tt_hide;
211       pinentry.touch_file = touch_file;
212       pinentry.owner_pid = owner_pid;
213       pinentry.owner_uid = owner_uid;
214       pinentry.owner_host = owner_host;
215 
216       pinentry.debug = debug;
217       pinentry.display = display;
218       pinentry.parent_wid = parent_wid;
219 
220       pinentry.color_fg = color_fg;
221       pinentry.color_fg_bright = color_fg_bright;
222       pinentry.color_bg = color_bg;
223       pinentry.color_so = color_so;
224       pinentry.color_so_bright = color_so_bright;
225 
226       pinentry.timeout = timeout;
227     }
228 }
229 
230 static gpg_error_t
pinentry_assuan_reset_handler(assuan_context_t ctx,char * line)231 pinentry_assuan_reset_handler (assuan_context_t ctx, char *line)
232 {
233   (void)ctx;
234   (void)line;
235 
236   pinentry_reset (0);
237 
238   return 0;
239 }
240 
241 
242 
243 #ifdef WITH_UTF8_CONVERSION
244 char *
pinentry_utf8_to_local(const char * lc_ctype,const char * text)245 pinentry_utf8_to_local (const char *lc_ctype, const char *text)
246 {
247   iconv_t cd;
248   const char *input = text;
249   size_t input_len = strlen (text) + 1;
250   char *output;
251   size_t output_len;
252   char *output_buf;
253   size_t processed;
254   char *old_ctype;
255   char *target_encoding;
256 
257   /* If no locale setting could be determined, simply copy the
258      string.  */
259   if (!lc_ctype)
260     {
261       if (! lc_ctype_unknown_warning)
262 	{
263 	  fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n",
264 		   this_pgmname);
265 	  lc_ctype_unknown_warning = 1;
266 	}
267       return strdup (text);
268     }
269 
270   old_ctype = strdup (setlocale (LC_CTYPE, NULL));
271   if (!old_ctype)
272     return NULL;
273   setlocale (LC_CTYPE, lc_ctype);
274   target_encoding = nl_langinfo (CODESET);
275   if (!target_encoding)
276     target_encoding = "?";
277   setlocale (LC_CTYPE, old_ctype);
278   free (old_ctype);
279 
280   /* This is overkill, but simplifies the iconv invocation greatly.  */
281   output_len = input_len * MB_LEN_MAX;
282   output_buf = output = malloc (output_len);
283   if (!output)
284     return NULL;
285 
286   cd = iconv_open (target_encoding, "UTF-8");
287   if (cd == (iconv_t) -1)
288     {
289       fprintf (stderr, "%s: can't convert from UTF-8 to %s: %s\n",
290                this_pgmname, target_encoding, strerror (errno));
291       free (output_buf);
292       return NULL;
293     }
294   processed = iconv (cd, (ICONV_CONST char **)&input, &input_len,
295                      &output, &output_len);
296   iconv_close (cd);
297   if (processed == (size_t) -1 || input_len)
298     {
299       fprintf (stderr, "%s: error converting from UTF-8 to %s: %s\n",
300                this_pgmname, target_encoding, strerror (errno));
301       free (output_buf);
302       return NULL;
303     }
304   return output_buf;
305 }
306 #endif /*WITH_UTF8_CONVERSION*/
307 
308 
309 /* Convert TEXT which is encoded according to LC_CTYPE to UTF-8.  With
310    SECURE set to true, use secure memory for the returned buffer.
311    Return NULL on error. */
312 #ifdef WITH_UTF8_CONVERSION
313 char *
pinentry_local_to_utf8(char * lc_ctype,char * text,int secure)314 pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure)
315 {
316   char *old_ctype;
317   char *source_encoding;
318   iconv_t cd;
319   const char *input = text;
320   size_t input_len = strlen (text) + 1;
321   char *output;
322   size_t output_len;
323   char *output_buf;
324   size_t processed;
325 
326   /* If no locale setting could be determined, simply copy the
327      string.  */
328   if (!lc_ctype)
329     {
330       if (! lc_ctype_unknown_warning)
331 	{
332 	  fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n",
333 		   this_pgmname);
334 	  lc_ctype_unknown_warning = 1;
335 	}
336       output_buf = secure? secmem_malloc (input_len) : malloc (input_len);
337       if (output_buf)
338         strcpy (output_buf, input);
339       return output_buf;
340     }
341 
342   old_ctype = strdup (setlocale (LC_CTYPE, NULL));
343   if (!old_ctype)
344     return NULL;
345   setlocale (LC_CTYPE, lc_ctype);
346   source_encoding = nl_langinfo (CODESET);
347   setlocale (LC_CTYPE, old_ctype);
348   free (old_ctype);
349 
350   /* This is overkill, but simplifies the iconv invocation greatly.  */
351   output_len = input_len * MB_LEN_MAX;
352   output_buf = output = secure? secmem_malloc (output_len):malloc (output_len);
353   if (!output)
354     return NULL;
355 
356   cd = iconv_open ("UTF-8", source_encoding);
357   if (cd == (iconv_t) -1)
358     {
359       fprintf (stderr, "%s: can't convert from %s to UTF-8: %s\n",
360                this_pgmname, source_encoding? source_encoding : "?",
361                strerror (errno));
362       if (secure)
363         secmem_free (output_buf);
364       else
365         free (output_buf);
366       return NULL;
367     }
368   processed = iconv (cd, (ICONV_CONST char **)&input, &input_len,
369                      &output, &output_len);
370   iconv_close (cd);
371   if (processed == (size_t) -1 || input_len)
372     {
373       fprintf (stderr, "%s: error converting from %s to UTF-8: %s\n",
374                this_pgmname, source_encoding? source_encoding : "?",
375                strerror (errno));
376       if (secure)
377         secmem_free (output_buf);
378       else
379         free (output_buf);
380       return NULL;
381     }
382   return output_buf;
383 }
384 #endif /*WITH_UTF8_CONVERSION*/
385 
386 
387 /* Copy TEXT or TEXTLEN to BUFFER and escape as required.  Return a
388    pointer to the end of the new buffer.  Note that BUFFER must be
389    large enough to keep the entire text; allocataing it 3 times of
390    TEXTLEN is sufficient.  */
391 static char *
copy_and_escape(char * buffer,const void * text,size_t textlen)392 copy_and_escape (char *buffer, const void *text, size_t textlen)
393 {
394   int i;
395   const unsigned char *s = (unsigned char *)text;
396   char *p = buffer;
397 
398   for (i=0; i < textlen; i++)
399     {
400       if (s[i] < ' ' || s[i] == '+')
401         {
402           snprintf (p, 4, "%%%02X", s[i]);
403           p += 3;
404         }
405       else if (s[i] == ' ')
406         *p++ = '+';
407       else
408         *p++ = s[i];
409     }
410   return p;
411 }
412 
413 
414 
415 /* Return a malloced copy of the commandline for PID.  If this is not
416  * possible NULL is returned.  */
417 #ifndef HAVE_W32_SYSTEM
418 static char *
get_cmdline(unsigned long pid)419 get_cmdline (unsigned long pid)
420 {
421   char buffer[200];
422   FILE *fp;
423   size_t i, n;
424 
425   snprintf (buffer, sizeof buffer, "/proc/%lu/cmdline", pid);
426   buffer[sizeof buffer - 1] = 0;
427 
428   fp = fopen (buffer, "rb");
429   if (!fp)
430     return NULL;
431   n = fread (buffer, 1, sizeof buffer - 1, fp);
432   if (n < sizeof buffer -1 && ferror (fp))
433     {
434       /* Some error occurred.  */
435       fclose (fp);
436       return NULL;
437     }
438   fclose (fp);
439   if (n == 0)
440     return NULL;
441   /* Arguments are delimited by Nuls.  We should do proper quoting but
442    * that can be a bit complicated, thus we simply replace the Nuls by
443    * spaces.  */
444   for (i=0; i < n; i++)
445     if (!buffer[i] && i < n-1)
446       buffer[i] = ' ';
447   buffer[i] = 0; /* Make sure the last byte is the string terminator.  */
448 
449   return strdup (buffer);
450 }
451 #endif /*!HAVE_W32_SYSTEM*/
452 
453 
454 /* Atomically ask the kernel for information about process PID.
455  * Return a malloc'ed copy of the process name as long as the process
456  * uid matches UID.  If it cannot determine that the process has uid
457  * UID, it returns NULL.
458  *
459  * This is not as informative as get_cmdline, but it verifies that the
460  * process does belong to the user in question.
461  */
462 #ifndef HAVE_W32_SYSTEM
463 static char *
get_pid_name_for_uid(unsigned long pid,int uid)464 get_pid_name_for_uid (unsigned long pid, int uid)
465 {
466   char buffer[400];
467   FILE *fp;
468   size_t end, n;
469   char *uidstr;
470 
471   snprintf (buffer, sizeof buffer, "/proc/%lu/status", pid);
472   buffer[sizeof buffer - 1] = 0;
473 
474   fp = fopen (buffer, "rb");
475   if (!fp)
476     return NULL;
477   n = fread (buffer, 1, sizeof buffer - 1, fp);
478   if (n < sizeof buffer -1 && ferror (fp))
479     {
480       /* Some error occurred.  */
481       fclose (fp);
482       return NULL;
483     }
484   fclose (fp);
485   if (n == 0)
486     return NULL;
487   /* Fixme: Is it specified that "Name" is always the first line?  For
488    * robustness I would prefer to have a real parser here. -wk  */
489   if (strncmp (buffer, "Name:\t", 6))
490     return NULL;
491   end = strcspn (buffer + 6, "\n") + 6;
492   buffer[end] = 0;
493 
494   /* check that uid matches what we expect */
495   uidstr = strstr (buffer + end + 1, "\nUid:\t");
496   if (!uidstr)
497     return NULL;
498   if (atoi (uidstr + 6) != uid)
499     return NULL;
500 
501   return strdup (buffer + 6);
502 }
503 #endif /*!HAVE_W32_SYSTEM*/
504 
505 
506 /* Return a malloced string with the title.  The caller mus free the
507  * string.  If no title is available or the title string has an error
508  * NULL is returned.  */
509 char *
pinentry_get_title(pinentry_t pe)510 pinentry_get_title (pinentry_t pe)
511 {
512   char *title;
513 
514   if (pe->title)
515     title = strdup (pe->title);
516 #ifndef HAVE_W32_SYSTEM
517   else if (pe->owner_pid)
518     {
519       char buf[200];
520       struct utsname utsbuf;
521       char *pidname = NULL;
522       char *cmdline = NULL;
523 
524       if (pe->owner_host &&
525           !uname (&utsbuf) && utsbuf.nodename &&
526           !strcmp (utsbuf.nodename, pe->owner_host))
527         {
528           pidname = get_pid_name_for_uid (pe->owner_pid, pe->owner_uid);
529           if (pidname)
530             cmdline = get_cmdline (pe->owner_pid);
531         }
532 
533       if (pe->owner_host && (cmdline || pidname))
534         snprintf (buf, sizeof buf, "[%lu]@%s (%s)",
535                   pe->owner_pid, pe->owner_host, cmdline ? cmdline : pidname);
536       else if (pe->owner_host)
537         snprintf (buf, sizeof buf, "[%lu]@%s",
538                   pe->owner_pid, pe->owner_host);
539       else
540         snprintf (buf, sizeof buf, "[%lu] <unknown host>",
541                   pe->owner_pid);
542       buf[sizeof buf - 1] = 0;
543       free (pidname);
544       free (cmdline);
545       title = strdup (buf);
546     }
547 #endif /*!HAVE_W32_SYSTEM*/
548   else
549     title = strdup (this_pgmname);
550 
551   return title;
552 }
553 
554 
555 /* Run a quality inquiry for PASSPHRASE of LENGTH.  (We need LENGTH
556    because not all backends might be able to return a proper
557    C-string.).  Returns: A value between -100 and 100 to give an
558    estimate of the passphrase's quality.  Negative values are use if
559    the caller won't even accept that passphrase.  Note that we expect
560    just one data line which should not be escaped in any represent a
561    numeric signed decimal value.  Extra data is currently ignored but
562    should not be send at all.  */
563 int
pinentry_inq_quality(pinentry_t pin,const char * passphrase,size_t length)564 pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length)
565 {
566   assuan_context_t ctx = pin->ctx_assuan;
567   const char prefix[] = "INQUIRE QUALITY ";
568   char *command;
569   char *line;
570   size_t linelen;
571   int gotvalue = 0;
572   int value = 0;
573   int rc;
574 
575   if (!ctx)
576     return 0; /* Can't run the callback.  */
577 
578   if (length > 300)
579     length = 300;  /* Limit so that it definitely fits into an Assuan
580                       line.  */
581 
582   command = secmem_malloc (strlen (prefix) + 3*length + 1);
583   if (!command)
584     return 0;
585   strcpy (command, prefix);
586   copy_and_escape (command + strlen(command), passphrase, length);
587   rc = assuan_write_line (ctx, command);
588   secmem_free (command);
589   if (rc)
590     {
591       fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc);
592       return 0;
593     }
594 
595   for (;;)
596     {
597       do
598         {
599           rc = assuan_read_line (ctx, &line, &linelen);
600           if (rc)
601             {
602               fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc);
603               return 0;
604             }
605         }
606       while (*line == '#' || !linelen);
607       if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
608           && (!line[3] || line[3] == ' '))
609         break; /* END command received*/
610       if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N'
611           && (!line[3] || line[3] == ' '))
612         break; /* CAN command received*/
613       if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
614           && (!line[3] || line[3] == ' '))
615         break; /* ERR command received*/
616       if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue)
617         continue;
618       gotvalue = 1;
619       value = atoi (line+2);
620     }
621   if (value < -100)
622     value = -100;
623   else if (value > 100)
624     value = 100;
625 
626   return value;
627 }
628 
629 /* Run a genpin inquiry */
630 char *
pinentry_inq_genpin(pinentry_t pin)631 pinentry_inq_genpin (pinentry_t pin)
632 {
633   assuan_context_t ctx = pin->ctx_assuan;
634   const char prefix[] = "INQUIRE GENPIN";
635   char *line;
636   size_t linelen;
637   int gotvalue = 0;
638   char *value = NULL;
639   int rc;
640 
641   if (!ctx)
642     return 0; /* Can't run the callback.  */
643 
644   rc = assuan_write_line (ctx, prefix);
645   if (rc)
646     {
647       fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc);
648       return 0;
649     }
650 
651   for (;;)
652     {
653       do
654         {
655           rc = assuan_read_line (ctx, &line, &linelen);
656           if (rc)
657             {
658               fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc);
659               return 0;
660             }
661         }
662       while (*line == '#' || !linelen);
663       if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
664           && (!line[3] || line[3] == ' '))
665         break; /* END command received*/
666       if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N'
667           && (!line[3] || line[3] == ' '))
668         break; /* CAN command received*/
669       if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
670           && (!line[3] || line[3] == ' '))
671         break; /* ERR command received*/
672       if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue)
673         continue;
674       gotvalue = 1;
675       value = strdup (line + 2);
676     }
677 
678   return value;
679 }
680 
681 /* Try to make room for at least LEN bytes in the pinentry.  Returns
682    new buffer on success and 0 on failure or when the old buffer is
683    sufficient.  */
684 char *
pinentry_setbufferlen(pinentry_t pin,int len)685 pinentry_setbufferlen (pinentry_t pin, int len)
686 {
687   char *newp;
688 
689   if (pin->pin_len)
690     assert (pin->pin);
691   else
692     assert (!pin->pin);
693 
694   if (len < 2048)
695     len = 2048;
696 
697   if (len <= pin->pin_len)
698     return pin->pin;
699 
700   newp = secmem_realloc (pin->pin, len);
701   if (newp)
702     {
703       pin->pin = newp;
704       pin->pin_len = len;
705     }
706   else
707     {
708       secmem_free (pin->pin);
709       pin->pin = 0;
710       pin->pin_len = 0;
711     }
712   return newp;
713 }
714 
715 static void
pinentry_setbuffer_clear(pinentry_t pin)716 pinentry_setbuffer_clear (pinentry_t pin)
717 {
718   if (! pin->pin)
719     {
720       assert (pin->pin_len == 0);
721       return;
722     }
723 
724   assert (pin->pin_len > 0);
725 
726   secmem_free (pin->pin);
727   pin->pin = NULL;
728   pin->pin_len = 0;
729 }
730 
731 static void
pinentry_setbuffer_init(pinentry_t pin)732 pinentry_setbuffer_init (pinentry_t pin)
733 {
734   pinentry_setbuffer_clear (pin);
735   pinentry_setbufferlen (pin, 0);
736 }
737 
738 /* passphrase better be alloced with secmem_alloc.  */
739 void
pinentry_setbuffer_use(pinentry_t pin,char * passphrase,int len)740 pinentry_setbuffer_use (pinentry_t pin, char *passphrase, int len)
741 {
742   if (! passphrase)
743     {
744       assert (len == 0);
745       pinentry_setbuffer_clear (pin);
746 
747       return;
748     }
749 
750   if (passphrase && len == 0)
751     len = strlen (passphrase) + 1;
752 
753   if (pin->pin)
754     secmem_free (pin->pin);
755 
756   pin->pin = passphrase;
757   pin->pin_len = len;
758 }
759 
760 static struct assuan_malloc_hooks assuan_malloc_hooks = {
761   secmem_malloc, secmem_realloc, secmem_free
762 };
763 
764 /* Initialize the secure memory subsystem, drop privileges and return.
765    Must be called early. */
766 void
pinentry_init(const char * pgmname)767 pinentry_init (const char *pgmname)
768 {
769   /* Store away our name. */
770   if (strlen (pgmname) > sizeof this_pgmname - 2)
771     abort ();
772   strcpy (this_pgmname, pgmname);
773 
774   gpgrt_check_version (NULL);
775 
776   /* Initialize secure memory.  1 is too small, so the default size
777      will be used.  */
778   secmem_init (1);
779   secmem_set_flags (SECMEM_WARN);
780   drop_privs ();
781 
782   if (atexit (secmem_term))
783     {
784       /* FIXME: Could not register at-exit function, bail out.  */
785     }
786 
787   assuan_set_malloc_hooks (&assuan_malloc_hooks);
788 }
789 
790 /* Simple test to check whether DISPLAY is set or the option --display
791    was given.  Used to decide whether the GUI or curses should be
792    initialized.  */
793 int
pinentry_have_display(int argc,char ** argv)794 pinentry_have_display (int argc, char **argv)
795 {
796   int found = 0;
797 
798   for (; argc; argc--, argv++)
799     {
800       if (!strcmp (*argv, "--display"))
801         {
802           if (argv[1] && !remember_display)
803             {
804               remember_display = strdup (argv[1]);
805               if (!remember_display)
806                 {
807 #ifndef HAVE_W32CE_SYSTEM
808                   fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
809 #endif
810                   exit (EXIT_FAILURE);
811                 }
812             }
813           found = 1;
814           break;
815         }
816       else if (!strncmp (*argv, "--display=", 10))
817         {
818           if (!remember_display)
819             {
820               remember_display = strdup (*argv+10);
821               if (!remember_display)
822                 {
823 #ifndef HAVE_W32CE_SYSTEM
824                   fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
825 #endif
826                   exit (EXIT_FAILURE);
827                 }
828             }
829           found = 1;
830           break;
831         }
832     }
833 
834 #ifndef HAVE_W32CE_SYSTEM
835   {
836     const char *s;
837     s = getenv ("DISPLAY");
838     if (s && *s)
839       found = 1;
840   }
841 #endif
842 
843   return found;
844 }
845 
846 
847 
848 /* Print usage information and and provide strings for help. */
849 static const char *
my_strusage(int level)850 my_strusage( int level )
851 {
852   const char *p;
853 
854   switch (level)
855     {
856     case 11: p = this_pgmname; break;
857     case 12: p = "pinentry"; break;
858     case 13: p = PACKAGE_VERSION; break;
859     case 14: p = "Copyright (C) 2016 g10 Code GmbH"; break;
860     case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
861     case 1:
862     case 40:
863       {
864         static char *str;
865 
866         if (!str)
867           {
868             size_t n = 50 + strlen (this_pgmname);
869             str = malloc (n);
870             if (str)
871               {
872                 snprintf (str, n, "Usage: %s [options] (-h for help)",
873                           this_pgmname);
874                 str[n-1] = 0;
875               }
876           }
877         p = str;
878       }
879       break;
880     case 41:
881       p = "Ask securely for a secret and print it to stdout.";
882       break;
883 
884     case 42:
885       p = "1"; /* Flag print 40 as part of 41. */
886       break;
887 
888     default: p = NULL; break;
889     }
890   return p;
891 }
892 
893 
894 char *
parse_color(char * arg,pinentry_color_t * color_p,int * bright_p)895 parse_color (char *arg, pinentry_color_t *color_p, int *bright_p)
896 {
897   static struct
898   {
899     const char *name;
900     pinentry_color_t color;
901   } colors[] = { { "none", PINENTRY_COLOR_NONE },
902 		 { "default", PINENTRY_COLOR_DEFAULT },
903 		 { "black", PINENTRY_COLOR_BLACK },
904 		 { "red", PINENTRY_COLOR_RED },
905 		 { "green", PINENTRY_COLOR_GREEN },
906 		 { "yellow", PINENTRY_COLOR_YELLOW },
907 		 { "blue", PINENTRY_COLOR_BLUE },
908 		 { "magenta", PINENTRY_COLOR_MAGENTA },
909 		 { "cyan", PINENTRY_COLOR_CYAN },
910 		 { "white", PINENTRY_COLOR_WHITE } };
911 
912   int i;
913   char *new_arg;
914   pinentry_color_t color = PINENTRY_COLOR_DEFAULT;
915 
916   if (!arg)
917     return NULL;
918 
919   new_arg = strchr (arg, ',');
920   if (new_arg)
921     new_arg++;
922 
923   if (bright_p)
924     {
925       const char *bname[] = { "bright-", "bright", "bold-", "bold" };
926 
927       *bright_p = 0;
928       for (i = 0; i < sizeof (bname) / sizeof (bname[0]); i++)
929 	if (!strncasecmp (arg, bname[i], strlen (bname[i])))
930 	  {
931 	    *bright_p = 1;
932 	    arg += strlen (bname[i]);
933 	  }
934     }
935 
936   for (i = 0; i < sizeof (colors) / sizeof (colors[0]); i++)
937     if (!strncasecmp (arg, colors[i].name, strlen (colors[i].name)))
938       color = colors[i].color;
939 
940   *color_p = color;
941   return new_arg;
942 }
943 
944 /* Parse the command line options.  May exit the program if only help
945    or version output is requested.  */
946 void
pinentry_parse_opts(int argc,char * argv[])947 pinentry_parse_opts (int argc, char *argv[])
948 {
949   static ARGPARSE_OPTS opts[] = {
950     ARGPARSE_s_n('d', "debug",    "Turn on debugging output"),
951     ARGPARSE_s_s('D', "display",  "|DISPLAY|Set the X display"),
952     ARGPARSE_s_s('T', "ttyname",  "|FILE|Set the tty terminal node name"),
953     ARGPARSE_s_s('N', "ttytype",  "|NAME|Set the tty terminal type"),
954     ARGPARSE_s_s('C', "lc-ctype", "|STRING|Set the tty LC_CTYPE value"),
955     ARGPARSE_s_s('M', "lc-messages", "|STRING|Set the tty LC_MESSAGES value"),
956     ARGPARSE_s_i('o', "timeout",
957                  "|SECS|Timeout waiting for input after this many seconds"),
958     ARGPARSE_s_n('g', "no-global-grab",
959                  "Grab keyboard only while window is focused"),
960     ARGPARSE_s_u('W', "parent-wid", "Parent window ID (for positioning)"),
961     ARGPARSE_s_s('c', "colors", "|STRING|Set custom colors for ncurses"),
962     ARGPARSE_s_s('a', "ttyalert", "|STRING|Set the alert mode (none, beep or flash)"),
963     ARGPARSE_end()
964   };
965   ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
966 
967   set_strusage (my_strusage);
968 
969   pinentry_reset (1);
970 
971   while (arg_parse  (&pargs, opts))
972     {
973       switch (pargs.r_opt)
974         {
975         case 'd':
976           pinentry.debug = 1;
977           break;
978         case 'g':
979           pinentry.grab = 0;
980           break;
981 
982 	case 'D':
983           /* Note, this is currently not used because the GUI engine
984              has already been initialized when parsing these options. */
985 	  pinentry.display = strdup (pargs.r.ret_str);
986 	  if (!pinentry.display)
987 	    {
988 #ifndef HAVE_W32CE_SYSTEM
989 	      fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
990 #endif
991 	      exit (EXIT_FAILURE);
992 	    }
993 	  break;
994 	case 'T':
995 	  pinentry.ttyname = strdup (pargs.r.ret_str);
996 	  if (!pinentry.ttyname)
997 	    {
998 #ifndef HAVE_W32CE_SYSTEM
999 	      fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
1000 #endif
1001 	      exit (EXIT_FAILURE);
1002 	    }
1003 	  break;
1004 	case 'N':
1005 	  pinentry.ttytype_l = strdup (pargs.r.ret_str);
1006 	  if (!pinentry.ttytype_l)
1007 	    {
1008 #ifndef HAVE_W32CE_SYSTEM
1009 	      fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
1010 #endif
1011 	      exit (EXIT_FAILURE);
1012 	    }
1013 	  break;
1014 	case 'C':
1015 	  pinentry.lc_ctype = strdup (pargs.r.ret_str);
1016 	  if (!pinentry.lc_ctype)
1017 	    {
1018 #ifndef HAVE_W32CE_SYSTEM
1019 	      fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
1020 #endif
1021 	      exit (EXIT_FAILURE);
1022 	    }
1023 	  break;
1024 	case 'M':
1025 	  pinentry.lc_messages = strdup (pargs.r.ret_str);
1026 	  if (!pinentry.lc_messages)
1027 	    {
1028 #ifndef HAVE_W32CE_SYSTEM
1029 	      fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
1030 #endif
1031 	      exit (EXIT_FAILURE);
1032 	    }
1033 	  break;
1034 	case 'W':
1035 	  pinentry.parent_wid = pargs.r.ret_ulong;
1036 	  break;
1037 
1038 	case 'c':
1039           {
1040             char *tmpstr = pargs.r.ret_str;
1041 
1042             tmpstr = parse_color (tmpstr, &pinentry.color_fg,
1043                                   &pinentry.color_fg_bright);
1044             tmpstr = parse_color (tmpstr, &pinentry.color_bg, NULL);
1045             tmpstr = parse_color (tmpstr, &pinentry.color_so,
1046                                   &pinentry.color_so_bright);
1047           }
1048 	  break;
1049 
1050 	case 'o':
1051 	  pinentry.timeout = pargs.r.ret_int;
1052 	  break;
1053 
1054 	case 'a':
1055 	  pinentry.ttyalert = strdup (pargs.r.ret_str);
1056 	  if (!pinentry.ttyalert)
1057 	    {
1058 #ifndef HAVE_W32CE_SYSTEM
1059 	      fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
1060 #endif
1061 	      exit (EXIT_FAILURE);
1062 	    }
1063 	  break;
1064 
1065         default:
1066           pargs.err = ARGPARSE_PRINT_WARNING;
1067 	  break;
1068         }
1069     }
1070 
1071   if (!pinentry.display && remember_display)
1072     {
1073       pinentry.display = remember_display;
1074       remember_display = NULL;
1075     }
1076 }
1077 
1078 
1079 /* Set the optional flag used with getinfo. */
1080 void
pinentry_set_flavor_flag(const char * string)1081 pinentry_set_flavor_flag (const char *string)
1082 {
1083   flavor_flag = string;
1084 }
1085 
1086 
1087 
1088 
1089 static gpg_error_t
option_handler(assuan_context_t ctx,const char * key,const char * value)1090 option_handler (assuan_context_t ctx, const char *key, const char *value)
1091 {
1092   (void)ctx;
1093 
1094   if (!strcmp (key, "no-grab") && !*value)
1095     pinentry.grab = 0;
1096   else if (!strcmp (key, "grab") && !*value)
1097     pinentry.grab = 1;
1098   else if (!strcmp (key, "debug-wait"))
1099     {
1100 #ifndef HAVE_W32_SYSTEM
1101       fprintf (stderr, "%s: waiting for debugger - my pid is %u ...\n",
1102 	       this_pgmname, (unsigned int) getpid());
1103       sleep (*value?atoi (value):5);
1104       fprintf (stderr, "%s: ... okay\n", this_pgmname);
1105 #endif
1106     }
1107   else if (!strcmp (key, "display"))
1108     {
1109       if (pinentry.display)
1110 	free (pinentry.display);
1111       pinentry.display = strdup (value);
1112       if (!pinentry.display)
1113 	return gpg_error_from_syserror ();
1114     }
1115   else if (!strcmp (key, "ttyname"))
1116     {
1117       if (pinentry.ttyname)
1118 	free (pinentry.ttyname);
1119       pinentry.ttyname = strdup (value);
1120       if (!pinentry.ttyname)
1121 	return gpg_error_from_syserror ();
1122     }
1123   else if (!strcmp (key, "ttytype"))
1124     {
1125       if (pinentry.ttytype_l)
1126 	free (pinentry.ttytype_l);
1127       pinentry.ttytype_l = strdup (value);
1128       if (!pinentry.ttytype_l)
1129 	return gpg_error_from_syserror ();
1130     }
1131   else if (!strcmp (key, "ttyalert"))
1132     {
1133       if (pinentry.ttyalert)
1134 	free (pinentry.ttyalert);
1135       pinentry.ttyalert = strdup (value);
1136       if (!pinentry.ttyalert)
1137 	return gpg_error_from_syserror ();
1138     }
1139   else if (!strcmp (key, "lc-ctype"))
1140     {
1141       if (pinentry.lc_ctype)
1142 	free (pinentry.lc_ctype);
1143       pinentry.lc_ctype = strdup (value);
1144       if (!pinentry.lc_ctype)
1145 	return gpg_error_from_syserror ();
1146     }
1147   else if (!strcmp (key, "lc-messages"))
1148     {
1149       if (pinentry.lc_messages)
1150 	free (pinentry.lc_messages);
1151       pinentry.lc_messages = strdup (value);
1152       if (!pinentry.lc_messages)
1153 	return gpg_error_from_syserror ();
1154     }
1155   else if (!strcmp (key, "owner"))
1156     {
1157       long along;
1158       char *endp;
1159 
1160       free (pinentry.owner_host);
1161       pinentry.owner_host = NULL;
1162       pinentry.owner_uid = -1;
1163       pinentry.owner_pid = 0;
1164 
1165       errno = 0;
1166       along = strtol (value, &endp, 10);
1167       if (along && !errno)
1168         {
1169           pinentry.owner_pid = (unsigned long)along;
1170           if (*endp)
1171             {
1172               errno = 0;
1173               if (*endp == '/') { /* we have a uid */
1174                 endp++;
1175                 along = strtol (endp, &endp, 10);
1176                 if (along >= 0 && !errno)
1177                   pinentry.owner_uid = (int)along;
1178               }
1179               if (endp)
1180                 {
1181                   while (*endp == ' ')
1182                     endp++;
1183                   if (*endp)
1184                     {
1185                       pinentry.owner_host = strdup (endp);
1186                       for (endp=pinentry.owner_host;
1187                            *endp && *endp != ' '; endp++)
1188                         ;
1189                       *endp = 0;
1190                     }
1191                 }
1192             }
1193         }
1194     }
1195   else if (!strcmp (key, "parent-wid"))
1196     {
1197       pinentry.parent_wid = atoi (value);
1198       /* FIXME: Use strtol and add some error handling.  */
1199     }
1200   else if (!strcmp (key, "touch-file"))
1201     {
1202       if (pinentry.touch_file)
1203         free (pinentry.touch_file);
1204       pinentry.touch_file = strdup (value);
1205       if (!pinentry.touch_file)
1206 	return gpg_error_from_syserror ();
1207     }
1208   else if (!strcmp (key, "default-ok"))
1209     {
1210       pinentry.default_ok = strdup (value);
1211       if (!pinentry.default_ok)
1212 	return gpg_error_from_syserror ();
1213     }
1214   else if (!strcmp (key, "default-cancel"))
1215     {
1216       pinentry.default_cancel = strdup (value);
1217       if (!pinentry.default_cancel)
1218 	return gpg_error_from_syserror ();
1219     }
1220   else if (!strcmp (key, "default-prompt"))
1221     {
1222       pinentry.default_prompt = strdup (value);
1223       if (!pinentry.default_prompt)
1224 	return gpg_error_from_syserror ();
1225     }
1226   else if (!strcmp (key, "default-pwmngr"))
1227     {
1228       pinentry.default_pwmngr = strdup (value);
1229       if (!pinentry.default_pwmngr)
1230 	return gpg_error_from_syserror ();
1231     }
1232   else if (!strcmp (key, "default-cf-visi"))
1233     {
1234       pinentry.default_cf_visi = strdup (value);
1235       if (!pinentry.default_cf_visi)
1236 	return gpg_error_from_syserror ();
1237     }
1238   else if (!strcmp (key, "default-tt-visi"))
1239     {
1240       pinentry.default_tt_visi = strdup (value);
1241       if (!pinentry.default_tt_visi)
1242 	return gpg_error_from_syserror ();
1243     }
1244   else if (!strcmp (key, "default-tt-hide"))
1245     {
1246       pinentry.default_tt_hide = strdup (value);
1247       if (!pinentry.default_tt_hide)
1248 	return gpg_error_from_syserror ();
1249     }
1250   else if (!strcmp (key, "allow-external-password-cache") && !*value)
1251     {
1252       pinentry.allow_external_password_cache = 1;
1253       pinentry.tried_password_cache = 0;
1254     }
1255   else if (!strcmp (key, "allow-emacs-prompt") && !*value)
1256     {
1257 #ifdef INSIDE_EMACS
1258       pinentry_enable_emacs_cmd_handler ();
1259 #endif
1260     }
1261   else if (!strcmp (key, "invisible-char"))
1262     {
1263       if (pinentry.invisible_char)
1264         free (pinentry.invisible_char);
1265       pinentry.invisible_char = strdup (value);
1266       if (!pinentry.invisible_char)
1267 	return gpg_error_from_syserror ();
1268     }
1269   else
1270     return gpg_error (GPG_ERR_UNKNOWN_OPTION);
1271   return 0;
1272 }
1273 
1274 
1275 /* Note, that it is sufficient to allocate the target string D as
1276    long as the source string S, i.e.: strlen(s)+1; */
1277 static void
strcpy_escaped(char * d,const char * s)1278 strcpy_escaped (char *d, const char *s)
1279 {
1280   while (*s)
1281     {
1282       if (*s == '%' && s[1] && s[2])
1283         {
1284           s++;
1285           *d++ = xtoi_2 ( s);
1286           s += 2;
1287         }
1288       else
1289         *d++ = *s++;
1290     }
1291   *d = 0;
1292 }
1293 
1294 
1295 static void
write_status_error(assuan_context_t ctx,pinentry_t pe)1296 write_status_error (assuan_context_t ctx, pinentry_t pe)
1297 {
1298   char buf[500];
1299   const char *pgm;
1300 
1301   pgm = strchr (this_pgmname, '-');
1302   if (pgm && pgm[1])
1303     pgm++;
1304   else
1305     pgm = this_pgmname;
1306 
1307   snprintf (buf, sizeof buf, "%s.%s %d %s",
1308             pgm,
1309             pe->specific_err_loc? pe->specific_err_loc : "?",
1310             pe->specific_err,
1311             pe->specific_err_info? pe->specific_err_info : "");
1312   buf[sizeof buf -1] = 0;
1313   assuan_write_status (ctx, "ERROR", buf);
1314 }
1315 
1316 
1317 static gpg_error_t
cmd_setdesc(assuan_context_t ctx,char * line)1318 cmd_setdesc (assuan_context_t ctx, char *line)
1319 {
1320   char *newd;
1321 
1322   (void)ctx;
1323 
1324   newd = malloc (strlen (line) + 1);
1325   if (!newd)
1326     return gpg_error_from_syserror ();
1327 
1328   strcpy_escaped (newd, line);
1329   if (pinentry.description)
1330     free (pinentry.description);
1331   pinentry.description = newd;
1332   return 0;
1333 }
1334 
1335 
1336 static gpg_error_t
cmd_setprompt(assuan_context_t ctx,char * line)1337 cmd_setprompt (assuan_context_t ctx, char *line)
1338 {
1339   char *newp;
1340 
1341   (void)ctx;
1342 
1343   newp = malloc (strlen (line) + 1);
1344   if (!newp)
1345     return gpg_error_from_syserror ();
1346 
1347   strcpy_escaped (newp, line);
1348   if (pinentry.prompt)
1349     free (pinentry.prompt);
1350   pinentry.prompt = newp;
1351   return 0;
1352 }
1353 
1354 
1355 /* The data provided at LINE may be used by pinentry implementations
1356    to identify a key for caching strategies of its own.  The empty
1357    string and --clear mean that the key does not have a stable
1358    identifier.  */
1359 static gpg_error_t
cmd_setkeyinfo(assuan_context_t ctx,char * line)1360 cmd_setkeyinfo (assuan_context_t ctx, char *line)
1361 {
1362   (void)ctx;
1363 
1364   if (pinentry.keyinfo)
1365     free (pinentry.keyinfo);
1366 
1367   if (*line && strcmp(line, "--clear") != 0)
1368     pinentry.keyinfo = strdup (line);
1369   else
1370     pinentry.keyinfo = NULL;
1371 
1372   return 0;
1373 }
1374 
1375 
1376 static gpg_error_t
cmd_setrepeat(assuan_context_t ctx,char * line)1377 cmd_setrepeat (assuan_context_t ctx, char *line)
1378 {
1379   char *p;
1380 
1381   (void)ctx;
1382 
1383   p = malloc (strlen (line) + 1);
1384   if (!p)
1385     return gpg_error_from_syserror ();
1386 
1387   strcpy_escaped (p, line);
1388   free (pinentry.repeat_passphrase);
1389   pinentry.repeat_passphrase = p;
1390   return 0;
1391 }
1392 
1393 
1394 static gpg_error_t
cmd_setrepeaterror(assuan_context_t ctx,char * line)1395 cmd_setrepeaterror (assuan_context_t ctx, char *line)
1396 {
1397   char *p;
1398 
1399   (void)ctx;
1400 
1401   p = malloc (strlen (line) + 1);
1402   if (!p)
1403     return gpg_error_from_syserror ();
1404 
1405   strcpy_escaped (p, line);
1406   free (pinentry.repeat_error_string);
1407   pinentry.repeat_error_string = p;
1408   return 0;
1409 }
1410 
1411 
1412 static gpg_error_t
cmd_seterror(assuan_context_t ctx,char * line)1413 cmd_seterror (assuan_context_t ctx, char *line)
1414 {
1415   char *newe;
1416 
1417   (void)ctx;
1418 
1419   newe = malloc (strlen (line) + 1);
1420   if (!newe)
1421     return gpg_error_from_syserror ();
1422 
1423   strcpy_escaped (newe, line);
1424   if (pinentry.error)
1425     free (pinentry.error);
1426   pinentry.error = newe;
1427   return 0;
1428 }
1429 
1430 
1431 static gpg_error_t
cmd_setok(assuan_context_t ctx,char * line)1432 cmd_setok (assuan_context_t ctx, char *line)
1433 {
1434   char *newo;
1435 
1436   (void)ctx;
1437 
1438   newo = malloc (strlen (line) + 1);
1439   if (!newo)
1440     return gpg_error_from_syserror ();
1441 
1442   strcpy_escaped (newo, line);
1443   if (pinentry.ok)
1444     free (pinentry.ok);
1445   pinentry.ok = newo;
1446   return 0;
1447 }
1448 
1449 
1450 static gpg_error_t
cmd_setnotok(assuan_context_t ctx,char * line)1451 cmd_setnotok (assuan_context_t ctx, char *line)
1452 {
1453   char *newo;
1454 
1455   (void)ctx;
1456 
1457   newo = malloc (strlen (line) + 1);
1458   if (!newo)
1459     return gpg_error_from_syserror ();
1460 
1461   strcpy_escaped (newo, line);
1462   if (pinentry.notok)
1463     free (pinentry.notok);
1464   pinentry.notok = newo;
1465   return 0;
1466 }
1467 
1468 
1469 static gpg_error_t
cmd_setcancel(assuan_context_t ctx,char * line)1470 cmd_setcancel (assuan_context_t ctx, char *line)
1471 {
1472   char *newc;
1473 
1474   (void)ctx;
1475 
1476   newc = malloc (strlen (line) + 1);
1477   if (!newc)
1478     return gpg_error_from_syserror ();
1479 
1480   strcpy_escaped (newc, line);
1481   if (pinentry.cancel)
1482     free (pinentry.cancel);
1483   pinentry.cancel = newc;
1484   return 0;
1485 }
1486 
1487 
1488 static gpg_error_t
cmd_settimeout(assuan_context_t ctx,char * line)1489 cmd_settimeout (assuan_context_t ctx, char *line)
1490 {
1491   (void)ctx;
1492 
1493   if (line && *line)
1494     pinentry.timeout = atoi (line);
1495 
1496   return 0;
1497 }
1498 
1499 static gpg_error_t
cmd_settitle(assuan_context_t ctx,char * line)1500 cmd_settitle (assuan_context_t ctx, char *line)
1501 {
1502   char *newt;
1503 
1504   (void)ctx;
1505 
1506   newt = malloc (strlen (line) + 1);
1507   if (!newt)
1508     return gpg_error_from_syserror ();
1509 
1510   strcpy_escaped (newt, line);
1511   if (pinentry.title)
1512     free (pinentry.title);
1513   pinentry.title = newt;
1514   return 0;
1515 }
1516 
1517 static gpg_error_t
cmd_setqualitybar(assuan_context_t ctx,char * line)1518 cmd_setqualitybar (assuan_context_t ctx, char *line)
1519 {
1520   char *newval;
1521 
1522   (void)ctx;
1523 
1524   if (!*line)
1525     line = "Quality:";
1526 
1527   newval = malloc (strlen (line) + 1);
1528   if (!newval)
1529     return gpg_error_from_syserror ();
1530 
1531   strcpy_escaped (newval, line);
1532   if (pinentry.quality_bar)
1533     free (pinentry.quality_bar);
1534   pinentry.quality_bar = newval;
1535   return 0;
1536 }
1537 
1538 /* Set the tooltip to be used for a quality bar.  */
1539 static gpg_error_t
cmd_setqualitybar_tt(assuan_context_t ctx,char * line)1540 cmd_setqualitybar_tt (assuan_context_t ctx, char *line)
1541 {
1542   char *newval;
1543 
1544   (void)ctx;
1545 
1546   if (*line)
1547     {
1548       newval = malloc (strlen (line) + 1);
1549       if (!newval)
1550         return gpg_error_from_syserror ();
1551 
1552       strcpy_escaped (newval, line);
1553     }
1554   else
1555     newval = NULL;
1556   if (pinentry.quality_bar_tt)
1557     free (pinentry.quality_bar_tt);
1558   pinentry.quality_bar_tt = newval;
1559   return 0;
1560 }
1561 
1562 /* Set the tooltip to be used for a generate action.  */
1563 static gpg_error_t
cmd_setgenpin_tt(assuan_context_t ctx,char * line)1564 cmd_setgenpin_tt (assuan_context_t ctx, char *line)
1565 {
1566   char *newval;
1567 
1568   (void)ctx;
1569 
1570   if (*line)
1571     {
1572       newval = malloc (strlen (line) + 1);
1573       if (!newval)
1574         return gpg_error_from_syserror ();
1575 
1576       strcpy_escaped (newval, line);
1577     }
1578   else
1579     newval = NULL;
1580   if (pinentry.genpin_tt)
1581     free (pinentry.genpin_tt);
1582   pinentry.genpin_tt = newval;
1583   return 0;
1584 }
1585 
1586 /* Set the label to be used for a generate action.  */
1587 static gpg_error_t
cmd_setgenpin_label(assuan_context_t ctx,char * line)1588 cmd_setgenpin_label (assuan_context_t ctx, char *line)
1589 {
1590   char *newval;
1591 
1592   (void)ctx;
1593 
1594   if (*line)
1595     {
1596       newval = malloc (strlen (line) + 1);
1597       if (!newval)
1598         return gpg_error_from_syserror ();
1599 
1600       strcpy_escaped (newval, line);
1601     }
1602   else
1603     newval = NULL;
1604   if (pinentry.genpin_label)
1605     free (pinentry.genpin_label);
1606   pinentry.genpin_label = newval;
1607   return 0;
1608 }
1609 
1610 static gpg_error_t
cmd_getpin(assuan_context_t ctx,char * line)1611 cmd_getpin (assuan_context_t ctx, char *line)
1612 {
1613   int result;
1614   int set_prompt = 0;
1615   int just_read_password_from_cache = 0;
1616 
1617   (void)line;
1618 
1619   pinentry_setbuffer_init (&pinentry);
1620   if (!pinentry.pin)
1621     return gpg_error (GPG_ERR_ENOMEM);
1622 
1623   /* Try reading from the password cache.  */
1624   if (/* If repeat passphrase is set, then we don't want to read from
1625 	 the cache.  */
1626       ! pinentry.repeat_passphrase
1627       /* Are we allowed to read from the cache?  */
1628       && pinentry.allow_external_password_cache
1629       && pinentry.keyinfo
1630       /* Only read from the cache if we haven't already tried it.  */
1631       && ! pinentry.tried_password_cache
1632       /* If the last read resulted in an error, then don't read from
1633 	 the cache.  */
1634       && ! pinentry.error)
1635     {
1636       char *password;
1637       int give_up_on_password_store = 0;
1638 
1639       pinentry.tried_password_cache = 1;
1640 
1641       password = password_cache_lookup (pinentry.keyinfo, &give_up_on_password_store);
1642       if (give_up_on_password_store)
1643 	pinentry.allow_external_password_cache = 0;
1644 
1645       if (password)
1646 	/* There is a cached password.  Try it.  */
1647 	{
1648 	  int len = strlen(password) + 1;
1649 	  if (len > pinentry.pin_len)
1650 	    len = pinentry.pin_len;
1651 
1652 	  memcpy (pinentry.pin, password, len);
1653 	  pinentry.pin[len] = '\0';
1654 
1655 	  secmem_free (password);
1656 
1657 	  pinentry.pin_from_cache = 1;
1658 
1659 	  assuan_write_status (ctx, "PASSWORD_FROM_CACHE", "");
1660 
1661 	  /* Result is the length of the password not including the
1662 	     NUL terminator.  */
1663 	  result = len - 1;
1664 
1665 	  just_read_password_from_cache = 1;
1666 
1667 	  goto out;
1668 	}
1669     }
1670 
1671   /* The password was not cached (or we are not allowed to / cannot
1672      use the cache).  Prompt the user.  */
1673   pinentry.pin_from_cache = 0;
1674 
1675   if (!pinentry.prompt)
1676     {
1677       pinentry.prompt = pinentry.default_prompt?pinentry.default_prompt:"PIN:";
1678       set_prompt = 1;
1679     }
1680   pinentry.locale_err = 0;
1681   pinentry.specific_err = 0;
1682   pinentry.specific_err_loc = NULL;
1683   free (pinentry.specific_err_info);
1684   pinentry.specific_err_info = NULL;
1685   pinentry.close_button = 0;
1686   pinentry.repeat_okay = 0;
1687   pinentry.one_button = 0;
1688   pinentry.ctx_assuan = ctx;
1689   result = (*pinentry_cmd_handler) (&pinentry);
1690   pinentry.ctx_assuan = NULL;
1691   if (pinentry.error)
1692     {
1693       free (pinentry.error);
1694       pinentry.error = NULL;
1695     }
1696   if (pinentry.repeat_passphrase)
1697     {
1698       free (pinentry.repeat_passphrase);
1699       pinentry.repeat_passphrase = NULL;
1700     }
1701   if (set_prompt)
1702     pinentry.prompt = NULL;
1703 
1704   pinentry.quality_bar = 0;  /* Reset it after the command.  */
1705 
1706   if (pinentry.close_button)
1707     assuan_write_status (ctx, "BUTTON_INFO", "close");
1708 
1709   if (result < 0)
1710     {
1711       pinentry_setbuffer_clear (&pinentry);
1712       if (pinentry.specific_err)
1713         {
1714           write_status_error (ctx, &pinentry);
1715 
1716           if (gpg_err_code (pinentry.specific_err) == GPG_ERR_FULLY_CANCELED)
1717             assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
1718 
1719           return pinentry.specific_err;
1720         }
1721       return (pinentry.locale_err
1722 	      ? gpg_error (GPG_ERR_LOCALE_PROBLEM)
1723 	      : gpg_error (GPG_ERR_CANCELED));
1724     }
1725 
1726  out:
1727   if (result)
1728     {
1729       if (pinentry.repeat_okay)
1730         assuan_write_status (ctx, "PIN_REPEATED", "");
1731       result = assuan_send_data (ctx, pinentry.pin, strlen(pinentry.pin));
1732       if (!result)
1733 	result = assuan_send_data (ctx, NULL, 0);
1734 
1735       if (/* GPG Agent says it's okay.  */
1736 	  pinentry.allow_external_password_cache && pinentry.keyinfo
1737 	  /* We didn't just read it from the cache.  */
1738 	  && ! just_read_password_from_cache
1739 	  /* And the user said it's okay.  */
1740 	  && pinentry.may_cache_password)
1741 	/* Cache the password.  */
1742 	password_cache_save (pinentry.keyinfo, pinentry.pin);
1743     }
1744 
1745   pinentry_setbuffer_clear (&pinentry);
1746 
1747   return result;
1748 }
1749 
1750 
1751 /* Note that the option --one-button is a hack to allow the use of old
1752    pinentries while the caller is ignoring the result.  Given that
1753    options have never been used or flagged as an error the new option
1754    is an easy way to enable the messsage mode while not requiring to
1755    update pinentry or to have the caller test for the message
1756    command.  New applications which are free to require an updated
1757    pinentry should use MESSAGE instead. */
1758 static gpg_error_t
cmd_confirm(assuan_context_t ctx,char * line)1759 cmd_confirm (assuan_context_t ctx, char *line)
1760 {
1761   int result;
1762 
1763   pinentry.one_button = !!strstr (line, "--one-button");
1764   pinentry.quality_bar = 0;
1765   pinentry.close_button = 0;
1766   pinentry.locale_err = 0;
1767   pinentry.specific_err = 0;
1768   pinentry.specific_err_loc = NULL;
1769   free (pinentry.specific_err_info);
1770   pinentry.specific_err_info = NULL;
1771   pinentry.canceled = 0;
1772   pinentry_setbuffer_clear (&pinentry);
1773   result = (*pinentry_cmd_handler) (&pinentry);
1774   if (pinentry.error)
1775     {
1776       free (pinentry.error);
1777       pinentry.error = NULL;
1778     }
1779 
1780   if (pinentry.close_button)
1781     assuan_write_status (ctx, "BUTTON_INFO", "close");
1782 
1783   if (result > 0)
1784     return 0; /* OK */
1785 
1786   if (pinentry.specific_err)
1787     {
1788       write_status_error (ctx, &pinentry);
1789 
1790       if (gpg_err_code (pinentry.specific_err) == GPG_ERR_FULLY_CANCELED)
1791         assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
1792 
1793       return pinentry.specific_err;
1794     }
1795 
1796   if (pinentry.locale_err)
1797     return gpg_error (GPG_ERR_LOCALE_PROBLEM);
1798 
1799   if (pinentry.one_button)
1800     return 0; /* OK */
1801 
1802   if (pinentry.canceled)
1803     return gpg_error (GPG_ERR_CANCELED);
1804   return gpg_error (GPG_ERR_NOT_CONFIRMED);
1805 }
1806 
1807 
1808 static gpg_error_t
cmd_message(assuan_context_t ctx,char * line)1809 cmd_message (assuan_context_t ctx, char *line)
1810 {
1811   (void)line;
1812 
1813   return cmd_confirm (ctx, "--one-button");
1814 }
1815 
1816 
1817 /* Return a staically allocated string with information on the mode,
1818  * uid, and gid of DEVICE.  On error "?" is returned if DEVICE is
1819  * NULL, "-" is returned.  */
1820 static const char *
device_stat_string(const char * device)1821 device_stat_string (const char *device)
1822 {
1823 #ifdef HAVE_STAT
1824   static char buf[40];
1825   struct stat st;
1826 
1827   if (!device || !*device)
1828     return "-";
1829 
1830   if (stat (device, &st))
1831     return "?";  /* Error */
1832   snprintf (buf, sizeof buf, "%lo/%lu/%lu",
1833             (unsigned long)st.st_mode,
1834             (unsigned long)st.st_uid,
1835             (unsigned long)st.st_gid);
1836   return buf;
1837 #else
1838   return "-";
1839 #endif
1840 }
1841 
1842 
1843 /* GETINFO <what>
1844 
1845    Multipurpose function to return a variety of information.
1846    Supported values for WHAT are:
1847 
1848      version     - Return the version of the program.
1849      pid         - Return the process id of the server.
1850      flavor      - Return information about the used pinentry flavor
1851      ttyinfo     - Return DISPLAY, ttyinfo and an emacs pinentry status
1852  */
1853 static gpg_error_t
cmd_getinfo(assuan_context_t ctx,char * line)1854 cmd_getinfo (assuan_context_t ctx, char *line)
1855 {
1856   int rc;
1857   const char *s;
1858   char buffer[150];
1859 
1860   if (!strcmp (line, "version"))
1861     {
1862       s = VERSION;
1863       rc = assuan_send_data (ctx, s, strlen (s));
1864     }
1865   else if (!strcmp (line, "pid"))
1866     {
1867 
1868       snprintf (buffer, sizeof buffer, "%lu", (unsigned long)getpid ());
1869       buffer[sizeof buffer -1] = 0;
1870       rc = assuan_send_data (ctx, buffer, strlen (buffer));
1871     }
1872   else if (!strcmp (line, "flavor"))
1873     {
1874       if (!strncmp (this_pgmname, "pinentry-", 9) && this_pgmname[9])
1875         s = this_pgmname + 9;
1876       else
1877         s = this_pgmname;
1878 
1879       snprintf (buffer, sizeof buffer, "%s%s%s",
1880                 s,
1881                 flavor_flag? ":":"",
1882                 flavor_flag? flavor_flag : "");
1883       buffer[sizeof buffer -1] = 0;
1884       rc = assuan_send_data (ctx, buffer, strlen (buffer));
1885       /* if (!rc) */
1886       /*   rc = assuan_write_status (ctx, "FEATURES", "tabbing foo bar"); */
1887     }
1888   else if (!strcmp (line, "ttyinfo"))
1889     {
1890       char emacs_status[10];
1891 #ifdef INSIDE_EMACS
1892       snprintf (emacs_status, sizeof emacs_status,
1893                 "%d", pinentry_emacs_status ());
1894 #else
1895       strcpy (emacs_status, "-");
1896 #endif
1897       snprintf (buffer, sizeof buffer, "%s %s %s %s %lu/%lu %s",
1898                 pinentry.ttyname? pinentry.ttyname : "-",
1899                 pinentry.ttytype_l? pinentry.ttytype_l : "-",
1900                 pinentry.display? pinentry.display : "-",
1901                 device_stat_string (pinentry.ttyname),
1902 #ifdef HAVE_DOSISH_SYSTEM
1903                 0l, 0l,
1904 #else
1905                 (unsigned long)geteuid (), (unsigned long)getegid (),
1906 #endif
1907                 emacs_status
1908                 );
1909       buffer[sizeof buffer -1] = 0;
1910       rc = assuan_send_data (ctx, buffer, strlen (buffer));
1911     }
1912   else
1913     rc = gpg_error (GPG_ERR_ASS_PARAMETER);
1914   return rc;
1915 }
1916 
1917 /* CLEARPASSPHRASE <cacheid>
1918 
1919    Clear the cache passphrase associated with the key identified by
1920    cacheid.
1921  */
1922 static gpg_error_t
cmd_clear_passphrase(assuan_context_t ctx,char * line)1923 cmd_clear_passphrase (assuan_context_t ctx, char *line)
1924 {
1925   (void)ctx;
1926 
1927   if (! line)
1928     return gpg_error (GPG_ERR_ASS_INV_VALUE);
1929 
1930   /* Remove leading and trailing white space.  */
1931   while (*line == ' ')
1932     line ++;
1933   while (line[strlen (line) - 1] == ' ')
1934     line[strlen (line) - 1] = 0;
1935 
1936   switch (password_cache_clear (line))
1937     {
1938     case 1: return 0;
1939     case 0: return gpg_error (GPG_ERR_ASS_INV_VALUE);
1940     default: return gpg_error (GPG_ERR_ASS_GENERAL);
1941     }
1942 }
1943 
1944 /* Tell the assuan library about our commands.  */
1945 static gpg_error_t
register_commands(assuan_context_t ctx)1946 register_commands (assuan_context_t ctx)
1947 {
1948   static struct
1949   {
1950     const char *name;
1951     gpg_error_t (*handler) (assuan_context_t, char *line);
1952   } table[] =
1953     {
1954       { "SETDESC",    cmd_setdesc },
1955       { "SETPROMPT",  cmd_setprompt },
1956       { "SETKEYINFO", cmd_setkeyinfo },
1957       { "SETREPEAT",  cmd_setrepeat },
1958       { "SETREPEATERROR", cmd_setrepeaterror },
1959       { "SETERROR",   cmd_seterror },
1960       { "SETOK",      cmd_setok },
1961       { "SETNOTOK",   cmd_setnotok },
1962       { "SETCANCEL",  cmd_setcancel },
1963       { "GETPIN",     cmd_getpin },
1964       { "CONFIRM",    cmd_confirm },
1965       { "MESSAGE",    cmd_message },
1966       { "SETQUALITYBAR", cmd_setqualitybar },
1967       { "SETQUALITYBAR_TT", cmd_setqualitybar_tt },
1968       { "SETGENPIN",    cmd_setgenpin_label },
1969       { "SETGENPIN_TT", cmd_setgenpin_tt },
1970       { "GETINFO",    cmd_getinfo },
1971       { "SETTITLE",   cmd_settitle },
1972       { "SETTIMEOUT", cmd_settimeout },
1973       { "CLEARPASSPHRASE", cmd_clear_passphrase },
1974       { NULL }
1975     };
1976   int i, j;
1977   gpg_error_t rc;
1978 
1979   for (i = j = 0; table[i].name; i++)
1980     {
1981       rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL);
1982       if (rc)
1983         return rc;
1984     }
1985   return 0;
1986 }
1987 
1988 
1989 int
pinentry_loop2(int infd,int outfd)1990 pinentry_loop2 (int infd, int outfd)
1991 {
1992   gpg_error_t rc;
1993   assuan_fd_t filedes[2];
1994   assuan_context_t ctx;
1995 
1996   /* Extra check to make sure we have dropped privs. */
1997 #ifndef HAVE_DOSISH_SYSTEM
1998   if (getuid() != geteuid())
1999     abort ();
2000 #endif
2001 
2002   rc = assuan_new (&ctx);
2003   if (rc)
2004     {
2005       fprintf (stderr, "server context creation failed: %s\n",
2006 	       gpg_strerror (rc));
2007       return -1;
2008     }
2009 
2010   /* For now we use a simple pipe based server so that we can work
2011      from scripts.  We will later add options to run as a daemon and
2012      wait for requests on a Unix domain socket.  */
2013   filedes[0] = assuan_fdopen (infd);
2014   filedes[1] = assuan_fdopen (outfd);
2015   rc = assuan_init_pipe_server (ctx, filedes);
2016   if (rc)
2017     {
2018       fprintf (stderr, "%s: failed to initialize the server: %s\n",
2019                this_pgmname, gpg_strerror (rc));
2020       return -1;
2021     }
2022   rc = register_commands (ctx);
2023   if (rc)
2024     {
2025       fprintf (stderr, "%s: failed to the register commands with Assuan: %s\n",
2026                this_pgmname, gpg_strerror (rc));
2027       return -1;
2028     }
2029 
2030   assuan_register_option_handler (ctx, option_handler);
2031 #if 0
2032   assuan_set_log_stream (ctx, stderr);
2033 #endif
2034   assuan_register_reset_notify (ctx, pinentry_assuan_reset_handler);
2035 
2036   for (;;)
2037     {
2038       rc = assuan_accept (ctx);
2039       if (rc == -1)
2040           break;
2041       else if (rc)
2042         {
2043           fprintf (stderr, "%s: Assuan accept problem: %s\n",
2044                    this_pgmname, gpg_strerror (rc));
2045           break;
2046         }
2047 
2048       rc = assuan_process (ctx);
2049       if (rc)
2050         {
2051           fprintf (stderr, "%s: Assuan processing failed: %s\n",
2052                    this_pgmname, gpg_strerror (rc));
2053           continue;
2054         }
2055     }
2056 
2057   assuan_release (ctx);
2058   return 0;
2059 }
2060 
2061 
2062 /* Start the pinentry event loop.  The program will start to process
2063    Assuan commands until it is finished or an error occurs.  If an
2064    error occurs, -1 is returned.  Otherwise, 0 is returned.  */
2065 int
pinentry_loop(void)2066 pinentry_loop (void)
2067 {
2068   return pinentry_loop2 (STDIN_FILENO, STDOUT_FILENO);
2069 }
2070