14cc4229ac8523b70fc28cde93eeaae77d6e9dac
[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 \f
417 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
418    number here and repeat it as long as we have invalid formed
419    numbers. */
420 int
421 agent_askpin (ctrl_t ctrl,
422               const char *desc_text, const char *prompt_text,
423               const char *initial_errtext,
424               struct pin_entry_info_s *pininfo)
425 {
426   int rc;
427   char line[ASSUAN_LINELENGTH];
428   struct entry_parm_s parm;
429   const char *errtext = NULL;
430   int is_pin = 0;
431
432   if (opt.batch)
433     return 0; /* fixme: we should return BAD PIN */
434
435   if (!pininfo || pininfo->max_length < 1)
436     return gpg_error (GPG_ERR_INV_VALUE);
437   if (!desc_text && pininfo->min_digits)
438     desc_text = _("Please enter your PIN, so that the secret key "
439                   "can be unlocked for this session");
440   else if (!desc_text)
441     desc_text = _("Please enter your passphrase, so that the secret key "
442                   "can be unlocked for this session");
443
444   if (prompt_text)
445     is_pin = !!strstr (prompt_text, "PIN");
446   else
447     is_pin = desc_text && strstr (desc_text, "PIN");
448
449   rc = start_pinentry (ctrl);
450   if (rc)
451     return rc;
452
453   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
454   line[DIM(line)-1] = 0;
455   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
456   if (rc)
457     return unlock_pinentry (rc);
458
459   snprintf (line, DIM(line)-1, "SETPROMPT %s",
460             prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
461   line[DIM(line)-1] = 0;
462   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
463   if (rc)
464     return unlock_pinentry (rc);
465
466
467   if (initial_errtext)
468     { 
469       snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
470       line[DIM(line)-1] = 0;
471       rc = assuan_transact (entry_ctx, line,
472                             NULL, NULL, NULL, NULL, NULL, NULL);
473       if (rc)
474         return unlock_pinentry (rc);
475     }
476
477   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
478     {
479       memset (&parm, 0, sizeof parm);
480       parm.size = pininfo->max_length;
481       *pininfo->pin = 0; /* Reset the PIN. */
482       parm.buffer = (unsigned char*)pininfo->pin;
483
484       if (errtext)
485         { 
486           /* TRANLATORS: The string is appended to an error message in
487              the pinentry.  The %s is the actual error message, the
488              two %d give the current and maximum number of tries. */
489           snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
490                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
491           line[DIM(line)-1] = 0;
492           rc = assuan_transact (entry_ctx, line,
493                                 NULL, NULL, NULL, NULL, NULL, NULL);
494           if (rc)
495             return unlock_pinentry (rc);
496           errtext = NULL;
497         }
498       
499       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
500                             NULL, NULL, NULL, NULL);
501       /* Most pinentries out in the wild return the old Assuan error code
502          for canceled which gets translated to an assuan Cancel error and
503          not to the code for a user cancel.  Fix this here. */
504       if (rc && gpg_err_source (rc)
505           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
506         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
507
508       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
509         errtext = is_pin? _("PIN too long")
510                         : _("Passphrase too long");
511       else if (rc)
512         return unlock_pinentry (rc);
513
514       if (!errtext && pininfo->min_digits)
515         {
516           /* do some basic checks on the entered PIN. */
517           if (!all_digitsp (pininfo->pin))
518             errtext = _("Invalid characters in PIN");
519           else if (pininfo->max_digits
520                    && strlen (pininfo->pin) > pininfo->max_digits)
521             errtext = _("PIN too long");
522           else if (strlen (pininfo->pin) < pininfo->min_digits)
523             errtext = _("PIN too short");
524         }
525
526       if (!errtext && pininfo->check_cb)
527         {
528           /* More checks by utilizing the optional callback. */
529           pininfo->cb_errtext = NULL;
530           rc = pininfo->check_cb (pininfo);
531           if (rc == -1 && pininfo->cb_errtext)
532             errtext = pininfo->cb_errtext;
533           else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
534                    || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
535             errtext = (is_pin? _("Bad PIN")
536                        : _("Bad Passphrase"));
537           else if (rc)
538             return unlock_pinentry (rc);
539         }
540
541       if (!errtext)
542         return unlock_pinentry (0); /* okay, got a PIN or passphrase */
543     }
544
545   return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
546                           : GPG_ERR_BAD_PASSPHRASE));
547 }
548
549
550 \f
551 /* Ask for the passphrase using the supplied arguments.  The returned
552    passphrase needs to be freed by the caller. */
553 int 
554 agent_get_passphrase (ctrl_t ctrl,
555                       char **retpass, const char *desc, const char *prompt,
556                       const char *errtext)
557 {
558
559   int rc;
560   char line[ASSUAN_LINELENGTH];
561   struct entry_parm_s parm;
562
563   *retpass = NULL;
564   if (opt.batch)
565     return gpg_error (GPG_ERR_BAD_PASSPHRASE); 
566
567   rc = start_pinentry (ctrl);
568   if (rc)
569     return rc;
570
571   if (!prompt)
572     prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
573
574
575   if (desc)
576     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
577   else
578     snprintf (line, DIM(line)-1, "RESET");
579   line[DIM(line)-1] = 0;
580   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
581   if (rc)
582     return unlock_pinentry (rc);
583
584   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
585   line[DIM(line)-1] = 0;
586   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
587   if (rc)
588     return unlock_pinentry (rc);
589
590   if (errtext)
591     {
592       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
593       line[DIM(line)-1] = 0;
594       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
595       if (rc)
596         return unlock_pinentry (rc);
597     }
598
599   memset (&parm, 0, sizeof parm);
600   parm.size = ASSUAN_LINELENGTH/2 - 5;
601   parm.buffer = gcry_malloc_secure (parm.size+10);
602   if (!parm.buffer)
603     return unlock_pinentry (out_of_core ());
604
605   assuan_begin_confidential (entry_ctx);
606   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
607                         NULL, NULL, NULL, NULL);
608   /* Most pinentries out in the wild return the old Assuan error code
609      for canceled which gets translated to an assuan Cancel error and
610      not to the code for a user cancel.  Fix this here. */
611   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
612     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
613   if (rc)
614     xfree (parm.buffer);
615   else
616     *retpass = parm.buffer;
617   return unlock_pinentry (rc);
618 }
619
620
621 \f
622 /* Pop up the PIN-entry, display the text and the prompt and ask the
623    user to confirm this.  We return 0 for success, ie. the user
624    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
625    other error. */
626 int 
627 agent_get_confirmation (ctrl_t ctrl,
628                         const char *desc, const char *ok, const char *cancel)
629 {
630   int rc;
631   char line[ASSUAN_LINELENGTH];
632
633   rc = start_pinentry (ctrl);
634   if (rc)
635     return rc;
636
637   if (desc)
638     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
639   else
640     snprintf (line, DIM(line)-1, "RESET");
641   line[DIM(line)-1] = 0;
642   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
643   /* Most pinentries out in the wild return the old Assuan error code
644      for canceled which gets translated to an assuan Cancel error and
645      not to the code for a user cancel.  Fix this here. */
646   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
647     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
648
649   if (rc)
650     return unlock_pinentry (rc);
651
652   if (ok)
653     {
654       snprintf (line, DIM(line)-1, "SETOK %s", ok);
655       line[DIM(line)-1] = 0;
656       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
657       if (rc)
658         return unlock_pinentry (rc);
659     }
660   if (cancel)
661     {
662       snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
663       line[DIM(line)-1] = 0;
664       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
665       if (rc)
666         return unlock_pinentry (rc);
667     }
668
669   rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
670   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
671     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
672
673   return unlock_pinentry (rc);
674 }
675
676
677 \f
678 /* Pop up the PINentry, display the text DESC and a button with the
679    text OK_BTN (which may be NULL to use the default of "OK") and waut
680    for the user to hit this button.  The return value is not
681    relevant.  */
682 int 
683 agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
684 {
685   int rc;
686   char line[ASSUAN_LINELENGTH];
687
688   rc = start_pinentry (ctrl);
689   if (rc)
690     return rc;
691
692   if (desc)
693     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
694   else
695     snprintf (line, DIM(line)-1, "RESET");
696   line[DIM(line)-1] = 0;
697   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
698   /* Most pinentries out in the wild return the old Assuan error code
699      for canceled which gets translated to an assuan Cancel error and
700      not to the code for a user cancel.  Fix this here. */
701   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
702     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
703
704   if (rc)
705     return unlock_pinentry (rc);
706
707   if (ok_btn)
708     {
709       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
710       line[DIM(line)-1] = 0;
711       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
712                             NULL, NULL, NULL);
713       if (rc)
714         return unlock_pinentry (rc);
715     }
716   
717   rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
718                         NULL, NULL, NULL);
719   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
720     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
721
722   return unlock_pinentry (rc);
723 }
724
725
726 /* The thread running the popup message. */
727 static void *
728 popup_message_thread (void *arg)
729 {
730   /* We use the --one-button hack instead of the MESSAGE command to
731      allow the use of old Pinentries.  Those old Pinentries will then
732      show an additional Cancel button but that is mostly a visual
733      annoyance. */
734   assuan_transact (entry_ctx, "CONFIRM --one-button", 
735                    NULL, NULL, NULL, NULL, NULL, NULL);
736   popup_finished = 1;
737   return NULL;
738 }
739
740
741 /* Pop up a message window similar to the confirm one but keep it open
742    until agent_popup_message_stop has been called.  It is crucial for
743    the caller to make sure that the stop function gets called as soon
744    as the message is not anymore required because the message is
745    system modal and all other attempts to use the pinentry will fail
746    (after a timeout). */
747 int 
748 agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
749 {
750   int rc;
751   char line[ASSUAN_LINELENGTH];
752   pth_attr_t tattr;
753
754   rc = start_pinentry (ctrl);
755   if (rc)
756     return rc;
757
758   if (desc)
759     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
760   else
761     snprintf (line, DIM(line)-1, "RESET");
762   line[DIM(line)-1] = 0;
763   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
764   if (rc)
765     return unlock_pinentry (rc);
766
767   if (ok_btn)
768     {
769       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
770       line[DIM(line)-1] = 0;
771       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
772       if (rc)
773         return unlock_pinentry (rc);
774     }
775
776   tattr = pth_attr_new();
777   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
778   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
779   pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
780
781   popup_finished = 0;
782   popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
783   if (!popup_tid)
784     {
785       rc = gpg_error_from_syserror ();
786       log_error ("error spawning popup message handler: %s\n",
787                  strerror (errno) );
788       pth_attr_destroy (tattr);
789       return unlock_pinentry (rc);
790     }
791   pth_attr_destroy (tattr);
792
793   return 0;
794 }
795
796 /* Close a popup window. */
797 void
798 agent_popup_message_stop (ctrl_t ctrl)
799 {
800   int rc;
801   pid_t pid;
802
803   if (!popup_tid || !entry_ctx)
804     {
805       log_debug ("agent_popup_message_stop called with no active popup\n");
806       return; 
807     }
808
809   pid = assuan_get_pid (entry_ctx);
810   if (pid == (pid_t)(-1))
811     ; /* No pid available can't send a kill. */
812   else if (popup_finished)
813     ; /* Already finished and ready for joining. */
814 #ifdef HAVE_W32_SYSTEM
815   /* Older versions of assuan set PID to 0 on Windows to indicate an
816      invalid value.  */
817   else if (pid != (pid_t) INVALID_HANDLE_VALUE
818            && pid != 0)
819     {
820       HANDLE process = (HANDLE) pid;
821       
822       /* Arbitrary error code.  */
823       TerminateProcess (process, 1);
824     }
825 #else
826   else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
827     { /* The daemon already died.  No need to send a kill.  However
828          because we already waited for the process, we need to tell
829          assuan that it should not wait again (done by
830          unlock_pinentry). */
831       if (rc == pid)
832         assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
833     }
834   else if (pid > 0)
835     kill (pid, SIGKILL);  /* Need to use SIGKILL due to bad
836                              interaction of SIGINT with Pth. */
837 #endif
838
839   /* Now wait for the thread to terminate. */
840   rc = pth_join (popup_tid, NULL);
841   if (!rc)
842     log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
843                strerror (errno));
844   popup_tid = NULL;
845   entry_owner = NULL;
846
847   /* Now we can close the connection. */
848   unlock_pinentry (0);
849 }
850
851