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)
108
log_printf ("unknown under W32");
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");
115
log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
120
/* This function may be called to print infromation pertaining to the
121
current state of this module to the log. */
123
agent_query_dump_state (void)
125
log_info ("agent_query_dump_state: entry_lock=");
126
dump_mutex_state (&entry_lock);
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);
132
/* Called to make sure that a popup window owned by the current
133
connection gets closed. */
135
agent_reset_query (ctrl_t ctrl)
137
if (entry_ctx && popup_tid && entry_owner == ctrl)
139
agent_popup_message_stop (ctrl);
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. */
149
unlock_pinentry (int rc)
151
assuan_context_t ctx = entry_ctx;
154
if (!pth_mutex_release (&entry_lock))
156
log_error ("failed to release the entry lock\n");
158
rc = gpg_error (GPG_ERR_INTERNAL);
160
assuan_disconnect (ctx);
165
/* To make sure we leave no secrets in our image after forking of the
166
pinentry, we use this callback. */
168
atfork_cb (void *opaque, int where)
170
ctrl_t ctrl = opaque;
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 );
183
getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
185
unsigned long *pid = opaque;
188
/* There is only the pid in the server's response. */
189
if (length >= sizeof pidbuf)
190
length = sizeof pidbuf -1;
193
strncpy (pidbuf, buffer, length);
195
*pid = strtoul (pidbuf, NULL, 10);
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.
205
start_pinentry (ctrl_t ctrl)
209
assuan_context_t ctx;
211
int no_close_list[3];
215
unsigned long pinentry_pid;
217
evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
218
if (!pth_mutex_acquire (&entry_lock, 0, evt))
220
if (pth_event_occurred (evt))
221
rc = gpg_error (GPG_ERR_TIMEOUT);
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"),
229
pth_event_free (evt, PTH_FREE_THIS);
237
log_info ("starting a new PIN Entry\n");
239
#ifdef HAVE_W32_SYSTEM
245
#ifndef HAVE_W32_SYSTEM
246
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
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);
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;
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. */
270
argv[0] = opt.pinentry_program;
275
if (ctrl->display && !opt.keep_display)
277
argv[1] = "--display";
278
argv[2] = ctrl->display;
285
if (!opt.running_detached)
287
if (log_get_fd () != -1)
288
no_close_list[i++] = log_get_fd ();
289
no_close_list[i++] = fileno (stderr);
291
no_close_list[i] = -1;
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
297
rc = assuan_pipe_connect_ext (&ctx, opt.pinentry_program, argv,
298
no_close_list, atfork_cb, ctrl, 128);
301
log_error ("can't connect to the PIN entry module: %s\n",
303
return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
308
log_debug ("connection to PIN entry established\n");
310
rc = assuan_transact (entry_ctx,
311
opt.no_grab? "OPTION no-grab":"OPTION grab",
312
NULL, NULL, NULL, NULL, NULL, NULL);
314
return unlock_pinentry (rc);
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,
324
return unlock_pinentry (rc);
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,
334
return unlock_pinentry (rc);
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,
344
return unlock_pinentry (rc);
346
if (ctrl->lc_messages)
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,
354
return unlock_pinentry (rc);
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"))
365
tmpstr = get_agent_socket_name ();
370
if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
374
assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
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);
390
log_info ("You may want to update to a newer pinentry\n");
393
else if (!rc && (pid_t)pinentry_pid == (pid_t)(-1))
394
log_error ("pinentry did not return a PID\n");
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));
407
/* Returns True is the pinentry is currently active. If WAITSECONDS is
408
greater than zero the function will wait for this many seconds
411
pinentry_active_p (ctrl_t ctrl, int waitseconds)
418
evt = pth_event (PTH_EVENT_TIME, pth_timeout (waitseconds, 0));
419
if (!pth_mutex_acquire (&entry_lock, 0, evt))
421
if (pth_event_occurred (evt))
422
rc = gpg_error (GPG_ERR_TIMEOUT);
424
rc = gpg_error (GPG_ERR_INTERNAL);
425
pth_event_free (evt, PTH_FREE_THIS);
428
pth_event_free (evt, PTH_FREE_THIS);
432
if (!pth_mutex_acquire (&entry_lock, 1, NULL))
433
return gpg_error (GPG_ERR_LOCKED);
436
if (!pth_mutex_release (&entry_lock))
437
log_error ("failed to release the entry lock at %d\n", __LINE__);
443
getpin_cb (void *opaque, const void *buffer, size_t length)
445
struct entry_parm_s *parm = opaque;
450
/* we expect the pin to fit on one line */
451
if (parm->lines || length >= parm->size)
452
return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
454
/* fixme: we should make sure that the assuan buffer is allocated in
455
secure memory or read the response byte by byte */
456
memcpy (parm->buffer, buffer, length);
457
parm->buffer[length] = 0;
464
all_digitsp( const char *s)
466
for (; *s && *s >= '0' && *s <= '9'; s++)
472
/* Return a new malloced string by unescaping the string S. Escaping
473
is percent escaping and '+'/space mapping. A binary Nul will
474
silently be replaced by a 0xFF. Function returns NULL to indicate
475
an out of memory status. PArsing stops at the end of the string or
476
a white space character. */
478
unescape_passphrase_string (const unsigned char *s)
482
buffer = d = xtrymalloc_secure (strlen ((const char*)s)+1);
485
while (*s && !spacep (s))
487
if (*s == '%' && s[1] && s[2])
509
/* Estimate the quality of the passphrase PW and return a value in the
512
estimate_passphrase_quality (const char *pw)
514
int goodlength = opt.min_passphrase_len + opt.min_passphrase_len/3;
521
for (length = 0, s = pw; *s; s++)
525
if (length > goodlength)
527
return ((length*10) / goodlength)*10;
531
/* Handle the QUALITY inquiry. */
533
inq_quality (void *opaque, const char *line)
535
assuan_context_t ctx = opaque;
541
if (!strncmp (line, "QUALITY", 7) && (line[7] == ' ' || !line[7]))
547
pin = unescape_passphrase_string (line);
549
rc = gpg_error_from_syserror ();
552
percent = estimate_passphrase_quality (pin);
553
if (check_passphrase_constraints (NULL, pin, 1))
555
snprintf (numbuf, sizeof numbuf, "%d", percent);
556
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
562
log_error ("unsupported inquiry `%s' from pinentry\n", line);
563
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
573
/* Call the Entry and ask for the PIN. We do check for a valid PIN
574
number here and repeat it as long as we have invalid formed
577
agent_askpin (ctrl_t ctrl,
578
const char *desc_text, const char *prompt_text,
579
const char *initial_errtext,
580
struct pin_entry_info_s *pininfo)
583
char line[ASSUAN_LINELENGTH];
584
struct entry_parm_s parm;
585
const char *errtext = NULL;
589
return 0; /* fixme: we should return BAD PIN */
591
if (!pininfo || pininfo->max_length < 1)
592
return gpg_error (GPG_ERR_INV_VALUE);
593
if (!desc_text && pininfo->min_digits)
594
desc_text = _("Please enter your PIN, so that the secret key "
595
"can be unlocked for this session");
597
desc_text = _("Please enter your passphrase, so that the secret key "
598
"can be unlocked for this session");
601
is_pin = !!strstr (prompt_text, "PIN");
603
is_pin = desc_text && strstr (desc_text, "PIN");
605
rc = start_pinentry (ctrl);
609
snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
610
line[DIM(line)-1] = 0;
611
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
613
return unlock_pinentry (rc);
615
snprintf (line, DIM(line)-1, "SETPROMPT %s",
616
prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
617
line[DIM(line)-1] = 0;
618
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
620
return unlock_pinentry (rc);
622
/* If a passphrase quality indicator has been requested and a
623
minimum passphrase length has not been disabled, send the command
625
if (pininfo->with_qualitybar && opt.min_passphrase_len )
627
char *tmpstr, *tmpstr2;
630
/* TRANSLATORS: This string is displayed by pinentry as the
631
label for the quality bar. */
632
tmpstr = try_percent_escape (_("Quality:"), "\t\r\n\f\v");
633
snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
634
line[DIM(line)-1] = 0;
636
rc = assuan_transact (entry_ctx, line,
637
NULL, NULL, NULL, NULL, NULL, NULL);
638
if (rc == 103 /*(Old assuan error code)*/
639
|| gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
640
; /* Ignore Unknown Command from old pinentry versions. */
642
return unlock_pinentry (rc);
644
tmpstr2 = gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
649
/* TRANSLATORS: This string is a tooltip, shown by pinentry
650
when hovering over the quality bar. Please use an
651
appropriate string to describe what this is about. The
652
length of the tooltip is limited to about 900 characters.
653
If you do not translate this entry, a default english
654
text (see source) will be used. */
655
tooltip = _("pinentry.qualitybar.tooltip");
656
if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
657
tooltip = ("The quality of the text entered above.\n"
658
"Please ask your administrator for "
659
"details about the criteria.");
661
tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
663
snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
664
line[DIM(line)-1] = 0;
666
rc = assuan_transact (entry_ctx, line,
667
NULL, NULL, NULL, NULL, NULL, NULL);
668
if (rc == 103 /*(Old assuan error code)*/
669
|| gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
670
; /* Ignore Unknown Command from old pinentry versions. */
672
return unlock_pinentry (rc);
677
snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
678
line[DIM(line)-1] = 0;
679
rc = assuan_transact (entry_ctx, line,
680
NULL, NULL, NULL, NULL, NULL, NULL);
682
return unlock_pinentry (rc);
685
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
687
memset (&parm, 0, sizeof parm);
688
parm.size = pininfo->max_length;
689
*pininfo->pin = 0; /* Reset the PIN. */
690
parm.buffer = (unsigned char*)pininfo->pin;
694
/* TRANLATORS: The string is appended to an error message in
695
the pinentry. The %s is the actual error message, the
696
two %d give the current and maximum number of tries. */
697
snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"),
698
errtext, pininfo->failed_tries+1, pininfo->max_tries);
699
line[DIM(line)-1] = 0;
700
rc = assuan_transact (entry_ctx, line,
701
NULL, NULL, NULL, NULL, NULL, NULL);
703
return unlock_pinentry (rc);
707
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
708
inq_quality, entry_ctx, NULL, NULL);
709
/* Most pinentries out in the wild return the old Assuan error code
710
for canceled which gets translated to an assuan Cancel error and
711
not to the code for a user cancel. Fix this here. */
712
if (rc && gpg_err_source (rc)
713
&& gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
714
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
716
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
717
errtext = is_pin? _("PIN too long")
718
: _("Passphrase too long");
720
return unlock_pinentry (rc);
722
if (!errtext && pininfo->min_digits)
724
/* do some basic checks on the entered PIN. */
725
if (!all_digitsp (pininfo->pin))
726
errtext = _("Invalid characters in PIN");
727
else if (pininfo->max_digits
728
&& strlen (pininfo->pin) > pininfo->max_digits)
729
errtext = _("PIN too long");
730
else if (strlen (pininfo->pin) < pininfo->min_digits)
731
errtext = _("PIN too short");
734
if (!errtext && pininfo->check_cb)
736
/* More checks by utilizing the optional callback. */
737
pininfo->cb_errtext = NULL;
738
rc = pininfo->check_cb (pininfo);
739
if (rc == -1 && pininfo->cb_errtext)
740
errtext = pininfo->cb_errtext;
741
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
742
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
743
errtext = (is_pin? _("Bad PIN")
744
: _("Bad Passphrase"));
746
return unlock_pinentry (rc);
750
return unlock_pinentry (0); /* okay, got a PIN or passphrase */
753
return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
754
: GPG_ERR_BAD_PASSPHRASE));
759
/* Ask for the passphrase using the supplied arguments. The returned
760
passphrase needs to be freed by the caller. */
762
agent_get_passphrase (ctrl_t ctrl,
763
char **retpass, const char *desc, const char *prompt,
768
char line[ASSUAN_LINELENGTH];
769
struct entry_parm_s parm;
773
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
775
rc = start_pinentry (ctrl);
780
prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
784
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
786
snprintf (line, DIM(line)-1, "RESET");
787
line[DIM(line)-1] = 0;
788
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
790
return unlock_pinentry (rc);
792
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
793
line[DIM(line)-1] = 0;
794
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
796
return unlock_pinentry (rc);
800
snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
801
line[DIM(line)-1] = 0;
802
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
804
return unlock_pinentry (rc);
807
memset (&parm, 0, sizeof parm);
808
parm.size = ASSUAN_LINELENGTH/2 - 5;
809
parm.buffer = gcry_malloc_secure (parm.size+10);
811
return unlock_pinentry (out_of_core ());
813
assuan_begin_confidential (entry_ctx);
814
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
815
NULL, NULL, NULL, NULL);
816
/* Most pinentries out in the wild return the old Assuan error code
817
for canceled which gets translated to an assuan Cancel error and
818
not to the code for a user cancel. Fix this here. */
819
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
820
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
824
*retpass = parm.buffer;
825
return unlock_pinentry (rc);
830
/* Pop up the PIN-entry, display the text and the prompt and ask the
831
user to confirm this. We return 0 for success, ie. the user
832
confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
835
agent_get_confirmation (ctrl_t ctrl,
836
const char *desc, const char *ok, const char *cancel)
839
char line[ASSUAN_LINELENGTH];
841
rc = start_pinentry (ctrl);
846
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
848
snprintf (line, DIM(line)-1, "RESET");
849
line[DIM(line)-1] = 0;
850
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
851
/* Most pinentries out in the wild return the old Assuan error code
852
for canceled which gets translated to an assuan Cancel error and
853
not to the code for a user cancel. Fix this here. */
854
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
855
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
858
return unlock_pinentry (rc);
862
snprintf (line, DIM(line)-1, "SETOK %s", ok);
863
line[DIM(line)-1] = 0;
864
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
866
return unlock_pinentry (rc);
870
snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
871
line[DIM(line)-1] = 0;
872
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
874
return unlock_pinentry (rc);
877
rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
878
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
879
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
881
return unlock_pinentry (rc);
886
/* Pop up the PINentry, display the text DESC and a button with the
887
text OK_BTN (which may be NULL to use the default of "OK") and waut
888
for the user to hit this button. The return value is not
891
agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
894
char line[ASSUAN_LINELENGTH];
896
rc = start_pinentry (ctrl);
901
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
903
snprintf (line, DIM(line)-1, "RESET");
904
line[DIM(line)-1] = 0;
905
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
906
/* Most pinentries out in the wild return the old Assuan error code
907
for canceled which gets translated to an assuan Cancel error and
908
not to the code for a user cancel. Fix this here. */
909
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
910
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
913
return unlock_pinentry (rc);
917
snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
918
line[DIM(line)-1] = 0;
919
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
922
return unlock_pinentry (rc);
925
rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
927
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
928
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
930
return unlock_pinentry (rc);
934
/* The thread running the popup message. */
936
popup_message_thread (void *arg)
938
/* We use the --one-button hack instead of the MESSAGE command to
939
allow the use of old Pinentries. Those old Pinentries will then
940
show an additional Cancel button but that is mostly a visual
942
assuan_transact (entry_ctx, "CONFIRM --one-button",
943
NULL, NULL, NULL, NULL, NULL, NULL);
949
/* Pop up a message window similar to the confirm one but keep it open
950
until agent_popup_message_stop has been called. It is crucial for
951
the caller to make sure that the stop function gets called as soon
952
as the message is not anymore required because the message is
953
system modal and all other attempts to use the pinentry will fail
954
(after a timeout). */
956
agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
959
char line[ASSUAN_LINELENGTH];
962
rc = start_pinentry (ctrl);
967
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
969
snprintf (line, DIM(line)-1, "RESET");
970
line[DIM(line)-1] = 0;
971
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
973
return unlock_pinentry (rc);
977
snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
978
line[DIM(line)-1] = 0;
979
rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
981
return unlock_pinentry (rc);
984
tattr = pth_attr_new();
985
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
986
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
987
pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
990
popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
993
rc = gpg_error_from_syserror ();
994
log_error ("error spawning popup message handler: %s\n",
996
pth_attr_destroy (tattr);
997
return unlock_pinentry (rc);
999
pth_attr_destroy (tattr);
1004
/* Close a popup window. */
1006
agent_popup_message_stop (ctrl_t ctrl)
1011
if (!popup_tid || !entry_ctx)
1013
log_debug ("agent_popup_message_stop called with no active popup\n");
1017
pid = assuan_get_pid (entry_ctx);
1018
if (pid == (pid_t)(-1))
1019
; /* No pid available can't send a kill. */
1020
else if (popup_finished)
1021
; /* Already finished and ready for joining. */
1022
#ifdef HAVE_W32_SYSTEM
1023
/* Older versions of assuan set PID to 0 on Windows to indicate an
1025
else if (pid != (pid_t) INVALID_HANDLE_VALUE
1028
HANDLE process = (HANDLE) pid;
1030
/* Arbitrary error code. */
1031
TerminateProcess (process, 1);
1034
else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
1035
{ /* The daemon already died. No need to send a kill. However
1036
because we already waited for the process, we need to tell
1037
assuan that it should not wait again (done by
1038
unlock_pinentry). */
1040
assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
1043
kill (pid, SIGKILL); /* Need to use SIGKILL due to bad
1044
interaction of SIGINT with Pth. */
1047
/* Now wait for the thread to terminate. */
1048
rc = pth_join (popup_tid, NULL);
1050
log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
1055
/* Now we can close the connection. */
1056
unlock_pinentry (0);