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.
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/>.
29 #ifndef HAVE_W32_SYSTEM
30 # include <sys/wait.h>
31 # include <sys/types.h>
41 #ifdef _POSIX_OPEN_MAX
42 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
44 #define MAX_OPEN_FDS 20
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
52 #define LOCK_TIMEOUT (1*60)
54 /* The assuan context of the current pinentry. */
55 static assuan_context_t entry_ctx
;
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
61 static ctrl_t entry_owner
;
63 /* A mutex used to serialize access to the pinentry. */
64 static pth_mutex_t entry_lock
;
66 /* The thread ID of the popup working thread. */
67 static pth_t popup_tid
;
69 /* A flag used in communication between the popup working thread and
71 static int popup_finished
;
75 /* Data to be passed to our callbacks, */
80 unsigned char *buffer
;
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. */
91 initialize_module_call_pinentry (void)
93 static int initialized
;
97 if (pth_mutex_init (&entry_lock
))
105 dump_mutex_state (pth_mutex_t
*m
)
109 log_printf ("unknown under W32");
111 if (!(m
->mx_state
& PTH_MUTEX_INITIALIZED
))
112 log_printf ("not_initialized");
113 else if (!(m
->mx_state
& PTH_MUTEX_LOCKED
))
114 log_printf ("not_locked");
116 log_printf ("locked tid=0x%lx count=%lu", (long)m
->mx_owner
, m
->mx_count
);
121 /* This function may be called to print infromation pertaining to the
122 current state of this module to the log. */
124 agent_query_dump_state (void)
126 log_info ("agent_query_dump_state: entry_lock=");
127 dump_mutex_state (&entry_lock
);
129 log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
130 entry_ctx
, (long)assuan_get_pid (entry_ctx
), popup_tid
);
133 /* Called to make sure that a popup window owned by the current
134 connection gets closed. */
136 agent_reset_query (ctrl_t ctrl
)
138 if (entry_ctx
&& popup_tid
&& entry_owner
== ctrl
)
140 agent_popup_message_stop (ctrl
);
145 /* Unlock the pinentry so that another thread can start one and
146 disconnect that pinentry - we do this after the unlock so that a
147 stalled pinentry does not block other threads. Fixme: We should
148 have a timeout in Assuan for the disconnect operation. */
150 unlock_pinentry (int rc
)
152 assuan_context_t ctx
= entry_ctx
;
155 if (!pth_mutex_release (&entry_lock
))
157 log_error ("failed to release the entry lock\n");
159 rc
= gpg_error (GPG_ERR_INTERNAL
);
161 assuan_release (ctx
);
166 /* To make sure we leave no secrets in our image after forking of the
167 pinentry, we use this callback. */
169 atfork_cb (void *opaque
, int where
)
171 ctrl_t ctrl
= opaque
;
176 const char *name
, *assname
, *value
;
178 gcry_control (GCRYCTL_TERM_SECMEM
);
180 while ((name
= session_env_list_stdenvnames (&iterator
, &assname
)))
182 /* For all new envvars (!ASSNAME) and the two medium old
183 ones which do have an assuan name but are conveyed using
184 environment variables, update the environment of the
187 || !strcmp (name
, "XAUTHORITY")
188 || !strcmp (name
, "PINENTRY_USER_DATA"))
190 value
= session_env_getenv (ctrl
->session_env
, name
);
192 setenv (name
, value
, 1);
200 getinfo_pid_cb (void *opaque
, const void *buffer
, size_t length
)
202 unsigned long *pid
= opaque
;
205 /* There is only the pid in the server's response. */
206 if (length
>= sizeof pidbuf
)
207 length
= sizeof pidbuf
-1;
210 strncpy (pidbuf
, buffer
, length
);
212 *pid
= strtoul (pidbuf
, NULL
, 10);
217 /* Fork off the pin entry if this has not already been done. Note,
218 that this function must always be used to aquire the lock for the
219 pinentry - we will serialize _all_ pinentry calls.
222 start_pinentry (ctrl_t ctrl
)
226 assuan_context_t ctx
;
228 int no_close_list
[3];
232 unsigned long pinentry_pid
;
235 evt
= pth_event (PTH_EVENT_TIME
, pth_timeout (LOCK_TIMEOUT
, 0));
236 if (!pth_mutex_acquire (&entry_lock
, 0, evt
))
238 if (pth_event_occurred (evt
))
239 rc
= gpg_error (GPG_ERR_TIMEOUT
);
241 rc
= gpg_error (GPG_ERR_INTERNAL
);
242 pth_event_free (evt
, PTH_FREE_THIS
);
243 log_error (_("failed to acquire the pinentry lock: %s\n"),
247 pth_event_free (evt
, PTH_FREE_THIS
);
255 log_info ("starting a new PIN Entry\n");
257 #ifdef HAVE_W32_SYSTEM
263 #ifndef HAVE_W32_SYSTEM
264 gpg_error_t tmperr
= gpg_error (gpg_err_code_from_errno (errno
));
266 log_error ("error flushing pending output: %s\n", strerror (errno
));
267 /* At least Windows XP fails here with EBADF. According to docs
268 and Wine an fflush(NULL) is the same as _flushall. However
269 the Wime implementaion does not flush stdin,stdout and stderr
270 - see above. Lets try to ignore the error. */
271 #ifndef HAVE_W32_SYSTEM
272 return unlock_pinentry (tmperr
);
276 if (!opt
.pinentry_program
|| !*opt
.pinentry_program
)
277 opt
.pinentry_program
= gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY
);
278 pgmname
= opt
.pinentry_program
;
279 if ( !(pgmname
= strrchr (opt
.pinentry_program
, '/')))
280 pgmname
= opt
.pinentry_program
;
284 /* OS X needs the entire file name in argv[0], so that it can locate
285 the resource bundle. For other systems we stick to the usual
286 convention of supplying only the name of the program. */
288 argv
[0] = opt
.pinentry_program
;
293 if (!opt
.keep_display
294 && (value
= session_env_getenv (ctrl
->session_env
, "DISPLAY")))
296 argv
[1] = "--display";
304 if (!opt
.running_detached
)
306 if (log_get_fd () != -1)
307 no_close_list
[i
++] = log_get_fd ();
308 no_close_list
[i
++] = fileno (stderr
);
310 no_close_list
[i
] = -1;
312 rc
= assuan_new (&ctx
);
315 log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc
));
319 /* Connect to the pinentry and perform initial handshaking. Note
320 that atfork is used to change the environment for pinentry. We
321 start the server in detached mode to suppress the console window
323 rc
= assuan_pipe_connect_ext (ctx
, opt
.pinentry_program
, argv
,
324 no_close_list
, atfork_cb
, ctrl
, 128);
327 log_error ("can't connect to the PIN entry module: %s\n",
329 assuan_release (ctx
);
330 return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY
));
335 log_debug ("connection to PIN entry established\n");
337 rc
= assuan_transact (entry_ctx
,
338 opt
.no_grab
? "OPTION no-grab":"OPTION grab",
339 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
341 return unlock_pinentry (rc
);
343 value
= session_env_getenv (ctrl
->session_env
, "GPG_TTY");
347 if (asprintf (&optstr
, "OPTION ttyname=%s", value
) < 0 )
348 return unlock_pinentry (out_of_core ());
349 rc
= assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
353 return unlock_pinentry (rc
);
355 value
= session_env_getenv (ctrl
->session_env
, "TERM");
359 if (asprintf (&optstr
, "OPTION ttytype=%s", value
) < 0 )
360 return unlock_pinentry (out_of_core ());
361 rc
= assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
364 return unlock_pinentry (rc
);
369 if (asprintf (&optstr
, "OPTION lc-ctype=%s", ctrl
->lc_ctype
) < 0 )
370 return unlock_pinentry (out_of_core ());
371 rc
= assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
374 return unlock_pinentry (rc
);
376 if (ctrl
->lc_messages
)
379 if (asprintf (&optstr
, "OPTION lc-messages=%s", ctrl
->lc_messages
) < 0 )
380 return unlock_pinentry (out_of_core ());
381 rc
= assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
384 return unlock_pinentry (rc
);
388 /* Tell the pinentry the name of a file it shall touch after having
389 messed with the tty. This is optional and only supported by
390 newer pinentries and thus we do no error checking. */
391 tmpstr
= opt
.pinentry_touch_file
;
392 if (tmpstr
&& !strcmp (tmpstr
, "/dev/null"))
395 tmpstr
= get_agent_socket_name ();
400 if (asprintf (&optstr
, "OPTION touch-file=%s", tmpstr
) < 0 )
404 assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
411 /* Now ask the Pinentry for its PID. If the Pinentry is new enough
412 it will send the pid back and we will use an inquire to notify
413 our client. The client may answer the inquiry either with END or
414 with CAN to cancel the pinentry. */
415 rc
= assuan_transact (entry_ctx
, "GETINFO pid",
416 getinfo_pid_cb
, &pinentry_pid
,
417 NULL
, NULL
, NULL
, NULL
);
420 log_info ("You may want to update to a newer pinentry\n");
423 else if (!rc
&& (pid_t
)pinentry_pid
== (pid_t
)(-1))
424 log_error ("pinentry did not return a PID\n");
427 rc
= agent_inq_pinentry_launched (ctrl
, pinentry_pid
);
428 if (gpg_err_code (rc
) == GPG_ERR_CANCELED
)
429 return unlock_pinentry (gpg_error (GPG_ERR_CANCELED
));
437 /* Returns True is the pinentry is currently active. If WAITSECONDS is
438 greater than zero the function will wait for this many seconds
441 pinentry_active_p (ctrl_t ctrl
, int waitseconds
)
450 evt
= pth_event (PTH_EVENT_TIME
, pth_timeout (waitseconds
, 0));
451 if (!pth_mutex_acquire (&entry_lock
, 0, evt
))
453 if (pth_event_occurred (evt
))
454 rc
= gpg_error (GPG_ERR_TIMEOUT
);
456 rc
= gpg_error (GPG_ERR_INTERNAL
);
457 pth_event_free (evt
, PTH_FREE_THIS
);
460 pth_event_free (evt
, PTH_FREE_THIS
);
464 if (!pth_mutex_acquire (&entry_lock
, 1, NULL
))
465 return gpg_error (GPG_ERR_LOCKED
);
468 if (!pth_mutex_release (&entry_lock
))
469 log_error ("failed to release the entry lock at %d\n", __LINE__
);
475 getpin_cb (void *opaque
, const void *buffer
, size_t length
)
477 struct entry_parm_s
*parm
= opaque
;
482 /* we expect the pin to fit on one line */
483 if (parm
->lines
|| length
>= parm
->size
)
484 return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA
);
486 /* fixme: we should make sure that the assuan buffer is allocated in
487 secure memory or read the response byte by byte */
488 memcpy (parm
->buffer
, buffer
, length
);
489 parm
->buffer
[length
] = 0;
496 all_digitsp( const char *s
)
498 for (; *s
&& *s
>= '0' && *s
<= '9'; s
++)
504 /* Return a new malloced string by unescaping the string S. Escaping
505 is percent escaping and '+'/space mapping. A binary Nul will
506 silently be replaced by a 0xFF. Function returns NULL to indicate
507 an out of memory status. PArsing stops at the end of the string or
508 a white space character. */
510 unescape_passphrase_string (const unsigned char *s
)
514 buffer
= d
= xtrymalloc_secure (strlen ((const char*)s
)+1);
517 while (*s
&& !spacep (s
))
519 if (*s
== '%' && s
[1] && s
[2])
541 /* Estimate the quality of the passphrase PW and return a value in the
544 estimate_passphrase_quality (const char *pw
)
546 int goodlength
= opt
.min_passphrase_len
+ opt
.min_passphrase_len
/3;
553 for (length
= 0, s
= pw
; *s
; s
++)
557 if (length
> goodlength
)
559 return ((length
*10) / goodlength
)*10;
563 /* Handle the QUALITY inquiry. */
565 inq_quality (void *opaque
, const char *line
)
567 assuan_context_t ctx
= opaque
;
573 if (!strncmp (line
, "QUALITY", 7) && (line
[7] == ' ' || !line
[7]))
579 pin
= unescape_passphrase_string (line
);
581 rc
= gpg_error_from_syserror ();
584 percent
= estimate_passphrase_quality (pin
);
585 if (check_passphrase_constraints (NULL
, pin
, 1))
587 snprintf (numbuf
, sizeof numbuf
, "%d", percent
);
588 rc
= assuan_send_data (ctx
, numbuf
, strlen (numbuf
));
594 log_error ("unsupported inquiry `%s' from pinentry\n", line
);
595 rc
= gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE
);
602 /* Helper for agent_askpin and agent_get_passphrase. */
604 setup_qualitybar (void)
607 char line
[ASSUAN_LINELENGTH
];
608 char *tmpstr
, *tmpstr2
;
611 /* TRANSLATORS: This string is displayed by Pinentry as the label
612 for the quality bar. */
613 tmpstr
= try_percent_escape (_("Quality:"), "\t\r\n\f\v");
614 snprintf (line
, DIM(line
)-1, "SETQUALITYBAR %s", tmpstr
? tmpstr
:"");
615 line
[DIM(line
)-1] = 0;
617 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
618 if (rc
== 103 /*(Old assuan error code)*/
619 || gpg_err_code (rc
) == GPG_ERR_ASS_UNKNOWN_CMD
)
620 ; /* Ignore Unknown Command from old Pinentry versions. */
624 tmpstr2
= gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
629 /* TRANSLATORS: This string is a tooltip, shown by pinentry when
630 hovering over the quality bar. Please use an appropriate
631 string to describe what this is about. The length of the
632 tooltip is limited to about 900 characters. If you do not
633 translate this entry, a default english text (see source)
635 tooltip
= _("pinentry.qualitybar.tooltip");
636 if (!strcmp ("pinentry.qualitybar.tooltip", tooltip
))
637 tooltip
= ("The quality of the text entered above.\n"
638 "Please ask your administrator for "
639 "details about the criteria.");
641 tmpstr
= try_percent_escape (tooltip
, "\t\r\n\f\v");
643 snprintf (line
, DIM(line
)-1, "SETQUALITYBAR_TT %s", tmpstr
? tmpstr
:"");
644 line
[DIM(line
)-1] = 0;
646 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
647 if (rc
== 103 /*(Old assuan error code)*/
648 || gpg_err_code (rc
) == GPG_ERR_ASS_UNKNOWN_CMD
)
649 ; /* Ignore Unknown Command from old pinentry versions. */
658 /* Call the Entry and ask for the PIN. We do check for a valid PIN
659 number here and repeat it as long as we have invalid formed
662 agent_askpin (ctrl_t ctrl
,
663 const char *desc_text
, const char *prompt_text
,
664 const char *initial_errtext
,
665 struct pin_entry_info_s
*pininfo
)
668 char line
[ASSUAN_LINELENGTH
];
669 struct entry_parm_s parm
;
670 const char *errtext
= NULL
;
674 return 0; /* fixme: we should return BAD PIN */
676 if (!pininfo
|| pininfo
->max_length
< 1)
677 return gpg_error (GPG_ERR_INV_VALUE
);
678 if (!desc_text
&& pininfo
->min_digits
)
679 desc_text
= _("Please enter your PIN, so that the secret key "
680 "can be unlocked for this session");
682 desc_text
= _("Please enter your passphrase, so that the secret key "
683 "can be unlocked for this session");
686 is_pin
= !!strstr (prompt_text
, "PIN");
688 is_pin
= desc_text
&& strstr (desc_text
, "PIN");
690 rc
= start_pinentry (ctrl
);
694 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc_text
);
695 line
[DIM(line
)-1] = 0;
696 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
698 return unlock_pinentry (rc
);
700 snprintf (line
, DIM(line
)-1, "SETPROMPT %s",
701 prompt_text
? prompt_text
: is_pin
? "PIN:" : "Passphrase:");
702 line
[DIM(line
)-1] = 0;
703 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
705 return unlock_pinentry (rc
);
707 /* If a passphrase quality indicator has been requested and a
708 minimum passphrase length has not been disabled, send the command
710 if (pininfo
->with_qualitybar
&& opt
.min_passphrase_len
)
712 rc
= setup_qualitybar ();
714 return unlock_pinentry (rc
);
719 snprintf (line
, DIM(line
)-1, "SETERROR %s", initial_errtext
);
720 line
[DIM(line
)-1] = 0;
721 rc
= assuan_transact (entry_ctx
, line
,
722 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
724 return unlock_pinentry (rc
);
727 for (;pininfo
->failed_tries
< pininfo
->max_tries
; pininfo
->failed_tries
++)
729 memset (&parm
, 0, sizeof parm
);
730 parm
.size
= pininfo
->max_length
;
731 *pininfo
->pin
= 0; /* Reset the PIN. */
732 parm
.buffer
= (unsigned char*)pininfo
->pin
;
736 /* TRANLATORS: The string is appended to an error message in
737 the pinentry. The %s is the actual error message, the
738 two %d give the current and maximum number of tries. */
739 snprintf (line
, DIM(line
)-1, _("SETERROR %s (try %d of %d)"),
740 errtext
, pininfo
->failed_tries
+1, pininfo
->max_tries
);
741 line
[DIM(line
)-1] = 0;
742 rc
= assuan_transact (entry_ctx
, line
,
743 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
745 return unlock_pinentry (rc
);
749 rc
= assuan_transact (entry_ctx
, "GETPIN", getpin_cb
, &parm
,
750 inq_quality
, entry_ctx
, NULL
, NULL
);
751 /* Most pinentries out in the wild return the old Assuan error code
752 for canceled which gets translated to an assuan Cancel error and
753 not to the code for a user cancel. Fix this here. */
754 if (rc
&& gpg_err_source (rc
)
755 && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
756 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
758 if (gpg_err_code (rc
) == GPG_ERR_ASS_TOO_MUCH_DATA
)
759 errtext
= is_pin
? _("PIN too long")
760 : _("Passphrase too long");
762 return unlock_pinentry (rc
);
764 if (!errtext
&& pininfo
->min_digits
)
766 /* do some basic checks on the entered PIN. */
767 if (!all_digitsp (pininfo
->pin
))
768 errtext
= _("Invalid characters in PIN");
769 else if (pininfo
->max_digits
770 && strlen (pininfo
->pin
) > pininfo
->max_digits
)
771 errtext
= _("PIN too long");
772 else if (strlen (pininfo
->pin
) < pininfo
->min_digits
)
773 errtext
= _("PIN too short");
776 if (!errtext
&& pininfo
->check_cb
)
778 /* More checks by utilizing the optional callback. */
779 pininfo
->cb_errtext
= NULL
;
780 rc
= pininfo
->check_cb (pininfo
);
781 if (rc
== -1 && pininfo
->cb_errtext
)
782 errtext
= pininfo
->cb_errtext
;
783 else if (gpg_err_code (rc
) == GPG_ERR_BAD_PASSPHRASE
784 || gpg_err_code (rc
) == GPG_ERR_BAD_PIN
)
785 errtext
= (is_pin
? _("Bad PIN")
786 : _("Bad Passphrase"));
788 return unlock_pinentry (rc
);
792 return unlock_pinentry (0); /* okay, got a PIN or passphrase */
795 return unlock_pinentry (gpg_error (pininfo
->min_digits
? GPG_ERR_BAD_PIN
796 : GPG_ERR_BAD_PASSPHRASE
));
801 /* Ask for the passphrase using the supplied arguments. The returned
802 passphrase needs to be freed by the caller. */
804 agent_get_passphrase (ctrl_t ctrl
,
805 char **retpass
, const char *desc
, const char *prompt
,
806 const char *errtext
, int with_qualitybar
)
810 char line
[ASSUAN_LINELENGTH
];
811 struct entry_parm_s parm
;
815 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
817 rc
= start_pinentry (ctrl
);
822 prompt
= desc
&& strstr (desc
, "PIN")? "PIN": _("Passphrase");
826 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc
);
828 snprintf (line
, DIM(line
)-1, "RESET");
829 line
[DIM(line
)-1] = 0;
830 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
832 return unlock_pinentry (rc
);
834 snprintf (line
, DIM(line
)-1, "SETPROMPT %s", prompt
);
835 line
[DIM(line
)-1] = 0;
836 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
838 return unlock_pinentry (rc
);
840 if (with_qualitybar
&& opt
.min_passphrase_len
)
842 rc
= setup_qualitybar ();
844 return unlock_pinentry (rc
);
849 snprintf (line
, DIM(line
)-1, "SETERROR %s", errtext
);
850 line
[DIM(line
)-1] = 0;
851 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
853 return unlock_pinentry (rc
);
856 memset (&parm
, 0, sizeof parm
);
857 parm
.size
= ASSUAN_LINELENGTH
/2 - 5;
858 parm
.buffer
= gcry_malloc_secure (parm
.size
+10);
860 return unlock_pinentry (out_of_core ());
862 assuan_begin_confidential (entry_ctx
);
863 rc
= assuan_transact (entry_ctx
, "GETPIN", getpin_cb
, &parm
,
864 inq_quality
, entry_ctx
, NULL
, NULL
);
865 /* Most pinentries out in the wild return the old Assuan error code
866 for canceled which gets translated to an assuan Cancel error and
867 not to the code for a user cancel. Fix this here. */
868 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
869 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
873 *retpass
= parm
.buffer
;
874 return unlock_pinentry (rc
);
879 /* Pop up the PIN-entry, display the text and the prompt and ask the
880 user to confirm this. We return 0 for success, ie. the user
881 confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
882 other error. If WITH_CANCEL it true an extra cancel button is
883 displayed to allow the user to easily return a GPG_ERR_CANCELED.
884 if the Pinentry does not support this, the user can still cancel by
885 closing the Pinentry window. */
887 agent_get_confirmation (ctrl_t ctrl
,
888 const char *desc
, const char *ok
,
889 const char *notok
, int with_cancel
)
892 char line
[ASSUAN_LINELENGTH
];
894 rc
= start_pinentry (ctrl
);
899 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc
);
901 snprintf (line
, DIM(line
)-1, "RESET");
902 line
[DIM(line
)-1] = 0;
903 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
904 /* Most pinentries out in the wild return the old Assuan error code
905 for canceled which gets translated to an assuan Cancel error and
906 not to the code for a user cancel. Fix this here. */
907 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
908 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
911 return unlock_pinentry (rc
);
915 snprintf (line
, DIM(line
)-1, "SETOK %s", ok
);
916 line
[DIM(line
)-1] = 0;
917 rc
= assuan_transact (entry_ctx
,
918 line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
920 return unlock_pinentry (rc
);
924 /* Try to use the newer NOTOK feature if a cancel button is
925 requested. If no cacnel button is requested we keep on using
926 the standard cancel. */
929 snprintf (line
, DIM(line
)-1, "SETNOTOK %s", notok
);
930 line
[DIM(line
)-1] = 0;
931 rc
= assuan_transact (entry_ctx
,
932 line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
935 rc
= GPG_ERR_ASS_UNKNOWN_CMD
;
937 if (gpg_err_code (rc
) == GPG_ERR_ASS_UNKNOWN_CMD
)
939 snprintf (line
, DIM(line
)-1, "SETCANCEL %s", notok
);
940 line
[DIM(line
)-1] = 0;
941 rc
= assuan_transact (entry_ctx
, line
,
942 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
945 return unlock_pinentry (rc
);
948 rc
= assuan_transact (entry_ctx
, "CONFIRM",
949 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
950 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
951 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
953 return unlock_pinentry (rc
);
958 /* Pop up the PINentry, display the text DESC and a button with the
959 text OK_BTN (which may be NULL to use the default of "OK") and waut
960 for the user to hit this button. The return value is not
963 agent_show_message (ctrl_t ctrl
, const char *desc
, const char *ok_btn
)
966 char line
[ASSUAN_LINELENGTH
];
968 rc
= start_pinentry (ctrl
);
973 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc
);
975 snprintf (line
, DIM(line
)-1, "RESET");
976 line
[DIM(line
)-1] = 0;
977 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
978 /* Most pinentries out in the wild return the old Assuan error code
979 for canceled which gets translated to an assuan Cancel error and
980 not to the code for a user cancel. Fix this here. */
981 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
982 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
985 return unlock_pinentry (rc
);
989 snprintf (line
, DIM(line
)-1, "SETOK %s", ok_btn
);
990 line
[DIM(line
)-1] = 0;
991 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
,
994 return unlock_pinentry (rc
);
997 rc
= assuan_transact (entry_ctx
, "CONFIRM --one-button", NULL
, NULL
, NULL
,
999 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
1000 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
1002 return unlock_pinentry (rc
);
1006 /* The thread running the popup message. */
1008 popup_message_thread (void *arg
)
1012 /* We use the --one-button hack instead of the MESSAGE command to
1013 allow the use of old Pinentries. Those old Pinentries will then
1014 show an additional Cancel button but that is mostly a visual
1016 assuan_transact (entry_ctx
, "CONFIRM --one-button",
1017 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1023 /* Pop up a message window similar to the confirm one but keep it open
1024 until agent_popup_message_stop has been called. It is crucial for
1025 the caller to make sure that the stop function gets called as soon
1026 as the message is not anymore required because the message is
1027 system modal and all other attempts to use the pinentry will fail
1028 (after a timeout). */
1030 agent_popup_message_start (ctrl_t ctrl
, const char *desc
, const char *ok_btn
)
1033 char line
[ASSUAN_LINELENGTH
];
1036 rc
= start_pinentry (ctrl
);
1041 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc
);
1043 snprintf (line
, DIM(line
)-1, "RESET");
1044 line
[DIM(line
)-1] = 0;
1045 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1047 return unlock_pinentry (rc
);
1051 snprintf (line
, DIM(line
)-1, "SETOK %s", ok_btn
);
1052 line
[DIM(line
)-1] = 0;
1053 rc
= assuan_transact (entry_ctx
, line
, NULL
,NULL
,NULL
,NULL
,NULL
,NULL
);
1055 return unlock_pinentry (rc
);
1058 tattr
= pth_attr_new();
1059 pth_attr_set (tattr
, PTH_ATTR_JOINABLE
, 1);
1060 pth_attr_set (tattr
, PTH_ATTR_STACK_SIZE
, 256*1024);
1061 pth_attr_set (tattr
, PTH_ATTR_NAME
, "popup-message");
1064 popup_tid
= pth_spawn (tattr
, popup_message_thread
, NULL
);
1067 rc
= gpg_error_from_syserror ();
1068 log_error ("error spawning popup message handler: %s\n",
1070 pth_attr_destroy (tattr
);
1071 return unlock_pinentry (rc
);
1073 pth_attr_destroy (tattr
);
1078 /* Close a popup window. */
1080 agent_popup_message_stop (ctrl_t ctrl
)
1087 if (!popup_tid
|| !entry_ctx
)
1089 log_debug ("agent_popup_message_stop called with no active popup\n");
1093 pid
= assuan_get_pid (entry_ctx
);
1094 if (pid
== (pid_t
)(-1))
1095 ; /* No pid available can't send a kill. */
1096 else if (popup_finished
)
1097 ; /* Already finished and ready for joining. */
1098 #ifdef HAVE_W32_SYSTEM
1099 /* Older versions of assuan set PID to 0 on Windows to indicate an
1101 else if (pid
!= (pid_t
) INVALID_HANDLE_VALUE
1104 HANDLE process
= (HANDLE
) pid
;
1106 /* Arbitrary error code. */
1107 TerminateProcess (process
, 1);
1110 else if (pid
&& ((rc
=waitpid (pid
, NULL
, WNOHANG
))==-1 || (rc
== pid
)) )
1111 { /* The daemon already died. No need to send a kill. However
1112 because we already waited for the process, we need to tell
1113 assuan that it should not wait again (done by
1114 unlock_pinentry). */
1116 assuan_set_flag (entry_ctx
, ASSUAN_NO_WAITPID
, 1);
1119 kill (pid
, SIGKILL
); /* Need to use SIGKILL due to bad
1120 interaction of SIGINT with Pth. */
1123 /* Now wait for the thread to terminate. */
1124 rc
= pth_join (popup_tid
, NULL
);
1126 log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
1131 /* Now we can close the connection. */
1132 unlock_pinentry (0);