agent: Minor change for 56b5c9f.
[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 mutually exclusive dialog) we better timeout pending
51    requests after some time.  1 minute 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 Wine implementaion does not flush stdin,stdout and stderr
283          - see above.  Let's 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   /* Indicate to the pinentry that it may read from an external cache.
412
413      It is essential that the pinentry respect this.  If the cached
414      password is not up to date and retry == 1, then, using a version
415      of GPG Agent that doesn't support this, won't issue another pin
416      request and the user won't get a chance to correct the
417      password.  */
418   rc = assuan_transact (entry_ctx, "OPTION allow-external-password-cache",
419                         NULL, NULL, NULL, NULL, NULL, NULL);
420   if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION)
421     return unlock_pinentry (rc);
422
423
424   {
425     /* Provide a few default strings for use by the pinentries.  This
426        may help a pinentry to avoid implementing localization code.  */
427     static struct { const char *key, *value; } tbl[] = {
428       /* TRANSLATORS: These are labels for buttons etc used in
429          Pinentries.  An underscore indicates that the next letter
430          should be used as an accelerator.  Double the underscore for
431          a literal one.  The actual to be translated text starts after
432          the second vertical bar.  */
433       { "ok",     N_("|pinentry-label|_OK") },
434       { "cancel", N_("|pinentry-label|_Cancel") },
435       { "prompt", N_("|pinentry-label|PIN:") },
436       { NULL, NULL}
437     };
438     char *optstr;
439     int idx;
440     const char *s, *s2;
441
442     for (idx=0; tbl[idx].key; idx++)
443       {
444         s = _(tbl[idx].value);
445         if (*s == '|' && (s2=strchr (s+1,'|')))
446           s = s2+1;
447         if (asprintf (&optstr, "OPTION default-%s=%s", tbl[idx].key, s) < 0 )
448           return unlock_pinentry (out_of_core ());
449         assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
450                          NULL);
451         xfree (optstr);
452       }
453   }
454
455
456   /* Tell the pinentry the name of a file it shall touch after having
457      messed with the tty.  This is optional and only supported by
458      newer pinentries and thus we do no error checking. */
459   tmpstr = opt.pinentry_touch_file;
460   if (tmpstr && !strcmp (tmpstr, "/dev/null"))
461     tmpstr = NULL;
462   else if (!tmpstr)
463     tmpstr = get_agent_socket_name ();
464   if (tmpstr)
465     {
466       char *optstr;
467
468       if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
469         ;
470       else
471         {
472           assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
473                            NULL);
474           xfree (optstr);
475         }
476     }
477
478
479   /* Now ask the Pinentry for its PID.  If the Pinentry is new enough
480      it will send the pid back and we will use an inquire to notify
481      our client.  The client may answer the inquiry either with END or
482      with CAN to cancel the pinentry. */
483   rc = assuan_transact (entry_ctx, "GETINFO pid",
484                         getinfo_pid_cb, &pinentry_pid,
485                         NULL, NULL, NULL, NULL);
486   if (rc)
487     {
488       log_info ("You may want to update to a newer pinentry\n");
489       rc = 0;
490     }
491   else if (!rc && (pid_t)pinentry_pid == (pid_t)(-1))
492     log_error ("pinentry did not return a PID\n");
493   else
494     {
495       rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
496       if (gpg_err_code (rc) == GPG_ERR_CANCELED
497           || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
498         return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT,
499                                               gpg_err_code (rc)));
500       rc = 0;
501     }
502
503   return 0;
504 }
505
506
507 /* Returns True if the pinentry is currently active. If WAITSECONDS is
508    greater than zero the function will wait for this many seconds
509    before returning.  */
510 int
511 pinentry_active_p (ctrl_t ctrl, int waitseconds)
512 {
513   int err;
514   (void)ctrl;
515
516   if (waitseconds > 0)
517     {
518       struct timespec abstime;
519       int rc;
520
521       npth_clock_gettime (&abstime);
522       abstime.tv_sec += waitseconds;
523       err = npth_mutex_timedlock (&entry_lock, &abstime);
524       if (err)
525         {
526           if (err == ETIMEDOUT)
527             rc = gpg_error (GPG_ERR_TIMEOUT);
528           else
529             rc = gpg_error (GPG_ERR_INTERNAL);
530           return rc;
531         }
532     }
533   else
534     {
535       err = npth_mutex_trylock (&entry_lock);
536       if (err)
537         return gpg_error (GPG_ERR_LOCKED);
538     }
539
540   err = npth_mutex_unlock (&entry_lock);
541   if (err)
542     log_error ("failed to release the entry lock at %d: %s\n", __LINE__,
543                strerror (errno));
544   return 0;
545 }
546
547
548 static gpg_error_t
549 getpin_cb (void *opaque, const void *buffer, size_t length)
550 {
551   struct entry_parm_s *parm = opaque;
552
553   if (!buffer)
554     return 0;
555
556   /* we expect the pin to fit on one line */
557   if (parm->lines || length >= parm->size)
558     return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
559
560   /* fixme: we should make sure that the assuan buffer is allocated in
561      secure memory or read the response byte by byte */
562   memcpy (parm->buffer, buffer, length);
563   parm->buffer[length] = 0;
564   parm->lines++;
565   return 0;
566 }
567
568
569 static int
570 all_digitsp( const char *s)
571 {
572   for (; *s && *s >= '0' && *s <= '9'; s++)
573     ;
574   return !*s;
575 }
576
577
578 /* Return a new malloced string by unescaping the string S.  Escaping
579    is percent escaping and '+'/space mapping.  A binary Nul will
580    silently be replaced by a 0xFF.  Function returns NULL to indicate
581    an out of memory status.  Parsing stops at the end of the string or
582    a white space character. */
583 static char *
584 unescape_passphrase_string (const unsigned char *s)
585 {
586   char *buffer, *d;
587
588   buffer = d = xtrymalloc_secure (strlen ((const char*)s)+1);
589   if (!buffer)
590     return NULL;
591   while (*s && !spacep (s))
592     {
593       if (*s == '%' && s[1] && s[2])
594         {
595           s++;
596           *d = xtoi_2 (s);
597           if (!*d)
598             *d = '\xff';
599           d++;
600           s += 2;
601         }
602       else if (*s == '+')
603         {
604           *d++ = ' ';
605           s++;
606         }
607       else
608         *d++ = *s++;
609     }
610   *d = 0;
611   return buffer;
612 }
613
614
615 /* Estimate the quality of the passphrase PW and return a value in the
616    range 0..100.  */
617 static int
618 estimate_passphrase_quality (const char *pw)
619 {
620   int goodlength = opt.min_passphrase_len + opt.min_passphrase_len/3;
621   int length;
622   const char *s;
623
624   if (goodlength < 1)
625     return 0;
626
627   for (length = 0, s = pw; *s; s++)
628     if (!spacep (s))
629       length ++;
630
631   if (length > goodlength)
632     return 100;
633   return ((length*10) / goodlength)*10;
634 }
635
636
637 /* Handle the QUALITY inquiry. */
638 static gpg_error_t
639 inq_quality (void *opaque, const char *line)
640 {
641   assuan_context_t ctx = opaque;
642   const char *s;
643   char *pin;
644   int rc;
645   int percent;
646   char numbuf[20];
647
648   if ((s = has_leading_keyword (line, "QUALITY")))
649     {
650       pin = unescape_passphrase_string (s);
651       if (!pin)
652         rc = gpg_error_from_syserror ();
653       else
654         {
655           percent = estimate_passphrase_quality (pin);
656           if (check_passphrase_constraints (NULL, pin, 1))
657             percent = -percent;
658           snprintf (numbuf, sizeof numbuf, "%d", percent);
659           rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
660           xfree (pin);
661         }
662     }
663   else
664     {
665       log_error ("unsupported inquiry '%s' from pinentry\n", line);
666       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
667     }
668
669   return rc;
670 }
671
672
673 /* Helper for agent_askpin and agent_get_passphrase.  */
674 static int
675 setup_qualitybar (void)
676 {
677   int rc;
678   char line[ASSUAN_LINELENGTH];
679   char *tmpstr, *tmpstr2;
680   const char *tooltip;
681
682   /* TRANSLATORS: This string is displayed by Pinentry as the label
683      for the quality bar.  */
684   tmpstr = try_percent_escape (_("Quality:"), "\t\r\n\f\v");
685   snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
686   line[DIM(line)-1] = 0;
687   xfree (tmpstr);
688   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
689   if (rc == 103 /*(Old assuan error code)*/
690       || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
691     ; /* Ignore Unknown Command from old Pinentry versions.  */
692   else if (rc)
693     return rc;
694
695   tmpstr2 = gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
696   if (tmpstr2)
697     tooltip = tmpstr2;
698   else
699     {
700       /* TRANSLATORS: This string is a tooltip, shown by pinentry when
701          hovering over the quality bar.  Please use an appropriate
702          string to describe what this is about.  The length of the
703          tooltip is limited to about 900 characters.  If you do not
704          translate this entry, a default english text (see source)
705          will be used. */
706       tooltip =  _("pinentry.qualitybar.tooltip");
707       if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
708         tooltip = ("The quality of the text entered above.\n"
709                    "Please ask your administrator for "
710                    "details about the criteria.");
711     }
712   tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
713   xfree (tmpstr2);
714   snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
715   line[DIM(line)-1] = 0;
716   xfree (tmpstr);
717   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
718   if (rc == 103 /*(Old assuan error code)*/
719           || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
720     ; /* Ignore Unknown Command from old pinentry versions.  */
721   else if (rc)
722     return rc;
723
724   return 0;
725 }
726
727 enum
728   {
729     PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
730     PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
731     PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
732   };
733
734 /* Check the button_info line for a close action.  Also check for the
735    PIN_REPEATED flag.  */
736 static gpg_error_t
737 pinentry_status_cb (void *opaque, const char *line)
738 {
739   unsigned int *flag = opaque;
740   const char *args;
741
742   if ((args = has_leading_keyword (line, "BUTTON_INFO")))
743     {
744       if (!strcmp (args, "close"))
745         *flag |= PINENTRY_STATUS_CLOSE_BUTTON;
746     }
747   else if (has_leading_keyword (line, "PIN_REPEATED"))
748     {
749       *flag |= PINENTRY_STATUS_PIN_REPEATED;
750     }
751   else if (has_leading_keyword (line, "PASSWORD_FROM_CACHE"))
752     {
753       *flag |= PINENTRY_STATUS_PASSWORD_FROM_CACHE;
754     }
755
756   return 0;
757 }
758
759
760
761 \f
762 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
763    number here and repeat it as long as we have invalid formed
764    numbers.  KEYINFO and CACHE_MODE are used to tell pinentry something
765    about the key. */
766 int
767 agent_askpin (ctrl_t ctrl,
768               const char *desc_text, const char *prompt_text,
769               const char *initial_errtext,
770               struct pin_entry_info_s *pininfo,
771               const char *keyinfo, cache_mode_t cache_mode)
772 {
773   int rc;
774   char line[ASSUAN_LINELENGTH];
775   struct entry_parm_s parm;
776   const char *errtext = NULL;
777   int is_pin = 0;
778   int saveflag;
779   unsigned int pinentry_status;
780
781   if (opt.batch)
782     return 0; /* fixme: we should return BAD PIN */
783
784   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
785     {
786       if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
787         return gpg_error (GPG_ERR_CANCELED);
788       if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
789         {
790           unsigned char *passphrase;
791           size_t size;
792
793           *pininfo->pin = 0; /* Reset the PIN. */
794           rc = pinentry_loopback(ctrl, "PASSPHRASE", &passphrase, &size,
795                   pininfo->max_length);
796           if (rc)
797             return rc;
798
799           memcpy(&pininfo->pin, passphrase, size);
800           xfree(passphrase);
801           pininfo->pin[size] = 0;
802           if (pininfo->check_cb)
803             {
804               /* More checks by utilizing the optional callback. */
805               pininfo->cb_errtext = NULL;
806               rc = pininfo->check_cb (pininfo);
807             }
808           return rc;
809         }
810       return gpg_error(GPG_ERR_NO_PIN_ENTRY);
811     }
812
813   if (!pininfo || pininfo->max_length < 1)
814     return gpg_error (GPG_ERR_INV_VALUE);
815   if (!desc_text && pininfo->min_digits)
816     desc_text = _("Please enter your PIN, so that the secret key "
817                   "can be unlocked for this session");
818   else if (!desc_text)
819     desc_text = _("Please enter your passphrase, so that the secret key "
820                   "can be unlocked for this session");
821
822   if (prompt_text)
823     is_pin = !!strstr (prompt_text, "PIN");
824   else
825     is_pin = desc_text && strstr (desc_text, "PIN");
826
827   rc = start_pinentry (ctrl);
828   if (rc)
829     return rc;
830
831   /* If we have a KEYINFO string and are normal, user, or ssh cache
832      mode, we tell that the Pinentry so it may use it for own caching
833      purposes.  Most pinentries won't have this implemented and thus
834      we do not error out in this case.  */
835   if (keyinfo && (cache_mode == CACHE_MODE_NORMAL
836                   || cache_mode == CACHE_MODE_USER
837                   || cache_mode == CACHE_MODE_SSH))
838     snprintf (line, DIM(line)-1, "SETKEYINFO %c/%s",
839               cache_mode == CACHE_MODE_USER? 'u' :
840               cache_mode == CACHE_MODE_SSH? 's' : 'n',
841               keyinfo);
842   else
843     snprintf (line, DIM(line)-1, "SETKEYINFO --clear");
844
845   rc = assuan_transact (entry_ctx, line,
846                         NULL, NULL, NULL, NULL, NULL, NULL);
847   if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
848     return unlock_pinentry (rc);
849
850   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
851   line[DIM(line)-1] = 0;
852   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
853   if (rc)
854     return unlock_pinentry (rc);
855
856   snprintf (line, DIM(line)-1, "SETPROMPT %s",
857             prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
858   line[DIM(line)-1] = 0;
859   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
860   if (rc)
861     return unlock_pinentry (rc);
862
863   /* If a passphrase quality indicator has been requested and a
864      minimum passphrase length has not been disabled, send the command
865      to the pinentry.  */
866   if (pininfo->with_qualitybar && opt.min_passphrase_len )
867     {
868       rc = setup_qualitybar ();
869       if (rc)
870         return unlock_pinentry (rc);
871     }
872
873   if (initial_errtext)
874     {
875       snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
876       line[DIM(line)-1] = 0;
877       rc = assuan_transact (entry_ctx, line,
878                             NULL, NULL, NULL, NULL, NULL, NULL);
879       if (rc)
880         return unlock_pinentry (rc);
881     }
882
883   if (pininfo->with_repeat)
884     {
885       snprintf (line, DIM(line)-1, "SETREPEATERROR %s",
886                 _("does not match - try again"));
887       line[DIM(line)-1] = 0;
888       rc = assuan_transact (entry_ctx, line,
889                             NULL, NULL, NULL, NULL, NULL, NULL);
890       if (rc)
891         pininfo->with_repeat = 0; /* Pinentry does not support it.  */
892     }
893   pininfo->repeat_okay = 0;
894
895   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
896     {
897       memset (&parm, 0, sizeof parm);
898       parm.size = pininfo->max_length;
899       *pininfo->pin = 0; /* Reset the PIN. */
900       parm.buffer = (unsigned char*)pininfo->pin;
901
902       if (errtext)
903         {
904           /* TRANSLATORS: The string is appended to an error message in
905              the pinentry.  The %s is the actual error message, the
906              two %d give the current and maximum number of tries. */
907           snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
908                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
909           line[DIM(line)-1] = 0;
910           rc = assuan_transact (entry_ctx, line,
911                                 NULL, NULL, NULL, NULL, NULL, NULL);
912           if (rc)
913             return unlock_pinentry (rc);
914           errtext = NULL;
915         }
916
917       if (pininfo->with_repeat)
918         {
919           snprintf (line, DIM(line)-1, "SETREPEAT %s", _("Repeat:"));
920           line[DIM(line)-1] = 0;
921           rc = assuan_transact (entry_ctx, line,
922                                 NULL, NULL, NULL, NULL, NULL, NULL);
923           if (rc)
924             return unlock_pinentry (rc);
925         }
926
927       saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
928       assuan_begin_confidential (entry_ctx);
929       pinentry_status = 0;
930       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
931                             inq_quality, entry_ctx,
932                             pinentry_status_cb, &pinentry_status);
933       assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
934       /* Most pinentries out in the wild return the old Assuan error code
935          for canceled which gets translated to an assuan Cancel error and
936          not to the code for a user cancel.  Fix this here. */
937       if (rc && gpg_err_source (rc)
938           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
939         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
940
941
942       /* Change error code in case the window close button was clicked
943          to cancel the operation.  */
944       if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
945           && gpg_err_code (rc) == GPG_ERR_CANCELED)
946         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
947
948       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
949         errtext = is_pin? _("PIN too long")
950                         : _("Passphrase too long");
951       else if (rc)
952         return unlock_pinentry (rc);
953
954       if (!errtext && pininfo->min_digits)
955         {
956           /* do some basic checks on the entered PIN. */
957           if (!all_digitsp (pininfo->pin))
958             errtext = _("Invalid characters in PIN");
959           else if (pininfo->max_digits
960                    && strlen (pininfo->pin) > pininfo->max_digits)
961             errtext = _("PIN too long");
962           else if (strlen (pininfo->pin) < pininfo->min_digits)
963             errtext = _("PIN too short");
964         }
965
966       if (!errtext && pininfo->check_cb)
967         {
968           /* More checks by utilizing the optional callback. */
969           pininfo->cb_errtext = NULL;
970           rc = pininfo->check_cb (pininfo);
971           if (rc == -1 && pininfo->cb_errtext)
972             errtext = pininfo->cb_errtext;
973           else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
974                    || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
975             errtext = (is_pin? _("Bad PIN")
976                        : _("Bad Passphrase"));
977           else if (rc)
978             return unlock_pinentry (rc);
979         }
980
981       if (!errtext)
982         {
983           if (pininfo->with_repeat
984               && (pinentry_status & PINENTRY_STATUS_PIN_REPEATED))
985             pininfo->repeat_okay = 1;
986           return unlock_pinentry (0); /* okay, got a PIN or passphrase */
987         }
988
989       if ((pinentry_status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
990         /* The password was read from the cache.  Don't count this
991            against the retry count.  */
992         pininfo->failed_tries --;
993     }
994
995   return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
996                           : GPG_ERR_BAD_PASSPHRASE));
997 }
998
999
1000 \f
1001 /* Ask for the passphrase using the supplied arguments.  The returned
1002    passphrase needs to be freed by the caller. */
1003 int
1004 agent_get_passphrase (ctrl_t ctrl,
1005                       char **retpass, const char *desc, const char *prompt,
1006                       const char *errtext, int with_qualitybar)
1007 {
1008
1009   int rc;
1010   char line[ASSUAN_LINELENGTH];
1011   struct entry_parm_s parm;
1012   int saveflag;
1013   unsigned int pinentry_status;
1014
1015   *retpass = NULL;
1016   if (opt.batch)
1017     return gpg_error (GPG_ERR_BAD_PASSPHRASE);
1018
1019   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1020     {
1021       if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
1022         return gpg_error (GPG_ERR_CANCELED);
1023
1024       if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
1025         {
1026           size_t size;
1027           size_t len = ASSUAN_LINELENGTH/2;
1028           unsigned char *buffer = gcry_malloc_secure (len);
1029
1030           rc = pinentry_loopback(ctrl, "PASSPHRASE", &buffer, &size, len);
1031           if (rc)
1032             xfree(buffer);
1033           else
1034             {
1035               buffer[size] = 0;
1036               *retpass = buffer;
1037             }
1038           return rc;
1039         }
1040       return gpg_error (GPG_ERR_NO_PIN_ENTRY);
1041     }
1042
1043   rc = start_pinentry (ctrl);
1044   if (rc)
1045     return rc;
1046
1047   if (!prompt)
1048     prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
1049
1050
1051   if (desc)
1052     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
1053   else
1054     snprintf (line, DIM(line)-1, "RESET");
1055   line[DIM(line)-1] = 0;
1056   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1057   if (rc)
1058     return unlock_pinentry (rc);
1059
1060   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
1061   line[DIM(line)-1] = 0;
1062   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1063   if (rc)
1064     return unlock_pinentry (rc);
1065
1066   if (with_qualitybar && opt.min_passphrase_len)
1067     {
1068       rc = setup_qualitybar ();
1069       if (rc)
1070         return unlock_pinentry (rc);
1071     }
1072
1073   if (errtext)
1074     {
1075       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
1076       line[DIM(line)-1] = 0;
1077       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1078       if (rc)
1079         return unlock_pinentry (rc);
1080     }
1081
1082   memset (&parm, 0, sizeof parm);
1083   parm.size = ASSUAN_LINELENGTH/2 - 5;
1084   parm.buffer = gcry_malloc_secure (parm.size+10);
1085   if (!parm.buffer)
1086     return unlock_pinentry (out_of_core ());
1087
1088   saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
1089   assuan_begin_confidential (entry_ctx);
1090   pinentry_status = 0;
1091   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
1092                         inq_quality, entry_ctx,
1093                         pinentry_status_cb, &pinentry_status);
1094   assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
1095   /* Most pinentries out in the wild return the old Assuan error code
1096      for canceled which gets translated to an assuan Cancel error and
1097      not to the code for a user cancel.  Fix this here. */
1098   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1099     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1100   /* Change error code in case the window close button was clicked
1101      to cancel the operation.  */
1102   if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
1103       && gpg_err_code (rc) == GPG_ERR_CANCELED)
1104     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
1105
1106   if (rc)
1107     xfree (parm.buffer);
1108   else
1109     *retpass = parm.buffer;
1110   return unlock_pinentry (rc);
1111 }
1112
1113
1114 \f
1115 /* Pop up the PIN-entry, display the text and the prompt and ask the
1116    user to confirm this.  We return 0 for success, ie. the user
1117    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
1118    other error.  If WITH_CANCEL it true an extra cancel button is
1119    displayed to allow the user to easily return a GPG_ERR_CANCELED.
1120    if the Pinentry does not support this, the user can still cancel by
1121    closing the Pinentry window.  */
1122 int
1123 agent_get_confirmation (ctrl_t ctrl,
1124                         const char *desc, const char *ok,
1125                         const char *notok, int with_cancel)
1126 {
1127   int rc;
1128   char line[ASSUAN_LINELENGTH];
1129
1130   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1131     {
1132       if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
1133         return gpg_error (GPG_ERR_CANCELED);
1134
1135       return gpg_error (GPG_ERR_NO_PIN_ENTRY);
1136     }
1137
1138   rc = start_pinentry (ctrl);
1139   if (rc)
1140     return rc;
1141
1142   if (desc)
1143     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
1144   else
1145     snprintf (line, DIM(line)-1, "RESET");
1146   line[DIM(line)-1] = 0;
1147   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1148   /* Most pinentries out in the wild return the old Assuan error code
1149      for canceled which gets translated to an assuan Cancel error and
1150      not to the code for a user cancel.  Fix this here. */
1151   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1152     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1153
1154   if (rc)
1155     return unlock_pinentry (rc);
1156
1157   if (ok)
1158     {
1159       snprintf (line, DIM(line)-1, "SETOK %s", ok);
1160       line[DIM(line)-1] = 0;
1161       rc = assuan_transact (entry_ctx,
1162                             line, NULL, NULL, NULL, NULL, NULL, NULL);
1163       if (rc)
1164         return unlock_pinentry (rc);
1165     }
1166   if (notok)
1167     {
1168       /* Try to use the newer NOTOK feature if a cancel button is
1169          requested.  If no cancel button is requested we keep on using
1170          the standard cancel.  */
1171       if (with_cancel)
1172         {
1173           snprintf (line, DIM(line)-1, "SETNOTOK %s", notok);
1174           line[DIM(line)-1] = 0;
1175           rc = assuan_transact (entry_ctx,
1176                                 line, NULL, NULL, NULL, NULL, NULL, NULL);
1177         }
1178       else
1179         rc = GPG_ERR_ASS_UNKNOWN_CMD;
1180
1181       if (gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
1182         {
1183           snprintf (line, DIM(line)-1, "SETCANCEL %s", notok);
1184           line[DIM(line)-1] = 0;
1185           rc = assuan_transact (entry_ctx, line,
1186                                 NULL, NULL, NULL, NULL, NULL, NULL);
1187         }
1188       if (rc)
1189         return unlock_pinentry (rc);
1190     }
1191
1192   rc = assuan_transact (entry_ctx, "CONFIRM",
1193                         NULL, NULL, NULL, NULL, NULL, NULL);
1194   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1195     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1196
1197   return unlock_pinentry (rc);
1198 }
1199
1200
1201 \f
1202 /* Pop up the PINentry, display the text DESC and a button with the
1203    text OK_BTN (which may be NULL to use the default of "OK") and wait
1204    for the user to hit this button.  The return value is not
1205    relevant.  */
1206 int
1207 agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
1208 {
1209   int rc;
1210   char line[ASSUAN_LINELENGTH];
1211
1212   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1213     return gpg_error (GPG_ERR_CANCELED);
1214
1215   rc = start_pinentry (ctrl);
1216   if (rc)
1217     return rc;
1218
1219   if (desc)
1220     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
1221   else
1222     snprintf (line, DIM(line)-1, "RESET");
1223   line[DIM(line)-1] = 0;
1224   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1225   /* Most pinentries out in the wild return the old Assuan error code
1226      for canceled which gets translated to an assuan Cancel error and
1227      not to the code for a user cancel.  Fix this here. */
1228   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1229     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1230
1231   if (rc)
1232     return unlock_pinentry (rc);
1233
1234   if (ok_btn)
1235     {
1236       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
1237       line[DIM(line)-1] = 0;
1238       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
1239                             NULL, NULL, NULL);
1240       if (rc)
1241         return unlock_pinentry (rc);
1242     }
1243
1244   rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
1245                         NULL, NULL, NULL);
1246   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1247     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1248
1249   return unlock_pinentry (rc);
1250 }
1251
1252
1253 /* The thread running the popup message. */
1254 static void *
1255 popup_message_thread (void *arg)
1256 {
1257   (void)arg;
1258
1259   /* We use the --one-button hack instead of the MESSAGE command to
1260      allow the use of old Pinentries.  Those old Pinentries will then
1261      show an additional Cancel button but that is mostly a visual
1262      annoyance. */
1263   assuan_transact (entry_ctx, "CONFIRM --one-button",
1264                    NULL, NULL, NULL, NULL, NULL, NULL);
1265   popup_finished = 1;
1266   return NULL;
1267 }
1268
1269
1270 /* Pop up a message window similar to the confirm one but keep it open
1271    until agent_popup_message_stop has been called.  It is crucial for
1272    the caller to make sure that the stop function gets called as soon
1273    as the message is not anymore required because the message is
1274    system modal and all other attempts to use the pinentry will fail
1275    (after a timeout). */
1276 int
1277 agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
1278 {
1279   int rc;
1280   char line[ASSUAN_LINELENGTH];
1281   npth_attr_t tattr;
1282   int err;
1283
1284   if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1285     return gpg_error (GPG_ERR_CANCELED);
1286
1287   rc = start_pinentry (ctrl);
1288   if (rc)
1289     return rc;
1290
1291   if (desc)
1292     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
1293   else
1294     snprintf (line, DIM(line)-1, "RESET");
1295   line[DIM(line)-1] = 0;
1296   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1297   if (rc)
1298     return unlock_pinentry (rc);
1299
1300   if (ok_btn)
1301     {
1302       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
1303       line[DIM(line)-1] = 0;
1304       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
1305       if (rc)
1306         return unlock_pinentry (rc);
1307     }
1308
1309   err = npth_attr_init (&tattr);
1310   if (err)
1311     return unlock_pinentry (gpg_error_from_errno (err));
1312   npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
1313
1314   popup_finished = 0;
1315   err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL);
1316   npth_attr_destroy (&tattr);
1317   if (err)
1318     {
1319       rc = gpg_error_from_errno (err);
1320       log_error ("error spawning popup message handler: %s\n",
1321                  strerror (err) );
1322       return unlock_pinentry (rc);
1323     }
1324   npth_setname_np (popup_tid, "popup-message");
1325
1326   return 0;
1327 }
1328
1329 /* Close a popup window. */
1330 void
1331 agent_popup_message_stop (ctrl_t ctrl)
1332 {
1333   int rc;
1334   pid_t pid;
1335
1336   (void)ctrl;
1337
1338   if (!popup_tid || !entry_ctx)
1339     {
1340       log_debug ("agent_popup_message_stop called with no active popup\n");
1341       return;
1342     }
1343
1344   pid = assuan_get_pid (entry_ctx);
1345   if (pid == (pid_t)(-1))
1346     ; /* No pid available can't send a kill. */
1347   else if (popup_finished)
1348     ; /* Already finished and ready for joining. */
1349 #ifdef HAVE_W32_SYSTEM
1350   /* Older versions of assuan set PID to 0 on Windows to indicate an
1351      invalid value.  */
1352   else if (pid != (pid_t) INVALID_HANDLE_VALUE
1353            && pid != 0)
1354     {
1355       HANDLE process = (HANDLE) pid;
1356
1357       /* Arbitrary error code.  */
1358       TerminateProcess (process, 1);
1359     }
1360 #else
1361   else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
1362     { /* The daemon already died.  No need to send a kill.  However
1363          because we already waited for the process, we need to tell
1364          assuan that it should not wait again (done by
1365          unlock_pinentry). */
1366       if (rc == pid)
1367         assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
1368     }
1369   else if (pid > 0)
1370     kill (pid, SIGINT);
1371 #endif
1372
1373   /* Now wait for the thread to terminate. */
1374   rc = npth_join (popup_tid, NULL);
1375   if (rc)
1376     log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
1377                strerror (rc));
1378   /* Thread IDs are opaque, but we try our best here by resetting it
1379      to the same content that a static global variable has.  */
1380   memset (&popup_tid, '\0', sizeof (popup_tid));
1381   entry_owner = NULL;
1382
1383   /* Now we can close the connection. */
1384   unlock_pinentry (0);
1385 }