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