Marked all unused args on non-W32 platforms.
[gnupg.git] / agent / call-pinentry.c
1 /* call-pinentry.c - fork of the pinentry to query stuff from the user
2  * Copyright (C) 2001, 2002, 2004, 2007, 2008 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <assert.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #ifndef HAVE_W32_SYSTEM
30 # include <sys/wait.h>
31 # include <sys/types.h>
32 # include <signal.h>
33 #endif
34 #include <pth.h>
35 #include <assuan.h>
36
37 #include "agent.h"
38 #include "setenv.h"
39 #include "i18n.h"
40
41 #ifdef _POSIX_OPEN_MAX
42 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
43 #else
44 #define MAX_OPEN_FDS 20
45 #endif
46
47
48 /* Because access to the pinentry must be serialized (it is and shall
49    be a global mutual dialog) we should better timeout further
50    requests after some time.  2 minutes seem to be a reasonable
51    time. */
52 #define LOCK_TIMEOUT  (1*60)
53
54 /* The assuan context of the current pinentry. */
55 static assuan_context_t entry_ctx;
56
57 /* The control variable of the connection owning the current pinentry.
58    This is only valid if ENTRY_CTX is not NULL.  Note, that we care
59    only about the value of the pointer and that it should never be
60    dereferenced.  */
61 static ctrl_t entry_owner;
62
63 /* A mutex used to serialize access to the pinentry. */
64 static pth_mutex_t entry_lock;
65
66 /* The thread ID of the popup working thread. */
67 static pth_t  popup_tid;
68
69 /* A flag used in communication between the popup working thread and
70    its stop function. */
71 static int popup_finished;
72
73
74
75 /* Data to be passed to our callbacks, */
76 struct entry_parm_s
77 {
78   int lines;
79   size_t size;
80   unsigned char *buffer;
81 };
82
83
84
85 \f
86 /* This function must be called once to initialize this module.  This
87    has to be done before a second thread is spawned.  We can't do the
88    static initialization because Pth emulation code might not be able
89    to do a static init; in particular, it is not possible for W32. */
90 void
91 initialize_module_call_pinentry (void)
92 {
93   static int initialized;
94
95   if (!initialized)
96     {
97       if (pth_mutex_init (&entry_lock))
98         initialized = 1;
99     }
100 }
101
102
103
104 static void
105 dump_mutex_state (pth_mutex_t *m)
106 {
107 #ifdef _W32_PTH_H
108   log_printf ("unknown under W32");
109 #else
110   if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
111     log_printf ("not_initialized");
112   else if (!(m->mx_state & PTH_MUTEX_LOCKED))
113     log_printf ("not_locked");
114   else
115     log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
116 #endif
117 }
118
119
120 /* This function may be called to print infromation pertaining to the
121    current state of this module to the log. */
122 void
123 agent_query_dump_state (void)
124 {
125   log_info ("agent_query_dump_state: entry_lock=");
126   dump_mutex_state (&entry_lock);
127   log_printf ("\n");
128   log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
129             entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid);
130 }
131
132 /* Called to make sure that a popup window owned by the current
133    connection gets closed. */
134 void
135 agent_reset_query (ctrl_t ctrl)
136 {
137   if (entry_ctx && popup_tid && entry_owner == ctrl)
138     {
139       agent_popup_message_stop (ctrl);
140     }
141 }
142
143
144 /* Unlock the pinentry so that another thread can start one and
145    disconnect that pinentry - we do this after the unlock so that a
146    stalled pinentry does not block other threads.  Fixme: We should
147    have a timeout in Assuan for the disconnect operation. */
148 static int 
149 unlock_pinentry (int rc)
150 {
151   assuan_context_t ctx = entry_ctx;
152
153   entry_ctx = NULL;
154   if (!pth_mutex_release (&entry_lock))
155     {
156       log_error ("failed to release the entry lock\n");
157       if (!rc)
158         rc = gpg_error (GPG_ERR_INTERNAL);
159     }
160   assuan_disconnect (ctx);
161   return rc;
162 }
163
164
165 /* To make sure we leave no secrets in our image after forking of the
166    pinentry, we use this callback. */
167 static void
168 atfork_cb (void *opaque, int where)
169 {
170   ctrl_t ctrl = opaque;
171
172   if (!where)
173     {
174       gcry_control (GCRYCTL_TERM_SECMEM);
175       if (ctrl->xauthority)
176         setenv ("XAUTHORITY", ctrl->xauthority, 1);
177       if (ctrl->pinentry_user_data)
178         setenv ("PINENTRY_USER_DATA", ctrl->pinentry_user_data, 1 );
179     }
180 }
181
182 static int
183 getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
184 {
185   unsigned long *pid = opaque;
186   char pidbuf[50];
187
188   /* There is only the pid in the server's response.  */
189   if (length >= sizeof pidbuf)
190     length = sizeof pidbuf -1;
191   if (length)
192     {
193       strncpy (pidbuf, buffer, length);
194       pidbuf[length] = 0;
195       *pid = strtoul (pidbuf, NULL, 10);
196     }
197   return 0;
198 }
199
200 /* Fork off the pin entry if this has not already been done.  Note,
201    that this function must always be used to aquire the lock for the
202    pinentry - we will serialize _all_ pinentry calls.
203  */
204 static int
205 start_pinentry (ctrl_t ctrl)
206 {
207   int rc;
208   const char *pgmname;
209   assuan_context_t ctx;
210   const char *argv[5];
211   int no_close_list[3];
212   int i;
213   pth_event_t evt;
214   const char *tmpstr;
215   unsigned long pinentry_pid;
216
217   evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
218   if (!pth_mutex_acquire (&entry_lock, 0, evt))
219     {
220       if (pth_event_occurred (evt))
221         rc = gpg_error (GPG_ERR_TIMEOUT);
222       else
223         rc = gpg_error (GPG_ERR_INTERNAL);
224       pth_event_free (evt, PTH_FREE_THIS);
225       log_error (_("failed to acquire the pinentry lock: %s\n"),
226                  gpg_strerror (rc));
227       return rc;
228     }
229   pth_event_free (evt, PTH_FREE_THIS);
230
231   entry_owner = ctrl;
232
233   if (entry_ctx)
234     return 0; 
235
236   if (opt.verbose)
237     log_info ("starting a new PIN Entry\n");
238
239 #ifdef HAVE_W32_SYSTEM      
240   fflush (stdout);
241   fflush (stderr);
242 #endif
243   if (fflush (NULL))
244     {
245 #ifndef HAVE_W32_SYSTEM
246       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
247 #endif
248       log_error ("error flushing pending output: %s\n", strerror (errno));
249       /* At least Windows XP fails here with EBADF.  According to docs
250          and Wine an fflush(NULL) is the same as _flushall.  However
251          the Wime implementaion does not flush stdin,stdout and stderr
252          - see above.  Lets try to ignore the error. */
253 #ifndef HAVE_W32_SYSTEM
254       return unlock_pinentry (tmperr);
255 #endif
256     }
257
258   if (!opt.pinentry_program || !*opt.pinentry_program)
259     opt.pinentry_program = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
260     pgmname = opt.pinentry_program;
261   if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
262     pgmname = opt.pinentry_program;
263   else
264     pgmname++;
265
266   /* OS X needs the entire file name in argv[0], so that it can locate
267      the resource bundle.  For other systems we stick to the usual
268      convention of supplying only the name of the program.  */
269 #ifdef __APPLE__
270   argv[0] = opt.pinentry_program;
271 #else /*!__APPLE__*/
272   argv[0] = pgmname;
273 #endif /*__APPLE__*/
274
275   if (ctrl->display && !opt.keep_display)
276     {
277       argv[1] = "--display";
278       argv[2] = ctrl->display;
279       argv[3] = NULL;
280     }
281   else
282     argv[1] = NULL;
283   
284   i=0;
285   if (!opt.running_detached)
286     {
287       if (log_get_fd () != -1)
288         no_close_list[i++] = log_get_fd ();
289       no_close_list[i++] = fileno (stderr);
290     }
291   no_close_list[i] = -1;
292
293   /* Connect to the pinentry and perform initial handshaking.  Note
294      that atfork is used to change the environment for pinentry.  We
295      start the server in detached mode to suppress the console window
296      under Windows.  */
297   rc = assuan_pipe_connect_ext (&ctx, opt.pinentry_program, argv,
298                                 no_close_list, atfork_cb, ctrl, 128);
299   if (rc)
300     {
301       log_error ("can't connect to the PIN entry module: %s\n",
302                  gpg_strerror (rc));
303       return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
304     }
305   entry_ctx = ctx;
306
307   if (DBG_ASSUAN)
308     log_debug ("connection to PIN entry established\n");
309
310   rc = assuan_transact (entry_ctx, 
311                         opt.no_grab? "OPTION no-grab":"OPTION grab",
312                         NULL, NULL, NULL, NULL, NULL, NULL);
313   if (rc)
314     return unlock_pinentry (rc);
315   if (ctrl->ttyname)
316     {
317       char *optstr;
318       if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
319         return unlock_pinentry (out_of_core ());
320       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
321                             NULL);
322       xfree (optstr);
323       if (rc)
324         return unlock_pinentry (rc);
325     }
326   if (ctrl->ttytype)
327     {
328       char *optstr;
329       if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
330         return unlock_pinentry (out_of_core ());
331       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
332                             NULL);
333       if (rc)
334         return unlock_pinentry (rc);
335     }
336   if (ctrl->lc_ctype)
337     {
338       char *optstr;
339       if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
340         return unlock_pinentry (out_of_core ());
341       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
342                             NULL);
343       if (rc)
344         return unlock_pinentry (rc);
345     }
346   if (ctrl->lc_messages)
347     {
348       char *optstr;
349       if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
350         return unlock_pinentry (out_of_core ());
351       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
352                             NULL);
353       if (rc)
354         return unlock_pinentry (rc);
355     }
356
357   
358   /* Tell the pinentry the name of a file it shall touch after having
359      messed with the tty.  This is optional and only supported by
360      newer pinentries and thus we do no error checking. */
361   tmpstr = opt.pinentry_touch_file;
362   if (tmpstr && !strcmp (tmpstr, "/dev/null"))
363     tmpstr = NULL;
364   else if (!tmpstr)
365     tmpstr = get_agent_socket_name ();
366   if (tmpstr)
367     {
368       char *optstr;
369       
370       if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
371         ;
372       else
373         {
374           assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
375                            NULL);
376           xfree (optstr);
377         }
378     }
379
380
381   /* Now ask the Pinentry for its PID.  If the Pinentry is new enough
382      it will send the pid back and we will use an inquire to notify
383      our client.  The client may answer the inquiry either with END or
384      with CAN to cancel the pinentry. */
385   rc = assuan_transact (entry_ctx, "GETINFO pid", 
386                         getinfo_pid_cb, &pinentry_pid,
387                         NULL, NULL, NULL, NULL);
388   if (rc)
389     {
390       log_info ("You may want to update to a newer pinentry\n");
391       rc = 0;
392     }
393   else if (!rc && (pid_t)pinentry_pid == (pid_t)(-1))
394     log_error ("pinentry did not return a PID\n");
395   else
396     {
397       rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
398       if (gpg_err_code (rc) == GPG_ERR_CANCELED)
399         return unlock_pinentry (gpg_error (GPG_ERR_CANCELED));
400       rc = 0;
401     }
402
403   return 0;
404 }
405
406
407 /* Returns True is the pinentry is currently active. If WAITSECONDS is
408    greater than zero the function will wait for this many seconds
409    before returning.  */
410 int
411 pinentry_active_p (ctrl_t ctrl, int waitseconds)
412 {
413   (void)ctrl;
414
415   if (waitseconds > 0)
416     {
417       pth_event_t evt;
418       int rc;
419
420       evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0));
421       if (!pth_mutex_acquire (&entry_lock, 0, evt))
422         {
423           if (pth_event_occurred (evt))
424             rc = gpg_error (GPG_ERR_TIMEOUT);
425           else
426             rc = gpg_error (GPG_ERR_INTERNAL);
427           pth_event_free (evt, PTH_FREE_THIS);
428           return rc;
429         }
430       pth_event_free (evt, PTH_FREE_THIS);
431     }
432   else
433     {
434       if (!pth_mutex_acquire (&entry_lock, 1, NULL))
435         return gpg_error (GPG_ERR_LOCKED);
436     }
437
438   if (!pth_mutex_release (&entry_lock))
439     log_error ("failed to release the entry lock at %d\n", __LINE__);
440   return 0;
441 }
442
443
444 static int
445 getpin_cb (void *opaque, const void *buffer, size_t length)
446 {
447   struct entry_parm_s *parm = opaque;
448
449   if (!buffer)
450     return 0;
451
452   /* we expect the pin to fit on one line */
453   if (parm->lines || length >= parm->size)
454     return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
455
456   /* fixme: we should make sure that the assuan buffer is allocated in
457      secure memory or read the response byte by byte */
458   memcpy (parm->buffer, buffer, length);
459   parm->buffer[length] = 0;
460   parm->lines++;
461   return 0;
462 }
463
464
465 static int
466 all_digitsp( const char *s)
467 {
468   for (; *s && *s >= '0' && *s <= '9'; s++)
469     ;
470   return !*s;
471 }  
472
473
474 /* Return a new malloced string by unescaping the string S.  Escaping
475    is percent escaping and '+'/space mapping.  A binary Nul will
476    silently be replaced by a 0xFF.  Function returns NULL to indicate
477    an out of memory status.  PArsing stops at the end of the string or
478    a white space character. */
479 static char *
480 unescape_passphrase_string (const unsigned char *s)
481 {
482   char *buffer, *d;
483
484   buffer = d = xtrymalloc_secure (strlen ((const char*)s)+1);
485   if (!buffer)
486     return NULL;
487   while (*s && !spacep (s))
488     {
489       if (*s == '%' && s[1] && s[2])
490         { 
491           s++;
492           *d = xtoi_2 (s);
493           if (!*d)
494             *d = '\xff';
495           d++;
496           s += 2;
497         }
498       else if (*s == '+')
499         {
500           *d++ = ' ';
501           s++;
502         }
503       else
504         *d++ = *s++;
505     }
506   *d = 0; 
507   return buffer;
508 }
509
510
511 /* Estimate the quality of the passphrase PW and return a value in the
512    range 0..100.  */
513 static int
514 estimate_passphrase_quality (const char *pw)
515 {
516   int goodlength = opt.min_passphrase_len + opt.min_passphrase_len/3;
517   int length;
518   const char *s;
519
520   if (goodlength < 1)
521     return 0;
522
523   for (length = 0, s = pw; *s; s++)
524     if (!spacep (s))
525       length ++;
526
527   if (length > goodlength)
528     return 100;
529   return ((length*10) / goodlength)*10;
530 }
531
532
533 /* Handle the QUALITY inquiry. */
534 static int
535 inq_quality (void *opaque, const char *line)
536 {
537   assuan_context_t ctx = opaque;
538   char *pin;
539   int rc;
540   int percent;
541   char numbuf[20];
542
543   if (!strncmp (line, "QUALITY", 7) && (line[7] == ' ' || !line[7]))
544     {
545       line += 7;
546       while (*line == ' ')
547         line++;
548       
549       pin = unescape_passphrase_string (line);
550       if (!pin)
551         rc = gpg_error_from_syserror ();
552       else
553         {
554           percent = estimate_passphrase_quality (pin);
555           if (check_passphrase_constraints (NULL, pin, 1))
556             percent = -percent;
557           snprintf (numbuf, sizeof numbuf, "%d", percent);
558           rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
559           xfree (pin);
560         }
561     }
562   else
563     {
564       log_error ("unsupported inquiry `%s' from pinentry\n", line);
565       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
566     }
567
568   return rc;
569 }
570
571
572
573
574 \f
575 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
576    number here and repeat it as long as we have invalid formed
577    numbers. */
578 int
579 agent_askpin (ctrl_t ctrl,
580               const char *desc_text, const char *prompt_text,
581               const char *initial_errtext,
582               struct pin_entry_info_s *pininfo)
583 {
584   int rc;
585   char line[ASSUAN_LINELENGTH];
586   struct entry_parm_s parm;
587   const char *errtext = NULL;
588   int is_pin = 0;
589
590   if (opt.batch)
591     return 0; /* fixme: we should return BAD PIN */
592
593   if (!pininfo || pininfo->max_length < 1)
594     return gpg_error (GPG_ERR_INV_VALUE);
595   if (!desc_text && pininfo->min_digits)
596     desc_text = _("Please enter your PIN, so that the secret key "
597                   "can be unlocked for this session");
598   else if (!desc_text)
599     desc_text = _("Please enter your passphrase, so that the secret key "
600                   "can be unlocked for this session");
601
602   if (prompt_text)
603     is_pin = !!strstr (prompt_text, "PIN");
604   else
605     is_pin = desc_text && strstr (desc_text, "PIN");
606
607   rc = start_pinentry (ctrl);
608   if (rc)
609     return rc;
610
611   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
612   line[DIM(line)-1] = 0;
613   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
614   if (rc)
615     return unlock_pinentry (rc);
616
617   snprintf (line, DIM(line)-1, "SETPROMPT %s",
618             prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
619   line[DIM(line)-1] = 0;
620   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
621   if (rc)
622     return unlock_pinentry (rc);
623
624   /* If a passphrase quality indicator has been requested and a
625      minimum passphrase length has not been disabled, send the command
626      to the pinentry.  */
627   if (pininfo->with_qualitybar && opt.min_passphrase_len )
628     {
629       char *tmpstr, *tmpstr2;
630       const char *tooltip;
631
632       /* TRANSLATORS: This string is displayed by pinentry as the
633          label for the quality bar.  */
634       tmpstr = try_percent_escape (_("Quality:"), "\t\r\n\f\v");
635       snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
636       line[DIM(line)-1] = 0;
637       xfree (tmpstr);
638       rc = assuan_transact (entry_ctx, line,
639                             NULL, NULL, NULL, NULL, NULL, NULL);
640       if (rc == 103 /*(Old assuan error code)*/
641           || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
642         ; /* Ignore Unknown Command from old pinentry versions.  */
643       else if (rc)
644         return unlock_pinentry (rc);
645
646       tmpstr2 = gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
647       if (tmpstr2)
648         tooltip = tmpstr2;
649       else
650         {
651           /* TRANSLATORS: This string is a tooltip, shown by pinentry
652              when hovering over the quality bar.  Please use an
653              appropriate string to describe what this is about.  The
654              length of the tooltip is limited to about 900 characters.
655              If you do not translate this entry, a default english
656              text (see source) will be used. */
657           tooltip =  _("pinentry.qualitybar.tooltip");
658           if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
659             tooltip = ("The quality of the text entered above.\n"
660                        "Please ask your administrator for "
661                        "details about the criteria.");
662         }
663       tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
664       xfree (tmpstr2);
665       snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
666       line[DIM(line)-1] = 0;
667       xfree (tmpstr);
668       rc = assuan_transact (entry_ctx, line,
669                             NULL, NULL, NULL, NULL, NULL, NULL);
670       if (rc == 103 /*(Old assuan error code)*/
671           || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
672         ; /* Ignore Unknown Command from old pinentry versions.  */
673       else if (rc)
674         return unlock_pinentry (rc);
675     }
676
677   if (initial_errtext)
678     { 
679       snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
680       line[DIM(line)-1] = 0;
681       rc = assuan_transact (entry_ctx, line,
682                             NULL, NULL, NULL, NULL, NULL, NULL);
683       if (rc)
684         return unlock_pinentry (rc);
685     }
686
687   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
688     {
689       memset (&parm, 0, sizeof parm);
690       parm.size = pininfo->max_length;
691       *pininfo->pin = 0; /* Reset the PIN. */
692       parm.buffer = (unsigned char*)pininfo->pin;
693
694       if (errtext)
695         { 
696           /* TRANLATORS: The string is appended to an error message in
697              the pinentry.  The %s is the actual error message, the
698              two %d give the current and maximum number of tries. */
699           snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
700                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
701           line[DIM(line)-1] = 0;
702           rc = assuan_transact (entry_ctx, line,
703                                 NULL, NULL, NULL, NULL, NULL, NULL);
704           if (rc)
705             return unlock_pinentry (rc);
706           errtext = NULL;
707         }
708       
709       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
710                             inq_quality, entry_ctx, NULL, NULL);
711       /* Most pinentries out in the wild return the old Assuan error code
712          for canceled which gets translated to an assuan Cancel error and
713          not to the code for a user cancel.  Fix this here. */
714       if (rc && gpg_err_source (rc)
715           && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
716         rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
717
718       if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
719         errtext = is_pin? _("PIN too long")
720                         : _("Passphrase too long");
721       else if (rc)
722         return unlock_pinentry (rc);
723
724       if (!errtext && pininfo->min_digits)
725         {
726           /* do some basic checks on the entered PIN. */
727           if (!all_digitsp (pininfo->pin))
728             errtext = _("Invalid characters in PIN");
729           else if (pininfo->max_digits
730                    && strlen (pininfo->pin) > pininfo->max_digits)
731             errtext = _("PIN too long");
732           else if (strlen (pininfo->pin) < pininfo->min_digits)
733             errtext = _("PIN too short");
734         }
735
736       if (!errtext && pininfo->check_cb)
737         {
738           /* More checks by utilizing the optional callback. */
739           pininfo->cb_errtext = NULL;
740           rc = pininfo->check_cb (pininfo);
741           if (rc == -1 && pininfo->cb_errtext)
742             errtext = pininfo->cb_errtext;
743           else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
744                    || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
745             errtext = (is_pin? _("Bad PIN")
746                        : _("Bad Passphrase"));
747           else if (rc)
748             return unlock_pinentry (rc);
749         }
750
751       if (!errtext)
752         return unlock_pinentry (0); /* okay, got a PIN or passphrase */
753     }
754
755   return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
756                           : GPG_ERR_BAD_PASSPHRASE));
757 }
758
759
760 \f
761 /* Ask for the passphrase using the supplied arguments.  The returned
762    passphrase needs to be freed by the caller. */
763 int 
764 agent_get_passphrase (ctrl_t ctrl,
765                       char **retpass, const char *desc, const char *prompt,
766                       const char *errtext)
767 {
768
769   int rc;
770   char line[ASSUAN_LINELENGTH];
771   struct entry_parm_s parm;
772
773   *retpass = NULL;
774   if (opt.batch)
775     return gpg_error (GPG_ERR_BAD_PASSPHRASE); 
776
777   rc = start_pinentry (ctrl);
778   if (rc)
779     return rc;
780
781   if (!prompt)
782     prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
783
784
785   if (desc)
786     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
787   else
788     snprintf (line, DIM(line)-1, "RESET");
789   line[DIM(line)-1] = 0;
790   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
791   if (rc)
792     return unlock_pinentry (rc);
793
794   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
795   line[DIM(line)-1] = 0;
796   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
797   if (rc)
798     return unlock_pinentry (rc);
799
800   if (errtext)
801     {
802       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
803       line[DIM(line)-1] = 0;
804       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
805       if (rc)
806         return unlock_pinentry (rc);
807     }
808
809   memset (&parm, 0, sizeof parm);
810   parm.size = ASSUAN_LINELENGTH/2 - 5;
811   parm.buffer = gcry_malloc_secure (parm.size+10);
812   if (!parm.buffer)
813     return unlock_pinentry (out_of_core ());
814
815   assuan_begin_confidential (entry_ctx);
816   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
817                         NULL, NULL, NULL, NULL);
818   /* Most pinentries out in the wild return the old Assuan error code
819      for canceled which gets translated to an assuan Cancel error and
820      not to the code for a user cancel.  Fix this here. */
821   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
822     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
823   if (rc)
824     xfree (parm.buffer);
825   else
826     *retpass = parm.buffer;
827   return unlock_pinentry (rc);
828 }
829
830
831 \f
832 /* Pop up the PIN-entry, display the text and the prompt and ask the
833    user to confirm this.  We return 0 for success, ie. the user
834    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
835    other error. */
836 int 
837 agent_get_confirmation (ctrl_t ctrl,
838                         const char *desc, const char *ok, const char *cancel)
839 {
840   int rc;
841   char line[ASSUAN_LINELENGTH];
842
843   rc = start_pinentry (ctrl);
844   if (rc)
845     return rc;
846
847   if (desc)
848     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
849   else
850     snprintf (line, DIM(line)-1, "RESET");
851   line[DIM(line)-1] = 0;
852   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
853   /* Most pinentries out in the wild return the old Assuan error code
854      for canceled which gets translated to an assuan Cancel error and
855      not to the code for a user cancel.  Fix this here. */
856   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
857     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
858
859   if (rc)
860     return unlock_pinentry (rc);
861
862   if (ok)
863     {
864       snprintf (line, DIM(line)-1, "SETOK %s", ok);
865       line[DIM(line)-1] = 0;
866       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
867       if (rc)
868         return unlock_pinentry (rc);
869     }
870   if (cancel)
871     {
872       snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
873       line[DIM(line)-1] = 0;
874       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
875       if (rc)
876         return unlock_pinentry (rc);
877     }
878
879   rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
880   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
881     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
882
883   return unlock_pinentry (rc);
884 }
885
886
887 \f
888 /* Pop up the PINentry, display the text DESC and a button with the
889    text OK_BTN (which may be NULL to use the default of "OK") and waut
890    for the user to hit this button.  The return value is not
891    relevant.  */
892 int 
893 agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
894 {
895   int rc;
896   char line[ASSUAN_LINELENGTH];
897
898   rc = start_pinentry (ctrl);
899   if (rc)
900     return rc;
901
902   if (desc)
903     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
904   else
905     snprintf (line, DIM(line)-1, "RESET");
906   line[DIM(line)-1] = 0;
907   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
908   /* Most pinentries out in the wild return the old Assuan error code
909      for canceled which gets translated to an assuan Cancel error and
910      not to the code for a user cancel.  Fix this here. */
911   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
912     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
913
914   if (rc)
915     return unlock_pinentry (rc);
916
917   if (ok_btn)
918     {
919       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
920       line[DIM(line)-1] = 0;
921       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
922                             NULL, NULL, NULL);
923       if (rc)
924         return unlock_pinentry (rc);
925     }
926   
927   rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
928                         NULL, NULL, NULL);
929   if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
930     rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
931
932   return unlock_pinentry (rc);
933 }
934
935
936 /* The thread running the popup message. */
937 static void *
938 popup_message_thread (void *arg)
939 {
940   (void)arg;
941
942   /* We use the --one-button hack instead of the MESSAGE command to
943      allow the use of old Pinentries.  Those old Pinentries will then
944      show an additional Cancel button but that is mostly a visual
945      annoyance. */
946   assuan_transact (entry_ctx, "CONFIRM --one-button", 
947                    NULL, NULL, NULL, NULL, NULL, NULL);
948   popup_finished = 1;
949   return NULL;
950 }
951
952
953 /* Pop up a message window similar to the confirm one but keep it open
954    until agent_popup_message_stop has been called.  It is crucial for
955    the caller to make sure that the stop function gets called as soon
956    as the message is not anymore required because the message is
957    system modal and all other attempts to use the pinentry will fail
958    (after a timeout). */
959 int 
960 agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
961 {
962   int rc;
963   char line[ASSUAN_LINELENGTH];
964   pth_attr_t tattr;
965
966   rc = start_pinentry (ctrl);
967   if (rc)
968     return rc;
969
970   if (desc)
971     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
972   else
973     snprintf (line, DIM(line)-1, "RESET");
974   line[DIM(line)-1] = 0;
975   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
976   if (rc)
977     return unlock_pinentry (rc);
978
979   if (ok_btn)
980     {
981       snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
982       line[DIM(line)-1] = 0;
983       rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
984       if (rc)
985         return unlock_pinentry (rc);
986     }
987
988   tattr = pth_attr_new();
989   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
990   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
991   pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
992
993   popup_finished = 0;
994   popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
995   if (!popup_tid)
996     {
997       rc = gpg_error_from_syserror ();
998       log_error ("error spawning popup message handler: %s\n",
999                  strerror (errno) );
1000       pth_attr_destroy (tattr);
1001       return unlock_pinentry (rc);
1002     }
1003   pth_attr_destroy (tattr);
1004
1005   return 0;
1006 }
1007
1008 /* Close a popup window. */
1009 void
1010 agent_popup_message_stop (ctrl_t ctrl)
1011 {
1012   int rc;
1013   pid_t pid;
1014
1015   (void)ctrl;
1016
1017   if (!popup_tid || !entry_ctx)
1018     {
1019       log_debug ("agent_popup_message_stop called with no active popup\n");
1020       return; 
1021     }
1022
1023   pid = assuan_get_pid (entry_ctx);
1024   if (pid == (pid_t)(-1))
1025     ; /* No pid available can't send a kill. */
1026   else if (popup_finished)
1027     ; /* Already finished and ready for joining. */
1028 #ifdef HAVE_W32_SYSTEM
1029   /* Older versions of assuan set PID to 0 on Windows to indicate an
1030      invalid value.  */
1031   else if (pid != (pid_t) INVALID_HANDLE_VALUE
1032            && pid != 0)
1033     {
1034       HANDLE process = (HANDLE) pid;
1035       
1036       /* Arbitrary error code.  */
1037       TerminateProcess (process, 1);
1038     }
1039 #else
1040   else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
1041     { /* The daemon already died.  No need to send a kill.  However
1042          because we already waited for the process, we need to tell
1043          assuan that it should not wait again (done by
1044          unlock_pinentry). */
1045       if (rc == pid)
1046         assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
1047     }
1048   else if (pid > 0)
1049     kill (pid, SIGKILL);  /* Need to use SIGKILL due to bad
1050                              interaction of SIGINT with Pth. */
1051 #endif
1052
1053   /* Now wait for the thread to terminate. */
1054   rc = pth_join (popup_tid, NULL);
1055   if (!rc)
1056     log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
1057                strerror (errno));
1058   popup_tid = NULL;
1059   entry_owner = NULL;
1060
1061   /* Now we can close the connection. */
1062   unlock_pinentry (0);
1063 }
1064
1065