Line data Source code
1 : /* call-pinentry.c - Spawn the pinentry to query stuff from the user
2 : * Copyright (C) 2001, 2002, 2004, 2007, 2008,
3 : * 2010 Free Software Foundation, Inc.
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * GnuPG is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <errno.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <ctype.h>
27 : #include <assert.h>
28 : #include <unistd.h>
29 : #include <sys/stat.h>
30 : #ifndef HAVE_W32_SYSTEM
31 : # include <sys/wait.h>
32 : # include <sys/types.h>
33 : # include <signal.h>
34 : #endif
35 : #include <npth.h>
36 :
37 : #include "agent.h"
38 : #include <assuan.h>
39 : #include "sysutils.h"
40 : #include "i18n.h"
41 :
42 : #ifdef _POSIX_OPEN_MAX
43 : #define MAX_OPEN_FDS _POSIX_OPEN_MAX
44 : #else
45 : #define MAX_OPEN_FDS 20
46 : #endif
47 :
48 :
49 : /* Because access to the pinentry must be serialized (it is and shall
50 : be a global mutually exclusive dialog) we better timeout pending
51 : requests after some time. 1 minute seem to be a reasonable
52 : time. */
53 : #define LOCK_TIMEOUT (1*60)
54 :
55 : /* The assuan context of the current pinentry. */
56 : static assuan_context_t entry_ctx;
57 :
58 : /* The control variable of the connection owning the current pinentry.
59 : This is only valid if ENTRY_CTX is not NULL. Note, that we care
60 : only about the value of the pointer and that it should never be
61 : dereferenced. */
62 : static ctrl_t entry_owner;
63 :
64 : /* A mutex used to serialize access to the pinentry. */
65 : static npth_mutex_t entry_lock;
66 :
67 : /* The thread ID of the popup working thread. */
68 : static npth_t popup_tid;
69 :
70 : /* A flag used in communication between the popup working thread and
71 : its stop function. */
72 : static int popup_finished;
73 :
74 :
75 :
76 : /* Data to be passed to our callbacks, */
77 : struct entry_parm_s
78 : {
79 : int lines;
80 : size_t size;
81 : unsigned char *buffer;
82 : };
83 :
84 :
85 :
86 :
87 : /* This function must be called once to initialize this module. This
88 : has to be done before a second thread is spawned. We can't do the
89 : static initialization because Pth emulation code might not be able
90 : to do a static init; in particular, it is not possible for W32. */
91 : void
92 50 : initialize_module_call_pinentry (void)
93 : {
94 : static int initialized;
95 :
96 50 : if (!initialized)
97 : {
98 50 : if (npth_mutex_init (&entry_lock, NULL))
99 0 : initialized = 1;
100 : }
101 50 : }
102 :
103 :
104 :
105 : /* This function may be called to print infromation pertaining to the
106 : current state of this module to the log. */
107 : void
108 0 : agent_query_dump_state (void)
109 : {
110 0 : log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
111 0 : entry_ctx, (long)assuan_get_pid (entry_ctx), (void*)popup_tid);
112 0 : }
113 :
114 : /* Called to make sure that a popup window owned by the current
115 : connection gets closed. */
116 : void
117 759 : agent_reset_query (ctrl_t ctrl)
118 : {
119 759 : if (entry_ctx && popup_tid && entry_owner == ctrl)
120 : {
121 0 : agent_popup_message_stop (ctrl);
122 : }
123 759 : }
124 :
125 :
126 : /* Unlock the pinentry so that another thread can start one and
127 : disconnect that pinentry - we do this after the unlock so that a
128 : stalled pinentry does not block other threads. Fixme: We should
129 : have a timeout in Assuan for the disconnect operation. */
130 : static gpg_error_t
131 13 : unlock_pinentry (gpg_error_t rc)
132 : {
133 13 : assuan_context_t ctx = entry_ctx;
134 : int err;
135 :
136 13 : if (rc)
137 : {
138 0 : if (DBG_IPC)
139 0 : log_debug ("error calling pinentry: %s <%s>\n",
140 : gpg_strerror (rc), gpg_strsource (rc));
141 :
142 : /* Change the source of the error to pinentry so that the final
143 : consumer of the error code knows that the problem is with
144 : pinentry. For backward compatibility we do not do that for
145 : some common error codes. */
146 0 : switch (gpg_err_code (rc))
147 : {
148 : case GPG_ERR_NO_PIN_ENTRY:
149 : case GPG_ERR_CANCELED:
150 : case GPG_ERR_FULLY_CANCELED:
151 : case GPG_ERR_ASS_UNKNOWN_INQUIRE:
152 : case GPG_ERR_ASS_TOO_MUCH_DATA:
153 : case GPG_ERR_NO_PASSPHRASE:
154 : case GPG_ERR_BAD_PASSPHRASE:
155 : case GPG_ERR_BAD_PIN:
156 0 : break;
157 :
158 : default:
159 0 : rc = gpg_err_make (GPG_ERR_SOURCE_PINENTRY, gpg_err_code (rc));
160 0 : break;
161 : }
162 : }
163 :
164 13 : entry_ctx = NULL;
165 13 : err = npth_mutex_unlock (&entry_lock);
166 13 : if (err)
167 : {
168 0 : log_error ("failed to release the entry lock: %s\n", strerror (err));
169 0 : if (!rc)
170 0 : rc = gpg_error_from_errno (err);
171 : }
172 13 : assuan_release (ctx);
173 13 : return rc;
174 : }
175 :
176 :
177 : /* To make sure we leave no secrets in our image after forking of the
178 : pinentry, we use this callback. */
179 : static void
180 0 : atfork_cb (void *opaque, int where)
181 : {
182 0 : ctrl_t ctrl = opaque;
183 :
184 0 : if (!where)
185 : {
186 0 : int iterator = 0;
187 : const char *name, *assname, *value;
188 :
189 0 : gcry_control (GCRYCTL_TERM_SECMEM);
190 :
191 0 : while ((name = session_env_list_stdenvnames (&iterator, &assname)))
192 : {
193 : /* For all new envvars (!ASSNAME) and the two medium old
194 : ones which do have an assuan name but are conveyed using
195 : environment variables, update the environment of the
196 : forked process. */
197 0 : if (!assname
198 0 : || !strcmp (name, "XAUTHORITY")
199 0 : || !strcmp (name, "PINENTRY_USER_DATA"))
200 : {
201 0 : value = session_env_getenv (ctrl->session_env, name);
202 0 : if (value)
203 0 : gnupg_setenv (name, value, 1);
204 : }
205 : }
206 : }
207 0 : }
208 :
209 :
210 : static gpg_error_t
211 0 : getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
212 : {
213 0 : unsigned long *pid = opaque;
214 : char pidbuf[50];
215 :
216 : /* There is only the pid in the server's response. */
217 0 : if (length >= sizeof pidbuf)
218 0 : length = sizeof pidbuf -1;
219 0 : if (length)
220 : {
221 0 : strncpy (pidbuf, buffer, length);
222 0 : pidbuf[length] = 0;
223 0 : *pid = strtoul (pidbuf, NULL, 10);
224 : }
225 0 : return 0;
226 : }
227 :
228 :
229 : /* Fork off the pin entry if this has not already been done. Note,
230 : that this function must always be used to acquire the lock for the
231 : pinentry - we will serialize _all_ pinentry calls.
232 : */
233 : static gpg_error_t
234 13 : start_pinentry (ctrl_t ctrl)
235 : {
236 13 : int rc = 0;
237 : const char *full_pgmname;
238 : const char *pgmname;
239 : assuan_context_t ctx;
240 : const char *argv[5];
241 : assuan_fd_t no_close_list[3];
242 : int i;
243 : const char *tmpstr;
244 : unsigned long pinentry_pid;
245 : const char *value;
246 : struct timespec abstime;
247 : char *flavor_version;
248 : int err;
249 :
250 13 : npth_clock_gettime (&abstime);
251 13 : abstime.tv_sec += LOCK_TIMEOUT;
252 13 : err = npth_mutex_timedlock (&entry_lock, &abstime);
253 13 : if (err)
254 : {
255 0 : if (err == ETIMEDOUT)
256 0 : rc = gpg_error (GPG_ERR_TIMEOUT);
257 : else
258 0 : rc = gpg_error_from_errno (rc);
259 0 : log_error (_("failed to acquire the pinentry lock: %s\n"),
260 : gpg_strerror (rc));
261 0 : return rc;
262 : }
263 :
264 13 : entry_owner = ctrl;
265 :
266 13 : if (entry_ctx)
267 0 : return 0;
268 :
269 13 : if (opt.verbose)
270 0 : log_info ("starting a new PIN Entry\n");
271 :
272 : #ifdef HAVE_W32_SYSTEM
273 : fflush (stdout);
274 : fflush (stderr);
275 : #endif
276 13 : if (fflush (NULL))
277 : {
278 : #ifndef HAVE_W32_SYSTEM
279 0 : gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
280 : #endif
281 0 : log_error ("error flushing pending output: %s\n", strerror (errno));
282 : /* At least Windows XP fails here with EBADF. According to docs
283 : and Wine an fflush(NULL) is the same as _flushall. However
284 : the Wine implementaion does not flush stdin,stdout and stderr
285 : - see above. Let's try to ignore the error. */
286 : #ifndef HAVE_W32_SYSTEM
287 0 : return unlock_pinentry (tmperr);
288 : #endif
289 : }
290 :
291 13 : full_pgmname = opt.pinentry_program;
292 13 : if (!full_pgmname || !*full_pgmname)
293 0 : full_pgmname = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
294 13 : if ( !(pgmname = strrchr (full_pgmname, '/')))
295 0 : pgmname = full_pgmname;
296 : else
297 13 : pgmname++;
298 :
299 : /* OS X needs the entire file name in argv[0], so that it can locate
300 : the resource bundle. For other systems we stick to the usual
301 : convention of supplying only the name of the program. */
302 : #ifdef __APPLE__
303 : argv[0] = full_pgmname;
304 : #else /*!__APPLE__*/
305 13 : argv[0] = pgmname;
306 : #endif /*__APPLE__*/
307 :
308 13 : if (!opt.keep_display
309 13 : && (value = session_env_getenv (ctrl->session_env, "DISPLAY")))
310 : {
311 13 : argv[1] = "--display";
312 13 : argv[2] = value;
313 13 : argv[3] = NULL;
314 : }
315 : else
316 0 : argv[1] = NULL;
317 :
318 13 : i=0;
319 13 : if (!opt.running_detached)
320 : {
321 0 : if (log_get_fd () != -1)
322 0 : no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
323 0 : no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
324 : }
325 13 : no_close_list[i] = ASSUAN_INVALID_FD;
326 :
327 13 : rc = assuan_new (&ctx);
328 13 : if (rc)
329 : {
330 0 : log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
331 0 : return rc;
332 : }
333 : /* We don't want to log the pinentry communication to make the logs
334 : easier to read. We might want to add a new debug option to enable
335 : pinentry logging. */
336 : #ifdef ASSUAN_NO_LOGGING
337 13 : assuan_set_flag (ctx, ASSUAN_NO_LOGGING, !opt.debug_pinentry);
338 : #endif
339 :
340 : /* Connect to the pinentry and perform initial handshaking. Note
341 : that atfork is used to change the environment for pinentry. We
342 : start the server in detached mode to suppress the console window
343 : under Windows. */
344 13 : rc = assuan_pipe_connect (ctx, full_pgmname, argv,
345 : no_close_list, atfork_cb, ctrl,
346 : ASSUAN_PIPE_CONNECT_DETACHED);
347 13 : if (rc)
348 : {
349 0 : log_error ("can't connect to the PIN entry module '%s': %s\n",
350 : full_pgmname, gpg_strerror (rc));
351 0 : assuan_release (ctx);
352 0 : return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
353 : }
354 13 : entry_ctx = ctx;
355 :
356 13 : if (DBG_IPC)
357 0 : log_debug ("connection to PIN entry established\n");
358 :
359 13 : value = session_env_getenv (ctrl->session_env, "PINENTRY_USER_DATA");
360 13 : if (value != NULL)
361 : {
362 : char *optstr;
363 5 : if (asprintf (&optstr, "OPTION pinentry-user-data=%s", value) < 0 )
364 0 : return unlock_pinentry (out_of_core ());
365 5 : rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
366 : NULL);
367 5 : xfree (optstr);
368 5 : if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION)
369 0 : return unlock_pinentry (rc);
370 : }
371 :
372 13 : rc = assuan_transact (entry_ctx,
373 13 : opt.no_grab? "OPTION no-grab":"OPTION grab",
374 : NULL, NULL, NULL, NULL, NULL, NULL);
375 13 : if (rc)
376 0 : return unlock_pinentry (rc);
377 :
378 13 : value = session_env_getenv (ctrl->session_env, "GPG_TTY");
379 13 : if (value)
380 : {
381 : char *optstr;
382 0 : if (asprintf (&optstr, "OPTION ttyname=%s", value) < 0 )
383 0 : return unlock_pinentry (out_of_core ());
384 0 : rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
385 : NULL);
386 0 : xfree (optstr);
387 0 : if (rc)
388 0 : return unlock_pinentry (rc);
389 : }
390 13 : value = session_env_getenv (ctrl->session_env, "TERM");
391 13 : if (value)
392 : {
393 : char *optstr;
394 13 : if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 )
395 0 : return unlock_pinentry (out_of_core ());
396 13 : rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
397 : NULL);
398 13 : xfree (optstr);
399 13 : if (rc)
400 0 : return unlock_pinentry (rc);
401 : }
402 13 : if (ctrl->lc_ctype)
403 : {
404 : char *optstr;
405 8 : if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
406 0 : return unlock_pinentry (out_of_core ());
407 8 : rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
408 : NULL);
409 8 : xfree (optstr);
410 8 : if (rc)
411 0 : return unlock_pinentry (rc);
412 : }
413 13 : if (ctrl->lc_messages)
414 : {
415 : char *optstr;
416 0 : if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
417 0 : return unlock_pinentry (out_of_core ());
418 0 : rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
419 : NULL);
420 0 : xfree (optstr);
421 0 : if (rc)
422 0 : return unlock_pinentry (rc);
423 : }
424 :
425 :
426 13 : if (opt.allow_external_cache)
427 : {
428 : /* Indicate to the pinentry that it may read from an external cache.
429 :
430 : It is essential that the pinentry respect this. If the
431 : cached password is not up to date and retry == 1, then, using
432 : a version of GPG Agent that doesn't support this, won't issue
433 : another pin request and the user won't get a chance to
434 : correct the password. */
435 13 : rc = assuan_transact (entry_ctx, "OPTION allow-external-password-cache",
436 : NULL, NULL, NULL, NULL, NULL, NULL);
437 13 : if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION)
438 0 : return unlock_pinentry (rc);
439 : }
440 :
441 13 : if (opt.allow_emacs_pinentry)
442 : {
443 : /* Indicate to the pinentry that it may read passphrase through
444 : Emacs minibuffer, if possible. */
445 0 : rc = assuan_transact (entry_ctx, "OPTION allow-emacs-prompt",
446 : NULL, NULL, NULL, NULL, NULL, NULL);
447 0 : if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION)
448 0 : return unlock_pinentry (rc);
449 : }
450 :
451 :
452 : {
453 : /* Provide a few default strings for use by the pinentries. This
454 : may help a pinentry to avoid implementing localization code. */
455 : static struct { const char *key, *value; int what; } tbl[] = {
456 : /* TRANSLATORS: These are labels for buttons etc used in
457 : Pinentries. An underscore indicates that the next letter
458 : should be used as an accelerator. Double the underscore for
459 : a literal one. The actual to be translated text starts after
460 : the second vertical bar. Note that gpg-agent has been set to
461 : utf-8 so that the strings are in the expected encoding. */
462 : { "ok", N_("|pinentry-label|_OK") },
463 : { "cancel", N_("|pinentry-label|_Cancel") },
464 : { "yes", N_("|pinentry-label|_Yes") },
465 : { "no", N_("|pinentry-label|_No") },
466 : { "prompt", N_("|pinentry-label|PIN:") },
467 : { "pwmngr", N_("|pinentry-label|_Save in password manager"), 1 },
468 : { "cf-visi",N_("Do you really want to make your "
469 : "passphrase visible on the screen?") },
470 : { "tt-visi",N_("|pinentry-tt|Make passphrase visible") },
471 : { "tt-hide",N_("|pinentry-tt|Hide passphrase") },
472 : { NULL, NULL}
473 : };
474 : char *optstr;
475 : int idx;
476 : const char *s, *s2;
477 :
478 130 : for (idx=0; tbl[idx].key; idx++)
479 : {
480 117 : if (!opt.allow_external_cache && tbl[idx].what == 1)
481 0 : continue; /* No need for it. */
482 117 : s = L_(tbl[idx].value);
483 117 : if (*s == '|' && (s2=strchr (s+1,'|')))
484 104 : s = s2+1;
485 117 : if (asprintf (&optstr, "OPTION default-%s=%s", tbl[idx].key, s) < 0 )
486 0 : return unlock_pinentry (out_of_core ());
487 117 : assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
488 : NULL);
489 117 : xfree (optstr);
490 : }
491 : }
492 :
493 : /* Tell the pinentry that we would prefer that the given character
494 : is used as the invisible character by the entry widget. */
495 13 : if (opt.pinentry_invisible_char)
496 : {
497 : char *optstr;
498 0 : if ((optstr = xtryasprintf ("OPTION invisible-char=%s",
499 : opt.pinentry_invisible_char)))
500 : {
501 0 : assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
502 : NULL);
503 : /* We ignore errors because this is just a fancy thing and
504 : older pinentries do not support this feature. */
505 0 : xfree (optstr);
506 : }
507 : }
508 :
509 13 : if (opt.pinentry_timeout)
510 : {
511 : char *optstr;
512 0 : if ((optstr = xtryasprintf ("SETTIMEOUT %lu", opt.pinentry_timeout)))
513 : {
514 0 : assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
515 : NULL);
516 : /* We ignore errors because this is just a fancy thing. */
517 0 : xfree (optstr);
518 : }
519 : }
520 :
521 : /* Tell the pinentry the name of a file it shall touch after having
522 : messed with the tty. This is optional and only supported by
523 : newer pinentries and thus we do no error checking. */
524 13 : tmpstr = opt.pinentry_touch_file;
525 13 : if (tmpstr && !strcmp (tmpstr, "/dev/null"))
526 0 : tmpstr = NULL;
527 13 : else if (!tmpstr)
528 13 : tmpstr = get_agent_socket_name ();
529 13 : if (tmpstr)
530 : {
531 : char *optstr;
532 :
533 13 : if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
534 : ;
535 : else
536 : {
537 13 : assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
538 : NULL);
539 13 : xfree (optstr);
540 : }
541 : }
542 :
543 :
544 : /* Ask the pinentry for its version and flavor and streo that as a
545 : * string in MB. This information is useful for helping users to
546 : * figure out Pinentry problems. */
547 : {
548 : membuf_t mb;
549 :
550 13 : init_membuf (&mb, 256);
551 13 : if (assuan_transact (entry_ctx, "GETINFO flavor",
552 : put_membuf_cb, &mb, NULL, NULL, NULL, NULL))
553 0 : put_membuf_str (&mb, "unknown");
554 13 : put_membuf_str (&mb, " ");
555 13 : if (assuan_transact (entry_ctx, "GETINFO version",
556 : put_membuf_cb, &mb, NULL, NULL, NULL, NULL))
557 0 : put_membuf_str (&mb, "unknown");
558 13 : put_membuf (&mb, "", 1);
559 13 : flavor_version = get_membuf (&mb, NULL);
560 : }
561 :
562 :
563 : /* Now ask the Pinentry for its PID. If the Pinentry is new enough
564 : it will send the pid back and we will use an inquire to notify
565 : our client. The client may answer the inquiry either with END or
566 : with CAN to cancel the pinentry. */
567 13 : rc = assuan_transact (entry_ctx, "GETINFO pid",
568 : getinfo_pid_cb, &pinentry_pid,
569 : NULL, NULL, NULL, NULL);
570 13 : if (rc)
571 : {
572 0 : log_info ("You may want to update to a newer pinentry\n");
573 0 : rc = 0;
574 : }
575 13 : else if (!rc && (pid_t)pinentry_pid == (pid_t)(-1))
576 0 : log_error ("pinentry did not return a PID\n");
577 : else
578 : {
579 13 : rc = agent_inq_pinentry_launched (ctrl, pinentry_pid, flavor_version);
580 13 : if (gpg_err_code (rc) == GPG_ERR_CANCELED
581 13 : || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
582 0 : return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT,
583 : gpg_err_code (rc)));
584 13 : rc = 0;
585 : }
586 :
587 13 : xfree (flavor_version);
588 :
589 13 : return 0;
590 : }
591 :
592 :
593 : /* Returns True if the pinentry is currently active. If WAITSECONDS is
594 : greater than zero the function will wait for this many seconds
595 : before returning. */
596 : int
597 1 : pinentry_active_p (ctrl_t ctrl, int waitseconds)
598 : {
599 : int err;
600 : (void)ctrl;
601 :
602 1 : if (waitseconds > 0)
603 : {
604 : struct timespec abstime;
605 : int rc;
606 :
607 0 : npth_clock_gettime (&abstime);
608 0 : abstime.tv_sec += waitseconds;
609 0 : err = npth_mutex_timedlock (&entry_lock, &abstime);
610 0 : if (err)
611 : {
612 0 : if (err == ETIMEDOUT)
613 0 : rc = gpg_error (GPG_ERR_TIMEOUT);
614 : else
615 0 : rc = gpg_error (GPG_ERR_INTERNAL);
616 0 : return rc;
617 : }
618 : }
619 : else
620 : {
621 1 : err = npth_mutex_trylock (&entry_lock);
622 1 : if (err)
623 0 : return gpg_error (GPG_ERR_LOCKED);
624 : }
625 :
626 1 : err = npth_mutex_unlock (&entry_lock);
627 1 : if (err)
628 0 : log_error ("failed to release the entry lock at %d: %s\n", __LINE__,
629 0 : strerror (errno));
630 1 : return 0;
631 : }
632 :
633 :
634 : static gpg_error_t
635 12 : getpin_cb (void *opaque, const void *buffer, size_t length)
636 : {
637 12 : struct entry_parm_s *parm = opaque;
638 :
639 12 : if (!buffer)
640 0 : return 0;
641 :
642 : /* we expect the pin to fit on one line */
643 12 : if (parm->lines || length >= parm->size)
644 0 : return gpg_error (GPG_ERR_ASS_TOO_MUCH_DATA);
645 :
646 : /* fixme: we should make sure that the assuan buffer is allocated in
647 : secure memory or read the response byte by byte */
648 12 : memcpy (parm->buffer, buffer, length);
649 12 : parm->buffer[length] = 0;
650 12 : parm->lines++;
651 12 : return 0;
652 : }
653 :
654 :
655 : static int
656 0 : all_digitsp( const char *s)
657 : {
658 0 : for (; *s && *s >= '0' && *s <= '9'; s++)
659 : ;
660 0 : return !*s;
661 : }
662 :
663 :
664 : /* Return a new malloced string by unescaping the string S. Escaping
665 : is percent escaping and '+'/space mapping. A binary Nul will
666 : silently be replaced by a 0xFF. Function returns NULL to indicate
667 : an out of memory status. Parsing stops at the end of the string or
668 : a white space character. */
669 : static char *
670 0 : unescape_passphrase_string (const unsigned char *s)
671 : {
672 : char *buffer, *d;
673 :
674 0 : buffer = d = xtrymalloc_secure (strlen ((const char*)s)+1);
675 0 : if (!buffer)
676 0 : return NULL;
677 0 : while (*s && !spacep (s))
678 : {
679 0 : if (*s == '%' && s[1] && s[2])
680 : {
681 0 : s++;
682 0 : *d = xtoi_2 (s);
683 0 : if (!*d)
684 0 : *d = '\xff';
685 0 : d++;
686 0 : s += 2;
687 : }
688 0 : else if (*s == '+')
689 : {
690 0 : *d++ = ' ';
691 0 : s++;
692 : }
693 : else
694 0 : *d++ = *s++;
695 : }
696 0 : *d = 0;
697 0 : return buffer;
698 : }
699 :
700 :
701 : /* Estimate the quality of the passphrase PW and return a value in the
702 : range 0..100. */
703 : static int
704 0 : estimate_passphrase_quality (const char *pw)
705 : {
706 0 : int goodlength = opt.min_passphrase_len + opt.min_passphrase_len/3;
707 : int length;
708 : const char *s;
709 :
710 0 : if (goodlength < 1)
711 0 : return 0;
712 :
713 0 : for (length = 0, s = pw; *s; s++)
714 0 : if (!spacep (s))
715 0 : length ++;
716 :
717 0 : if (length > goodlength)
718 0 : return 100;
719 0 : return ((length*10) / goodlength)*10;
720 : }
721 :
722 :
723 : /* Handle the QUALITY inquiry. */
724 : static gpg_error_t
725 0 : inq_quality (void *opaque, const char *line)
726 : {
727 0 : assuan_context_t ctx = opaque;
728 : const char *s;
729 : char *pin;
730 : int rc;
731 : int percent;
732 : char numbuf[20];
733 :
734 0 : if ((s = has_leading_keyword (line, "QUALITY")))
735 : {
736 0 : pin = unescape_passphrase_string (s);
737 0 : if (!pin)
738 0 : rc = gpg_error_from_syserror ();
739 : else
740 : {
741 0 : percent = estimate_passphrase_quality (pin);
742 0 : if (check_passphrase_constraints (NULL, pin, NULL))
743 0 : percent = -percent;
744 0 : snprintf (numbuf, sizeof numbuf, "%d", percent);
745 0 : rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
746 0 : xfree (pin);
747 : }
748 : }
749 : else
750 : {
751 0 : log_error ("unsupported inquiry '%s' from pinentry\n", line);
752 0 : rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
753 : }
754 :
755 0 : return rc;
756 : }
757 :
758 :
759 : /* Helper for agent_askpin and agent_get_passphrase. */
760 : static gpg_error_t
761 1 : setup_qualitybar (ctrl_t ctrl)
762 : {
763 : int rc;
764 : char line[ASSUAN_LINELENGTH];
765 : char *tmpstr, *tmpstr2;
766 : const char *tooltip;
767 :
768 : (void)ctrl;
769 :
770 : /* TRANSLATORS: This string is displayed by Pinentry as the label
771 : for the quality bar. */
772 1 : tmpstr = try_percent_escape (L_("Quality:"), "\t\r\n\f\v");
773 1 : snprintf (line, DIM(line), "SETQUALITYBAR %s", tmpstr? tmpstr:"");
774 1 : xfree (tmpstr);
775 1 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
776 1 : if (rc == 103 /*(Old assuan error code)*/
777 1 : || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
778 : ; /* Ignore Unknown Command from old Pinentry versions. */
779 1 : else if (rc)
780 0 : return rc;
781 :
782 1 : tmpstr2 = gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
783 1 : if (tmpstr2)
784 0 : tooltip = tmpstr2;
785 : else
786 : {
787 : /* TRANSLATORS: This string is a tooltip, shown by pinentry when
788 : hovering over the quality bar. Please use an appropriate
789 : string to describe what this is about. The length of the
790 : tooltip is limited to about 900 characters. If you do not
791 : translate this entry, a default english text (see source)
792 : will be used. */
793 1 : tooltip = L_("pinentry.qualitybar.tooltip");
794 1 : if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
795 1 : tooltip = ("The quality of the text entered above.\n"
796 : "Please ask your administrator for "
797 : "details about the criteria.");
798 : }
799 1 : tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
800 1 : xfree (tmpstr2);
801 1 : snprintf (line, DIM(line), "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
802 1 : xfree (tmpstr);
803 1 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
804 1 : if (rc == 103 /*(Old assuan error code)*/
805 1 : || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
806 : ; /* Ignore Unknown Command from old pinentry versions. */
807 1 : else if (rc)
808 0 : return rc;
809 :
810 1 : return 0;
811 : }
812 :
813 : enum
814 : {
815 : PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
816 : PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
817 : PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
818 : };
819 :
820 : /* Check the button_info line for a close action. Also check for the
821 : PIN_REPEATED flag. */
822 : static gpg_error_t
823 0 : pinentry_status_cb (void *opaque, const char *line)
824 : {
825 0 : unsigned int *flag = opaque;
826 : const char *args;
827 :
828 0 : if ((args = has_leading_keyword (line, "BUTTON_INFO")))
829 : {
830 0 : if (!strcmp (args, "close"))
831 0 : *flag |= PINENTRY_STATUS_CLOSE_BUTTON;
832 : }
833 0 : else if (has_leading_keyword (line, "PIN_REPEATED"))
834 : {
835 0 : *flag |= PINENTRY_STATUS_PIN_REPEATED;
836 : }
837 0 : else if (has_leading_keyword (line, "PASSWORD_FROM_CACHE"))
838 : {
839 0 : *flag |= PINENTRY_STATUS_PASSWORD_FROM_CACHE;
840 : }
841 :
842 0 : return 0;
843 : }
844 :
845 :
846 :
847 :
848 : /* Call the Entry and ask for the PIN. We do check for a valid PIN
849 : number here and repeat it as long as we have invalid formed
850 : numbers. KEYINFO and CACHE_MODE are used to tell pinentry something
851 : about the key. */
852 : gpg_error_t
853 12 : agent_askpin (ctrl_t ctrl,
854 : const char *desc_text, const char *prompt_text,
855 : const char *initial_errtext,
856 : struct pin_entry_info_s *pininfo,
857 : const char *keyinfo, cache_mode_t cache_mode)
858 : {
859 : gpg_error_t rc;
860 : char line[ASSUAN_LINELENGTH];
861 : struct entry_parm_s parm;
862 12 : const char *errtext = NULL;
863 12 : int is_pin = 0;
864 : int saveflag;
865 : unsigned int pinentry_status;
866 :
867 12 : if (opt.batch)
868 0 : return 0; /* fixme: we should return BAD PIN */
869 :
870 12 : if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
871 : {
872 0 : if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
873 0 : return gpg_error (GPG_ERR_CANCELED);
874 0 : if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
875 : {
876 : unsigned char *passphrase;
877 : size_t size;
878 :
879 0 : *pininfo->pin = 0; /* Reset the PIN. */
880 0 : rc = pinentry_loopback(ctrl, "PASSPHRASE", &passphrase, &size,
881 0 : pininfo->max_length - 1);
882 0 : if (rc)
883 0 : return rc;
884 :
885 0 : memcpy(&pininfo->pin, passphrase, size);
886 0 : xfree(passphrase);
887 0 : pininfo->pin[size] = 0;
888 0 : if (pininfo->check_cb)
889 : {
890 : /* More checks by utilizing the optional callback. */
891 0 : pininfo->cb_errtext = NULL;
892 0 : rc = pininfo->check_cb (pininfo);
893 : }
894 0 : return rc;
895 : }
896 0 : return gpg_error(GPG_ERR_NO_PIN_ENTRY);
897 : }
898 :
899 12 : if (!pininfo || pininfo->max_length < 1)
900 0 : return gpg_error (GPG_ERR_INV_VALUE);
901 12 : if (!desc_text && pininfo->min_digits)
902 0 : desc_text = L_("Please enter your PIN, so that the secret key "
903 : "can be unlocked for this session");
904 12 : else if (!desc_text)
905 0 : desc_text = L_("Please enter your passphrase, so that the secret key "
906 : "can be unlocked for this session");
907 :
908 12 : if (prompt_text)
909 0 : is_pin = !!strstr (prompt_text, "PIN");
910 : else
911 12 : is_pin = desc_text && strstr (desc_text, "PIN");
912 :
913 12 : rc = start_pinentry (ctrl);
914 12 : if (rc)
915 0 : return rc;
916 :
917 : /* If we have a KEYINFO string and are normal, user, or ssh cache
918 : mode, we tell that the Pinentry so it may use it for own caching
919 : purposes. Most pinentries won't have this implemented and thus
920 : we do not error out in this case. */
921 12 : if (keyinfo && (cache_mode == CACHE_MODE_NORMAL
922 1 : || cache_mode == CACHE_MODE_USER
923 1 : || cache_mode == CACHE_MODE_SSH))
924 2 : snprintf (line, DIM(line), "SETKEYINFO %c/%s",
925 : cache_mode == CACHE_MODE_USER? 'u' :
926 1 : cache_mode == CACHE_MODE_SSH? 's' : 'n',
927 : keyinfo);
928 : else
929 11 : snprintf (line, DIM(line), "SETKEYINFO --clear");
930 :
931 12 : rc = assuan_transact (entry_ctx, line,
932 : NULL, NULL, NULL, NULL, NULL, NULL);
933 12 : if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
934 0 : return unlock_pinentry (rc);
935 :
936 12 : snprintf (line, DIM(line), "SETDESC %s", desc_text);
937 12 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
938 12 : if (rc)
939 0 : return unlock_pinentry (rc);
940 :
941 24 : snprintf (line, DIM(line), "SETPROMPT %s",
942 12 : prompt_text? prompt_text : is_pin? L_("PIN:") : L_("Passphrase:"));
943 12 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
944 12 : if (rc)
945 0 : return unlock_pinentry (rc);
946 :
947 : /* If a passphrase quality indicator has been requested and a
948 : minimum passphrase length has not been disabled, send the command
949 : to the pinentry. */
950 12 : if (pininfo->with_qualitybar && opt.min_passphrase_len )
951 : {
952 1 : rc = setup_qualitybar (ctrl);
953 1 : if (rc)
954 0 : return unlock_pinentry (rc);
955 : }
956 :
957 12 : if (initial_errtext)
958 : {
959 0 : snprintf (line, DIM(line), "SETERROR %s", initial_errtext);
960 0 : rc = assuan_transact (entry_ctx, line,
961 : NULL, NULL, NULL, NULL, NULL, NULL);
962 0 : if (rc)
963 0 : return unlock_pinentry (rc);
964 : }
965 :
966 12 : if (pininfo->with_repeat)
967 : {
968 5 : snprintf (line, DIM(line), "SETREPEATERROR %s",
969 : L_("does not match - try again"));
970 5 : rc = assuan_transact (entry_ctx, line,
971 : NULL, NULL, NULL, NULL, NULL, NULL);
972 5 : if (rc)
973 0 : pininfo->with_repeat = 0; /* Pinentry does not support it. */
974 : }
975 12 : pininfo->repeat_okay = 0;
976 :
977 12 : for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
978 : {
979 12 : memset (&parm, 0, sizeof parm);
980 12 : parm.size = pininfo->max_length;
981 12 : *pininfo->pin = 0; /* Reset the PIN. */
982 12 : parm.buffer = (unsigned char*)pininfo->pin;
983 :
984 12 : if (errtext)
985 : {
986 : /* TRANSLATORS: The string is appended to an error message in
987 : the pinentry. The %s is the actual error message, the
988 : two %d give the current and maximum number of tries. */
989 0 : snprintf (line, DIM(line), L_("SETERROR %s (try %d of %d)"),
990 0 : errtext, pininfo->failed_tries+1, pininfo->max_tries);
991 0 : rc = assuan_transact (entry_ctx, line,
992 : NULL, NULL, NULL, NULL, NULL, NULL);
993 0 : if (rc)
994 0 : return unlock_pinentry (rc);
995 0 : errtext = NULL;
996 : }
997 :
998 12 : if (pininfo->with_repeat)
999 : {
1000 5 : snprintf (line, DIM(line), "SETREPEAT %s", L_("Repeat:"));
1001 5 : rc = assuan_transact (entry_ctx, line,
1002 : NULL, NULL, NULL, NULL, NULL, NULL);
1003 5 : if (rc)
1004 0 : return unlock_pinentry (rc);
1005 : }
1006 :
1007 12 : saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
1008 12 : assuan_begin_confidential (entry_ctx);
1009 12 : pinentry_status = 0;
1010 12 : rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
1011 : inq_quality, entry_ctx,
1012 : pinentry_status_cb, &pinentry_status);
1013 12 : assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
1014 : /* Most pinentries out in the wild return the old Assuan error code
1015 : for canceled which gets translated to an assuan Cancel error and
1016 : not to the code for a user cancel. Fix this here. */
1017 12 : if (rc && gpg_err_source (rc)
1018 0 : && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1019 0 : rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1020 :
1021 :
1022 : /* Change error code in case the window close button was clicked
1023 : to cancel the operation. */
1024 12 : if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
1025 0 : && gpg_err_code (rc) == GPG_ERR_CANCELED)
1026 0 : rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
1027 :
1028 12 : if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
1029 0 : errtext = is_pin? L_("PIN too long")
1030 0 : : L_("Passphrase too long");
1031 12 : else if (rc)
1032 0 : return unlock_pinentry (rc);
1033 :
1034 12 : if (!errtext && pininfo->min_digits)
1035 : {
1036 : /* do some basic checks on the entered PIN. */
1037 0 : if (!all_digitsp (pininfo->pin))
1038 0 : errtext = L_("Invalid characters in PIN");
1039 0 : else if (pininfo->max_digits
1040 0 : && strlen (pininfo->pin) > pininfo->max_digits)
1041 0 : errtext = L_("PIN too long");
1042 0 : else if (strlen (pininfo->pin) < pininfo->min_digits)
1043 0 : errtext = L_("PIN too short");
1044 : }
1045 :
1046 12 : if (!errtext && pininfo->check_cb)
1047 : {
1048 : /* More checks by utilizing the optional callback. */
1049 7 : pininfo->cb_errtext = NULL;
1050 7 : rc = pininfo->check_cb (pininfo);
1051 7 : if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1052 0 : && pininfo->cb_errtext)
1053 0 : errtext = pininfo->cb_errtext;
1054 7 : else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
1055 7 : || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
1056 0 : errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
1057 7 : else if (rc)
1058 0 : return unlock_pinentry (rc);
1059 : }
1060 :
1061 12 : if (!errtext)
1062 : {
1063 12 : if (pininfo->with_repeat
1064 5 : && (pinentry_status & PINENTRY_STATUS_PIN_REPEATED))
1065 0 : pininfo->repeat_okay = 1;
1066 12 : return unlock_pinentry (0); /* okay, got a PIN or passphrase */
1067 : }
1068 :
1069 0 : if ((pinentry_status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
1070 : /* The password was read from the cache. Don't count this
1071 : against the retry count. */
1072 0 : pininfo->failed_tries --;
1073 : }
1074 :
1075 0 : return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
1076 : : GPG_ERR_BAD_PASSPHRASE));
1077 : }
1078 :
1079 :
1080 :
1081 : /* Ask for the passphrase using the supplied arguments. The returned
1082 : passphrase needs to be freed by the caller. */
1083 : int
1084 0 : agent_get_passphrase (ctrl_t ctrl,
1085 : char **retpass, const char *desc, const char *prompt,
1086 : const char *errtext, int with_qualitybar,
1087 : const char *keyinfo, cache_mode_t cache_mode)
1088 : {
1089 :
1090 : int rc;
1091 : char line[ASSUAN_LINELENGTH];
1092 : struct entry_parm_s parm;
1093 : int saveflag;
1094 : unsigned int pinentry_status;
1095 :
1096 0 : *retpass = NULL;
1097 0 : if (opt.batch)
1098 0 : return gpg_error (GPG_ERR_BAD_PASSPHRASE);
1099 :
1100 0 : if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1101 : {
1102 0 : if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
1103 0 : return gpg_error (GPG_ERR_CANCELED);
1104 :
1105 0 : if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
1106 : {
1107 : size_t size;
1108 0 : size_t len = ASSUAN_LINELENGTH/2;
1109 :
1110 0 : return pinentry_loopback (ctrl, "PASSPHRASE",
1111 : (unsigned char **)retpass, &size, len);
1112 : }
1113 0 : return gpg_error (GPG_ERR_NO_PIN_ENTRY);
1114 : }
1115 :
1116 0 : rc = start_pinentry (ctrl);
1117 0 : if (rc)
1118 0 : return rc;
1119 :
1120 0 : if (!prompt)
1121 0 : prompt = desc && strstr (desc, "PIN")? L_("PIN:"): L_("Passphrase:");
1122 :
1123 :
1124 : /* If we have a KEYINFO string and are normal, user, or ssh cache
1125 : mode, we tell that the Pinentry so it may use it for own caching
1126 : purposes. Most pinentries won't have this implemented and thus
1127 : we do not error out in this case. */
1128 0 : if (keyinfo && (cache_mode == CACHE_MODE_NORMAL
1129 0 : || cache_mode == CACHE_MODE_USER
1130 0 : || cache_mode == CACHE_MODE_SSH))
1131 0 : snprintf (line, DIM(line), "SETKEYINFO %c/%s",
1132 : cache_mode == CACHE_MODE_USER? 'u' :
1133 0 : cache_mode == CACHE_MODE_SSH? 's' : 'n',
1134 : keyinfo);
1135 : else
1136 0 : snprintf (line, DIM(line), "SETKEYINFO --clear");
1137 :
1138 0 : rc = assuan_transact (entry_ctx, line,
1139 : NULL, NULL, NULL, NULL, NULL, NULL);
1140 0 : if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
1141 0 : return unlock_pinentry (rc);
1142 :
1143 :
1144 0 : if (desc)
1145 0 : snprintf (line, DIM(line), "SETDESC %s", desc);
1146 : else
1147 0 : snprintf (line, DIM(line), "RESET");
1148 0 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1149 0 : if (rc)
1150 0 : return unlock_pinentry (rc);
1151 :
1152 0 : snprintf (line, DIM(line), "SETPROMPT %s", prompt);
1153 0 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1154 0 : if (rc)
1155 0 : return unlock_pinentry (rc);
1156 :
1157 0 : if (with_qualitybar && opt.min_passphrase_len)
1158 : {
1159 0 : rc = setup_qualitybar (ctrl);
1160 0 : if (rc)
1161 0 : return unlock_pinentry (rc);
1162 : }
1163 :
1164 0 : if (errtext)
1165 : {
1166 0 : snprintf (line, DIM(line), "SETERROR %s", errtext);
1167 0 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1168 0 : if (rc)
1169 0 : return unlock_pinentry (rc);
1170 : }
1171 :
1172 0 : memset (&parm, 0, sizeof parm);
1173 0 : parm.size = ASSUAN_LINELENGTH/2 - 5;
1174 0 : parm.buffer = gcry_malloc_secure (parm.size+10);
1175 0 : if (!parm.buffer)
1176 0 : return unlock_pinentry (out_of_core ());
1177 :
1178 0 : saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
1179 0 : assuan_begin_confidential (entry_ctx);
1180 0 : pinentry_status = 0;
1181 0 : rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
1182 : inq_quality, entry_ctx,
1183 : pinentry_status_cb, &pinentry_status);
1184 0 : assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
1185 : /* Most pinentries out in the wild return the old Assuan error code
1186 : for canceled which gets translated to an assuan Cancel error and
1187 : not to the code for a user cancel. Fix this here. */
1188 0 : if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1189 0 : rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1190 : /* Change error code in case the window close button was clicked
1191 : to cancel the operation. */
1192 0 : if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON)
1193 0 : && gpg_err_code (rc) == GPG_ERR_CANCELED)
1194 0 : rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
1195 :
1196 0 : if (rc)
1197 0 : xfree (parm.buffer);
1198 : else
1199 0 : *retpass = parm.buffer;
1200 0 : return unlock_pinentry (rc);
1201 : }
1202 :
1203 :
1204 :
1205 : /* Pop up the PIN-entry, display the text and the prompt and ask the
1206 : user to confirm this. We return 0 for success, ie. the user
1207 : confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
1208 : other error. If WITH_CANCEL it true an extra cancel button is
1209 : displayed to allow the user to easily return a GPG_ERR_CANCELED.
1210 : if the Pinentry does not support this, the user can still cancel by
1211 : closing the Pinentry window. */
1212 : int
1213 1 : agent_get_confirmation (ctrl_t ctrl,
1214 : const char *desc, const char *ok,
1215 : const char *notok, int with_cancel)
1216 : {
1217 : int rc;
1218 : char line[ASSUAN_LINELENGTH];
1219 :
1220 1 : if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1221 : {
1222 0 : if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
1223 0 : return gpg_error (GPG_ERR_CANCELED);
1224 :
1225 0 : return gpg_error (GPG_ERR_NO_PIN_ENTRY);
1226 : }
1227 :
1228 1 : rc = start_pinentry (ctrl);
1229 1 : if (rc)
1230 0 : return rc;
1231 :
1232 1 : if (desc)
1233 1 : snprintf (line, DIM(line), "SETDESC %s", desc);
1234 : else
1235 0 : snprintf (line, DIM(line), "RESET");
1236 1 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1237 : /* Most pinentries out in the wild return the old Assuan error code
1238 : for canceled which gets translated to an assuan Cancel error and
1239 : not to the code for a user cancel. Fix this here. */
1240 1 : if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1241 0 : rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1242 :
1243 1 : if (rc)
1244 0 : return unlock_pinentry (rc);
1245 :
1246 1 : if (ok)
1247 : {
1248 1 : snprintf (line, DIM(line), "SETOK %s", ok);
1249 1 : rc = assuan_transact (entry_ctx,
1250 : line, NULL, NULL, NULL, NULL, NULL, NULL);
1251 1 : if (rc)
1252 0 : return unlock_pinentry (rc);
1253 : }
1254 1 : if (notok)
1255 : {
1256 : /* Try to use the newer NOTOK feature if a cancel button is
1257 : requested. If no cancel button is requested we keep on using
1258 : the standard cancel. */
1259 1 : if (with_cancel)
1260 : {
1261 0 : snprintf (line, DIM(line), "SETNOTOK %s", notok);
1262 0 : rc = assuan_transact (entry_ctx,
1263 : line, NULL, NULL, NULL, NULL, NULL, NULL);
1264 : }
1265 : else
1266 1 : rc = GPG_ERR_ASS_UNKNOWN_CMD;
1267 :
1268 1 : if (gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
1269 : {
1270 1 : snprintf (line, DIM(line), "SETCANCEL %s", notok);
1271 1 : rc = assuan_transact (entry_ctx, line,
1272 : NULL, NULL, NULL, NULL, NULL, NULL);
1273 : }
1274 1 : if (rc)
1275 0 : return unlock_pinentry (rc);
1276 : }
1277 :
1278 1 : rc = assuan_transact (entry_ctx, "CONFIRM",
1279 : NULL, NULL, NULL, NULL, NULL, NULL);
1280 1 : if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1281 0 : rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1282 :
1283 1 : return unlock_pinentry (rc);
1284 : }
1285 :
1286 :
1287 :
1288 : /* Pop up the PINentry, display the text DESC and a button with the
1289 : text OK_BTN (which may be NULL to use the default of "OK") and wait
1290 : for the user to hit this button. The return value is not
1291 : relevant. */
1292 : int
1293 0 : agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
1294 : {
1295 : int rc;
1296 : char line[ASSUAN_LINELENGTH];
1297 :
1298 0 : if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1299 0 : return gpg_error (GPG_ERR_CANCELED);
1300 :
1301 0 : rc = start_pinentry (ctrl);
1302 0 : if (rc)
1303 0 : return rc;
1304 :
1305 0 : if (desc)
1306 0 : snprintf (line, DIM(line), "SETDESC %s", desc);
1307 : else
1308 0 : snprintf (line, DIM(line), "RESET");
1309 0 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1310 : /* Most pinentries out in the wild return the old Assuan error code
1311 : for canceled which gets translated to an assuan Cancel error and
1312 : not to the code for a user cancel. Fix this here. */
1313 0 : if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1314 0 : rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1315 :
1316 0 : if (rc)
1317 0 : return unlock_pinentry (rc);
1318 :
1319 0 : if (ok_btn)
1320 : {
1321 0 : snprintf (line, DIM(line), "SETOK %s", ok_btn);
1322 0 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
1323 : NULL, NULL, NULL);
1324 0 : if (rc)
1325 0 : return unlock_pinentry (rc);
1326 : }
1327 :
1328 0 : rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
1329 : NULL, NULL, NULL);
1330 0 : if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
1331 0 : rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
1332 :
1333 0 : return unlock_pinentry (rc);
1334 : }
1335 :
1336 :
1337 : /* The thread running the popup message. */
1338 : static void *
1339 0 : popup_message_thread (void *arg)
1340 : {
1341 : (void)arg;
1342 :
1343 : /* We use the --one-button hack instead of the MESSAGE command to
1344 : allow the use of old Pinentries. Those old Pinentries will then
1345 : show an additional Cancel button but that is mostly a visual
1346 : annoyance. */
1347 0 : assuan_transact (entry_ctx, "CONFIRM --one-button",
1348 : NULL, NULL, NULL, NULL, NULL, NULL);
1349 0 : popup_finished = 1;
1350 0 : return NULL;
1351 : }
1352 :
1353 :
1354 : /* Pop up a message window similar to the confirm one but keep it open
1355 : until agent_popup_message_stop has been called. It is crucial for
1356 : the caller to make sure that the stop function gets called as soon
1357 : as the message is not anymore required because the message is
1358 : system modal and all other attempts to use the pinentry will fail
1359 : (after a timeout). */
1360 : int
1361 0 : agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
1362 : {
1363 : int rc;
1364 : char line[ASSUAN_LINELENGTH];
1365 : npth_attr_t tattr;
1366 : int err;
1367 :
1368 0 : if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
1369 0 : return gpg_error (GPG_ERR_CANCELED);
1370 :
1371 0 : rc = start_pinentry (ctrl);
1372 0 : if (rc)
1373 0 : return rc;
1374 :
1375 0 : if (desc)
1376 0 : snprintf (line, DIM(line), "SETDESC %s", desc);
1377 : else
1378 0 : snprintf (line, DIM(line), "RESET");
1379 0 : rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1380 0 : if (rc)
1381 0 : return unlock_pinentry (rc);
1382 :
1383 0 : if (ok_btn)
1384 : {
1385 0 : snprintf (line, DIM(line), "SETOK %s", ok_btn);
1386 0 : rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
1387 0 : if (rc)
1388 0 : return unlock_pinentry (rc);
1389 : }
1390 :
1391 0 : err = npth_attr_init (&tattr);
1392 0 : if (err)
1393 0 : return unlock_pinentry (gpg_error_from_errno (err));
1394 0 : npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
1395 :
1396 0 : popup_finished = 0;
1397 0 : err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL);
1398 0 : npth_attr_destroy (&tattr);
1399 0 : if (err)
1400 : {
1401 0 : rc = gpg_error_from_errno (err);
1402 0 : log_error ("error spawning popup message handler: %s\n",
1403 : strerror (err) );
1404 0 : return unlock_pinentry (rc);
1405 : }
1406 0 : npth_setname_np (popup_tid, "popup-message");
1407 :
1408 0 : return 0;
1409 : }
1410 :
1411 : /* Close a popup window. */
1412 : void
1413 0 : agent_popup_message_stop (ctrl_t ctrl)
1414 : {
1415 : int rc;
1416 : pid_t pid;
1417 :
1418 : (void)ctrl;
1419 :
1420 0 : if (!popup_tid || !entry_ctx)
1421 : {
1422 0 : log_debug ("agent_popup_message_stop called with no active popup\n");
1423 0 : return;
1424 : }
1425 :
1426 0 : pid = assuan_get_pid (entry_ctx);
1427 0 : if (pid == (pid_t)(-1))
1428 : ; /* No pid available can't send a kill. */
1429 0 : else if (popup_finished)
1430 : ; /* Already finished and ready for joining. */
1431 : #ifdef HAVE_W32_SYSTEM
1432 : /* Older versions of assuan set PID to 0 on Windows to indicate an
1433 : invalid value. */
1434 : else if (pid != (pid_t) INVALID_HANDLE_VALUE
1435 : && pid != 0)
1436 : {
1437 : HANDLE process = (HANDLE) pid;
1438 :
1439 : /* Arbitrary error code. */
1440 : TerminateProcess (process, 1);
1441 : }
1442 : #else
1443 0 : else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
1444 : { /* The daemon already died. No need to send a kill. However
1445 : because we already waited for the process, we need to tell
1446 : assuan that it should not wait again (done by
1447 : unlock_pinentry). */
1448 0 : if (rc == pid)
1449 0 : assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
1450 : }
1451 0 : else if (pid > 0)
1452 0 : kill (pid, SIGINT);
1453 : #endif
1454 :
1455 : /* Now wait for the thread to terminate. */
1456 0 : rc = npth_join (popup_tid, NULL);
1457 0 : if (rc)
1458 0 : log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
1459 : strerror (rc));
1460 : /* Thread IDs are opaque, but we try our best here by resetting it
1461 : to the same content that a static global variable has. */
1462 0 : memset (&popup_tid, '\0', sizeof (popup_tid));
1463 0 : entry_owner = NULL;
1464 :
1465 : /* Now we can close the connection. */
1466 0 : unlock_pinentry (0);
1467 : }
1468 :
1469 : int
1470 0 : agent_clear_passphrase (ctrl_t ctrl,
1471 : const char *keyinfo, cache_mode_t cache_mode)
1472 : {
1473 : int rc;
1474 : char line[ASSUAN_LINELENGTH];
1475 :
1476 0 : if (! (keyinfo && (cache_mode == CACHE_MODE_NORMAL
1477 0 : || cache_mode == CACHE_MODE_USER
1478 0 : || cache_mode == CACHE_MODE_SSH)))
1479 0 : return gpg_error (GPG_ERR_NOT_SUPPORTED);
1480 :
1481 0 : rc = start_pinentry (ctrl);
1482 0 : if (rc)
1483 0 : return rc;
1484 :
1485 0 : snprintf (line, DIM(line), "CLEARPASSPHRASE %c/%s",
1486 : cache_mode == CACHE_MODE_USER? 'u' :
1487 0 : cache_mode == CACHE_MODE_SSH? 's' : 'n',
1488 : keyinfo);
1489 0 : rc = assuan_transact (entry_ctx, line,
1490 : NULL, NULL, NULL, NULL, NULL, NULL);
1491 :
1492 0 : return unlock_pinentry (rc);
1493 : }
|