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
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           /* TRANLATORS: The string is appended to an error message in
438              the pinentry.  The %s is the actual error message, the
439              two %d give the current and maximum number of tries. */
440           snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
441                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
442           line[DIM(line)-1] = 0;
443           rc = assuan_transact (entry_ctx, line,
444                                 NULL, NULL, NULL, NULL, NULL, NULL);
445           if (rc)
446             return unlock_pinentry (rc);
447           errtext = NULL;
448         }
449       
450       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
451                             NULL, NULL, NULL, NULL);
452       /* Most pinentries out in the wild return the old Assuan error code
453          for canceled which gets translated to an assuan Cancel error and
454          not to the code for a user cancel.  Fix this here. */
455       if (rc && gpg_err_source (rc)
456           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
457         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
458
459       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
460         errtext = is_pin? _("PIN too long")
461                         : _("Passphrase too long");
462       else if (rc)
463         return unlock_pinentry (rc);
464
465       if (!errtext && pininfo->min_digits)
466         {
467           /* do some basic checks on the entered PIN. */
468           if (!all_digitsp (pininfo->pin))
469             errtext = _("Invalid characters in PIN");
470           else if (pininfo->max_digits
471                    && strlen (pininfo->pin) > pininfo->max_digits)
472             errtext = _("PIN too long");
473           else if (strlen (pininfo->pin) < pininfo->min_digits)
474             errtext = _("PIN too short");
475         }
476
477       if (!errtext && pininfo->check_cb)
478         {
479           /* More checks by utilizing the optional callback. */
480           pininfo->cb_errtext = NULL;
481           rc = pininfo->check_cb (pininfo);
482           if (rc == -1 && pininfo->cb_errtext)
483             errtext = pininfo->cb_errtext;
484           else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
485                    || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
486             errtext = (is_pin? _("Bad PIN")
487                        : _("Bad Passphrase"));
488           else if (rc)
489             return unlock_pinentry (rc);
490         }
491
492       if (!errtext)
493         return unlock_pinentry (0); /* okay, got a PIN or passphrase */
494     }
495
496   return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
497                           : GPG_ERR_BAD_PASSPHRASE));
498 }
499
500
501 \f
502 /* Ask for the passphrase using the supplied arguments.  The returned
503    passphrase needs to be freed by the caller. */
504 int 
505 agent_get_passphrase (ctrl_t ctrl,
506                       char **retpass, const char *desc, const char *prompt,
507                       const char *errtext)
508 {
509
510   int rc;
511   char line[ASSUAN_LINELENGTH];
512   struct entry_parm_s parm;
513
514   *retpass = NULL;
515   if (opt.batch)
516     return gpg_error (GPG_ERR_BAD_PASSPHRASE); 
517
518   rc = start_pinentry (ctrl);
519   if (rc)
520     return rc;
521
522   if (!prompt)
523     prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
524
525
526   if (desc)
527     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
528   else
529     snprintf (line, DIM(line)-1, "RESET");
530   line[DIM(line)-1] = 0;
531   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
532   if (rc)
533     return unlock_pinentry (rc);
534
535   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
536   line[DIM(line)-1] = 0;
537   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
538   if (rc)
539     return unlock_pinentry (rc);
540
541   if (errtext)
542     {
543       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
544       line[DIM(line)-1] = 0;
545       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
546       if (rc)
547         return unlock_pinentry (rc);
548     }
549
550   memset (&parm, 0, sizeof parm);
551   parm.size = ASSUAN_LINELENGTH/2 - 5;
552   parm.buffer = gcry_malloc_secure (parm.size+10);
553   if (!parm.buffer)
554     return unlock_pinentry (out_of_core ());
555
556   assuan_begin_confidential (entry_ctx);
557   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
558                         NULL, NULL, NULL, NULL);
559   /* Most pinentries out in the wild return the old Assuan error code
560      for canceled which gets translated to an assuan Cancel error and
561      not to the code for a user cancel.  Fix this here. */
562   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
563     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
564   if (rc)
565     xfree (parm.buffer);
566   else
567     *retpass = parm.buffer;
568   return unlock_pinentry (rc);
569 }
570
571
572 \f
573 /* Pop up the PIN-entry, display the text and the prompt and ask the
574    user to confirm this.  We return 0 for success, ie. the user
575    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
576    other error. */
577 int 
578 agent_get_confirmation (ctrl_t ctrl,
579                         const char *desc, const char *ok, const char *cancel)
580 {
581   int rc;
582   char line[ASSUAN_LINELENGTH];
583
584   rc = start_pinentry (ctrl);
585   if (rc)
586     return rc;
587
588   if (desc)
589     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
590   else
591     snprintf (line, DIM(line)-1, "RESET");
592   line[DIM(line)-1] = 0;
593   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
594   /* Most pinentries out in the wild return the old Assuan error code
595      for canceled which gets translated to an assuan Cancel error and
596      not to the code for a user cancel.  Fix this here. */
597   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
598     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
599
600   if (rc)
601     return unlock_pinentry (rc);
602
603   if (ok)
604     {
605       snprintf (line, DIM(line)-1, "SETOK %s", ok);
606       line[DIM(line)-1] = 0;
607       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
608       if (rc)
609         return unlock_pinentry (rc);
610     }
611   if (cancel)
612     {
613       snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
614       line[DIM(line)-1] = 0;
615       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
616       if (rc)
617         return unlock_pinentry (rc);
618     }
619
620   rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
621   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
622     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
623
624   return unlock_pinentry (rc);
625 }
626
627
628 /* The thread running the popup message. */
629 static void *
630 popup_message_thread (void *arg)
631 {
632   /* We use the --one-button hack instead of the MESSAGE command to
633      allow the use of old Pinentries.  Those old Pinentries will then
634      show an additional Cancel button but that is mostly a visual
635      annoyance. */
636   assuan_transact (entry_ctx, "CONFIRM --one-button", 
637                    NULL, NULL, NULL, NULL, NULL, NULL);
638   popup_finished = 1;
639   return NULL;
640 }
641
642
643 /* Pop up a message window similar to the confirm one but keep it open
644    until agent_popup_message_stop has been called.  It is crucial for
645    the caller to make sure that the stop function gets called as soon
646    as the message is not anymore required because the message is
647    system modal and all other attempts to use the pinentry will fail
648    (after a timeout). */
649 int 
650 agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
651 {
652   int rc;
653   char line[ASSUAN_LINELENGTH];
654   pth_attr_t tattr;
655
656   rc = start_pinentry (ctrl);
657   if (rc)
658     return rc;
659
660   if (desc)
661     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
662   else
663     snprintf (line, DIM(line)-1, "RESET");
664   line[DIM(line)-1] = 0;
665   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
666   if (rc)
667     return unlock_pinentry (rc);
668
669   if (ok_btn)
670     {
671       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
672       line[DIM(line)-1] = 0;
673       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
674       if (rc)
675         return unlock_pinentry (rc);
676     }
677
678   tattr = pth_attr_new();
679   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
680   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
681   pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
682
683   popup_finished = 0;
684   popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
685   if (!popup_tid)
686     {
687       rc = gpg_error_from_syserror ();
688       log_error ("error spawning popup message handler: %s\n",
689                  strerror (errno) );
690       pth_attr_destroy (tattr);
691       return unlock_pinentry (rc);
692     }
693   pth_attr_destroy (tattr);
694
695   return 0;
696 }
697
698 /* Close a popup window. */
699 void
700 agent_popup_message_stop (ctrl_t ctrl)
701 {
702   int rc;
703   pid_t pid;
704
705   if (!popup_tid || !entry_ctx)
706     {
707       log_debug ("agent_popup_message_stop called with no active popup\n");
708       return; 
709     }
710
711   pid = assuan_get_pid (entry_ctx);
712   if (pid == (pid_t)(-1))
713     ; /* No pid available can't send a kill. */
714   else if (popup_finished)
715     ; /* Already finished and ready for joining. */
716   else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
717     { /* The daemon already died.  No need to send a kill.  However
718          because we already waited for the process, we need to tell
719          assuan that it should not wait again (done by
720          unlock_pinentry). */
721       if (rc == pid)
722         assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
723     }
724   else if (pid > 0)
725     kill (pid, SIGKILL);  /* Need to use SIGKILL due to bad
726                              interaction of SIGINT with Pth. */
727
728   /* Now wait for the thread to terminate. */
729   rc = pth_join (popup_tid, NULL);
730   if (!rc)
731     log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
732                strerror (errno));
733   popup_tid = NULL;
734   entry_owner = NULL;
735
736   /* Now we can close the connection. */
737   unlock_pinentry (0);
738 }
739
740