agent/
[gnupg.git] / agent / call-pinentry.c
1 /* call-pinnetry.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 2 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <assert.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #ifndef HAVE_W32_SYSTEM
32 #include <sys/wait.h>
33 #endif
34 #include <pth.h>
35 #include <assuan.h>
36
37 #include "agent.h"
38 #include "i18n.h"
39
40 #ifdef _POSIX_OPEN_MAX
41 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
42 #else
43 #define MAX_OPEN_FDS 20
44 #endif
45
46
47 /* Because access to the pinentry must be serialized (it is and shall
48    be a global mutual dialog) we should better timeout further
49    requests after some time.  2 minutes seem to be a reasonable
50    time. */
51 #define LOCK_TIMEOUT  (1*60)
52
53 /* The assuan context of the current pinentry. */
54 static assuan_context_t entry_ctx;
55
56 /* The control variable of the connection owning the current pinentry.
57    This is only valid if ENTRY_CTX is not NULL.  Note, that we care
58    only about the value of the pointer and that it should never be
59    dereferenced.  */
60 static ctrl_t entry_owner;
61
62 /* A mutex used to serialize access to the pinentry. */
63 static pth_mutex_t entry_lock;
64
65 /* The thread ID of the popup working thread. */
66 static pth_t  popup_tid;
67
68 /* A flag used in communication between the popup working thread and
69    its stop function. */
70 static int popup_finished;
71
72
73
74 /* Data to be passed to our callbacks, */
75 struct entry_parm_s
76 {
77   int lines;
78   size_t size;
79   unsigned char *buffer;
80 };
81
82
83
84 \f
85 /* This function must be called once to initialize this module.  This
86    has to be done before a second thread is spawned.  We can't do the
87    static initialization because Pth emulation code might not be able
88    to do a static init; in particular, it is not possible for W32. */
89 void
90 initialize_module_query (void)
91 {
92   static int initialized;
93
94   if (!initialized)
95     {
96       if (pth_mutex_init (&entry_lock))
97         initialized = 1;
98     }
99 }
100
101
102
103 static void
104 dump_mutex_state (pth_mutex_t *m)
105 {
106   if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
107     log_printf ("not_initialized");
108   else if (!(m->mx_state & PTH_MUTEX_LOCKED))
109     log_printf ("not_locked");
110   else
111     log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
112 }
113
114
115 /* This function may be called to print infromation pertaining to the
116    current state of this module to the log. */
117 void
118 agent_query_dump_state (void)
119 {
120   log_info ("agent_query_dump_state: entry_lock=");
121   dump_mutex_state (&entry_lock);
122   log_printf ("\n");
123   log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
124             entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid);
125 }
126
127 /* Called to make sure that a popup window owned by the current
128    connection gets closed. */
129 void
130 agent_reset_query (ctrl_t ctrl)
131 {
132   if (entry_ctx && popup_tid && entry_owner == ctrl)
133     {
134       agent_popup_message_stop (ctrl);
135     }
136 }
137
138
139 /* Unlock the pinentry so that another thread can start one and
140    disconnect that pinentry - we do this after the unlock so that a
141    stalled pinentry does not block other threads.  Fixme: We should
142    have a timeout in Assuan for the disconnect operation. */
143 static int 
144 unlock_pinentry (int rc)
145 {
146   assuan_context_t ctx = entry_ctx;
147
148   entry_ctx = NULL;
149   if (!pth_mutex_release (&entry_lock))
150     {
151       log_error ("failed to release the entry lock\n");
152       if (!rc)
153         rc = gpg_error (GPG_ERR_INTERNAL);
154     }
155   assuan_disconnect (ctx);
156   return rc;
157 }
158
159
160 /* To make sure we leave no secrets in our image after forking of the
161    pinentry, we use this callback. */
162 static void
163 atfork_cb (void *opaque, int where)
164 {
165   if (!where)
166     gcry_control (GCRYCTL_TERM_SECMEM);
167 }
168
169
170 /* Fork off the pin entry if this has not already been done.  Note,
171    that this function must always be used to aquire the lock for the
172    pinentry - we will serialize _all_ pinentry calls.
173  */
174 static int
175 start_pinentry (ctrl_t ctrl)
176 {
177   int rc;
178   const char *pgmname;
179   assuan_context_t ctx;
180   const char *argv[5];
181   int no_close_list[3];
182   int i;
183   pth_event_t evt;
184   const char *tmpstr;
185
186   evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
187   if (!pth_mutex_acquire (&entry_lock, 0, evt))
188     {
189       if (pth_event_occurred (evt))
190         rc = gpg_error (GPG_ERR_TIMEOUT);
191       else
192         rc = gpg_error (GPG_ERR_INTERNAL);
193       pth_event_free (evt, PTH_FREE_THIS);
194       log_error (_("failed to acquire the pinentry lock: %s\n"),
195                  gpg_strerror (rc));
196       return rc;
197     }
198   pth_event_free (evt, PTH_FREE_THIS);
199
200   entry_owner = ctrl;
201
202   if (entry_ctx)
203     return 0; 
204
205   if (opt.verbose)
206     log_info ("starting a new PIN Entry\n");
207       
208   if (fflush (NULL))
209     {
210       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
211       log_error ("error flushing pending output: %s\n", strerror (errno));
212       return unlock_pinentry (tmperr);
213     }
214
215   if (!opt.pinentry_program || !*opt.pinentry_program)
216     opt.pinentry_program = GNUPG_DEFAULT_PINENTRY;
217   if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
218     pgmname = opt.pinentry_program;
219   else
220     pgmname++;
221
222   argv[0] = pgmname;
223   if (ctrl->display && !opt.keep_display)
224     {
225       argv[1] = "--display";
226       argv[2] = ctrl->display;
227       argv[3] = NULL;
228     }
229   else
230     argv[1] = NULL;
231   
232   i=0;
233   if (!opt.running_detached)
234     {
235       if (log_get_fd () != -1)
236         no_close_list[i++] = log_get_fd ();
237       no_close_list[i++] = fileno (stderr);
238     }
239   no_close_list[i] = -1;
240
241   /* Connect to the pinentry and perform initial handshaking */
242   rc = assuan_pipe_connect_ext (&ctx, opt.pinentry_program, argv,
243                                 no_close_list, atfork_cb, NULL, 0);
244   if (rc)
245     {
246       log_error ("can't connect to the PIN entry module: %s\n",
247                  gpg_strerror (rc));
248       return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
249     }
250   entry_ctx = ctx;
251
252   if (DBG_ASSUAN)
253     log_debug ("connection to PIN entry established\n");
254
255   rc = assuan_transact (entry_ctx, 
256                         opt.no_grab? "OPTION no-grab":"OPTION grab",
257                         NULL, NULL, NULL, NULL, NULL, NULL);
258   if (rc)
259     return unlock_pinentry (rc);
260   if (ctrl->ttyname)
261     {
262       char *optstr;
263       if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
264         return unlock_pinentry (out_of_core ());
265       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
266                             NULL);
267       free (optstr);
268       if (rc)
269         return unlock_pinentry (rc);
270     }
271   if (ctrl->ttytype)
272     {
273       char *optstr;
274       if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
275         return unlock_pinentry (out_of_core ());
276       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
277                             NULL);
278       if (rc)
279         return unlock_pinentry (rc);
280     }
281   if (ctrl->lc_ctype)
282     {
283       char *optstr;
284       if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
285         return unlock_pinentry (out_of_core ());
286       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
287                             NULL);
288       if (rc)
289         return unlock_pinentry (rc);
290     }
291   if (ctrl->lc_messages)
292     {
293       char *optstr;
294       if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
295         return unlock_pinentry (out_of_core ());
296       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
297                             NULL);
298       if (rc)
299         return unlock_pinentry (rc);
300     }
301
302   
303   /* Tell the pinentry the name of a file it shall touch after having
304      messed with the tty.  This is optional and only supported by
305      newer pinentries and thus we do no error checking. */
306   tmpstr = opt.pinentry_touch_file;
307   if (tmpstr && !strcmp (tmpstr, "/dev/null"))
308     tmpstr = NULL;
309   else if (!tmpstr)
310     tmpstr = get_agent_socket_name ();
311   if (tmpstr)
312     {
313       char *optstr;
314       
315       if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
316         ;
317       else
318         {
319           assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
320                            NULL);
321           free (optstr);
322         }
323     }
324
325   return 0;
326 }
327
328 /* Returns True is the pinentry is currently active. If WAITSECONDS is
329    greater than zero the function will wait for this many seconds
330    before returning.  */
331 int
332 pinentry_active_p (ctrl_t ctrl, int waitseconds)
333 {
334   if (waitseconds > 0)
335     {
336       pth_event_t evt;
337       int rc;
338
339       evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0));
340       if (!pth_mutex_acquire (&entry_lock, 0, evt))
341         {
342           if (pth_event_occurred (evt))
343             rc = gpg_error (GPG_ERR_TIMEOUT);
344           else
345             rc = gpg_error (GPG_ERR_INTERNAL);
346           pth_event_free (evt, PTH_FREE_THIS);
347           return rc;
348         }
349       pth_event_free (evt, PTH_FREE_THIS);
350     }
351   else
352     {
353       if (!pth_mutex_acquire (&entry_lock, 1, NULL))
354         return gpg_error (GPG_ERR_LOCKED);
355     }
356
357   if (!pth_mutex_release (&entry_lock))
358     log_error ("failed to release the entry lock at %d\n", __LINE__);
359   return 0;
360 }
361
362
363 static int
364 getpin_cb (void *opaque, const void *buffer, size_t length)
365 {
366   struct entry_parm_s *parm = opaque;
367
368   if (!buffer)
369     return 0;
370
371   /* we expect the pin to fit on one line */
372   if (parm->lines || length >= parm->size)
373     return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
374
375   /* fixme: we should make sure that the assuan buffer is allocated in
376      secure memory or read the response byte by byte */
377   memcpy (parm->buffer, buffer, length);
378   parm->buffer[length] = 0;
379   parm->lines++;
380   return 0;
381 }
382
383
384 static int
385 all_digitsp( const char *s)
386 {
387   for (; *s && *s >= '0' && *s <= '9'; s++)
388     ;
389   return !*s;
390 }  
391
392
393 \f
394 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
395    number here and repeat it as long as we have invalid formed
396    numbers. */
397 int
398 agent_askpin (ctrl_t ctrl,
399               const char *desc_text, const char *prompt_text,
400               const char *initial_errtext,
401               struct pin_entry_info_s *pininfo)
402 {
403   int rc;
404   char line[ASSUAN_LINELENGTH];
405   struct entry_parm_s parm;
406   const char *errtext = NULL;
407   int is_pin = 0;
408
409   if (opt.batch)
410     return 0; /* fixme: we should return BAD PIN */
411
412   if (!pininfo || pininfo->max_length < 1)
413     return gpg_error (GPG_ERR_INV_VALUE);
414   if (!desc_text && pininfo->min_digits)
415     desc_text = _("Please enter your PIN, so that the secret key "
416                   "can be unlocked for this session");
417   else if (!desc_text)
418     desc_text = _("Please enter your passphrase, so that the secret key "
419                   "can be unlocked for this session");
420
421   if (prompt_text)
422     is_pin = !!strstr (prompt_text, "PIN");
423   else
424     is_pin = desc_text && strstr (desc_text, "PIN");
425
426   rc = start_pinentry (ctrl);
427   if (rc)
428     return rc;
429
430   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
431   line[DIM(line)-1] = 0;
432   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
433   if (rc)
434     return unlock_pinentry (rc);
435
436   snprintf (line, DIM(line)-1, "SETPROMPT %s",
437             prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
438   line[DIM(line)-1] = 0;
439   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
440   if (rc)
441     return unlock_pinentry (rc);
442
443
444   if (initial_errtext)
445     { 
446       snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
447       line[DIM(line)-1] = 0;
448       rc = assuan_transact (entry_ctx, line,
449                             NULL, NULL, NULL, NULL, NULL, NULL);
450       if (rc)
451         return unlock_pinentry (rc);
452     }
453
454   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
455     {
456       memset (&parm, 0, sizeof parm);
457       parm.size = pininfo->max_length;
458       parm.buffer = (unsigned char*)pininfo->pin;
459
460       if (errtext)
461         { 
462           /* TRANLATORS: The string is appended to an error message in
463              the pinentry.  The %s is the actual error message, the
464              two %d give the current and maximum number of tries. */
465           snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
466                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
467           line[DIM(line)-1] = 0;
468           rc = assuan_transact (entry_ctx, line,
469                                 NULL, NULL, NULL, NULL, NULL, NULL);
470           if (rc)
471             return unlock_pinentry (rc);
472           errtext = NULL;
473         }
474       
475       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
476                             NULL, NULL, NULL, NULL);
477       /* Most pinentries out in the wild return the old Assuan error code
478          for canceled which gets translated to an assuan Cancel error and
479          not to the code for a user cancel.  Fix this here. */
480       if (rc && gpg_err_source (rc)
481           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
482         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
483
484       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
485         errtext = is_pin? _("PIN too long")
486                         : _("Passphrase too long");
487       else if (rc)
488         return unlock_pinentry (rc);
489
490       if (!errtext && pininfo->min_digits)
491         {
492           /* do some basic checks on the entered PIN. */
493           if (!all_digitsp (pininfo->pin))
494             errtext = _("Invalid characters in PIN");
495           else if (pininfo->max_digits
496                    && strlen (pininfo->pin) > pininfo->max_digits)
497             errtext = _("PIN too long");
498           else if (strlen (pininfo->pin) < pininfo->min_digits)
499             errtext = _("PIN too short");
500         }
501
502       if (!errtext && pininfo->check_cb)
503         {
504           /* More checks by utilizing the optional callback. */
505           pininfo->cb_errtext = NULL;
506           rc = pininfo->check_cb (pininfo);
507           if (rc == -1 && pininfo->cb_errtext)
508             errtext = pininfo->cb_errtext;
509           else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
510                    || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
511             errtext = (is_pin? _("Bad PIN")
512                        : _("Bad Passphrase"));
513           else if (rc)
514             return unlock_pinentry (rc);
515         }
516
517       if (!errtext)
518         return unlock_pinentry (0); /* okay, got a PIN or passphrase */
519     }
520
521   return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
522                           : GPG_ERR_BAD_PASSPHRASE));
523 }
524
525
526 \f
527 /* Ask for the passphrase using the supplied arguments.  The returned
528    passphrase needs to be freed by the caller. */
529 int 
530 agent_get_passphrase (ctrl_t ctrl,
531                       char **retpass, const char *desc, const char *prompt,
532                       const char *errtext)
533 {
534
535   int rc;
536   char line[ASSUAN_LINELENGTH];
537   struct entry_parm_s parm;
538
539   *retpass = NULL;
540   if (opt.batch)
541     return gpg_error (GPG_ERR_BAD_PASSPHRASE); 
542
543   rc = start_pinentry (ctrl);
544   if (rc)
545     return rc;
546
547   if (!prompt)
548     prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
549
550
551   if (desc)
552     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
553   else
554     snprintf (line, DIM(line)-1, "RESET");
555   line[DIM(line)-1] = 0;
556   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
557   if (rc)
558     return unlock_pinentry (rc);
559
560   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
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 (errtext)
567     {
568       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
569       line[DIM(line)-1] = 0;
570       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
571       if (rc)
572         return unlock_pinentry (rc);
573     }
574
575   memset (&parm, 0, sizeof parm);
576   parm.size = ASSUAN_LINELENGTH/2 - 5;
577   parm.buffer = gcry_malloc_secure (parm.size+10);
578   if (!parm.buffer)
579     return unlock_pinentry (out_of_core ());
580
581   assuan_begin_confidential (entry_ctx);
582   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
583                         NULL, NULL, NULL, NULL);
584   /* Most pinentries out in the wild return the old Assuan error code
585      for canceled which gets translated to an assuan Cancel error and
586      not to the code for a user cancel.  Fix this here. */
587   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
588     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
589   if (rc)
590     xfree (parm.buffer);
591   else
592     *retpass = parm.buffer;
593   return unlock_pinentry (rc);
594 }
595
596
597 \f
598 /* Pop up the PIN-entry, display the text and the prompt and ask the
599    user to confirm this.  We return 0 for success, ie. the user
600    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
601    other error. */
602 int 
603 agent_get_confirmation (ctrl_t ctrl,
604                         const char *desc, const char *ok, const char *cancel)
605 {
606   int rc;
607   char line[ASSUAN_LINELENGTH];
608
609   rc = start_pinentry (ctrl);
610   if (rc)
611     return rc;
612
613   if (desc)
614     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
615   else
616     snprintf (line, DIM(line)-1, "RESET");
617   line[DIM(line)-1] = 0;
618   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
619   /* Most pinentries out in the wild return the old Assuan error code
620      for canceled which gets translated to an assuan Cancel error and
621      not to the code for a user cancel.  Fix this here. */
622   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
623     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
624
625   if (rc)
626     return unlock_pinentry (rc);
627
628   if (ok)
629     {
630       snprintf (line, DIM(line)-1, "SETOK %s", ok);
631       line[DIM(line)-1] = 0;
632       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
633       if (rc)
634         return unlock_pinentry (rc);
635     }
636   if (cancel)
637     {
638       snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
639       line[DIM(line)-1] = 0;
640       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
641       if (rc)
642         return unlock_pinentry (rc);
643     }
644
645   rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
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   return unlock_pinentry (rc);
650 }
651
652
653 /* The thread running the popup message. */
654 static void *
655 popup_message_thread (void *arg)
656 {
657   /* We use the --one-button hack instead of the MESSAGE command to
658      allow the use of old Pinentries.  Those old Pinentries will then
659      show an additional Cancel button but that is mostly a visual
660      annoyance. */
661   assuan_transact (entry_ctx, "CONFIRM --one-button", 
662                    NULL, NULL, NULL, NULL, NULL, NULL);
663   popup_finished = 1;
664   return NULL;
665 }
666
667
668 /* Pop up a message window similar to the confirm one but keep it open
669    until agent_popup_message_stop has been called.  It is crucial for
670    the caller to make sure that the stop function gets called as soon
671    as the message is not anymore required because the message is
672    system modal and all other attempts to use the pinentry will fail
673    (after a timeout). */
674 int 
675 agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
676 {
677   int rc;
678   char line[ASSUAN_LINELENGTH];
679   pth_attr_t tattr;
680
681   rc = start_pinentry (ctrl);
682   if (rc)
683     return rc;
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   if (ok_btn)
695     {
696       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
697       line[DIM(line)-1] = 0;
698       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
699       if (rc)
700         return unlock_pinentry (rc);
701     }
702
703   tattr = pth_attr_new();
704   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
705   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
706   pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
707
708   popup_finished = 0;
709   popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
710   if (!popup_tid)
711     {
712       rc = gpg_error_from_syserror ();
713       log_error ("error spawning popup message handler: %s\n",
714                  strerror (errno) );
715       pth_attr_destroy (tattr);
716       return unlock_pinentry (rc);
717     }
718   pth_attr_destroy (tattr);
719
720   return 0;
721 }
722
723 /* Close a popup window. */
724 void
725 agent_popup_message_stop (ctrl_t ctrl)
726 {
727   int rc;
728   pid_t pid;
729
730   if (!popup_tid || !entry_ctx)
731     {
732       log_debug ("agent_popup_message_stop called with no active popup\n");
733       return; 
734     }
735
736   pid = assuan_get_pid (entry_ctx);
737   if (pid == (pid_t)(-1))
738     ; /* No pid available can't send a kill. */
739   else if (popup_finished)
740     ; /* Already finished and ready for joining. */
741   else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
742     { /* The daemon already died.  No need to send a kill.  However
743          because we already waited for the process, we need to tell
744          assuan that it should not wait again (done by
745          unlock_pinentry). */
746       if (rc == pid)
747         assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
748     }
749   else if (pid > 0)
750     kill (pid, SIGKILL);  /* Need to use SIGKILL due to bad
751                              interaction of SIGINT with Pth. */
752
753   /* Now wait for the thread to terminate. */
754   rc = pth_join (popup_tid, NULL);
755   if (!rc)
756     log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
757                strerror (errno));
758   popup_tid = NULL;
759   entry_owner = NULL;
760
761   /* Now we can close the connection. */
762   unlock_pinentry (0);
763 }
764
765