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_disconnect (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
;
175 gcry_control (GCRYCTL_TERM_SECMEM
);
176 if (ctrl
->xauthority
)
177 setenv ("XAUTHORITY", ctrl
->xauthority
, 1);
178 if (ctrl
->pinentry_user_data
)
179 setenv ("PINENTRY_USER_DATA", ctrl
->pinentry_user_data
, 1 );
184 getinfo_pid_cb (void *opaque
, const void *buffer
, size_t length
)
186 unsigned long *pid
= opaque
;
189 /* There is only the pid in the server's response. */
190 if (length
>= sizeof pidbuf
)
191 length
= sizeof pidbuf
-1;
194 strncpy (pidbuf
, buffer
, length
);
196 *pid
= strtoul (pidbuf
, NULL
, 10);
201 /* Fork off the pin entry if this has not already been done. Note,
202 that this function must always be used to aquire the lock for the
203 pinentry - we will serialize _all_ pinentry calls.
206 start_pinentry (ctrl_t ctrl
)
210 assuan_context_t ctx
;
212 int no_close_list
[3];
216 unsigned long pinentry_pid
;
218 evt
= pth_event (PTH_EVENT_TIME
, pth_timeout (LOCK_TIMEOUT
, 0));
219 if (!pth_mutex_acquire (&entry_lock
, 0, evt
))
221 if (pth_event_occurred (evt
))
222 rc
= gpg_error (GPG_ERR_TIMEOUT
);
224 rc
= gpg_error (GPG_ERR_INTERNAL
);
225 pth_event_free (evt
, PTH_FREE_THIS
);
226 log_error (_("failed to acquire the pinentry lock: %s\n"),
230 pth_event_free (evt
, PTH_FREE_THIS
);
238 log_info ("starting a new PIN Entry\n");
240 #ifdef HAVE_W32_SYSTEM
246 #ifndef HAVE_W32_SYSTEM
247 gpg_error_t tmperr
= gpg_error (gpg_err_code_from_errno (errno
));
249 log_error ("error flushing pending output: %s\n", strerror (errno
));
250 /* At least Windows XP fails here with EBADF. According to docs
251 and Wine an fflush(NULL) is the same as _flushall. However
252 the Wime implementaion does not flush stdin,stdout and stderr
253 - see above. Lets try to ignore the error. */
254 #ifndef HAVE_W32_SYSTEM
255 return unlock_pinentry (tmperr
);
259 if (!opt
.pinentry_program
|| !*opt
.pinentry_program
)
260 opt
.pinentry_program
= gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY
);
261 pgmname
= opt
.pinentry_program
;
262 if ( !(pgmname
= strrchr (opt
.pinentry_program
, '/')))
263 pgmname
= opt
.pinentry_program
;
267 /* OS X needs the entire file name in argv[0], so that it can locate
268 the resource bundle. For other systems we stick to the usual
269 convention of supplying only the name of the program. */
271 argv
[0] = opt
.pinentry_program
;
276 if (ctrl
->display
&& !opt
.keep_display
)
278 argv
[1] = "--display";
279 argv
[2] = ctrl
->display
;
286 if (!opt
.running_detached
)
288 if (log_get_fd () != -1)
289 no_close_list
[i
++] = log_get_fd ();
290 no_close_list
[i
++] = fileno (stderr
);
292 no_close_list
[i
] = -1;
294 /* Connect to the pinentry and perform initial handshaking. Note
295 that atfork is used to change the environment for pinentry. We
296 start the server in detached mode to suppress the console window
298 rc
= assuan_pipe_connect_ext (&ctx
, opt
.pinentry_program
, argv
,
299 no_close_list
, atfork_cb
, ctrl
, 128);
302 log_error ("can't connect to the PIN entry module: %s\n",
304 return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY
));
309 log_debug ("connection to PIN entry established\n");
311 rc
= assuan_transact (entry_ctx
,
312 opt
.no_grab
? "OPTION no-grab":"OPTION grab",
313 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
315 return unlock_pinentry (rc
);
319 if (asprintf (&optstr
, "OPTION ttyname=%s", ctrl
->ttyname
) < 0 )
320 return unlock_pinentry (out_of_core ());
321 rc
= assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
325 return unlock_pinentry (rc
);
330 if (asprintf (&optstr
, "OPTION ttytype=%s", ctrl
->ttytype
) < 0 )
331 return unlock_pinentry (out_of_core ());
332 rc
= assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
335 return unlock_pinentry (rc
);
340 if (asprintf (&optstr
, "OPTION lc-ctype=%s", ctrl
->lc_ctype
) < 0 )
341 return unlock_pinentry (out_of_core ());
342 rc
= assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
345 return unlock_pinentry (rc
);
347 if (ctrl
->lc_messages
)
350 if (asprintf (&optstr
, "OPTION lc-messages=%s", ctrl
->lc_messages
) < 0 )
351 return unlock_pinentry (out_of_core ());
352 rc
= assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
355 return unlock_pinentry (rc
);
359 /* Tell the pinentry the name of a file it shall touch after having
360 messed with the tty. This is optional and only supported by
361 newer pinentries and thus we do no error checking. */
362 tmpstr
= opt
.pinentry_touch_file
;
363 if (tmpstr
&& !strcmp (tmpstr
, "/dev/null"))
366 tmpstr
= get_agent_socket_name ();
371 if (asprintf (&optstr
, "OPTION touch-file=%s", tmpstr
) < 0 )
375 assuan_transact (entry_ctx
, optstr
, NULL
, NULL
, NULL
, NULL
, NULL
,
382 /* Now ask the Pinentry for its PID. If the Pinentry is new enough
383 it will send the pid back and we will use an inquire to notify
384 our client. The client may answer the inquiry either with END or
385 with CAN to cancel the pinentry. */
386 rc
= assuan_transact (entry_ctx
, "GETINFO pid",
387 getinfo_pid_cb
, &pinentry_pid
,
388 NULL
, NULL
, NULL
, NULL
);
391 log_info ("You may want to update to a newer pinentry\n");
394 else if (!rc
&& (pid_t
)pinentry_pid
== (pid_t
)(-1))
395 log_error ("pinentry did not return a PID\n");
398 rc
= agent_inq_pinentry_launched (ctrl
, pinentry_pid
);
399 if (gpg_err_code (rc
) == GPG_ERR_CANCELED
)
400 return unlock_pinentry (gpg_error (GPG_ERR_CANCELED
));
408 /* Returns True is the pinentry is currently active. If WAITSECONDS is
409 greater than zero the function will wait for this many seconds
412 pinentry_active_p (ctrl_t ctrl
, int waitseconds
)
421 evt
= pth_event (PTH_EVENT_TIME
, pth_timeout (waitseconds
, 0));
422 if (!pth_mutex_acquire (&entry_lock
, 0, evt
))
424 if (pth_event_occurred (evt
))
425 rc
= gpg_error (GPG_ERR_TIMEOUT
);
427 rc
= gpg_error (GPG_ERR_INTERNAL
);
428 pth_event_free (evt
, PTH_FREE_THIS
);
431 pth_event_free (evt
, PTH_FREE_THIS
);
435 if (!pth_mutex_acquire (&entry_lock
, 1, NULL
))
436 return gpg_error (GPG_ERR_LOCKED
);
439 if (!pth_mutex_release (&entry_lock
))
440 log_error ("failed to release the entry lock at %d\n", __LINE__
);
446 getpin_cb (void *opaque
, const void *buffer
, size_t length
)
448 struct entry_parm_s
*parm
= opaque
;
453 /* we expect the pin to fit on one line */
454 if (parm
->lines
|| length
>= parm
->size
)
455 return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA
);
457 /* fixme: we should make sure that the assuan buffer is allocated in
458 secure memory or read the response byte by byte */
459 memcpy (parm
->buffer
, buffer
, length
);
460 parm
->buffer
[length
] = 0;
467 all_digitsp( const char *s
)
469 for (; *s
&& *s
>= '0' && *s
<= '9'; s
++)
475 /* Return a new malloced string by unescaping the string S. Escaping
476 is percent escaping and '+'/space mapping. A binary Nul will
477 silently be replaced by a 0xFF. Function returns NULL to indicate
478 an out of memory status. PArsing stops at the end of the string or
479 a white space character. */
481 unescape_passphrase_string (const unsigned char *s
)
485 buffer
= d
= xtrymalloc_secure (strlen ((const char*)s
)+1);
488 while (*s
&& !spacep (s
))
490 if (*s
== '%' && s
[1] && s
[2])
512 /* Estimate the quality of the passphrase PW and return a value in the
515 estimate_passphrase_quality (const char *pw
)
517 int goodlength
= opt
.min_passphrase_len
+ opt
.min_passphrase_len
/3;
524 for (length
= 0, s
= pw
; *s
; s
++)
528 if (length
> goodlength
)
530 return ((length
*10) / goodlength
)*10;
534 /* Handle the QUALITY inquiry. */
536 inq_quality (void *opaque
, const char *line
)
538 assuan_context_t ctx
= opaque
;
544 if (!strncmp (line
, "QUALITY", 7) && (line
[7] == ' ' || !line
[7]))
550 pin
= unescape_passphrase_string (line
);
552 rc
= gpg_error_from_syserror ();
555 percent
= estimate_passphrase_quality (pin
);
556 if (check_passphrase_constraints (NULL
, pin
, 1))
558 snprintf (numbuf
, sizeof numbuf
, "%d", percent
);
559 rc
= assuan_send_data (ctx
, numbuf
, strlen (numbuf
));
565 log_error ("unsupported inquiry `%s' from pinentry\n", line
);
566 rc
= gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE
);
576 /* Call the Entry and ask for the PIN. We do check for a valid PIN
577 number here and repeat it as long as we have invalid formed
580 agent_askpin (ctrl_t ctrl
,
581 const char *desc_text
, const char *prompt_text
,
582 const char *initial_errtext
,
583 struct pin_entry_info_s
*pininfo
)
586 char line
[ASSUAN_LINELENGTH
];
587 struct entry_parm_s parm
;
588 const char *errtext
= NULL
;
592 return 0; /* fixme: we should return BAD PIN */
594 if (!pininfo
|| pininfo
->max_length
< 1)
595 return gpg_error (GPG_ERR_INV_VALUE
);
596 if (!desc_text
&& pininfo
->min_digits
)
597 desc_text
= _("Please enter your PIN, so that the secret key "
598 "can be unlocked for this session");
600 desc_text
= _("Please enter your passphrase, so that the secret key "
601 "can be unlocked for this session");
604 is_pin
= !!strstr (prompt_text
, "PIN");
606 is_pin
= desc_text
&& strstr (desc_text
, "PIN");
608 rc
= start_pinentry (ctrl
);
612 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc_text
);
613 line
[DIM(line
)-1] = 0;
614 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
616 return unlock_pinentry (rc
);
618 snprintf (line
, DIM(line
)-1, "SETPROMPT %s",
619 prompt_text
? prompt_text
: is_pin
? "PIN:" : "Passphrase:");
620 line
[DIM(line
)-1] = 0;
621 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
623 return unlock_pinentry (rc
);
625 /* If a passphrase quality indicator has been requested and a
626 minimum passphrase length has not been disabled, send the command
628 if (pininfo
->with_qualitybar
&& opt
.min_passphrase_len
)
630 char *tmpstr
, *tmpstr2
;
633 /* TRANSLATORS: This string is displayed by pinentry as the
634 label for the quality bar. */
635 tmpstr
= try_percent_escape (_("Quality:"), "\t\r\n\f\v");
636 snprintf (line
, DIM(line
)-1, "SETQUALITYBAR %s", tmpstr
? tmpstr
:"");
637 line
[DIM(line
)-1] = 0;
639 rc
= assuan_transact (entry_ctx
, line
,
640 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
641 if (rc
== 103 /*(Old assuan error code)*/
642 || gpg_err_code (rc
) == GPG_ERR_ASS_UNKNOWN_CMD
)
643 ; /* Ignore Unknown Command from old pinentry versions. */
645 return unlock_pinentry (rc
);
647 tmpstr2
= gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
652 /* TRANSLATORS: This string is a tooltip, shown by pinentry
653 when hovering over the quality bar. Please use an
654 appropriate string to describe what this is about. The
655 length of the tooltip is limited to about 900 characters.
656 If you do not translate this entry, a default english
657 text (see source) will be used. */
658 tooltip
= _("pinentry.qualitybar.tooltip");
659 if (!strcmp ("pinentry.qualitybar.tooltip", tooltip
))
660 tooltip
= ("The quality of the text entered above.\n"
661 "Please ask your administrator for "
662 "details about the criteria.");
664 tmpstr
= try_percent_escape (tooltip
, "\t\r\n\f\v");
666 snprintf (line
, DIM(line
)-1, "SETQUALITYBAR_TT %s", tmpstr
? tmpstr
:"");
667 line
[DIM(line
)-1] = 0;
669 rc
= assuan_transact (entry_ctx
, line
,
670 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
671 if (rc
== 103 /*(Old assuan error code)*/
672 || gpg_err_code (rc
) == GPG_ERR_ASS_UNKNOWN_CMD
)
673 ; /* Ignore Unknown Command from old pinentry versions. */
675 return unlock_pinentry (rc
);
680 snprintf (line
, DIM(line
)-1, "SETERROR %s", initial_errtext
);
681 line
[DIM(line
)-1] = 0;
682 rc
= assuan_transact (entry_ctx
, line
,
683 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
685 return unlock_pinentry (rc
);
688 for (;pininfo
->failed_tries
< pininfo
->max_tries
; pininfo
->failed_tries
++)
690 memset (&parm
, 0, sizeof parm
);
691 parm
.size
= pininfo
->max_length
;
692 *pininfo
->pin
= 0; /* Reset the PIN. */
693 parm
.buffer
= (unsigned char*)pininfo
->pin
;
697 /* TRANLATORS: The string is appended to an error message in
698 the pinentry. The %s is the actual error message, the
699 two %d give the current and maximum number of tries. */
700 snprintf (line
, DIM(line
)-1, _("SETERROR %s (try %d of %d)"),
701 errtext
, pininfo
->failed_tries
+1, pininfo
->max_tries
);
702 line
[DIM(line
)-1] = 0;
703 rc
= assuan_transact (entry_ctx
, line
,
704 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
706 return unlock_pinentry (rc
);
710 rc
= assuan_transact (entry_ctx
, "GETPIN", getpin_cb
, &parm
,
711 inq_quality
, entry_ctx
, NULL
, NULL
);
712 /* Most pinentries out in the wild return the old Assuan error code
713 for canceled which gets translated to an assuan Cancel error and
714 not to the code for a user cancel. Fix this here. */
715 if (rc
&& gpg_err_source (rc
)
716 && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
717 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
719 if (gpg_err_code (rc
) == GPG_ERR_ASS_TOO_MUCH_DATA
)
720 errtext
= is_pin
? _("PIN too long")
721 : _("Passphrase too long");
723 return unlock_pinentry (rc
);
725 if (!errtext
&& pininfo
->min_digits
)
727 /* do some basic checks on the entered PIN. */
728 if (!all_digitsp (pininfo
->pin
))
729 errtext
= _("Invalid characters in PIN");
730 else if (pininfo
->max_digits
731 && strlen (pininfo
->pin
) > pininfo
->max_digits
)
732 errtext
= _("PIN too long");
733 else if (strlen (pininfo
->pin
) < pininfo
->min_digits
)
734 errtext
= _("PIN too short");
737 if (!errtext
&& pininfo
->check_cb
)
739 /* More checks by utilizing the optional callback. */
740 pininfo
->cb_errtext
= NULL
;
741 rc
= pininfo
->check_cb (pininfo
);
742 if (rc
== -1 && pininfo
->cb_errtext
)
743 errtext
= pininfo
->cb_errtext
;
744 else if (gpg_err_code (rc
) == GPG_ERR_BAD_PASSPHRASE
745 || gpg_err_code (rc
) == GPG_ERR_BAD_PIN
)
746 errtext
= (is_pin
? _("Bad PIN")
747 : _("Bad Passphrase"));
749 return unlock_pinentry (rc
);
753 return unlock_pinentry (0); /* okay, got a PIN or passphrase */
756 return unlock_pinentry (gpg_error (pininfo
->min_digits
? GPG_ERR_BAD_PIN
757 : GPG_ERR_BAD_PASSPHRASE
));
762 /* Ask for the passphrase using the supplied arguments. The returned
763 passphrase needs to be freed by the caller. */
765 agent_get_passphrase (ctrl_t ctrl
,
766 char **retpass
, const char *desc
, const char *prompt
,
771 char line
[ASSUAN_LINELENGTH
];
772 struct entry_parm_s parm
;
776 return gpg_error (GPG_ERR_BAD_PASSPHRASE
);
778 rc
= start_pinentry (ctrl
);
783 prompt
= desc
&& strstr (desc
, "PIN")? "PIN": _("Passphrase");
787 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc
);
789 snprintf (line
, DIM(line
)-1, "RESET");
790 line
[DIM(line
)-1] = 0;
791 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
793 return unlock_pinentry (rc
);
795 snprintf (line
, DIM(line
)-1, "SETPROMPT %s", prompt
);
796 line
[DIM(line
)-1] = 0;
797 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
799 return unlock_pinentry (rc
);
803 snprintf (line
, DIM(line
)-1, "SETERROR %s", errtext
);
804 line
[DIM(line
)-1] = 0;
805 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
807 return unlock_pinentry (rc
);
810 memset (&parm
, 0, sizeof parm
);
811 parm
.size
= ASSUAN_LINELENGTH
/2 - 5;
812 parm
.buffer
= gcry_malloc_secure (parm
.size
+10);
814 return unlock_pinentry (out_of_core ());
816 assuan_begin_confidential (entry_ctx
);
817 rc
= assuan_transact (entry_ctx
, "GETPIN", getpin_cb
, &parm
,
818 NULL
, NULL
, NULL
, NULL
);
819 /* Most pinentries out in the wild return the old Assuan error code
820 for canceled which gets translated to an assuan Cancel error and
821 not to the code for a user cancel. Fix this here. */
822 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
823 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
827 *retpass
= parm
.buffer
;
828 return unlock_pinentry (rc
);
833 /* Pop up the PIN-entry, display the text and the prompt and ask the
834 user to confirm this. We return 0 for success, ie. the user
835 confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
838 agent_get_confirmation (ctrl_t ctrl
,
839 const char *desc
, const char *ok
, const char *cancel
)
842 char line
[ASSUAN_LINELENGTH
];
844 rc
= start_pinentry (ctrl
);
849 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc
);
851 snprintf (line
, DIM(line
)-1, "RESET");
852 line
[DIM(line
)-1] = 0;
853 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
854 /* Most pinentries out in the wild return the old Assuan error code
855 for canceled which gets translated to an assuan Cancel error and
856 not to the code for a user cancel. Fix this here. */
857 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
858 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
861 return unlock_pinentry (rc
);
865 snprintf (line
, DIM(line
)-1, "SETOK %s", ok
);
866 line
[DIM(line
)-1] = 0;
867 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
869 return unlock_pinentry (rc
);
873 snprintf (line
, DIM(line
)-1, "SETCANCEL %s", cancel
);
874 line
[DIM(line
)-1] = 0;
875 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
877 return unlock_pinentry (rc
);
880 rc
= assuan_transact (entry_ctx
, "CONFIRM", NULL
, NULL
, NULL
, 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
);
889 /* Pop up the PINentry, display the text DESC and a button with the
890 text OK_BTN (which may be NULL to use the default of "OK") and waut
891 for the user to hit this button. The return value is not
894 agent_show_message (ctrl_t ctrl
, const char *desc
, const char *ok_btn
)
897 char line
[ASSUAN_LINELENGTH
];
899 rc
= start_pinentry (ctrl
);
904 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc
);
906 snprintf (line
, DIM(line
)-1, "RESET");
907 line
[DIM(line
)-1] = 0;
908 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
909 /* Most pinentries out in the wild return the old Assuan error code
910 for canceled which gets translated to an assuan Cancel error and
911 not to the code for a user cancel. Fix this here. */
912 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
913 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
916 return unlock_pinentry (rc
);
920 snprintf (line
, DIM(line
)-1, "SETOK %s", ok_btn
);
921 line
[DIM(line
)-1] = 0;
922 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
,
925 return unlock_pinentry (rc
);
928 rc
= assuan_transact (entry_ctx
, "CONFIRM --one-button", NULL
, NULL
, NULL
,
930 if (rc
&& gpg_err_source (rc
) && gpg_err_code (rc
) == GPG_ERR_ASS_CANCELED
)
931 rc
= gpg_err_make (gpg_err_source (rc
), GPG_ERR_CANCELED
);
933 return unlock_pinentry (rc
);
937 /* The thread running the popup message. */
939 popup_message_thread (void *arg
)
943 /* We use the --one-button hack instead of the MESSAGE command to
944 allow the use of old Pinentries. Those old Pinentries will then
945 show an additional Cancel button but that is mostly a visual
947 assuan_transact (entry_ctx
, "CONFIRM --one-button",
948 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
954 /* Pop up a message window similar to the confirm one but keep it open
955 until agent_popup_message_stop has been called. It is crucial for
956 the caller to make sure that the stop function gets called as soon
957 as the message is not anymore required because the message is
958 system modal and all other attempts to use the pinentry will fail
959 (after a timeout). */
961 agent_popup_message_start (ctrl_t ctrl
, const char *desc
, const char *ok_btn
)
964 char line
[ASSUAN_LINELENGTH
];
967 rc
= start_pinentry (ctrl
);
972 snprintf (line
, DIM(line
)-1, "SETDESC %s", desc
);
974 snprintf (line
, DIM(line
)-1, "RESET");
975 line
[DIM(line
)-1] = 0;
976 rc
= assuan_transact (entry_ctx
, line
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
978 return unlock_pinentry (rc
);
982 snprintf (line
, DIM(line
)-1, "SETOK %s", ok_btn
);
983 line
[DIM(line
)-1] = 0;
984 rc
= assuan_transact (entry_ctx
, line
, NULL
,NULL
,NULL
,NULL
,NULL
,NULL
);
986 return unlock_pinentry (rc
);
989 tattr
= pth_attr_new();
990 pth_attr_set (tattr
, PTH_ATTR_JOINABLE
, 1);
991 pth_attr_set (tattr
, PTH_ATTR_STACK_SIZE
, 256*1024);
992 pth_attr_set (tattr
, PTH_ATTR_NAME
, "popup-message");
995 popup_tid
= pth_spawn (tattr
, popup_message_thread
, NULL
);
998 rc
= gpg_error_from_syserror ();
999 log_error ("error spawning popup message handler: %s\n",
1001 pth_attr_destroy (tattr
);
1002 return unlock_pinentry (rc
);
1004 pth_attr_destroy (tattr
);
1009 /* Close a popup window. */
1011 agent_popup_message_stop (ctrl_t ctrl
)
1018 if (!popup_tid
|| !entry_ctx
)
1020 log_debug ("agent_popup_message_stop called with no active popup\n");
1024 pid
= assuan_get_pid (entry_ctx
);
1025 if (pid
== (pid_t
)(-1))
1026 ; /* No pid available can't send a kill. */
1027 else if (popup_finished
)
1028 ; /* Already finished and ready for joining. */
1029 #ifdef HAVE_W32_SYSTEM
1030 /* Older versions of assuan set PID to 0 on Windows to indicate an
1032 else if (pid
!= (pid_t
) INVALID_HANDLE_VALUE
1035 HANDLE process
= (HANDLE
) pid
;
1037 /* Arbitrary error code. */
1038 TerminateProcess (process
, 1);
1041 else if (pid
&& ((rc
=waitpid (pid
, NULL
, WNOHANG
))==-1 || (rc
== pid
)) )
1042 { /* The daemon already died. No need to send a kill. However
1043 because we already waited for the process, we need to tell
1044 assuan that it should not wait again (done by
1045 unlock_pinentry). */
1047 assuan_set_flag (entry_ctx
, ASSUAN_NO_WAITPID
, 1);
1050 kill (pid
, SIGKILL
); /* Need to use SIGKILL due to bad
1051 interaction of SIGINT with Pth. */
1054 /* Now wait for the thread to terminate. */
1055 rc
= pth_join (popup_tid
, NULL
);
1057 log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
1062 /* Now we can close the connection. */
1063 unlock_pinentry (0);