Support the SETQUALITYBAR command of recent pinentries.
[gnupg.git] / agent / call-pinentry.c
1 /* call-pinentry.c - fork of the pinentry to query stuff from the user
2  * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <assert.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #ifndef HAVE_W32_SYSTEM
30 #include <sys/wait.h>
31 #endif
32 #include <pth.h>
33 #include <assuan.h>
34
35 #include "agent.h"
36 #include "i18n.h"
37
38 #ifdef _POSIX_OPEN_MAX
39 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
40 #else
41 #define MAX_OPEN_FDS 20
42 #endif
43
44
45 /* Because access to the pinentry must be serialized (it is and shall
46    be a global mutual dialog) we should better timeout further
47    requests after some time.  2 minutes seem to be a reasonable
48    time. */
49 #define LOCK_TIMEOUT  (1*60)
50
51 /* The assuan context of the current pinentry. */
52 static assuan_context_t entry_ctx;
53
54 /* The control variable of the connection owning the current pinentry.
55    This is only valid if ENTRY_CTX is not NULL.  Note, that we care
56    only about the value of the pointer and that it should never be
57    dereferenced.  */
58 static ctrl_t entry_owner;
59
60 /* A mutex used to serialize access to the pinentry. */
61 static pth_mutex_t entry_lock;
62
63 /* The thread ID of the popup working thread. */
64 static pth_t  popup_tid;
65
66 /* A flag used in communication between the popup working thread and
67    its stop function. */
68 static int popup_finished;
69
70
71
72 /* Data to be passed to our callbacks, */
73 struct entry_parm_s
74 {
75   int lines;
76   size_t size;
77   unsigned char *buffer;
78 };
79
80
81
82 \f
83 /* This function must be called once to initialize this module.  This
84    has to be done before a second thread is spawned.  We can't do the
85    static initialization because Pth emulation code might not be able
86    to do a static init; in particular, it is not possible for W32. */
87 void
88 initialize_module_call_pinentry (void)
89 {
90   static int initialized;
91
92   if (!initialized)
93     {
94       if (pth_mutex_init (&entry_lock))
95         initialized = 1;
96     }
97 }
98
99
100
101 static void
102 dump_mutex_state (pth_mutex_t *m)
103 {
104 #ifdef _W32_PTH_H
105   log_printf ("unknown under W32");
106 #else
107   if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
108     log_printf ("not_initialized");
109   else if (!(m->mx_state & PTH_MUTEX_LOCKED))
110     log_printf ("not_locked");
111   else
112     log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
113 #endif
114 }
115
116
117 /* This function may be called to print infromation pertaining to the
118    current state of this module to the log. */
119 void
120 agent_query_dump_state (void)
121 {
122   log_info ("agent_query_dump_state: entry_lock=");
123   dump_mutex_state (&entry_lock);
124   log_printf ("\n");
125   log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
126             entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid);
127 }
128
129 /* Called to make sure that a popup window owned by the current
130    connection gets closed. */
131 void
132 agent_reset_query (ctrl_t ctrl)
133 {
134   if (entry_ctx && popup_tid && entry_owner == ctrl)
135     {
136       agent_popup_message_stop (ctrl);
137     }
138 }
139
140
141 /* Unlock the pinentry so that another thread can start one and
142    disconnect that pinentry - we do this after the unlock so that a
143    stalled pinentry does not block other threads.  Fixme: We should
144    have a timeout in Assuan for the disconnect operation. */
145 static int 
146 unlock_pinentry (int rc)
147 {
148   assuan_context_t ctx = entry_ctx;
149
150   entry_ctx = NULL;
151   if (!pth_mutex_release (&entry_lock))
152     {
153       log_error ("failed to release the entry lock\n");
154       if (!rc)
155         rc = gpg_error (GPG_ERR_INTERNAL);
156     }
157   assuan_disconnect (ctx);
158   return rc;
159 }
160
161
162 /* To make sure we leave no secrets in our image after forking of the
163    pinentry, we use this callback. */
164 static void
165 atfork_cb (void *opaque, int where)
166 {
167   if (!where)
168     gcry_control (GCRYCTL_TERM_SECMEM);
169 }
170
171
172 /* Fork off the pin entry if this has not already been done.  Note,
173    that this function must always be used to aquire the lock for the
174    pinentry - we will serialize _all_ pinentry calls.
175  */
176 static int
177 start_pinentry (ctrl_t ctrl)
178 {
179   int rc;
180   const char *pgmname;
181   assuan_context_t ctx;
182   const char *argv[5];
183   int no_close_list[3];
184   int i;
185   pth_event_t evt;
186   const char *tmpstr;
187
188   evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
189   if (!pth_mutex_acquire (&entry_lock, 0, evt))
190     {
191       if (pth_event_occurred (evt))
192         rc = gpg_error (GPG_ERR_TIMEOUT);
193       else
194         rc = gpg_error (GPG_ERR_INTERNAL);
195       pth_event_free (evt, PTH_FREE_THIS);
196       log_error (_("failed to acquire the pinentry lock: %s\n"),
197                  gpg_strerror (rc));
198       return rc;
199     }
200   pth_event_free (evt, PTH_FREE_THIS);
201
202   entry_owner = ctrl;
203
204   if (entry_ctx)
205     return 0; 
206
207   if (opt.verbose)
208     log_info ("starting a new PIN Entry\n");
209
210 #ifdef HAVE_W32_SYSTEM      
211   fflush (stdout);
212   fflush (stderr);
213 #endif
214   if (fflush (NULL))
215     {
216 #ifndef HAVE_W32_SYSTEM
217       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
218 #endif
219       log_error ("error flushing pending output: %s\n", strerror (errno));
220       /* At least Windows XP fails here with EBADF.  According to docs
221          and Wine an fflush(NULL) is the same as _flushall.  However
222          the Wime implementaion does not flush stdin,stdout and stderr
223          - see above.  Lets try to ignore the error. */
224 #ifndef HAVE_W32_SYSTEM
225       return unlock_pinentry (tmperr);
226 #endif
227     }
228
229   if (!opt.pinentry_program || !*opt.pinentry_program)
230     opt.pinentry_program = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
231     pgmname = opt.pinentry_program;
232   if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
233     pgmname = opt.pinentry_program;
234   else
235     pgmname++;
236
237   /* OS X needs the entire file name in argv[0], so that it can locate
238      the resource bundle.  For other systems we stick to the usual
239      convention of supplying only the name of the program.  */
240 #ifdef __APPLE__
241   argv[0] = opt.pinentry_program;
242 #else /*!__APPLE__*/
243   argv[0] = pgmname;
244 #endif /*__APPLE__*/
245
246   if (ctrl->display && !opt.keep_display)
247     {
248       argv[1] = "--display";
249       argv[2] = ctrl->display;
250       argv[3] = NULL;
251     }
252   else
253     argv[1] = NULL;
254   
255   i=0;
256   if (!opt.running_detached)
257     {
258       if (log_get_fd () != -1)
259         no_close_list[i++] = log_get_fd ();
260       no_close_list[i++] = fileno (stderr);
261     }
262   no_close_list[i] = -1;
263
264   /* Connect to the pinentry and perform initial handshaking */
265   rc = assuan_pipe_connect_ext (&ctx, opt.pinentry_program, argv,
266                                 no_close_list, atfork_cb, NULL, 0);
267   if (rc)
268     {
269       log_error ("can't connect to the PIN entry module: %s\n",
270                  gpg_strerror (rc));
271       return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
272     }
273   entry_ctx = ctx;
274
275   if (DBG_ASSUAN)
276     log_debug ("connection to PIN entry established\n");
277
278   rc = assuan_transact (entry_ctx, 
279                         opt.no_grab? "OPTION no-grab":"OPTION grab",
280                         NULL, NULL, NULL, NULL, NULL, NULL);
281   if (rc)
282     return unlock_pinentry (rc);
283   if (ctrl->ttyname)
284     {
285       char *optstr;
286       if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
287         return unlock_pinentry (out_of_core ());
288       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
289                             NULL);
290       free (optstr);
291       if (rc)
292         return unlock_pinentry (rc);
293     }
294   if (ctrl->ttytype)
295     {
296       char *optstr;
297       if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
298         return unlock_pinentry (out_of_core ());
299       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
300                             NULL);
301       if (rc)
302         return unlock_pinentry (rc);
303     }
304   if (ctrl->lc_ctype)
305     {
306       char *optstr;
307       if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
308         return unlock_pinentry (out_of_core ());
309       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
310                             NULL);
311       if (rc)
312         return unlock_pinentry (rc);
313     }
314   if (ctrl->lc_messages)
315     {
316       char *optstr;
317       if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
318         return unlock_pinentry (out_of_core ());
319       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
320                             NULL);
321       if (rc)
322         return unlock_pinentry (rc);
323     }
324
325   
326   /* Tell the pinentry the name of a file it shall touch after having
327      messed with the tty.  This is optional and only supported by
328      newer pinentries and thus we do no error checking. */
329   tmpstr = opt.pinentry_touch_file;
330   if (tmpstr && !strcmp (tmpstr, "/dev/null"))
331     tmpstr = NULL;
332   else if (!tmpstr)
333     tmpstr = get_agent_socket_name ();
334   if (tmpstr)
335     {
336       char *optstr;
337       
338       if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
339         ;
340       else
341         {
342           assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
343                            NULL);
344           free (optstr);
345         }
346     }
347
348   return 0;
349 }
350
351 /* Returns True is the pinentry is currently active. If WAITSECONDS is
352    greater than zero the function will wait for this many seconds
353    before returning.  */
354 int
355 pinentry_active_p (ctrl_t ctrl, int waitseconds)
356 {
357   if (waitseconds > 0)
358     {
359       pth_event_t evt;
360       int rc;
361
362       evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0));
363       if (!pth_mutex_acquire (&entry_lock, 0, evt))
364         {
365           if (pth_event_occurred (evt))
366             rc = gpg_error (GPG_ERR_TIMEOUT);
367           else
368             rc = gpg_error (GPG_ERR_INTERNAL);
369           pth_event_free (evt, PTH_FREE_THIS);
370           return rc;
371         }
372       pth_event_free (evt, PTH_FREE_THIS);
373     }
374   else
375     {
376       if (!pth_mutex_acquire (&entry_lock, 1, NULL))
377         return gpg_error (GPG_ERR_LOCKED);
378     }
379
380   if (!pth_mutex_release (&entry_lock))
381     log_error ("failed to release the entry lock at %d\n", __LINE__);
382   return 0;
383 }
384
385
386 static int
387 getpin_cb (void *opaque, const void *buffer, size_t length)
388 {
389   struct entry_parm_s *parm = opaque;
390
391   if (!buffer)
392     return 0;
393
394   /* we expect the pin to fit on one line */
395   if (parm->lines || length >= parm->size)
396     return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
397
398   /* fixme: we should make sure that the assuan buffer is allocated in
399      secure memory or read the response byte by byte */
400   memcpy (parm->buffer, buffer, length);
401   parm->buffer[length] = 0;
402   parm->lines++;
403   return 0;
404 }
405
406
407 static int
408 all_digitsp( const char *s)
409 {
410   for (; *s && *s >= '0' && *s <= '9'; s++)
411     ;
412   return !*s;
413 }  
414
415
416 /* Return a new malloced string by unescaping the string S.  Escaping
417    is percent escaping and '+'/space mapping.  A binary Nul will
418    silently be replaced by a 0xFF.  Function returns NULL to indicate
419    an out of memory status.  PArsing stops at the end of the string or
420    a white space character. */
421 static char *
422 unescape_passphrase_string (const unsigned char *s)
423 {
424   char *buffer, *d;
425
426   buffer = d = xtrymalloc_secure (strlen ((const char*)s)+1);
427   if (!buffer)
428     return NULL;
429   while (*s && !spacep (s))
430     {
431       if (*s == '%' && s[1] && s[2])
432         { 
433           s++;
434           *d = xtoi_2 (s);
435           if (!*d)
436             *d = '\xff';
437           d++;
438           s += 2;
439         }
440       else if (*s == '+')
441         {
442           *d++ = ' ';
443           s++;
444         }
445       else
446         *d++ = *s++;
447     }
448   *d = 0; 
449   return buffer;
450 }
451
452
453 /* Estimate the quality of the passphrase PW and return a value in the
454    range 0..100.  */
455 static int
456 estimate_passphrase_quality (const char *pw)
457 {
458   int goodlength = opt.min_passphrase_len + opt.min_passphrase_len/3;
459   int length;
460   const char *s;
461
462   if (goodlength < 1)
463     return 0;
464
465   for (length = 0, s = pw; *s; s++)
466     if (!spacep (s))
467       length ++;
468
469   if (length > goodlength)
470     return 100;
471   return ((length*10) / goodlength)*10;
472 }
473
474
475 /* Handle the QUALITY inquiry. */
476 static int
477 inq_quality (void *opaque, const char *line)
478 {
479   assuan_context_t ctx = opaque;
480   char *pin;
481   int rc;
482   int percent;
483   char numbuf[20];
484
485   if (!strncmp (line, "QUALITY", 7) && (line[7] == ' ' || !line[7]))
486     {
487       line += 7;
488       while (*line == ' ')
489         line++;
490       
491       pin = unescape_passphrase_string (line);
492       if (!pin)
493         rc = gpg_error_from_syserror ();
494       else
495         {
496           percent = estimate_passphrase_quality (pin);
497           if (check_passphrase_constraints (NULL, pin, 1))
498             percent = -percent;
499           snprintf (numbuf, sizeof numbuf, "%d", percent);
500           rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
501           xfree (pin);
502         }
503     }
504   else
505     {
506       log_error ("unsupported inquiry `%s' from pinentry\n", line);
507       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
508     }
509
510   return rc;
511 }
512
513
514
515
516 \f
517 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
518    number here and repeat it as long as we have invalid formed
519    numbers. */
520 int
521 agent_askpin (ctrl_t ctrl,
522               const char *desc_text, const char *prompt_text,
523               const char *initial_errtext,
524               struct pin_entry_info_s *pininfo)
525 {
526   int rc;
527   char line[ASSUAN_LINELENGTH];
528   struct entry_parm_s parm;
529   const char *errtext = NULL;
530   int is_pin = 0;
531
532   if (opt.batch)
533     return 0; /* fixme: we should return BAD PIN */
534
535   if (!pininfo || pininfo->max_length < 1)
536     return gpg_error (GPG_ERR_INV_VALUE);
537   if (!desc_text && pininfo->min_digits)
538     desc_text = _("Please enter your PIN, so that the secret key "
539                   "can be unlocked for this session");
540   else if (!desc_text)
541     desc_text = _("Please enter your passphrase, so that the secret key "
542                   "can be unlocked for this session");
543
544   if (prompt_text)
545     is_pin = !!strstr (prompt_text, "PIN");
546   else
547     is_pin = desc_text && strstr (desc_text, "PIN");
548
549   rc = start_pinentry (ctrl);
550   if (rc)
551     return rc;
552
553   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
554   line[DIM(line)-1] = 0;
555   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
556   if (rc)
557     return unlock_pinentry (rc);
558
559   snprintf (line, DIM(line)-1, "SETPROMPT %s",
560             prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
561   line[DIM(line)-1] = 0;
562   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
563   if (rc)
564     return unlock_pinentry (rc);
565
566   /* If a passphrase quality indicator has been requested and a
567      minimum passphrase length has not been disabled, send the command
568      to the pinentry.  */
569   if (pininfo->with_qualitybar && opt.min_passphrase_len )
570     {
571       rc = assuan_transact (entry_ctx, "SETQUALITYBAR",
572                             NULL, NULL, NULL, NULL, NULL, NULL);
573       if (rc)
574         return unlock_pinentry (rc);
575     }
576
577   if (initial_errtext)
578     { 
579       snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
580       line[DIM(line)-1] = 0;
581       rc = assuan_transact (entry_ctx, line,
582                             NULL, NULL, NULL, NULL, NULL, NULL);
583       if (rc)
584         return unlock_pinentry (rc);
585     }
586
587   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
588     {
589       memset (&parm, 0, sizeof parm);
590       parm.size = pininfo->max_length;
591       *pininfo->pin = 0; /* Reset the PIN. */
592       parm.buffer = (unsigned char*)pininfo->pin;
593
594       if (errtext)
595         { 
596           /* TRANLATORS: The string is appended to an error message in
597              the pinentry.  The %s is the actual error message, the
598              two %d give the current and maximum number of tries. */
599           snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
600                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
601           line[DIM(line)-1] = 0;
602           rc = assuan_transact (entry_ctx, line,
603                                 NULL, NULL, NULL, NULL, NULL, NULL);
604           if (rc)
605             return unlock_pinentry (rc);
606           errtext = NULL;
607         }
608       
609       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
610                             inq_quality, entry_ctx, NULL, NULL);
611       /* Most pinentries out in the wild return the old Assuan error code
612          for canceled which gets translated to an assuan Cancel error and
613          not to the code for a user cancel.  Fix this here. */
614       if (rc && gpg_err_source (rc)
615           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
616         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
617
618       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
619         errtext = is_pin? _("PIN too long")
620                         : _("Passphrase too long");
621       else if (rc)
622         return unlock_pinentry (rc);
623
624       if (!errtext && pininfo->min_digits)
625         {
626           /* do some basic checks on the entered PIN. */
627           if (!all_digitsp (pininfo->pin))
628             errtext = _("Invalid characters in PIN");
629           else if (pininfo->max_digits
630                    && strlen (pininfo->pin) > pininfo->max_digits)
631             errtext = _("PIN too long");
632           else if (strlen (pininfo->pin) < pininfo->min_digits)
633             errtext = _("PIN too short");
634         }
635
636       if (!errtext && pininfo->check_cb)
637         {
638           /* More checks by utilizing the optional callback. */
639           pininfo->cb_errtext = NULL;
640           rc = pininfo->check_cb (pininfo);
641           if (rc == -1 && pininfo->cb_errtext)
642             errtext = pininfo->cb_errtext;
643           else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
644                    || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
645             errtext = (is_pin? _("Bad PIN")
646                        : _("Bad Passphrase"));
647           else if (rc)
648             return unlock_pinentry (rc);
649         }
650
651       if (!errtext)
652         return unlock_pinentry (0); /* okay, got a PIN or passphrase */
653     }
654
655   return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
656                           : GPG_ERR_BAD_PASSPHRASE));
657 }
658
659
660 \f
661 /* Ask for the passphrase using the supplied arguments.  The returned
662    passphrase needs to be freed by the caller. */
663 int 
664 agent_get_passphrase (ctrl_t ctrl,
665                       char **retpass, const char *desc, const char *prompt,
666                       const char *errtext)
667 {
668
669   int rc;
670   char line[ASSUAN_LINELENGTH];
671   struct entry_parm_s parm;
672
673   *retpass = NULL;
674   if (opt.batch)
675     return gpg_error (GPG_ERR_BAD_PASSPHRASE); 
676
677   rc = start_pinentry (ctrl);
678   if (rc)
679     return rc;
680
681   if (!prompt)
682     prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
683
684
685   if (desc)
686     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
687   else
688     snprintf (line, DIM(line)-1, "RESET");
689   line[DIM(line)-1] = 0;
690   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
691   if (rc)
692     return unlock_pinentry (rc);
693
694   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
695   line[DIM(line)-1] = 0;
696   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
697   if (rc)
698     return unlock_pinentry (rc);
699
700   if (errtext)
701     {
702       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
703       line[DIM(line)-1] = 0;
704       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
705       if (rc)
706         return unlock_pinentry (rc);
707     }
708
709   memset (&parm, 0, sizeof parm);
710   parm.size = ASSUAN_LINELENGTH/2 - 5;
711   parm.buffer = gcry_malloc_secure (parm.size+10);
712   if (!parm.buffer)
713     return unlock_pinentry (out_of_core ());
714
715   assuan_begin_confidential (entry_ctx);
716   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
717                         NULL, NULL, NULL, NULL);
718   /* Most pinentries out in the wild return the old Assuan error code
719      for canceled which gets translated to an assuan Cancel error and
720      not to the code for a user cancel.  Fix this here. */
721   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
722     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
723   if (rc)
724     xfree (parm.buffer);
725   else
726     *retpass = parm.buffer;
727   return unlock_pinentry (rc);
728 }
729
730
731 \f
732 /* Pop up the PIN-entry, display the text and the prompt and ask the
733    user to confirm this.  We return 0 for success, ie. the user
734    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
735    other error. */
736 int 
737 agent_get_confirmation (ctrl_t ctrl,
738                         const char *desc, const char *ok, const char *cancel)
739 {
740   int rc;
741   char line[ASSUAN_LINELENGTH];
742
743   rc = start_pinentry (ctrl);
744   if (rc)
745     return rc;
746
747   if (desc)
748     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
749   else
750     snprintf (line, DIM(line)-1, "RESET");
751   line[DIM(line)-1] = 0;
752   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
753   /* Most pinentries out in the wild return the old Assuan error code
754      for canceled which gets translated to an assuan Cancel error and
755      not to the code for a user cancel.  Fix this here. */
756   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
757     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
758
759   if (rc)
760     return unlock_pinentry (rc);
761
762   if (ok)
763     {
764       snprintf (line, DIM(line)-1, "SETOK %s", ok);
765       line[DIM(line)-1] = 0;
766       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
767       if (rc)
768         return unlock_pinentry (rc);
769     }
770   if (cancel)
771     {
772       snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
773       line[DIM(line)-1] = 0;
774       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
775       if (rc)
776         return unlock_pinentry (rc);
777     }
778
779   rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
780   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
781     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
782
783   return unlock_pinentry (rc);
784 }
785
786
787 \f
788 /* Pop up the PINentry, display the text DESC and a button with the
789    text OK_BTN (which may be NULL to use the default of "OK") and waut
790    for the user to hit this button.  The return value is not
791    relevant.  */
792 int 
793 agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
794 {
795   int rc;
796   char line[ASSUAN_LINELENGTH];
797
798   rc = start_pinentry (ctrl);
799   if (rc)
800     return rc;
801
802   if (desc)
803     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
804   else
805     snprintf (line, DIM(line)-1, "RESET");
806   line[DIM(line)-1] = 0;
807   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
808   /* Most pinentries out in the wild return the old Assuan error code
809      for canceled which gets translated to an assuan Cancel error and
810      not to the code for a user cancel.  Fix this here. */
811   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
812     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
813
814   if (rc)
815     return unlock_pinentry (rc);
816
817   if (ok_btn)
818     {
819       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
820       line[DIM(line)-1] = 0;
821       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
822                             NULL, NULL, NULL);
823       if (rc)
824         return unlock_pinentry (rc);
825     }
826   
827   rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
828                         NULL, NULL, NULL);
829   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
830     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
831
832   return unlock_pinentry (rc);
833 }
834
835
836 /* The thread running the popup message. */
837 static void *
838 popup_message_thread (void *arg)
839 {
840   /* We use the --one-button hack instead of the MESSAGE command to
841      allow the use of old Pinentries.  Those old Pinentries will then
842      show an additional Cancel button but that is mostly a visual
843      annoyance. */
844   assuan_transact (entry_ctx, "CONFIRM --one-button", 
845                    NULL, NULL, NULL, NULL, NULL, NULL);
846   popup_finished = 1;
847   return NULL;
848 }
849
850
851 /* Pop up a message window similar to the confirm one but keep it open
852    until agent_popup_message_stop has been called.  It is crucial for
853    the caller to make sure that the stop function gets called as soon
854    as the message is not anymore required because the message is
855    system modal and all other attempts to use the pinentry will fail
856    (after a timeout). */
857 int 
858 agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
859 {
860   int rc;
861   char line[ASSUAN_LINELENGTH];
862   pth_attr_t tattr;
863
864   rc = start_pinentry (ctrl);
865   if (rc)
866     return rc;
867
868   if (desc)
869     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
870   else
871     snprintf (line, DIM(line)-1, "RESET");
872   line[DIM(line)-1] = 0;
873   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
874   if (rc)
875     return unlock_pinentry (rc);
876
877   if (ok_btn)
878     {
879       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
880       line[DIM(line)-1] = 0;
881       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
882       if (rc)
883         return unlock_pinentry (rc);
884     }
885
886   tattr = pth_attr_new();
887   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
888   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
889   pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
890
891   popup_finished = 0;
892   popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
893   if (!popup_tid)
894     {
895       rc = gpg_error_from_syserror ();
896       log_error ("error spawning popup message handler: %s\n",
897                  strerror (errno) );
898       pth_attr_destroy (tattr);
899       return unlock_pinentry (rc);
900     }
901   pth_attr_destroy (tattr);
902
903   return 0;
904 }
905
906 /* Close a popup window. */
907 void
908 agent_popup_message_stop (ctrl_t ctrl)
909 {
910   int rc;
911   pid_t pid;
912
913   if (!popup_tid || !entry_ctx)
914     {
915       log_debug ("agent_popup_message_stop called with no active popup\n");
916       return; 
917     }
918
919   pid = assuan_get_pid (entry_ctx);
920   if (pid == (pid_t)(-1))
921     ; /* No pid available can't send a kill. */
922   else if (popup_finished)
923     ; /* Already finished and ready for joining. */
924 #ifdef HAVE_W32_SYSTEM
925   /* Older versions of assuan set PID to 0 on Windows to indicate an
926      invalid value.  */
927   else if (pid != (pid_t) INVALID_HANDLE_VALUE
928            && pid != 0)
929     {
930       HANDLE process = (HANDLE) pid;
931       
932       /* Arbitrary error code.  */
933       TerminateProcess (process, 1);
934     }
935 #else
936   else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
937     { /* The daemon already died.  No need to send a kill.  However
938          because we already waited for the process, we need to tell
939          assuan that it should not wait again (done by
940          unlock_pinentry). */
941       if (rc == pid)
942         assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
943     }
944   else if (pid > 0)
945     kill (pid, SIGKILL);  /* Need to use SIGKILL due to bad
946                              interaction of SIGINT with Pth. */
947 #endif
948
949   /* Now wait for the thread to terminate. */
950   rc = pth_join (popup_tid, NULL);
951   if (!rc)
952     log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
953                strerror (errno));
954   popup_tid = NULL;
955   entry_owner = NULL;
956
957   /* Now we can close the connection. */
958   unlock_pinentry (0);
959 }
960
961