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