agent: Improve support for externally cached passwords.
[gnupg.git] / agent / call-pinentry.c
1 /* call-pinentry.c - Spawn the pinentry to query stuff from the user
2  * Copyright (C) 2001, 2002, 2004, 2007, 2008,
3  *               2010  Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #ifndef HAVE_W32_SYSTEM
31 # include <sys/wait.h>
32 # include <sys/types.h>
33 # include <signal.h>
34 #endif
35 #include <npth.h>
36
37 #include "agent.h"
38 #include <assuan.h>
39 #include "sysutils.h"
40 #include "i18n.h"
41
42 #ifdef _POSIX_OPEN_MAX
43 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
44 #else
45 #define MAX_OPEN_FDS 20
46 #endif
47
48
49 /* Because access to the pinentry must be serialized (it is and shall
50    be a global mutual dialog) we should better timeout further
51    requests after some time.  2 minutes seem to be a reasonable
52    time. */
53 #define LOCK_TIMEOUT  (1*60)
54
55 /* The assuan context of the current pinentry. */
56 static assuan_context_t entry_ctx;
57
58 /* The control variable of the connection owning the current pinentry.
59    This is only valid if ENTRY_CTX is not NULL.  Note, that we care
60    only about the value of the pointer and that it should never be
61    dereferenced.  */
62 static ctrl_t entry_owner;
63
64 /* A mutex used to serialize access to the pinentry. */
65 static npth_mutex_t entry_lock;
66
67 /* The thread ID of the popup working thread. */
68 static npth_t  popup_tid;
69
70 /* A flag used in communication between the popup working thread and
71    its stop function. */
72 static int popup_finished;
73
74
75
76 /* Data to be passed to our callbacks, */
77 struct entry_parm_s
78 {
79   int lines;
80   size_t size;
81   unsigned char *buffer;
82 };
83
84
85
86 \f
87 /* This function must be called once to initialize this module.  This
88    has to be done before a second thread is spawned.  We can't do the
89    static initialization because Pth emulation code might not be able
90    to do a static init; in particular, it is not possible for W32. */
91 void
92 initialize_module_call_pinentry (void)
93 {
94   static int initialized;
95
96   if (!initialized)
97     {
98       if (npth_mutex_init (&entry_lock, NULL))
99         initialized = 1;
100     }
101 }
102
103
104
105 /* This function may be called to print infromation pertaining to the
106    current state of this module to the log. */
107 void
108 agent_query_dump_state (void)
109 {
110   log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
111             entry_ctx, (long)assuan_get_pid (entry_ctx), (void*)popup_tid);
112 }
113
114 /* Called to make sure that a popup window owned by the current
115    connection gets closed. */
116 void
117 agent_reset_query (ctrl_t ctrl)
118 {
119   if (entry_ctx && popup_tid && entry_owner == ctrl)
120     {
121       agent_popup_message_stop (ctrl);
122     }
123 }
124
125
126 /* Unlock the pinentry so that another thread can start one and
127    disconnect that pinentry - we do this after the unlock so that a
128    stalled pinentry does not block other threads.  Fixme: We should
129    have a timeout in Assuan for the disconnect operation. */
130 static int
131 unlock_pinentry (int rc)
132 {
133   assuan_context_t ctx = entry_ctx;
134   int err;
135
136   if (rc)
137     {
138       if (DBG_IPC)
139         log_debug ("error calling pinentry: %s <%s>\n",
140                    gpg_strerror (rc), gpg_strsource (rc));
141
142       /* Change the source of the error to pinentry so that the final
143          consumer of the error code knows that the problem is with
144          pinentry.  For backward compatibility we do not do that for
145          some common error codes.  */
146       switch (gpg_err_code (rc))
147         {
148         case GPG_ERR_NO_PIN_ENTRY:
149         case GPG_ERR_CANCELED:
150         case GPG_ERR_FULLY_CANCELED:
151         case GPG_ERR_ASS_UNKNOWN_INQUIRE:
152         case GPG_ERR_ASS_TOO_MUCH_DATA:
153         case GPG_ERR_NO_PASSPHRASE:
154         case GPG_ERR_BAD_PASSPHRASE:
155         case GPG_ERR_BAD_PIN:
156           break;
157
158         default:
159           rc = gpg_err_make (GPG_ERR_SOURCE_PINENTRY, gpg_err_code (rc));
160           break;
161         }
162     }
163
164   entry_ctx = NULL;
165   err = npth_mutex_unlock (&entry_lock);
166   if (err)
167     {
168       log_error ("failed to release the entry lock: %s\n", strerror (err));
169       if (!rc)
170         rc = gpg_error_from_errno (err);
171     }
172   assuan_release (ctx);
173   return rc;
174 }
175
176
177 /* To make sure we leave no secrets in our image after forking of the
178    pinentry, we use this callback. */
179 static void
180 atfork_cb (void *opaque, int where)
181 {
182   ctrl_t ctrl = opaque;
183
184   if (!where)
185     {
186       int iterator = 0;
187       const char *name, *assname, *value;
188
189       gcry_control (GCRYCTL_TERM_SECMEM);
190
191       while ((name = session_env_list_stdenvnames (&iterator, &assname)))
192         {
193           /* For all new envvars (!ASSNAME) and the two medium old
194              ones which do have an assuan name but are conveyed using
195              environment variables, update the environment of the
196              forked process.  */
197           if (!assname
198               || !strcmp (name, "XAUTHORITY")
199               || !strcmp (name, "PINENTRY_USER_DATA"))
200             {
201               value = session_env_getenv (ctrl->session_env, name);
202               if (value)
203                 gnupg_setenv (name, value, 1);
204             }
205         }
206     }
207 }
208
209
210 static gpg_error_t
211 getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
212 {
213   unsigned long *pid = opaque;
214   char pidbuf[50];
215
216   /* There is only the pid in the server's response.  */
217   if (length >= sizeof pidbuf)
218     length = sizeof pidbuf -1;
219   if (length)
220     {
221       strncpy (pidbuf, buffer, length);
222       pidbuf[length] = 0;
223       *pid = strtoul (pidbuf, NULL, 10);
224     }
225   return 0;
226 }
227
228 /* Fork off the pin entry if this has not already been done.  Note,
229    that this function must always be used to aquire the lock for the
230    pinentry - we will serialize _all_ pinentry calls.
231  */
232 static int
233 start_pinentry (ctrl_t ctrl)
234 {
235   int rc = 0;
236   const char *full_pgmname;
237   const char *pgmname;
238   assuan_context_t ctx;
239   const char *argv[5];
240   assuan_fd_t no_close_list[3];
241   int i;
242   const char *tmpstr;
243   unsigned long pinentry_pid;
244   const char *value;
245   struct timespec abstime;
246   int err;
247
248   npth_clock_gettime (&abstime);
249   abstime.tv_sec += LOCK_TIMEOUT;
250   err = npth_mutex_timedlock (&entry_lock, &abstime);
251   if (err)
252     {
253       if (err == ETIMEDOUT)
254         rc = gpg_error (GPG_ERR_TIMEOUT);
255       else
256         rc = gpg_error_from_errno (rc);
257       log_error (_("failed to acquire the pinentry lock: %s\n"),
258                  gpg_strerror (rc));
259       return rc;
260     }
261
262   entry_owner = ctrl;
263
264   if (entry_ctx)
265     return 0;
266
267   if (opt.verbose)
268     log_info ("starting a new PIN Entry\n");
269
270 #ifdef HAVE_W32_SYSTEM
271   fflush (stdout);
272   fflush (stderr);
273 #endif
274   if (fflush (NULL))
275     {
276 #ifndef HAVE_W32_SYSTEM
277       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
278 #endif
279       log_error ("error flushing pending output: %s\n", strerror (errno));
280       /* At least Windows XP fails here with EBADF.  According to docs
281          and Wine an fflush(NULL) is the same as _flushall.  However
282          the Wime implementaion does not flush stdin,stdout and stderr
283          - see above.  Lets try to ignore the error. */
284 #ifndef HAVE_W32_SYSTEM
285       return unlock_pinentry (tmperr);
286 #endif
287     }
288
289   full_pgmname = opt.pinentry_program;
290   if (!full_pgmname || !*full_pgmname)
291     full_pgmname = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
292   if ( !(pgmname = strrchr (full_pgmname, '/')))
293     pgmname = full_pgmname;
294   else
295     pgmname++;
296
297   /* OS X needs the entire file name in argv[0], so that it can locate
298      the resource bundle.  For other systems we stick to the usual
299      convention of supplying only the name of the program.  */
300 #ifdef __APPLE__
301   argv[0] = full_pgmname;
302 #else /*!__APPLE__*/
303   argv[0] = pgmname;
304 #endif /*__APPLE__*/
305
306   if (!opt.keep_display
307       && (value = session_env_getenv (ctrl->session_env, "DISPLAY")))
308     {
309       argv[1] = "--display";
310       argv[2] = value;
311       argv[3] = NULL;
312     }
313   else
314     argv[1] = NULL;
315
316   i=0;
317   if (!opt.running_detached)
318     {
319       if (log_get_fd () != -1)
320         no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
321       no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
322     }
323   no_close_list[i] = ASSUAN_INVALID_FD;
324
325   rc = assuan_new (&ctx);
326   if (rc)
327     {
328       log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
329       return rc;
330     }
331   /* We don't want to log the pinentry communication to make the logs
332      easier to read.  We might want to add a new debug option to enable
333      pinentry logging.  */
334 #ifdef ASSUAN_NO_LOGGING
335   assuan_set_flag (ctx, ASSUAN_NO_LOGGING, 1);
336 #endif
337
338   /* Connect to the pinentry and perform initial handshaking.  Note
339      that atfork is used to change the environment for pinentry.  We
340      start the server in detached mode to suppress the console window
341      under Windows.  */
342   rc = assuan_pipe_connect (ctx, full_pgmname, argv,
343                             no_close_list, atfork_cb, ctrl,
344                             ASSUAN_PIPE_CONNECT_DETACHED);
345   if (rc)
346     {
347       log_error ("can't connect to the PIN entry module '%s': %s\n",
348                  full_pgmname, gpg_strerror (rc));
349       assuan_release (ctx);
350       return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
351     }
352   entry_ctx = ctx;
353
354   if (DBG_IPC)
355     log_debug ("connection to PIN entry established\n");
356
357   rc = assuan_transact (entry_ctx,
358                         opt.no_grab? "OPTION no-grab":"OPTION grab",
359                         NULL, NULL, NULL, NULL, NULL, NULL);
360   if (rc)
361     return unlock_pinentry (rc);
362
363   value = session_env_getenv (ctrl->session_env, "GPG_TTY");
364   if (value)
365     {
366       char *optstr;
367       if (asprintf (&optstr, "OPTION ttyname=%s", value) < 0 )
368         return unlock_pinentry (out_of_core ());
369       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
370                             NULL);
371       xfree (optstr);
372       if (rc)
373         return unlock_pinentry (rc);
374     }
375   value = session_env_getenv (ctrl->session_env, "TERM");
376   if (value)
377     {
378       char *optstr;
379       if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 )
380         return unlock_pinentry (out_of_core ());
381       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
382                             NULL);
383       xfree (optstr);
384       if (rc)
385         return unlock_pinentry (rc);
386     }
387   if (ctrl->lc_ctype)
388     {
389       char *optstr;
390       if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
391         return unlock_pinentry (out_of_core ());
392       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
393                             NULL);
394       xfree (optstr);
395       if (rc)
396         return unlock_pinentry (rc);
397     }
398   if (ctrl->lc_messages)
399     {
400       char *optstr;
401       if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
402         return unlock_pinentry (out_of_core ());
403       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
404                             NULL);
405       xfree (optstr);
406       if (rc)
407         return unlock_pinentry (rc);
408     }
409
410   {
411     /* Provide a few default strings for use by the pinentries.  This
412        may help a pinentry to avoid implementing localization code.  */
413     static struct { const char *key, *value; } tbl[] = {
414       /* TRANSLATORS: These are labels for buttons etc used in
415          Pinentries.  An underscore indicates that the next letter
416          should be used as an accelerator.  Double the underscore for
417          a literal one.  The actual to be translated text starts after
418          the second vertical bar.  */
419       { "ok",     N_("|pinentry-label|_OK") },
420       { "cancel", N_("|pinentry-label|_Cancel") },
421       { "prompt", N_("|pinentry-label|PIN:") },
422       { NULL, NULL}
423     };
424     char *optstr;
425     int idx;
426     const char *s, *s2;
427
428     for (idx=0; tbl[idx].key; idx++)
429       {
430         s = _(tbl[idx].value);
431         if (*s == '|' && (s2=strchr (s+1,'|')))
432           s = s2+1;
433         if (asprintf (&optstr, "OPTION default-%s=%s", tbl[idx].key, s) < 0 )
434           return unlock_pinentry (out_of_core ());
435         assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
436                          NULL);
437         xfree (optstr);
438       }
439   }
440
441
442   /* Tell the pinentry the name of a file it shall touch after having
443      messed with the tty.  This is optional and only supported by
444      newer pinentries and thus we do no error checking. */
445   tmpstr = opt.pinentry_touch_file;
446   if (tmpstr && !strcmp (tmpstr, "/dev/null"))
447     tmpstr = NULL;
448   else if (!tmpstr)
449     tmpstr = get_agent_socket_name ();
450   if (tmpstr)
451     {
452       char *optstr;
453
454       if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
455         ;
456       else
457         {
458           assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
459                            NULL);
460           xfree (optstr);
461         }
462     }
463
464
465   /* Now ask the Pinentry for its PID.  If the Pinentry is new enough
466      it will send the pid back and we will use an inquire to notify
467      our client.  The client may answer the inquiry either with END or
468      with CAN to cancel the pinentry. */
469   rc = assuan_transact (entry_ctx, "GETINFO pid",
470                         getinfo_pid_cb, &pinentry_pid,
471                         NULL, NULL, NULL, NULL);
472   if (rc)
473     {
474       log_info ("You may want to update to a newer pinentry\n");
475       rc = 0;
476     }
477   else if (!rc && (pid_t)pinentry_pid == (pid_t)(-1))
478     log_error ("pinentry did not return a PID\n");
479   else
480     {
481       rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
482       if (gpg_err_code (rc) == GPG_ERR_CANCELED
483           || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
484         return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT,
485                                               gpg_err_code (rc)));
486       rc = 0;
487     }
488
489   return 0;
490 }
491
492
493 /* Returns True is the pinentry is currently active. If WAITSECONDS is
494    greater than zero the function will wait for this many seconds
495    before returning.  */
496 int
497 pinentry_active_p (ctrl_t ctrl, int waitseconds)
498 {
499   int err;
500   (void)ctrl;
501
502   if (waitseconds > 0)
503     {
504       struct timespec abstime;
505       int rc;
506
507       npth_clock_gettime (&abstime);
508       abstime.tv_sec += waitseconds;
509       err = npth_mutex_timedlock (&entry_lock, &abstime);
510       if (err)
511         {
512           if (err == ETIMEDOUT)
513             rc = gpg_error (GPG_ERR_TIMEOUT);
514           else
515             rc = gpg_error (GPG_ERR_INTERNAL);
516           return rc;
517         }
518     }
519   else
520     {
521       err = npth_mutex_trylock (&entry_lock);
522       if (err)
523         return gpg_error (GPG_ERR_LOCKED);
524     }
525
526   err = npth_mutex_unlock (&entry_lock);
527   if (err)
528     log_error ("failed to release the entry lock at %d: %s\n", __LINE__,
529                strerror (errno));
530   return 0;
531 }
532
533
534 static gpg_error_t
535 getpin_cb (void *opaque, const void *buffer, size_t length)
536 {
537   struct entry_parm_s *parm = opaque;
538
539   if (!buffer)
540     return 0;
541
542   /* we expect the pin to fit on one line */
543   if (parm->lines || length >= parm->size)
544     return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
545
546   /* fixme: we should make sure that the assuan buffer is allocated in
547      secure memory or read the response byte by byte */
548   memcpy (parm->buffer, buffer, length);
549   parm->buffer[length] = 0;
550   parm->lines++;
551   return 0;
552 }
553
554
555 static int
556 all_digitsp( const char *s)
557 {
558   for (; *s && *s >= '0' && *s <= '9'; s++)
559     ;
560   return !*s;
561 }
562
563
564 /* Return a new malloced string by unescaping the string S.  Escaping
565    is percent escaping and '+'/space mapping.  A binary Nul will
566    silently be replaced by a 0xFF.  Function returns NULL to indicate
567    an out of memory status.  PArsing stops at the end of the string or
568    a white space character. */
569 static char *
570 unescape_passphrase_string (const unsigned char *s)
571 {
572   char *buffer, *d;
573
574   buffer = d = xtrymalloc_secure (strlen ((const char*)s)+1);
575   if (!buffer)
576     return NULL;
577   while (*s && !spacep (s))
578     {
579       if (*s == '%' && s[1] && s[2])
580         {
581           s++;
582           *d = xtoi_2 (s);
583           if (!*d)
584             *d = '\xff';
585           d++;
586           s += 2;
587         }
588       else if (*s == '+')
589         {
590           *d++ = ' ';
591           s++;
592         }
593       else
594         *d++ = *s++;
595     }
596   *d = 0;
597   return buffer;
598 }
599
600
601 /* Estimate the quality of the passphrase PW and return a value in the
602    range 0..100.  */
603 static int
604 estimate_passphrase_quality (const char *pw)
605 {
606   int goodlength = opt.min_passphrase_len + opt.min_passphrase_len/3;
607   int length;
608   const char *s;
609
610   if (goodlength < 1)
611     return 0;
612
613   for (length = 0, s = pw; *s; s++)
614     if (!spacep (s))
615       length ++;
616
617   if (length > goodlength)
618     return 100;
619   return ((length*10) / goodlength)*10;
620 }
621
622
623 /* Handle the QUALITY inquiry. */
624 static gpg_error_t
625 inq_quality (void *opaque, const char *line)
626 {
627   assuan_context_t ctx = opaque;
628   const char *s;
629   char *pin;
630   int rc;
631   int percent;
632   char numbuf[20];
633
634   if ((s = has_leading_keyword (line, "QUALITY")))
635     {
636       pin = unescape_passphrase_string (s);
637       if (!pin)
638         rc = gpg_error_from_syserror ();
639       else
640         {
641           percent = estimate_passphrase_quality (pin);
642           if (check_passphrase_constraints (NULL, pin, 1))
643             percent = -percent;
644           snprintf (numbuf, sizeof numbuf, "%d", percent);
645           rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
646           xfree (pin);
647         }
648     }
649   else
650     {
651       log_error ("unsupported inquiry '%s' from pinentry\n", line);
652       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
653     }
654
655   return rc;
656 }
657
658
659 /* Helper for agent_askpin and agent_get_passphrase.  */
660 static int
661 setup_qualitybar (void)
662 {
663   int rc;
664   char line[ASSUAN_LINELENGTH];
665   char *tmpstr, *tmpstr2;
666   const char *tooltip;
667
668   /* TRANSLATORS: This string is displayed by Pinentry as the label
669      for the quality bar.  */
670   tmpstr = try_percent_escape (_("Quality:"), "\t\r\n\f\v");
671   snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
672   line[DIM(line)-1] = 0;
673   xfree (tmpstr);
674   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
675   if (rc == 103 /*(Old assuan error code)*/
676       || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
677     ; /* Ignore Unknown Command from old Pinentry versions.  */
678   else if (rc)
679     return rc;
680
681   tmpstr2 = gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
682   if (tmpstr2)
683     tooltip = tmpstr2;
684   else
685     {
686       /* TRANSLATORS: This string is a tooltip, shown by pinentry when
687          hovering over the quality bar.  Please use an appropriate
688          string to describe what this is about.  The length of the
689          tooltip is limited to about 900 characters.  If you do not
690          translate this entry, a default english text (see source)
691          will be used. */
692       tooltip =  _("pinentry.qualitybar.tooltip");
693       if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
694         tooltip = ("The quality of the text entered above.\n"
695                    "Please ask your administrator for "
696                    "details about the criteria.");
697     }
698   tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
699   xfree (tmpstr2);
700   snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
701   line[DIM(line)-1] = 0;
702   xfree (tmpstr);
703   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
704   if (rc == 103 /*(Old assuan error code)*/
705           || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
706     ; /* Ignore Unknown Command from old pinentry versions.  */
707   else if (rc)
708     return rc;
709
710   return 0;
711 }
712
713 enum
714   {
715     PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
716     PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
717     PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
718   };
719
720 /* Check the button_info line for a close action.  Also check for the
721    PIN_REPEATED flag.  */
722 static gpg_error_t
723 pinentry_status_cb (void *opaque, const char *line)
724 {
725   unsigned int *flag = opaque;
726   const char *args;
727
728   if ((args = has_leading_keyword (line, "BUTTON_INFO")))
729     {
730       if (!strcmp (args, "close"))
731         *flag |= PINENTRY_STATUS_CLOSE_BUTTON;
732     }
733   else if (has_leading_keyword (line, "PIN_REPEATED"))
734     {
735       *flag |= PINENTRY_STATUS_PIN_REPEATED;
736     }
737   else if (has_leading_keyword (line, "PASSWORD_FROM_CACHE"))
738     {
739       *flag |= PINENTRY_STATUS_PASSWORD_FROM_CACHE;
740     }
741
742   return 0;
743 }
744
745
746
747 \f
748 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
749    number here and repeat it as long as we have invalid formed
750    numbers.  KEYINFO and CACHEMODE are used to tell pinentry something
751    about the key. */
752 int
753 agent_askpin (ctrl_t ctrl,
754               const char *desc_text, const char *prompt_text,
755               const char *initial_errtext,
756               struct pin_entry_info_s *pininfo,
757               const char *keyinfo, cache_mode_t cache_mode)
758 {
759   int rc;
760   char line[ASSUAN_LINELENGTH];
761   struct entry_parm_s parm;
762   const char *errtext = NULL;
763   int is_pin = 0;
764   int saveflag;
765   unsigned int pinentry_status;
766
767   if (opt.batch)
768     return 0; /* fixme: we should return BAD PIN */
769
770   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
771     {
772       if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
773         return gpg_error (GPG_ERR_CANCELED);
774       if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
775         {
776           unsigned char *passphrase;
777           size_t size;
778
779           *pininfo->pin = 0; /* Reset the PIN. */
780           rc = pinentry_loopback(ctrl, "PASSPHRASE", &passphrase, &size,
781                   pininfo->max_length);
782           if (rc)
783             return rc;
784
785           memcpy(&pininfo->pin, passphrase, size);
786           xfree(passphrase);
787           pininfo->pin[size] = 0;
788           if (pininfo->check_cb)
789             {
790               /* More checks by utilizing the optional callback. */
791               pininfo->cb_errtext = NULL;
792               rc = pininfo->check_cb (pininfo);
793             }
794           return rc;
795         }
796       return gpg_error(GPG_ERR_NO_PIN_ENTRY);
797     }
798
799   if (!pininfo || pininfo->max_length < 1)
800     return gpg_error (GPG_ERR_INV_VALUE);
801   if (!desc_text && pininfo->min_digits)
802     desc_text = _("Please enter your PIN, so that the secret key "
803                   "can be unlocked for this session");
804   else if (!desc_text)
805     desc_text = _("Please enter your passphrase, so that the secret key "
806                   "can be unlocked for this session");
807
808   if (prompt_text)
809     is_pin = !!strstr (prompt_text, "PIN");
810   else
811     is_pin = desc_text && strstr (desc_text, "PIN");
812
813   rc = start_pinentry (ctrl);
814   if (rc)
815     return rc;
816
817   /* Indicate to the pinentry that it may read from an external cache.
818
819      It is essential that the pinentry respect this.  If the cached
820      password is not up to date and retry == 1, then, using a version
821      of GPG Agent that doesn't support this, won't issue another pin
822      request and the user won't get a chance to correct the
823      password.  */
824   rc = assuan_transact (entry_ctx, "OPTION allow-external-password-cache",
825                         NULL, NULL, NULL, NULL, NULL, NULL);
826   if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
827     return unlock_pinentry (rc);
828
829   /* If we have a KEYINFO string and are normal, user, or ssh cache
830      mode, we tell that the Pinentry so it may use it for own caching
831      purposes.  Most pinentries won't have this implemented and thus
832      we do not error out in this case.  */
833   if (keyinfo && (cache_mode == CACHE_MODE_NORMAL
834                   || cache_mode == CACHE_MODE_USER
835                   || cache_mode == CACHE_MODE_SSH))
836     snprintf (line, DIM(line)-1, "SETKEYINFO %c/%s",
837               cache_mode == CACHE_MODE_USER? 'u' :
838               cache_mode == CACHE_MODE_SSH? 's' : 'n',
839               keyinfo);
840   else
841     snprintf (line, DIM(line)-1, "SETKEYINFO --clear");
842
843   rc = assuan_transact (entry_ctx, line,
844                         NULL, NULL, NULL, NULL, NULL, NULL);
845   if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
846     return unlock_pinentry (rc);
847
848   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
849   line[DIM(line)-1] = 0;
850   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
851   if (rc)
852     return unlock_pinentry (rc);
853
854   snprintf (line, DIM(line)-1, "SETPROMPT %s",
855             prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
856   line[DIM(line)-1] = 0;
857   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
858   if (rc)
859     return unlock_pinentry (rc);
860
861   /* If a passphrase quality indicator has been requested and a
862      minimum passphrase length has not been disabled, send the command
863      to the pinentry.  */
864   if (pininfo->with_qualitybar && opt.min_passphrase_len )
865     {
866       rc = setup_qualitybar ();
867       if (rc)
868         return unlock_pinentry (rc);
869     }
870
871   if (initial_errtext)
872     {
873       snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
874       line[DIM(line)-1] = 0;
875       rc = assuan_transact (entry_ctx, line,
876                             NULL, NULL, NULL, NULL, NULL, NULL);
877       if (rc)
878         return unlock_pinentry (rc);
879     }
880
881   if (pininfo->with_repeat)
882     {
883       snprintf (line, DIM(line)-1, "SETREPEATERROR %s",
884                 _("does not match - try again"));
885       line[DIM(line)-1] = 0;
886       rc = assuan_transact (entry_ctx, line,
887                             NULL, NULL, NULL, NULL, NULL, NULL);
888       if (rc)
889         pininfo->with_repeat = 0; /* Pinentry does not support it.  */
890     }
891   pininfo->repeat_okay = 0;
892
893   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
894     {
895       memset (&parm, 0, sizeof parm);
896       parm.size = pininfo->max_length;
897       *pininfo->pin = 0; /* Reset the PIN. */
898       parm.buffer = (unsigned char*)pininfo->pin;
899
900       if (errtext)
901         {
902           /* TRANSLATORS: The string is appended to an error message in
903              the pinentry.  The %s is the actual error message, the
904              two %d give the current and maximum number of tries. */
905           snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
906                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
907           line[DIM(line)-1] = 0;
908           rc = assuan_transact (entry_ctx, line,
909                                 NULL, NULL, NULL, NULL, NULL, NULL);
910           if (rc)
911             return unlock_pinentry (rc);
912           errtext = NULL;
913         }
914
915       if (pininfo->with_repeat)
916         {
917           snprintf (line, DIM(line)-1, "SETREPEAT %s", _("Repeat:"));
918           line[DIM(line)-1] = 0;
919           rc = assuan_transact (entry_ctx, line,
920                                 NULL, NULL, NULL, NULL, NULL, NULL);
921           if (rc)
922             return unlock_pinentry (rc);
923         }
924
925       saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
926       assuan_begin_confidential (entry_ctx);
927       pinentry_status = 0;
928       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
929                             inq_quality, entry_ctx,
930                             pinentry_status_cb, &pinentry_status);
931       assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
932       /* Most pinentries out in the wild return the old Assuan error code
933          for canceled which gets translated to an assuan Cancel error and
934          not to the code for a user cancel.  Fix this here. */
935       if (rc && gpg_err_source (rc)
936           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
937         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
938
939
940       /* Change error code in case the window close button was clicked
941          to cancel the operation.  */
942       if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
943           && gpg_err_code (rc) == GPG_ERR_CANCELED)
944         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
945
946       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
947         errtext = is_pin? _("PIN too long")
948                         : _("Passphrase too long");
949       else if (rc)
950         return unlock_pinentry (rc);
951
952       if (!errtext && pininfo->min_digits)
953         {
954           /* do some basic checks on the entered PIN. */
955           if (!all_digitsp (pininfo->pin))
956             errtext = _("Invalid characters in PIN");
957           else if (pininfo->max_digits
958                    && strlen (pininfo->pin) > pininfo->max_digits)
959             errtext = _("PIN too long");
960           else if (strlen (pininfo->pin) < pininfo->min_digits)
961             errtext = _("PIN too short");
962         }
963
964       if (!errtext && pininfo->check_cb)
965         {
966           /* More checks by utilizing the optional callback. */
967           pininfo->cb_errtext = NULL;
968           rc = pininfo->check_cb (pininfo);
969           if (rc == -1 && pininfo->cb_errtext)
970             errtext = pininfo->cb_errtext;
971           else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
972                    || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
973             errtext = (is_pin? _("Bad PIN")
974                        : _("Bad Passphrase"));
975           else if (rc)
976             return unlock_pinentry (rc);
977         }
978
979       if (!errtext)
980         {
981           if (pininfo->with_repeat
982               && (pinentry_status & PINENTRY_STATUS_PIN_REPEATED))
983             pininfo->repeat_okay = 1;
984           return unlock_pinentry (0); /* okay, got a PIN or passphrase */
985         }
986
987       if ((pinentry_status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
988         /* The password was read from the cache.  Don't count this
989            against the retry count.  */
990         pininfo->failed_tries --;
991     }
992
993   return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
994                           : GPG_ERR_BAD_PASSPHRASE));
995 }
996
997
998 \f
999 /* Ask for the passphrase using the supplied arguments.  The returned
1000    passphrase needs to be freed by the caller. */
1001 int
1002 agent_get_passphrase (ctrl_t ctrl,
1003                       char **retpass, const char *desc, const char *prompt,
1004                       const char *errtext, int with_qualitybar)
1005 {
1006
1007   int rc;
1008   char line[ASSUAN_LINELENGTH];
1009   struct entry_parm_s parm;
1010   int saveflag;
1011   unsigned int pinentry_status;
1012
1013   *retpass = NULL;
1014   if (opt.batch)
1015     return gpg_error (GPG_ERR_BAD_PASSPHRASE);
1016
1017   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1018     {
1019       if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
1020         return gpg_error (GPG_ERR_CANCELED);
1021
1022       if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
1023         {
1024           size_t size;
1025           size_t len = ASSUAN_LINELENGTH/2;
1026           unsigned char *buffer = gcry_malloc_secure (len);
1027
1028           rc = pinentry_loopback(ctrl, "PASSPHRASE", &buffer, &size, len);
1029           if (rc)
1030             xfree(buffer);
1031           else
1032             {
1033               buffer[size] = 0;
1034               *retpass = buffer;
1035             }
1036           return rc;
1037         }
1038       return gpg_error (GPG_ERR_NO_PIN_ENTRY);
1039     }
1040
1041   rc = start_pinentry (ctrl);
1042   if (rc)
1043     return rc;
1044
1045   if (!prompt)
1046     prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
1047
1048
1049   if (desc)
1050     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
1051   else
1052     snprintf (line, DIM(line)-1, "RESET");
1053   line[DIM(line)-1] = 0;
1054   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1055   if (rc)
1056     return unlock_pinentry (rc);
1057
1058   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
1059   line[DIM(line)-1] = 0;
1060   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1061   if (rc)
1062     return unlock_pinentry (rc);
1063
1064   if (with_qualitybar && opt.min_passphrase_len)
1065     {
1066       rc = setup_qualitybar ();
1067       if (rc)
1068         return unlock_pinentry (rc);
1069     }
1070
1071   if (errtext)
1072     {
1073       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
1074       line[DIM(line)-1] = 0;
1075       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1076       if (rc)
1077         return unlock_pinentry (rc);
1078     }
1079
1080   memset (&parm, 0, sizeof parm);
1081   parm.size = ASSUAN_LINELENGTH/2 - 5;
1082   parm.buffer = gcry_malloc_secure (parm.size+10);
1083   if (!parm.buffer)
1084     return unlock_pinentry (out_of_core ());
1085
1086   saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
1087   assuan_begin_confidential (entry_ctx);
1088   pinentry_status = 0;
1089   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
1090                         inq_quality, entry_ctx,
1091                         pinentry_status_cb, &pinentry_status);
1092   assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
1093   /* Most pinentries out in the wild return the old Assuan error code
1094      for canceled which gets translated to an assuan Cancel error and
1095      not to the code for a user cancel.  Fix this here. */
1096   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1097     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1098   /* Change error code in case the window close button was clicked
1099      to cancel the operation.  */
1100   if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
1101       && gpg_err_code (rc) == GPG_ERR_CANCELED)
1102     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
1103
1104   if (rc)
1105     xfree (parm.buffer);
1106   else
1107     *retpass = parm.buffer;
1108   return unlock_pinentry (rc);
1109 }
1110
1111
1112 \f
1113 /* Pop up the PIN-entry, display the text and the prompt and ask the
1114    user to confirm this.  We return 0 for success, ie. the user
1115    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
1116    other error.  If WITH_CANCEL it true an extra cancel button is
1117    displayed to allow the user to easily return a GPG_ERR_CANCELED.
1118    if the Pinentry does not support this, the user can still cancel by
1119    closing the Pinentry window.  */
1120 int
1121 agent_get_confirmation (ctrl_t ctrl,
1122                         const char *desc, const char *ok,
1123                         const char *notok, int with_cancel)
1124 {
1125   int rc;
1126   char line[ASSUAN_LINELENGTH];
1127
1128   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1129     {
1130       if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
1131         return gpg_error (GPG_ERR_CANCELED);
1132
1133       return gpg_error (GPG_ERR_NO_PIN_ENTRY);
1134     }
1135
1136   rc = start_pinentry (ctrl);
1137   if (rc)
1138     return rc;
1139
1140   if (desc)
1141     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
1142   else
1143     snprintf (line, DIM(line)-1, "RESET");
1144   line[DIM(line)-1] = 0;
1145   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1146   /* Most pinentries out in the wild return the old Assuan error code
1147      for canceled which gets translated to an assuan Cancel error and
1148      not to the code for a user cancel.  Fix this here. */
1149   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1150     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1151
1152   if (rc)
1153     return unlock_pinentry (rc);
1154
1155   if (ok)
1156     {
1157       snprintf (line, DIM(line)-1, "SETOK %s", ok);
1158       line[DIM(line)-1] = 0;
1159       rc = assuan_transact (entry_ctx,
1160                             line, NULL, NULL, NULL, NULL, NULL, NULL);
1161       if (rc)
1162         return unlock_pinentry (rc);
1163     }
1164   if (notok)
1165     {
1166       /* Try to use the newer NOTOK feature if a cancel button is
1167          requested.  If no cancel button is requested we keep on using
1168          the standard cancel.  */
1169       if (with_cancel)
1170         {
1171           snprintf (line, DIM(line)-1, "SETNOTOK %s", notok);
1172           line[DIM(line)-1] = 0;
1173           rc = assuan_transact (entry_ctx,
1174                                 line, NULL, NULL, NULL, NULL, NULL, NULL);
1175         }
1176       else
1177         rc = GPG_ERR_ASS_UNKNOWN_CMD;
1178
1179       if (gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
1180         {
1181           snprintf (line, DIM(line)-1, "SETCANCEL %s", notok);
1182           line[DIM(line)-1] = 0;
1183           rc = assuan_transact (entry_ctx, line,
1184                                 NULL, NULL, NULL, NULL, NULL, NULL);
1185         }
1186       if (rc)
1187         return unlock_pinentry (rc);
1188     }
1189
1190   rc = assuan_transact (entry_ctx, "CONFIRM",
1191                         NULL, NULL, NULL, NULL, NULL, NULL);
1192   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1193     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1194
1195   return unlock_pinentry (rc);
1196 }
1197
1198
1199 \f
1200 /* Pop up the PINentry, display the text DESC and a button with the
1201    text OK_BTN (which may be NULL to use the default of "OK") and wait
1202    for the user to hit this button.  The return value is not
1203    relevant.  */
1204 int
1205 agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
1206 {
1207   int rc;
1208   char line[ASSUAN_LINELENGTH];
1209
1210   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1211     return gpg_error (GPG_ERR_CANCELED);
1212
1213   rc = start_pinentry (ctrl);
1214   if (rc)
1215     return rc;
1216
1217   if (desc)
1218     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
1219   else
1220     snprintf (line, DIM(line)-1, "RESET");
1221   line[DIM(line)-1] = 0;
1222   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1223   /* Most pinentries out in the wild return the old Assuan error code
1224      for canceled which gets translated to an assuan Cancel error and
1225      not to the code for a user cancel.  Fix this here. */
1226   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1227     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1228
1229   if (rc)
1230     return unlock_pinentry (rc);
1231
1232   if (ok_btn)
1233     {
1234       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
1235       line[DIM(line)-1] = 0;
1236       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
1237                             NULL, NULL, NULL);
1238       if (rc)
1239         return unlock_pinentry (rc);
1240     }
1241
1242   rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
1243                         NULL, NULL, NULL);
1244   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1245     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1246
1247   return unlock_pinentry (rc);
1248 }
1249
1250
1251 /* The thread running the popup message. */
1252 static void *
1253 popup_message_thread (void *arg)
1254 {
1255   (void)arg;
1256
1257   /* We use the --one-button hack instead of the MESSAGE command to
1258      allow the use of old Pinentries.  Those old Pinentries will then
1259      show an additional Cancel button but that is mostly a visual
1260      annoyance. */
1261   assuan_transact (entry_ctx, "CONFIRM --one-button",
1262                    NULL, NULL, NULL, NULL, NULL, NULL);
1263   popup_finished = 1;
1264   return NULL;
1265 }
1266
1267
1268 /* Pop up a message window similar to the confirm one but keep it open
1269    until agent_popup_message_stop has been called.  It is crucial for
1270    the caller to make sure that the stop function gets called as soon
1271    as the message is not anymore required because the message is
1272    system modal and all other attempts to use the pinentry will fail
1273    (after a timeout). */
1274 int
1275 agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
1276 {
1277   int rc;
1278   char line[ASSUAN_LINELENGTH];
1279   npth_attr_t tattr;
1280   int err;
1281
1282   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1283     return gpg_error (GPG_ERR_CANCELED);
1284
1285   rc = start_pinentry (ctrl);
1286   if (rc)
1287     return rc;
1288
1289   if (desc)
1290     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
1291   else
1292     snprintf (line, DIM(line)-1, "RESET");
1293   line[DIM(line)-1] = 0;
1294   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1295   if (rc)
1296     return unlock_pinentry (rc);
1297
1298   if (ok_btn)
1299     {
1300       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
1301       line[DIM(line)-1] = 0;
1302       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
1303       if (rc)
1304         return unlock_pinentry (rc);
1305     }
1306
1307   err = npth_attr_init (&tattr);
1308   if (err)
1309     return unlock_pinentry (gpg_error_from_errno (err));
1310   npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
1311
1312   popup_finished = 0;
1313   err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL);
1314   npth_attr_destroy (&tattr);
1315   if (err)
1316     {
1317       rc = gpg_error_from_errno (err);
1318       log_error ("error spawning popup message handler: %s\n",
1319                  strerror (err) );
1320       return unlock_pinentry (rc);
1321     }
1322   npth_setname_np (popup_tid, "popup-message");
1323
1324   return 0;
1325 }
1326
1327 /* Close a popup window. */
1328 void
1329 agent_popup_message_stop (ctrl_t ctrl)
1330 {
1331   int rc;
1332   pid_t pid;
1333
1334   (void)ctrl;
1335
1336   if (!popup_tid || !entry_ctx)
1337     {
1338       log_debug ("agent_popup_message_stop called with no active popup\n");
1339       return;
1340     }
1341
1342   pid = assuan_get_pid (entry_ctx);
1343   if (pid == (pid_t)(-1))
1344     ; /* No pid available can't send a kill. */
1345   else if (popup_finished)
1346     ; /* Already finished and ready for joining. */
1347 #ifdef HAVE_W32_SYSTEM
1348   /* Older versions of assuan set PID to 0 on Windows to indicate an
1349      invalid value.  */
1350   else if (pid != (pid_t) INVALID_HANDLE_VALUE
1351            && pid != 0)
1352     {
1353       HANDLE process = (HANDLE) pid;
1354
1355       /* Arbitrary error code.  */
1356       TerminateProcess (process, 1);
1357     }
1358 #else
1359   else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
1360     { /* The daemon already died.  No need to send a kill.  However
1361          because we already waited for the process, we need to tell
1362          assuan that it should not wait again (done by
1363          unlock_pinentry). */
1364       if (rc == pid)
1365         assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
1366     }
1367   else if (pid > 0)
1368     kill (pid, SIGINT);
1369 #endif
1370
1371   /* Now wait for the thread to terminate. */
1372   rc = npth_join (popup_tid, NULL);
1373   if (rc)
1374     log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
1375                strerror (rc));
1376   /* Thread IDs are opaque, but we try our best here by resetting it
1377      to the same content that a static global variable has.  */
1378   memset (&popup_tid, '\0', sizeof (popup_tid));
1379   entry_owner = NULL;
1380
1381   /* Now we can close the connection. */
1382   unlock_pinentry (0);
1383 }