Fixes
[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
185   evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
186   if (!pth_mutex_acquire (&entry_lock, 0, evt))
187     {
188       if (pth_event_occurred (evt))
189         rc = gpg_error (GPG_ERR_TIMEOUT);
190       else
191         rc = gpg_error (GPG_ERR_INTERNAL);
192       pth_event_free (evt, PTH_FREE_THIS);
193       log_error (_("failed to acquire the pinentry lock: %s\n"),
194                  gpg_strerror (rc));
195       return rc;
196     }
197   pth_event_free (evt, PTH_FREE_THIS);
198
199   entry_owner = ctrl;
200
201   if (entry_ctx)
202     return 0; 
203
204   if (opt.verbose)
205     log_info ("starting a new PIN Entry\n");
206       
207   if (fflush (NULL))
208     {
209       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
210       log_error ("error flushing pending output: %s\n", strerror (errno));
211       return unlock_pinentry (tmperr);
212     }
213
214   if (!opt.pinentry_program || !*opt.pinentry_program)
215     opt.pinentry_program = GNUPG_DEFAULT_PINENTRY;
216   if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
217     pgmname = opt.pinentry_program;
218   else
219     pgmname++;
220
221   argv[0] = pgmname;
222   if (ctrl->display && !opt.keep_display)
223     {
224       argv[1] = "--display";
225       argv[2] = ctrl->display;
226       argv[3] = NULL;
227     }
228   else
229     argv[1] = NULL;
230   
231   i=0;
232   if (!opt.running_detached)
233     {
234       if (log_get_fd () != -1)
235         no_close_list[i++] = log_get_fd ();
236       no_close_list[i++] = fileno (stderr);
237     }
238   no_close_list[i] = -1;
239
240   /* Connect to the pinentry and perform initial handshaking */
241   rc = assuan_pipe_connect_ext (&ctx, opt.pinentry_program, argv,
242                                 no_close_list, atfork_cb, NULL, 0);
243   if (rc)
244     {
245       log_error ("can't connect to the PIN entry module: %s\n",
246                  gpg_strerror (rc));
247       return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
248     }
249   entry_ctx = ctx;
250
251   if (DBG_ASSUAN)
252     log_debug ("connection to PIN entry established\n");
253
254   rc = assuan_transact (entry_ctx, 
255                         opt.no_grab? "OPTION no-grab":"OPTION grab",
256                         NULL, NULL, NULL, NULL, NULL, NULL);
257   if (rc)
258     return unlock_pinentry (rc);
259   if (ctrl->ttyname)
260     {
261       char *optstr;
262       if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
263         return unlock_pinentry (out_of_core ());
264       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
265                             NULL);
266       free (optstr);
267       if (rc)
268         return unlock_pinentry (rc);
269     }
270   if (ctrl->ttytype)
271     {
272       char *optstr;
273       if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
274         return unlock_pinentry (out_of_core ());
275       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
276                             NULL);
277       if (rc)
278         return unlock_pinentry (rc);
279     }
280   if (ctrl->lc_ctype)
281     {
282       char *optstr;
283       if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
284         return unlock_pinentry (out_of_core ());
285       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
286                             NULL);
287       if (rc)
288         return unlock_pinentry (rc);
289     }
290   if (ctrl->lc_messages)
291     {
292       char *optstr;
293       if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
294         return unlock_pinentry (out_of_core ());
295       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
296                             NULL);
297       if (rc)
298         return unlock_pinentry (rc);
299     }
300   return 0;
301 }
302
303 /* Returns True is the pinentry is currently active. If WAITSECONDS is
304    greater than zero the function will wait for this many seconds
305    before returning.  */
306 int
307 pinentry_active_p (ctrl_t ctrl, int waitseconds)
308 {
309   if (waitseconds > 0)
310     {
311       pth_event_t evt;
312       int rc;
313
314       evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0));
315       if (!pth_mutex_acquire (&entry_lock, 0, evt))
316         {
317           if (pth_event_occurred (evt))
318             rc = gpg_error (GPG_ERR_TIMEOUT);
319           else
320             rc = gpg_error (GPG_ERR_INTERNAL);
321           pth_event_free (evt, PTH_FREE_THIS);
322           return rc;
323         }
324       pth_event_free (evt, PTH_FREE_THIS);
325     }
326   else
327     {
328       if (!pth_mutex_acquire (&entry_lock, 1, NULL))
329         return gpg_error (GPG_ERR_LOCKED);
330     }
331
332   if (!pth_mutex_release (&entry_lock))
333     log_error ("failed to release the entry lock at %d\n", __LINE__);
334   return 0;
335 }
336
337
338 static int
339 getpin_cb (void *opaque, const void *buffer, size_t length)
340 {
341   struct entry_parm_s *parm = opaque;
342
343   if (!buffer)
344     return 0;
345
346   /* we expect the pin to fit on one line */
347   if (parm->lines || length >= parm->size)
348     return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
349
350   /* fixme: we should make sure that the assuan buffer is allocated in
351      secure memory or read the response byte by byte */
352   memcpy (parm->buffer, buffer, length);
353   parm->buffer[length] = 0;
354   parm->lines++;
355   return 0;
356 }
357
358
359 static int
360 all_digitsp( const char *s)
361 {
362   for (; *s && *s >= '0' && *s <= '9'; s++)
363     ;
364   return !*s;
365 }  
366
367
368 \f
369 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
370    number here and repeat it as long as we have invalid formed
371    numbers. */
372 int
373 agent_askpin (ctrl_t ctrl,
374               const char *desc_text, const char *prompt_text,
375               const char *initial_errtext,
376               struct pin_entry_info_s *pininfo)
377 {
378   int rc;
379   char line[ASSUAN_LINELENGTH];
380   struct entry_parm_s parm;
381   const char *errtext = NULL;
382   int is_pin = 0;
383
384   if (opt.batch)
385     return 0; /* fixme: we should return BAD PIN */
386
387   if (!pininfo || pininfo->max_length < 1)
388     return gpg_error (GPG_ERR_INV_VALUE);
389   if (!desc_text && pininfo->min_digits)
390     desc_text = _("Please enter your PIN, so that the secret key "
391                   "can be unlocked for this session");
392   else if (!desc_text)
393     desc_text = _("Please enter your passphrase, so that the secret key "
394                   "can be unlocked for this session");
395
396   if (prompt_text)
397     is_pin = !!strstr (prompt_text, "PIN");
398   else
399     is_pin = desc_text && strstr (desc_text, "PIN");
400
401   rc = start_pinentry (ctrl);
402   if (rc)
403     return rc;
404
405   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
406   line[DIM(line)-1] = 0;
407   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
408   if (rc)
409     return unlock_pinentry (rc);
410
411   snprintf (line, DIM(line)-1, "SETPROMPT %s",
412             prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
413   line[DIM(line)-1] = 0;
414   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
415   if (rc)
416     return unlock_pinentry (rc);
417
418
419   if (initial_errtext)
420     { 
421       snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
422       line[DIM(line)-1] = 0;
423       rc = assuan_transact (entry_ctx, line,
424                             NULL, NULL, NULL, NULL, NULL, NULL);
425       if (rc)
426         return unlock_pinentry (rc);
427     }
428
429   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
430     {
431       memset (&parm, 0, sizeof parm);
432       parm.size = pininfo->max_length;
433       parm.buffer = (unsigned char*)pininfo->pin;
434
435       if (errtext)
436         { 
437           /* fixme: should we show the try count? It must be translated */
438           snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
439                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
440           line[DIM(line)-1] = 0;
441           rc = assuan_transact (entry_ctx, line,
442                                 NULL, NULL, NULL, NULL, NULL, NULL);
443           if (rc)
444             return unlock_pinentry (rc);
445           errtext = NULL;
446         }
447       
448       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
449                             NULL, NULL, NULL, NULL);
450       /* Most pinentries out in the wild return the old Assuan error code
451          for canceled which gets translated to an assuan Cancel error and
452          not to the code for a user cancel.  Fix this here. */
453       if (rc && gpg_err_source (rc)
454           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
455         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
456
457       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
458         errtext = is_pin? _("PIN too long")
459                         : _("Passphrase too long");
460       else if (rc)
461         return unlock_pinentry (rc);
462
463       if (!errtext && pininfo->min_digits)
464         {
465           /* do some basic checks on the entered PIN. */
466           if (!all_digitsp (pininfo->pin))
467             errtext = _("Invalid characters in PIN");
468           else if (pininfo->max_digits
469                    && strlen (pininfo->pin) > pininfo->max_digits)
470             errtext = _("PIN too long");
471           else if (strlen (pininfo->pin) < pininfo->min_digits)
472             errtext = _("PIN too short");
473         }
474
475       if (!errtext && pininfo->check_cb)
476         {
477           /* More checks by utilizing the optional callback. */
478           pininfo->cb_errtext = NULL;
479           rc = pininfo->check_cb (pininfo);
480           if (rc == -1 && pininfo->cb_errtext)
481             errtext = pininfo->cb_errtext;
482           else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
483                    || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
484             errtext = (is_pin? _("Bad PIN")
485                        : _("Bad Passphrase"));
486           else if (rc)
487             return unlock_pinentry (rc);
488         }
489
490       if (!errtext)
491         return unlock_pinentry (0); /* okay, got a PIN or passphrase */
492     }
493
494   return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
495                           : GPG_ERR_BAD_PASSPHRASE));
496 }
497
498
499 \f
500 /* Ask for the passphrase using the supplied arguments.  The returned
501    passphrase needs to be freed by the caller. */
502 int 
503 agent_get_passphrase (ctrl_t ctrl,
504                       char **retpass, const char *desc, const char *prompt,
505                       const char *errtext)
506 {
507
508   int rc;
509   char line[ASSUAN_LINELENGTH];
510   struct entry_parm_s parm;
511
512   *retpass = NULL;
513   if (opt.batch)
514     return gpg_error (GPG_ERR_BAD_PASSPHRASE); 
515
516   rc = start_pinentry (ctrl);
517   if (rc)
518     return rc;
519
520   if (!prompt)
521     prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
522
523
524   if (desc)
525     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
526   else
527     snprintf (line, DIM(line)-1, "RESET");
528   line[DIM(line)-1] = 0;
529   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
530   if (rc)
531     return unlock_pinentry (rc);
532
533   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
534   line[DIM(line)-1] = 0;
535   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
536   if (rc)
537     return unlock_pinentry (rc);
538
539   if (errtext)
540     {
541       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
542       line[DIM(line)-1] = 0;
543       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
544       if (rc)
545         return unlock_pinentry (rc);
546     }
547
548   memset (&parm, 0, sizeof parm);
549   parm.size = ASSUAN_LINELENGTH/2 - 5;
550   parm.buffer = gcry_malloc_secure (parm.size+10);
551   if (!parm.buffer)
552     return unlock_pinentry (out_of_core ());
553
554   assuan_begin_confidential (entry_ctx);
555   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
556                         NULL, NULL, NULL, NULL);
557   /* Most pinentries out in the wild return the old Assuan error code
558      for canceled which gets translated to an assuan Cancel error and
559      not to the code for a user cancel.  Fix this here. */
560   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
561     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
562   if (rc)
563     xfree (parm.buffer);
564   else
565     *retpass = parm.buffer;
566   return unlock_pinentry (rc);
567 }
568
569
570 \f
571 /* Pop up the PIN-entry, display the text and the prompt and ask the
572    user to confirm this.  We return 0 for success, ie. the user
573    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
574    other error. */
575 int 
576 agent_get_confirmation (ctrl_t ctrl,
577                         const char *desc, const char *ok, const char *cancel)
578 {
579   int rc;
580   char line[ASSUAN_LINELENGTH];
581
582   rc = start_pinentry (ctrl);
583   if (rc)
584     return rc;
585
586   if (desc)
587     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
588   else
589     snprintf (line, DIM(line)-1, "RESET");
590   line[DIM(line)-1] = 0;
591   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
592   /* Most pinentries out in the wild return the old Assuan error code
593      for canceled which gets translated to an assuan Cancel error and
594      not to the code for a user cancel.  Fix this here. */
595   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
596     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
597
598   if (rc)
599     return unlock_pinentry (rc);
600
601   if (ok)
602     {
603       snprintf (line, DIM(line)-1, "SETOK %s", ok);
604       line[DIM(line)-1] = 0;
605       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
606       if (rc)
607         return unlock_pinentry (rc);
608     }
609   if (cancel)
610     {
611       snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
612       line[DIM(line)-1] = 0;
613       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
614       if (rc)
615         return unlock_pinentry (rc);
616     }
617
618   rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
619   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
620     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
621
622   return unlock_pinentry (rc);
623 }
624
625
626 /* The thread running the popup message. */
627 static void *
628 popup_message_thread (void *arg)
629 {
630   assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
631   popup_finished = 1;
632   return NULL;
633 }
634
635
636 /* Pop up a message window similar to the confirm one but keep it open
637    until agent_popup_message_stop has been called.  It is crucial for
638    the caller to make sure that the stop function gets called as soon
639    as the message is not anymore required becuase the message is
640    system modal and all other attempts to use the pinentry will fail
641    (after a timeout). */
642 int 
643 agent_popup_message_start (ctrl_t ctrl, const char *desc,
644                            const char *ok_btn, const char *cancel_btn)
645 {
646   int rc;
647   char line[ASSUAN_LINELENGTH];
648   pth_attr_t tattr;
649
650   rc = start_pinentry (ctrl);
651   if (rc)
652     return rc;
653
654   if (desc)
655     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
656   else
657     snprintf (line, DIM(line)-1, "RESET");
658   line[DIM(line)-1] = 0;
659   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
660   if (rc)
661     return unlock_pinentry (rc);
662
663   if (ok_btn)
664     {
665       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
666       line[DIM(line)-1] = 0;
667       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
668       if (rc)
669         return unlock_pinentry (rc);
670     }
671   if (cancel_btn)
672     {
673       snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel_btn);
674       line[DIM(line)-1] = 0;
675       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
676       if (rc)
677         return unlock_pinentry (rc);
678     }
679
680   tattr = pth_attr_new();
681   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
682   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
683   pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
684
685   popup_finished = 0;
686   popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
687   if (!popup_tid)
688     {
689       rc = gpg_error_from_syserror ();
690       log_error ("error spawning popup message handler: %s\n",
691                  strerror (errno) );
692       pth_attr_destroy (tattr);
693       return unlock_pinentry (rc);
694     }
695   pth_attr_destroy (tattr);
696
697   return 0;
698 }
699
700 /* Close a popup window. */
701 void
702 agent_popup_message_stop (ctrl_t ctrl)
703 {
704   int rc;
705   pid_t pid;
706
707   if (!popup_tid || !entry_ctx)
708     {
709       log_debug ("agent_popup_message_stop called with no active popup\n");
710       return; 
711     }
712
713   pid = assuan_get_pid (entry_ctx);
714   if (pid == (pid_t)(-1))
715     ; /* No pid available can't send a kill. */
716   else if (popup_finished)
717     ; /* Already finished and ready for joining. */
718   else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
719     { /* The daemon already died.  No need to send a kill.  However
720          because we already waited for the process, we need to tell
721          assuan that it should not wait again (done by
722          unlock_pinentry). */
723       if (rc == pid)
724         assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
725     }
726   else
727     kill (pid, SIGINT);
728
729   /* Now wait for the thread to terminate. */
730   rc = pth_join (popup_tid, NULL);
731   if (!rc)
732     log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
733                strerror (errno));
734   popup_tid = NULL;
735   entry_owner = NULL;
736
737   /* Now we can close the connection. */
738   unlock_pinentry (0);
739 }
740
741