2008-01-10 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / agent / call-pinentry.c
blobc8d0ed46f4602974e65ac34d68ab28573c08ece3
1 /* call-pinentry.c - fork of the pinentry to query stuff from the user
2 * Copyright (C) 2001, 2002, 2004, 2007 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
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 #endif
32 #include <pth.h>
33 #include <assuan.h>
35 #include "agent.h"
36 #include "setenv.h"
37 #include "i18n.h"
39 #ifdef _POSIX_OPEN_MAX
40 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
41 #else
42 #define MAX_OPEN_FDS 20
43 #endif
46 /* Because access to the pinentry must be serialized (it is and shall
47 be a global mutual dialog) we should better timeout further
48 requests after some time. 2 minutes seem to be a reasonable
49 time. */
50 #define LOCK_TIMEOUT (1*60)
52 /* The assuan context of the current pinentry. */
53 static assuan_context_t entry_ctx;
55 /* The control variable of the connection owning the current pinentry.
56 This is only valid if ENTRY_CTX is not NULL. Note, that we care
57 only about the value of the pointer and that it should never be
58 dereferenced. */
59 static ctrl_t entry_owner;
61 /* A mutex used to serialize access to the pinentry. */
62 static pth_mutex_t entry_lock;
64 /* The thread ID of the popup working thread. */
65 static pth_t popup_tid;
67 /* A flag used in communication between the popup working thread and
68 its stop function. */
69 static int popup_finished;
73 /* Data to be passed to our callbacks, */
74 struct entry_parm_s
76 int lines;
77 size_t size;
78 unsigned char *buffer;
84 /* This function must be called once to initialize this module. This
85 has to be done before a second thread is spawned. We can't do the
86 static initialization because Pth emulation code might not be able
87 to do a static init; in particular, it is not possible for W32. */
88 void
89 initialize_module_call_pinentry (void)
91 static int initialized;
93 if (!initialized)
95 if (pth_mutex_init (&entry_lock))
96 initialized = 1;
102 static void
103 dump_mutex_state (pth_mutex_t *m)
105 #ifdef _W32_PTH_H
106 log_printf ("unknown under W32");
107 #else
108 if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
109 log_printf ("not_initialized");
110 else if (!(m->mx_state & PTH_MUTEX_LOCKED))
111 log_printf ("not_locked");
112 else
113 log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
114 #endif
118 /* This function may be called to print infromation pertaining to the
119 current state of this module to the log. */
120 void
121 agent_query_dump_state (void)
123 log_info ("agent_query_dump_state: entry_lock=");
124 dump_mutex_state (&entry_lock);
125 log_printf ("\n");
126 log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
127 entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid);
130 /* Called to make sure that a popup window owned by the current
131 connection gets closed. */
132 void
133 agent_reset_query (ctrl_t ctrl)
135 if (entry_ctx && popup_tid && entry_owner == ctrl)
137 agent_popup_message_stop (ctrl);
142 /* Unlock the pinentry so that another thread can start one and
143 disconnect that pinentry - we do this after the unlock so that a
144 stalled pinentry does not block other threads. Fixme: We should
145 have a timeout in Assuan for the disconnect operation. */
146 static int
147 unlock_pinentry (int rc)
149 assuan_context_t ctx = entry_ctx;
151 entry_ctx = NULL;
152 if (!pth_mutex_release (&entry_lock))
154 log_error ("failed to release the entry lock\n");
155 if (!rc)
156 rc = gpg_error (GPG_ERR_INTERNAL);
158 assuan_disconnect (ctx);
159 return rc;
163 /* To make sure we leave no secrets in our image after forking of the
164 pinentry, we use this callback. */
165 static void
166 atfork_cb (void *opaque, int where)
168 ctrl_t ctrl = opaque;
170 if (!where)
172 gcry_control (GCRYCTL_TERM_SECMEM);
173 if (ctrl->xauthority)
174 setenv ("XAUTHORITY", ctrl->xauthority, 1);
175 if (ctrl->pinentry_user_data)
176 setenv ("PINENTRY_USER_DATA", ctrl->pinentry_user_data, 1 );
181 /* Fork off the pin entry if this has not already been done. Note,
182 that this function must always be used to aquire the lock for the
183 pinentry - we will serialize _all_ pinentry calls.
185 static int
186 start_pinentry (ctrl_t ctrl)
188 int rc;
189 const char *pgmname;
190 assuan_context_t ctx;
191 const char *argv[5];
192 int no_close_list[3];
193 int i;
194 pth_event_t evt;
195 const char *tmpstr;
197 evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
198 if (!pth_mutex_acquire (&entry_lock, 0, evt))
200 if (pth_event_occurred (evt))
201 rc = gpg_error (GPG_ERR_TIMEOUT);
202 else
203 rc = gpg_error (GPG_ERR_INTERNAL);
204 pth_event_free (evt, PTH_FREE_THIS);
205 log_error (_("failed to acquire the pinentry lock: %s\n"),
206 gpg_strerror (rc));
207 return rc;
209 pth_event_free (evt, PTH_FREE_THIS);
211 entry_owner = ctrl;
213 if (entry_ctx)
214 return 0;
216 if (opt.verbose)
217 log_info ("starting a new PIN Entry\n");
219 #ifdef HAVE_W32_SYSTEM
220 fflush (stdout);
221 fflush (stderr);
222 #endif
223 if (fflush (NULL))
225 #ifndef HAVE_W32_SYSTEM
226 gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
227 #endif
228 log_error ("error flushing pending output: %s\n", strerror (errno));
229 /* At least Windows XP fails here with EBADF. According to docs
230 and Wine an fflush(NULL) is the same as _flushall. However
231 the Wime implementaion does not flush stdin,stdout and stderr
232 - see above. Lets try to ignore the error. */
233 #ifndef HAVE_W32_SYSTEM
234 return unlock_pinentry (tmperr);
235 #endif
238 if (!opt.pinentry_program || !*opt.pinentry_program)
239 opt.pinentry_program = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
240 pgmname = opt.pinentry_program;
241 if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
242 pgmname = opt.pinentry_program;
243 else
244 pgmname++;
246 /* OS X needs the entire file name in argv[0], so that it can locate
247 the resource bundle. For other systems we stick to the usual
248 convention of supplying only the name of the program. */
249 #ifdef __APPLE__
250 argv[0] = opt.pinentry_program;
251 #else /*!__APPLE__*/
252 argv[0] = pgmname;
253 #endif /*__APPLE__*/
255 if (ctrl->display && !opt.keep_display)
257 argv[1] = "--display";
258 argv[2] = ctrl->display;
259 argv[3] = NULL;
261 else
262 argv[1] = NULL;
264 i=0;
265 if (!opt.running_detached)
267 if (log_get_fd () != -1)
268 no_close_list[i++] = log_get_fd ();
269 no_close_list[i++] = fileno (stderr);
271 no_close_list[i] = -1;
273 /* Connect to the pinentry and perform initial handshaking. Note
274 that atfork is used to change the environment for pinentry. */
275 rc = assuan_pipe_connect_ext (&ctx, opt.pinentry_program, argv,
276 no_close_list, atfork_cb, ctrl, 0);
277 if (rc)
279 log_error ("can't connect to the PIN entry module: %s\n",
280 gpg_strerror (rc));
281 return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
283 entry_ctx = ctx;
285 if (DBG_ASSUAN)
286 log_debug ("connection to PIN entry established\n");
288 rc = assuan_transact (entry_ctx,
289 opt.no_grab? "OPTION no-grab":"OPTION grab",
290 NULL, NULL, NULL, NULL, NULL, NULL);
291 if (rc)
292 return unlock_pinentry (rc);
293 if (ctrl->ttyname)
295 char *optstr;
296 if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
297 return unlock_pinentry (out_of_core ());
298 rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
299 NULL);
300 free (optstr);
301 if (rc)
302 return unlock_pinentry (rc);
304 if (ctrl->ttytype)
306 char *optstr;
307 if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
308 return unlock_pinentry (out_of_core ());
309 rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
310 NULL);
311 if (rc)
312 return unlock_pinentry (rc);
314 if (ctrl->lc_ctype)
316 char *optstr;
317 if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
318 return unlock_pinentry (out_of_core ());
319 rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
320 NULL);
321 if (rc)
322 return unlock_pinentry (rc);
324 if (ctrl->lc_messages)
326 char *optstr;
327 if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
328 return unlock_pinentry (out_of_core ());
329 rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
330 NULL);
331 if (rc)
332 return unlock_pinentry (rc);
336 /* Tell the pinentry the name of a file it shall touch after having
337 messed with the tty. This is optional and only supported by
338 newer pinentries and thus we do no error checking. */
339 tmpstr = opt.pinentry_touch_file;
340 if (tmpstr && !strcmp (tmpstr, "/dev/null"))
341 tmpstr = NULL;
342 else if (!tmpstr)
343 tmpstr = get_agent_socket_name ();
344 if (tmpstr)
346 char *optstr;
348 if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
350 else
352 assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
353 NULL);
354 free (optstr);
358 return 0;
361 /* Returns True is the pinentry is currently active. If WAITSECONDS is
362 greater than zero the function will wait for this many seconds
363 before returning. */
365 pinentry_active_p (ctrl_t ctrl, int waitseconds)
367 if (waitseconds > 0)
369 pth_event_t evt;
370 int rc;
372 evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0));
373 if (!pth_mutex_acquire (&entry_lock, 0, evt))
375 if (pth_event_occurred (evt))
376 rc = gpg_error (GPG_ERR_TIMEOUT);
377 else
378 rc = gpg_error (GPG_ERR_INTERNAL);
379 pth_event_free (evt, PTH_FREE_THIS);
380 return rc;
382 pth_event_free (evt, PTH_FREE_THIS);
384 else
386 if (!pth_mutex_acquire (&entry_lock, 1, NULL))
387 return gpg_error (GPG_ERR_LOCKED);
390 if (!pth_mutex_release (&entry_lock))
391 log_error ("failed to release the entry lock at %d\n", __LINE__);
392 return 0;
396 static int
397 getpin_cb (void *opaque, const void *buffer, size_t length)
399 struct entry_parm_s *parm = opaque;
401 if (!buffer)
402 return 0;
404 /* we expect the pin to fit on one line */
405 if (parm->lines || length >= parm->size)
406 return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
408 /* fixme: we should make sure that the assuan buffer is allocated in
409 secure memory or read the response byte by byte */
410 memcpy (parm->buffer, buffer, length);
411 parm->buffer[length] = 0;
412 parm->lines++;
413 return 0;
417 static int
418 all_digitsp( const char *s)
420 for (; *s && *s >= '0' && *s <= '9'; s++)
422 return !*s;
426 /* Return a new malloced string by unescaping the string S. Escaping
427 is percent escaping and '+'/space mapping. A binary Nul will
428 silently be replaced by a 0xFF. Function returns NULL to indicate
429 an out of memory status. PArsing stops at the end of the string or
430 a white space character. */
431 static char *
432 unescape_passphrase_string (const unsigned char *s)
434 char *buffer, *d;
436 buffer = d = xtrymalloc_secure (strlen ((const char*)s)+1);
437 if (!buffer)
438 return NULL;
439 while (*s && !spacep (s))
441 if (*s == '%' && s[1] && s[2])
443 s++;
444 *d = xtoi_2 (s);
445 if (!*d)
446 *d = '\xff';
447 d++;
448 s += 2;
450 else if (*s == '+')
452 *d++ = ' ';
453 s++;
455 else
456 *d++ = *s++;
458 *d = 0;
459 return buffer;
463 /* Estimate the quality of the passphrase PW and return a value in the
464 range 0..100. */
465 static int
466 estimate_passphrase_quality (const char *pw)
468 int goodlength = opt.min_passphrase_len + opt.min_passphrase_len/3;
469 int length;
470 const char *s;
472 if (goodlength < 1)
473 return 0;
475 for (length = 0, s = pw; *s; s++)
476 if (!spacep (s))
477 length ++;
479 if (length > goodlength)
480 return 100;
481 return ((length*10) / goodlength)*10;
485 /* Handle the QUALITY inquiry. */
486 static int
487 inq_quality (void *opaque, const char *line)
489 assuan_context_t ctx = opaque;
490 char *pin;
491 int rc;
492 int percent;
493 char numbuf[20];
495 if (!strncmp (line, "QUALITY", 7) && (line[7] == ' ' || !line[7]))
497 line += 7;
498 while (*line == ' ')
499 line++;
501 pin = unescape_passphrase_string (line);
502 if (!pin)
503 rc = gpg_error_from_syserror ();
504 else
506 percent = estimate_passphrase_quality (pin);
507 if (check_passphrase_constraints (NULL, pin, 1))
508 percent = -percent;
509 snprintf (numbuf, sizeof numbuf, "%d", percent);
510 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
511 xfree (pin);
514 else
516 log_error ("unsupported inquiry `%s' from pinentry\n", line);
517 rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
520 return rc;
527 /* Call the Entry and ask for the PIN. We do check for a valid PIN
528 number here and repeat it as long as we have invalid formed
529 numbers. */
531 agent_askpin (ctrl_t ctrl,
532 const char *desc_text, const char *prompt_text,
533 const char *initial_errtext,
534 struct pin_entry_info_s *pininfo)
536 int rc;
537 char line[ASSUAN_LINELENGTH];
538 struct entry_parm_s parm;
539 const char *errtext = NULL;
540 int is_pin = 0;
542 if (opt.batch)
543 return 0; /* fixme: we should return BAD PIN */
545 if (!pininfo || pininfo->max_length < 1)
546 return gpg_error (GPG_ERR_INV_VALUE);
547 if (!desc_text && pininfo->min_digits)
548 desc_text = _("Please enter your PIN, so that the secret key "
549 "can be unlocked for this session");
550 else if (!desc_text)
551 desc_text = _("Please enter your passphrase, so that the secret key "
552 "can be unlocked for this session");
554 if (prompt_text)
555 is_pin = !!strstr (prompt_text, "PIN");
556 else
557 is_pin = desc_text && strstr (desc_text, "PIN");
559 rc = start_pinentry (ctrl);
560 if (rc)
561 return rc;
563 snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
564 line[DIM(line)-1] = 0;
565 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
566 if (rc)
567 return unlock_pinentry (rc);
569 snprintf (line, DIM(line)-1, "SETPROMPT %s",
570 prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
571 line[DIM(line)-1] = 0;
572 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
573 if (rc)
574 return unlock_pinentry (rc);
576 /* If a passphrase quality indicator has been requested and a
577 minimum passphrase length has not been disabled, send the command
578 to the pinentry. */
579 if (pininfo->with_qualitybar && opt.min_passphrase_len )
581 char *tmpstr, *tmpstr2;
582 const char *tooltip;
584 /* TRANSLATORS: This string is displayed by pinentry as the
585 label for the quality bar. */
586 tmpstr = try_percent_escape (_("Quality:"), "\t\r\n\f\v");
587 snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
588 line[DIM(line)-1] = 0;
589 xfree (tmpstr);
590 rc = assuan_transact (entry_ctx, line,
591 NULL, NULL, NULL, NULL, NULL, NULL);
592 if (rc == 103 /*(Old assuan error code)*/
593 || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
594 ; /* Ignore Unknown Command from old pinentry versions. */
595 else if (rc)
596 return unlock_pinentry (rc);
598 tmpstr2 = gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
599 if (tmpstr2)
600 tooltip = tmpstr2;
601 else
603 /* TRANSLATORS: This string is a tooltip, shown by pinentry
604 when hovering over the quality bar. Please use an
605 appropriate string to describe what this is about. The
606 length of the tooltip is limited to about 900 characters.
607 If you do not translate this entry, a default english
608 text (see source) will be used. */
609 tooltip = _("pinentry.qualitybar.tooltip");
610 if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
611 tooltip = ("The quality of the text entered above.\n"
612 "Please ask your administrator for "
613 "details about the criteria.");
615 tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
616 xfree (tmpstr2);
617 snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
618 line[DIM(line)-1] = 0;
619 xfree (tmpstr);
620 rc = assuan_transact (entry_ctx, line,
621 NULL, NULL, NULL, NULL, NULL, NULL);
622 if (rc == 103 /*(Old assuan error code)*/
623 || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
624 ; /* Ignore Unknown Command from old pinentry versions. */
625 else if (rc)
626 return unlock_pinentry (rc);
629 if (initial_errtext)
631 snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
632 line[DIM(line)-1] = 0;
633 rc = assuan_transact (entry_ctx, line,
634 NULL, NULL, NULL, NULL, NULL, NULL);
635 if (rc)
636 return unlock_pinentry (rc);
639 for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
641 memset (&parm, 0, sizeof parm);
642 parm.size = pininfo->max_length;
643 *pininfo->pin = 0; /* Reset the PIN. */
644 parm.buffer = (unsigned char*)pininfo->pin;
646 if (errtext)
648 /* TRANLATORS: The string is appended to an error message in
649 the pinentry. The %s is the actual error message, the
650 two %d give the current and maximum number of tries. */
651 snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
652 errtext, pininfo->failed_tries+1, pininfo->max_tries);
653 line[DIM(line)-1] = 0;
654 rc = assuan_transact (entry_ctx, line,
655 NULL, NULL, NULL, NULL, NULL, NULL);
656 if (rc)
657 return unlock_pinentry (rc);
658 errtext = NULL;
661 rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
662 inq_quality, entry_ctx, NULL, NULL);
663 /* Most pinentries out in the wild return the old Assuan error code
664 for canceled which gets translated to an assuan Cancel error and
665 not to the code for a user cancel. Fix this here. */
666 if (rc && gpg_err_source (rc)
667 && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
668 rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
670 if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
671 errtext = is_pin? _("PIN too long")
672 : _("Passphrase too long");
673 else if (rc)
674 return unlock_pinentry (rc);
676 if (!errtext && pininfo->min_digits)
678 /* do some basic checks on the entered PIN. */
679 if (!all_digitsp (pininfo->pin))
680 errtext = _("Invalid characters in PIN");
681 else if (pininfo->max_digits
682 && strlen (pininfo->pin) > pininfo->max_digits)
683 errtext = _("PIN too long");
684 else if (strlen (pininfo->pin) < pininfo->min_digits)
685 errtext = _("PIN too short");
688 if (!errtext && pininfo->check_cb)
690 /* More checks by utilizing the optional callback. */
691 pininfo->cb_errtext = NULL;
692 rc = pininfo->check_cb (pininfo);
693 if (rc == -1 && pininfo->cb_errtext)
694 errtext = pininfo->cb_errtext;
695 else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
696 || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
697 errtext = (is_pin? _("Bad PIN")
698 : _("Bad Passphrase"));
699 else if (rc)
700 return unlock_pinentry (rc);
703 if (!errtext)
704 return unlock_pinentry (0); /* okay, got a PIN or passphrase */
707 return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
708 : GPG_ERR_BAD_PASSPHRASE));
713 /* Ask for the passphrase using the supplied arguments. The returned
714 passphrase needs to be freed by the caller. */
715 int
716 agent_get_passphrase (ctrl_t ctrl,
717 char **retpass, const char *desc, const char *prompt,
718 const char *errtext)
721 int rc;
722 char line[ASSUAN_LINELENGTH];
723 struct entry_parm_s parm;
725 *retpass = NULL;
726 if (opt.batch)
727 return gpg_error (GPG_ERR_BAD_PASSPHRASE);
729 rc = start_pinentry (ctrl);
730 if (rc)
731 return rc;
733 if (!prompt)
734 prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
737 if (desc)
738 snprintf (line, DIM(line)-1, "SETDESC %s", desc);
739 else
740 snprintf (line, DIM(line)-1, "RESET");
741 line[DIM(line)-1] = 0;
742 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
743 if (rc)
744 return unlock_pinentry (rc);
746 snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
747 line[DIM(line)-1] = 0;
748 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
749 if (rc)
750 return unlock_pinentry (rc);
752 if (errtext)
754 snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
755 line[DIM(line)-1] = 0;
756 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
757 if (rc)
758 return unlock_pinentry (rc);
761 memset (&parm, 0, sizeof parm);
762 parm.size = ASSUAN_LINELENGTH/2 - 5;
763 parm.buffer = gcry_malloc_secure (parm.size+10);
764 if (!parm.buffer)
765 return unlock_pinentry (out_of_core ());
767 assuan_begin_confidential (entry_ctx);
768 rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
769 NULL, NULL, NULL, NULL);
770 /* Most pinentries out in the wild return the old Assuan error code
771 for canceled which gets translated to an assuan Cancel error and
772 not to the code for a user cancel. Fix this here. */
773 if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
774 rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
775 if (rc)
776 xfree (parm.buffer);
777 else
778 *retpass = parm.buffer;
779 return unlock_pinentry (rc);
784 /* Pop up the PIN-entry, display the text and the prompt and ask the
785 user to confirm this. We return 0 for success, ie. the user
786 confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
787 other error. */
788 int
789 agent_get_confirmation (ctrl_t ctrl,
790 const char *desc, const char *ok, const char *cancel)
792 int rc;
793 char line[ASSUAN_LINELENGTH];
795 rc = start_pinentry (ctrl);
796 if (rc)
797 return rc;
799 if (desc)
800 snprintf (line, DIM(line)-1, "SETDESC %s", desc);
801 else
802 snprintf (line, DIM(line)-1, "RESET");
803 line[DIM(line)-1] = 0;
804 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
805 /* Most pinentries out in the wild return the old Assuan error code
806 for canceled which gets translated to an assuan Cancel error and
807 not to the code for a user cancel. Fix this here. */
808 if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
809 rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
811 if (rc)
812 return unlock_pinentry (rc);
814 if (ok)
816 snprintf (line, DIM(line)-1, "SETOK %s", ok);
817 line[DIM(line)-1] = 0;
818 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
819 if (rc)
820 return unlock_pinentry (rc);
822 if (cancel)
824 snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
825 line[DIM(line)-1] = 0;
826 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
827 if (rc)
828 return unlock_pinentry (rc);
831 rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
832 if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
833 rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
835 return unlock_pinentry (rc);
840 /* Pop up the PINentry, display the text DESC and a button with the
841 text OK_BTN (which may be NULL to use the default of "OK") and waut
842 for the user to hit this button. The return value is not
843 relevant. */
844 int
845 agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
847 int rc;
848 char line[ASSUAN_LINELENGTH];
850 rc = start_pinentry (ctrl);
851 if (rc)
852 return rc;
854 if (desc)
855 snprintf (line, DIM(line)-1, "SETDESC %s", desc);
856 else
857 snprintf (line, DIM(line)-1, "RESET");
858 line[DIM(line)-1] = 0;
859 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
860 /* Most pinentries out in the wild return the old Assuan error code
861 for canceled which gets translated to an assuan Cancel error and
862 not to the code for a user cancel. Fix this here. */
863 if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
864 rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
866 if (rc)
867 return unlock_pinentry (rc);
869 if (ok_btn)
871 snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
872 line[DIM(line)-1] = 0;
873 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
874 NULL, NULL, NULL);
875 if (rc)
876 return unlock_pinentry (rc);
879 rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
880 NULL, NULL, NULL);
881 if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
882 rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
884 return unlock_pinentry (rc);
888 /* The thread running the popup message. */
889 static void *
890 popup_message_thread (void *arg)
892 /* We use the --one-button hack instead of the MESSAGE command to
893 allow the use of old Pinentries. Those old Pinentries will then
894 show an additional Cancel button but that is mostly a visual
895 annoyance. */
896 assuan_transact (entry_ctx, "CONFIRM --one-button",
897 NULL, NULL, NULL, NULL, NULL, NULL);
898 popup_finished = 1;
899 return NULL;
903 /* Pop up a message window similar to the confirm one but keep it open
904 until agent_popup_message_stop has been called. It is crucial for
905 the caller to make sure that the stop function gets called as soon
906 as the message is not anymore required because the message is
907 system modal and all other attempts to use the pinentry will fail
908 (after a timeout). */
909 int
910 agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
912 int rc;
913 char line[ASSUAN_LINELENGTH];
914 pth_attr_t tattr;
916 rc = start_pinentry (ctrl);
917 if (rc)
918 return rc;
920 if (desc)
921 snprintf (line, DIM(line)-1, "SETDESC %s", desc);
922 else
923 snprintf (line, DIM(line)-1, "RESET");
924 line[DIM(line)-1] = 0;
925 rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
926 if (rc)
927 return unlock_pinentry (rc);
929 if (ok_btn)
931 snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
932 line[DIM(line)-1] = 0;
933 rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
934 if (rc)
935 return unlock_pinentry (rc);
938 tattr = pth_attr_new();
939 pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
940 pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
941 pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
943 popup_finished = 0;
944 popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
945 if (!popup_tid)
947 rc = gpg_error_from_syserror ();
948 log_error ("error spawning popup message handler: %s\n",
949 strerror (errno) );
950 pth_attr_destroy (tattr);
951 return unlock_pinentry (rc);
953 pth_attr_destroy (tattr);
955 return 0;
958 /* Close a popup window. */
959 void
960 agent_popup_message_stop (ctrl_t ctrl)
962 int rc;
963 pid_t pid;
965 if (!popup_tid || !entry_ctx)
967 log_debug ("agent_popup_message_stop called with no active popup\n");
968 return;
971 pid = assuan_get_pid (entry_ctx);
972 if (pid == (pid_t)(-1))
973 ; /* No pid available can't send a kill. */
974 else if (popup_finished)
975 ; /* Already finished and ready for joining. */
976 #ifdef HAVE_W32_SYSTEM
977 /* Older versions of assuan set PID to 0 on Windows to indicate an
978 invalid value. */
979 else if (pid != (pid_t) INVALID_HANDLE_VALUE
980 && pid != 0)
982 HANDLE process = (HANDLE) pid;
984 /* Arbitrary error code. */
985 TerminateProcess (process, 1);
987 #else
988 else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
989 { /* The daemon already died. No need to send a kill. However
990 because we already waited for the process, we need to tell
991 assuan that it should not wait again (done by
992 unlock_pinentry). */
993 if (rc == pid)
994 assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
996 else if (pid > 0)
997 kill (pid, SIGKILL); /* Need to use SIGKILL due to bad
998 interaction of SIGINT with Pth. */
999 #endif
1001 /* Now wait for the thread to terminate. */
1002 rc = pth_join (popup_tid, NULL);
1003 if (!rc)
1004 log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
1005 strerror (errno));
1006 popup_tid = NULL;
1007 entry_owner = NULL;
1009 /* Now we can close the connection. */
1010 unlock_pinentry (0);