Line data Source code
1 : /* command.c - gpg-agent command handler
2 : * Copyright (C) 2001-2011 Free Software Foundation, Inc.
3 : * Copyright (C) 2001-2013 Werner Koch
4 : * Copyright (C) 2015 g10 Code GmbH.
5 : *
6 : * This file is part of GnuPG.
7 : *
8 : * GnuPG is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 3 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * GnuPG is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License
19 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
20 : */
21 :
22 : /* FIXME: we should not use the default assuan buffering but setup
23 : some buffering in secure mempory to protect session keys etc. */
24 :
25 : #include <config.h>
26 :
27 : #include <errno.h>
28 : #include <stdio.h>
29 : #include <stdlib.h>
30 : #include <string.h>
31 : #include <ctype.h>
32 : #include <unistd.h>
33 : #include <assert.h>
34 : #include <sys/types.h>
35 : #include <sys/stat.h>
36 : #include <dirent.h>
37 :
38 : #include "agent.h"
39 : #include <assuan.h>
40 : #include "i18n.h"
41 : #include "cvt-openpgp.h"
42 : #include "../common/ssh-utils.h"
43 : #include "../common/asshelp.h"
44 : #include "../common/server-help.h"
45 :
46 :
47 : /* Maximum allowed size of the inquired ciphertext. */
48 : #define MAXLEN_CIPHERTEXT 4096
49 : /* Maximum allowed size of the key parameters. */
50 : #define MAXLEN_KEYPARAM 1024
51 : /* Maximum allowed size of key data as used in inquiries (bytes). */
52 : #define MAXLEN_KEYDATA 8192
53 : /* The size of the import/export KEK key (in bytes). */
54 : #define KEYWRAP_KEYSIZE (128/8)
55 :
56 : /* A shortcut to call assuan_set_error using an gpg_err_code_t and a
57 : text string. */
58 : #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
59 :
60 : /* Check that the maximum digest length we support has at least the
61 : length of the keygrip. */
62 : #if MAX_DIGEST_LEN < 20
63 : #error MAX_DIGEST_LEN shorter than keygrip
64 : #endif
65 :
66 : /* Data used to associate an Assuan context with local server data.
67 : This is this modules local part of the server_control_s struct. */
68 : struct server_local_s
69 : {
70 : /* Our Assuan context. */
71 : assuan_context_t assuan_ctx;
72 :
73 : /* If this flag is true, the passphrase cache is used for signing
74 : operations. It defaults to true but may be set on a per
75 : connection base. The global option opt.ignore_cache_for_signing
76 : takes precedence over this flag. */
77 : unsigned int use_cache_for_signing : 1;
78 :
79 : /* Flag to suppress I/O logging during a command. */
80 : unsigned int pause_io_logging : 1;
81 :
82 : /* Flag indicating that the connection is from ourselves. */
83 : unsigned int connect_from_self : 1;
84 :
85 : /* Helper flag for io_monitor to allow suppressing of our own
86 : * greeting in some cases. See io_monitor for details. */
87 : unsigned int greeting_seen : 1;
88 :
89 : /* If this flag is set to true the agent will be terminated after
90 : the end of the current session. */
91 : unsigned int stopme : 1;
92 :
93 : /* Flag indicating whether pinentry notifications shall be done. */
94 : unsigned int allow_pinentry_notify : 1;
95 :
96 : /* An allocated description for the next key operation. This is
97 : used if a pinnetry needs to be popped up. */
98 : char *keydesc;
99 :
100 : /* Malloced KEK (Key-Encryption-Key) for the import_key command. */
101 : void *import_key;
102 :
103 : /* Malloced KEK for the export_key command. */
104 : void *export_key;
105 :
106 : /* Client is aware of the error code GPG_ERR_FULLY_CANCELED. */
107 : int allow_fully_canceled;
108 :
109 : /* Last CACHE_NONCE sent as status (malloced). */
110 : char *last_cache_nonce;
111 :
112 : /* Last PASSWD_NONCE sent as status (malloced). */
113 : char *last_passwd_nonce;
114 : };
115 :
116 :
117 : /* An entry for the getval/putval commands. */
118 : struct putval_item_s
119 : {
120 : struct putval_item_s *next;
121 : size_t off; /* Offset to the value into DATA. */
122 : size_t len; /* Length of the value. */
123 : char d[1]; /* Key | Nul | value. */
124 : };
125 :
126 :
127 : /* A list of key value pairs fpr the getval/putval commands. */
128 : static struct putval_item_s *putval_list;
129 :
130 :
131 :
132 : /* To help polling clients, we keep track of the number of certain
133 : events. This structure keeps those counters. The counters are
134 : integers and there should be no problem if they are overflowing as
135 : callers need to check only whether a counter changed. The actual
136 : values are not meaningful. */
137 : struct
138 : {
139 : /* Incremented if any of the other counters below changed. */
140 : unsigned int any;
141 :
142 : /* Incremented if a key is added or removed from the internal privat
143 : key database. */
144 : unsigned int key;
145 :
146 : /* Incremented if a change of the card readers stati has been
147 : detected. */
148 : unsigned int card;
149 :
150 : } eventcounter;
151 :
152 :
153 :
154 : /* Local prototypes. */
155 : static int command_has_option (const char *cmd, const char *cmdopt);
156 :
157 :
158 :
159 :
160 : /* Release the memory buffer MB but first wipe out the used memory. */
161 : static void
162 0 : clear_outbuf (membuf_t *mb)
163 : {
164 : void *p;
165 : size_t n;
166 :
167 0 : p = get_membuf (mb, &n);
168 0 : if (p)
169 : {
170 0 : wipememory (p, n);
171 0 : xfree (p);
172 : }
173 0 : }
174 :
175 :
176 : /* Write the content of memory buffer MB as assuan data to CTX and
177 : wipe the buffer out afterwards. */
178 : static gpg_error_t
179 408 : write_and_clear_outbuf (assuan_context_t ctx, membuf_t *mb)
180 : {
181 : gpg_error_t ae;
182 : void *p;
183 : size_t n;
184 :
185 408 : p = get_membuf (mb, &n);
186 408 : if (!p)
187 0 : return out_of_core ();
188 408 : ae = assuan_send_data (ctx, p, n);
189 408 : memset (p, 0, n);
190 408 : xfree (p);
191 408 : return ae;
192 : }
193 :
194 :
195 : /* Clear the nonces used to enable the passphrase cache for certain
196 : multi-command command sequences. */
197 : static void
198 1791 : clear_nonce_cache (ctrl_t ctrl)
199 : {
200 1791 : if (ctrl->server_local->last_cache_nonce)
201 : {
202 1 : agent_put_cache (ctrl->server_local->last_cache_nonce,
203 : CACHE_MODE_NONCE, NULL, 0);
204 1 : xfree (ctrl->server_local->last_cache_nonce);
205 1 : ctrl->server_local->last_cache_nonce = NULL;
206 : }
207 1791 : if (ctrl->server_local->last_passwd_nonce)
208 : {
209 0 : agent_put_cache (ctrl->server_local->last_passwd_nonce,
210 : CACHE_MODE_NONCE, NULL, 0);
211 0 : xfree (ctrl->server_local->last_passwd_nonce);
212 0 : ctrl->server_local->last_passwd_nonce = NULL;
213 : }
214 1791 : }
215 :
216 :
217 : /* This function is called by Libassuan whenever the client sends a
218 : reset. It has been registered similar to the other Assuan
219 : commands. */
220 : static gpg_error_t
221 1032 : reset_notify (assuan_context_t ctx, char *line)
222 : {
223 1032 : ctrl_t ctrl = assuan_get_pointer (ctx);
224 :
225 : (void) line;
226 :
227 1032 : memset (ctrl->keygrip, 0, 20);
228 1032 : ctrl->have_keygrip = 0;
229 1032 : ctrl->digest.valuelen = 0;
230 :
231 1032 : xfree (ctrl->server_local->keydesc);
232 1032 : ctrl->server_local->keydesc = NULL;
233 :
234 1032 : clear_nonce_cache (ctrl);
235 :
236 1032 : return 0;
237 : }
238 :
239 :
240 : /* Replace all '+' by a blank in the string S. */
241 : static void
242 441 : plus_to_blank (char *s)
243 : {
244 83913 : for (; *s; s++)
245 : {
246 83472 : if (*s == '+')
247 8647 : *s = ' ';
248 : }
249 441 : }
250 :
251 :
252 : /* Parse a hex string. Return an Assuan error code or 0 on success and the
253 : length of the parsed string in LEN. */
254 : static int
255 1940 : parse_hexstring (assuan_context_t ctx, const char *string, size_t *len)
256 : {
257 : const char *p;
258 : size_t n;
259 :
260 : /* parse the hash value */
261 1940 : for (p=string, n=0; hexdigitp (p); p++, n++)
262 : ;
263 1940 : if (*p != ' ' && *p != '\t' && *p)
264 0 : return set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
265 1940 : if ((n&1))
266 0 : return set_error (GPG_ERR_ASS_PARAMETER, "odd number of digits");
267 1940 : *len = n;
268 1940 : return 0;
269 : }
270 :
271 :
272 : /* Parse the keygrip in STRING into the provided buffer BUF. BUF must
273 : provide space for 20 bytes. BUF is not changed if the function
274 : returns an error. */
275 : static int
276 1664 : parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
277 : {
278 : int rc;
279 1664 : size_t n = 0;
280 :
281 1664 : rc = parse_hexstring (ctx, string, &n);
282 1664 : if (rc)
283 0 : return rc;
284 1664 : n /= 2;
285 1664 : if (n != 20)
286 0 : return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of keygrip");
287 :
288 1664 : if (hex2bin (string, buf, 20) < 0)
289 0 : return set_error (GPG_ERR_BUG, "hex2bin");
290 :
291 1664 : return 0;
292 : }
293 :
294 :
295 : /* Write an Assuan status line. KEYWORD is the first item on the
296 : status line. The following arguments are all separated by a space
297 : in the output. The last argument must be a NULL. Linefeeds and
298 : carriage returns characters (which are not allowed in an Assuan
299 : status line) are silently quoted in C-style. */
300 : gpg_error_t
301 62 : agent_write_status (ctrl_t ctrl, const char *keyword, ...)
302 : {
303 62 : gpg_error_t err = 0;
304 : va_list arg_ptr;
305 : const char *text;
306 62 : assuan_context_t ctx = ctrl->server_local->assuan_ctx;
307 : char buf[950], *p;
308 : size_t n;
309 :
310 62 : va_start (arg_ptr, keyword);
311 :
312 62 : p = buf;
313 62 : n = 0;
314 666 : while ( (text = va_arg (arg_ptr, const char *)) )
315 : {
316 542 : if (n)
317 : {
318 480 : *p++ = ' ';
319 480 : n++;
320 : }
321 3470 : for ( ; *text && n < DIM (buf)-3; n++, text++)
322 : {
323 2928 : if (*text == '\n')
324 : {
325 0 : *p++ = '\\';
326 0 : *p++ = 'n';
327 : }
328 2928 : else if (*text == '\r')
329 : {
330 0 : *p++ = '\\';
331 0 : *p++ = 'r';
332 : }
333 : else
334 2928 : *p++ = *text;
335 : }
336 : }
337 62 : *p = 0;
338 62 : err = assuan_write_status (ctx, keyword, buf);
339 :
340 62 : va_end (arg_ptr);
341 62 : return err;
342 : }
343 :
344 :
345 : /* This function is similar to print_assuan_status but takes a CTRL
346 : arg instead of an assuan context as first argument. */
347 : gpg_error_t
348 414 : agent_print_status (ctrl_t ctrl, const char *keyword, const char *format, ...)
349 : {
350 : gpg_error_t err;
351 : va_list arg_ptr;
352 414 : assuan_context_t ctx = ctrl->server_local->assuan_ctx;
353 :
354 414 : va_start (arg_ptr, format);
355 414 : err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
356 414 : va_end (arg_ptr);
357 414 : return err;
358 : }
359 :
360 :
361 : /* Helper to notify the client about a launched Pinentry. Because
362 : that might disturb some older clients, this is only done if enabled
363 : via an option. Returns an gpg error code. */
364 : gpg_error_t
365 13 : agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid, const char *extra)
366 : {
367 : char line[256];
368 :
369 13 : if (!ctrl || !ctrl->server_local
370 5 : || !ctrl->server_local->allow_pinentry_notify)
371 8 : return 0;
372 5 : snprintf (line, DIM(line), "PINENTRY_LAUNCHED %lu%s%s",
373 : pid, extra?" ":"", extra? extra:"");
374 5 : return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
375 : }
376 :
377 :
378 : /* An agent progress callback for Libgcrypt. This has been registered
379 : * to be called via the progress dispatcher mechanism from
380 : * gpg-agent.c */
381 : static void
382 414 : progress_cb (ctrl_t ctrl, const char *what, int printchar,
383 : int current, int total)
384 : {
385 414 : if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
386 : ;
387 414 : else if (printchar == '\n' && what && !strcmp (what, "primegen"))
388 8 : agent_print_status (ctrl, "PROGRESS", "%.20s X 100 100", what);
389 : else
390 406 : agent_print_status (ctrl, "PROGRESS", "%.20s %c %d %d",
391 : what, printchar=='\n'?'X':printchar, current, total);
392 414 : }
393 :
394 :
395 : /* Helper to print a message while leaving a command. Note that this
396 : * function does not call assuan_set_error; the caller may do this
397 : * prior to calling us. */
398 : static gpg_error_t
399 603 : leave_cmd (assuan_context_t ctx, gpg_error_t err)
400 : {
401 603 : if (err)
402 : {
403 2 : const char *name = assuan_get_command_name (ctx);
404 2 : if (!name)
405 0 : name = "?";
406 :
407 : /* Not all users of gpg-agent know about the fully canceled
408 : error code; map it back if needed. */
409 2 : if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
410 : {
411 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
412 :
413 0 : if (!ctrl->server_local->allow_fully_canceled)
414 0 : err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
415 : }
416 :
417 : /* Most code from common/ does not know the error source, thus
418 : we fix this here. */
419 2 : if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN)
420 0 : err = gpg_err_make (GPG_ERR_SOURCE_DEFAULT, gpg_err_code (err));
421 :
422 2 : if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
423 2 : log_error ("command '%s' failed: %s\n", name,
424 : gpg_strerror (err));
425 : else
426 0 : log_error ("command '%s' failed: %s <%s>\n", name,
427 : gpg_strerror (err), gpg_strsource (err));
428 : }
429 603 : return err;
430 : }
431 :
432 :
433 :
434 : static const char hlp_geteventcounter[] =
435 : "GETEVENTCOUNTER\n"
436 : "\n"
437 : "Return a a status line named EVENTCOUNTER with the current values\n"
438 : "of all event counters. The values are decimal numbers in the range\n"
439 : "0 to UINT_MAX and wrapping around to 0. The actual values should\n"
440 : "not be relied upon, they shall only be used to detect a change.\n"
441 : "\n"
442 : "The currently defined counters are:\n"
443 : "\n"
444 : "ANY - Incremented with any change of any of the other counters.\n"
445 : "KEY - Incremented for added or removed private keys.\n"
446 : "CARD - Incremented for changes of the card readers stati.";
447 : static gpg_error_t
448 0 : cmd_geteventcounter (assuan_context_t ctx, char *line)
449 : {
450 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
451 :
452 : (void)line;
453 :
454 0 : if (ctrl->restricted)
455 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
456 :
457 0 : return agent_print_status (ctrl, "EVENTCOUNTER", "%u %u %u",
458 : eventcounter.any,
459 : eventcounter.key,
460 : eventcounter.card);
461 : }
462 :
463 :
464 : /* This function should be called once for all key removals or
465 : additions. This function is assured not to do any context
466 : switches. */
467 : void
468 48 : bump_key_eventcounter (void)
469 : {
470 48 : eventcounter.key++;
471 48 : eventcounter.any++;
472 48 : }
473 :
474 :
475 : /* This function should be called for all card reader status
476 : changes. This function is assured not to do any context
477 : switches. */
478 : void
479 0 : bump_card_eventcounter (void)
480 : {
481 0 : eventcounter.card++;
482 0 : eventcounter.any++;
483 0 : }
484 :
485 :
486 :
487 :
488 : static const char hlp_istrusted[] =
489 : "ISTRUSTED <hexstring_with_fingerprint>\n"
490 : "\n"
491 : "Return OK when we have an entry with this fingerprint in our\n"
492 : "trustlist";
493 : static gpg_error_t
494 0 : cmd_istrusted (assuan_context_t ctx, char *line)
495 : {
496 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
497 : int rc, n, i;
498 : char *p;
499 : char fpr[41];
500 :
501 : /* Parse the fingerprint value. */
502 0 : for (p=line,n=0; hexdigitp (p); p++, n++)
503 : ;
504 0 : if (*p || !(n == 40 || n == 32))
505 0 : return set_error (GPG_ERR_ASS_PARAMETER, "invalid fingerprint");
506 0 : i = 0;
507 0 : if (n==32)
508 : {
509 0 : strcpy (fpr, "00000000");
510 0 : i += 8;
511 : }
512 0 : for (p=line; i < 40; p++, i++)
513 0 : fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
514 0 : fpr[i] = 0;
515 0 : rc = agent_istrusted (ctrl, fpr, NULL);
516 0 : if (!rc || gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
517 0 : return rc;
518 0 : else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF )
519 0 : return gpg_error (GPG_ERR_NOT_TRUSTED);
520 : else
521 0 : return leave_cmd (ctx, rc);
522 : }
523 :
524 :
525 : static const char hlp_listtrusted[] =
526 : "LISTTRUSTED\n"
527 : "\n"
528 : "List all entries from the trustlist.";
529 : static gpg_error_t
530 0 : cmd_listtrusted (assuan_context_t ctx, char *line)
531 : {
532 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
533 : int rc;
534 :
535 : (void)line;
536 :
537 0 : if (ctrl->restricted)
538 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
539 :
540 0 : rc = agent_listtrusted (ctx);
541 0 : return leave_cmd (ctx, rc);
542 : }
543 :
544 :
545 : static const char hlp_martrusted[] =
546 : "MARKTRUSTED <hexstring_with_fingerprint> <flag> <display_name>\n"
547 : "\n"
548 : "Store a new key in into the trustlist.";
549 : static gpg_error_t
550 0 : cmd_marktrusted (assuan_context_t ctx, char *line)
551 : {
552 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
553 : int rc, n, i;
554 : char *p;
555 : char fpr[41];
556 : int flag;
557 :
558 0 : if (ctrl->restricted)
559 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
560 :
561 : /* parse the fingerprint value */
562 0 : for (p=line,n=0; hexdigitp (p); p++, n++)
563 : ;
564 0 : if (!spacep (p) || !(n == 40 || n == 32))
565 0 : return set_error (GPG_ERR_ASS_PARAMETER, "invalid fingerprint");
566 0 : i = 0;
567 0 : if (n==32)
568 : {
569 0 : strcpy (fpr, "00000000");
570 0 : i += 8;
571 : }
572 0 : for (p=line; i < 40; p++, i++)
573 0 : fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
574 0 : fpr[i] = 0;
575 :
576 0 : while (spacep (p))
577 0 : p++;
578 0 : flag = *p++;
579 0 : if ( (flag != 'S' && flag != 'P') || !spacep (p) )
580 0 : return set_error (GPG_ERR_ASS_PARAMETER, "invalid flag - must be P or S");
581 0 : while (spacep (p))
582 0 : p++;
583 :
584 0 : rc = agent_marktrusted (ctrl, p, fpr, flag);
585 0 : return leave_cmd (ctx, rc);
586 : }
587 :
588 :
589 :
590 :
591 : static const char hlp_havekey[] =
592 : "HAVEKEY <hexstrings_with_keygrips>\n"
593 : "\n"
594 : "Return success if at least one of the secret keys with the given\n"
595 : "keygrips is available.";
596 : static gpg_error_t
597 1196 : cmd_havekey (assuan_context_t ctx, char *line)
598 : {
599 : gpg_error_t err;
600 : unsigned char buf[20];
601 :
602 : do
603 : {
604 1196 : err = parse_keygrip (ctx, line, buf);
605 1196 : if (err)
606 0 : return err;
607 :
608 1196 : if (!agent_key_available (buf))
609 965 : return 0; /* Found. */
610 :
611 9702 : while (*line && *line != ' ' && *line != '\t')
612 9240 : line++;
613 462 : while (*line == ' ' || *line == '\t')
614 0 : line++;
615 : }
616 231 : while (*line);
617 :
618 : /* No leave_cmd() here because errors are expected and would clutter
619 : the log. */
620 231 : return gpg_error (GPG_ERR_NO_SECKEY);
621 : }
622 :
623 :
624 : static const char hlp_sigkey[] =
625 : "SIGKEY <hexstring_with_keygrip>\n"
626 : "SETKEY <hexstring_with_keygrip>\n"
627 : "\n"
628 : "Set the key used for a sign or decrypt operation.";
629 : static gpg_error_t
630 403 : cmd_sigkey (assuan_context_t ctx, char *line)
631 : {
632 : int rc;
633 403 : ctrl_t ctrl = assuan_get_pointer (ctx);
634 :
635 403 : rc = parse_keygrip (ctx, line, ctrl->keygrip);
636 403 : if (rc)
637 0 : return rc;
638 403 : ctrl->have_keygrip = 1;
639 403 : return 0;
640 : }
641 :
642 :
643 : static const char hlp_setkeydesc[] =
644 : "SETKEYDESC plus_percent_escaped_string\n"
645 : "\n"
646 : "Set a description to be used for the next PKSIGN, PKDECRYPT, IMPORT_KEY\n"
647 : "or EXPORT_KEY operation if this operation requires a passphrase. If\n"
648 : "this command is not used a default text will be used. Note, that\n"
649 : "this description implictly selects the label used for the entry\n"
650 : "box; if the string contains the string PIN (which in general will\n"
651 : "not be translated), \"PIN\" is used, otherwise the translation of\n"
652 : "\"passphrase\" is used. The description string should not contain\n"
653 : "blanks unless they are percent or '+' escaped.\n"
654 : "\n"
655 : "The description is only valid for the next PKSIGN, PKDECRYPT,\n"
656 : "IMPORT_KEY, EXPORT_KEY, or DELETE_KEY operation.";
657 : static gpg_error_t
658 441 : cmd_setkeydesc (assuan_context_t ctx, char *line)
659 : {
660 441 : ctrl_t ctrl = assuan_get_pointer (ctx);
661 : char *desc, *p;
662 :
663 441 : for (p=line; *p == ' '; p++)
664 : ;
665 441 : desc = p;
666 441 : p = strchr (desc, ' ');
667 441 : if (p)
668 0 : *p = 0; /* We ignore any garbage; we might late use it for other args. */
669 :
670 441 : if (!*desc)
671 0 : return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
672 :
673 : /* Note, that we only need to replace the + characters and should
674 : leave the other escaping in place because the escaped string is
675 : send verbatim to the pinentry which does the unescaping (but not
676 : the + replacing) */
677 441 : plus_to_blank (desc);
678 :
679 441 : xfree (ctrl->server_local->keydesc);
680 :
681 441 : if (ctrl->restricted)
682 : {
683 0 : ctrl->server_local->keydesc = strconcat
684 0 : ((ctrl->restricted == 2
685 : ? _("Note: Request from the web browser.")
686 : : _("Note: Request from a remote site.") ), "%0A%0A", desc, NULL);
687 : }
688 : else
689 441 : ctrl->server_local->keydesc = xtrystrdup (desc);
690 441 : if (!ctrl->server_local->keydesc)
691 0 : return out_of_core ();
692 441 : return 0;
693 : }
694 :
695 :
696 : static const char hlp_sethash[] =
697 : "SETHASH (--hash=<name>)|(<algonumber>) <hexstring>\n"
698 : "\n"
699 : "The client can use this command to tell the server about the data\n"
700 : "(which usually is a hash) to be signed.";
701 : static gpg_error_t
702 141 : cmd_sethash (assuan_context_t ctx, char *line)
703 : {
704 : int rc;
705 : size_t n;
706 : char *p;
707 141 : ctrl_t ctrl = assuan_get_pointer (ctx);
708 : unsigned char *buf;
709 : char *endp;
710 : int algo;
711 :
712 : /* Parse the alternative hash options which may be used instead of
713 : the algo number. */
714 141 : if (has_option_name (line, "--hash"))
715 : {
716 0 : if (has_option (line, "--hash=sha1"))
717 0 : algo = GCRY_MD_SHA1;
718 0 : else if (has_option (line, "--hash=sha224"))
719 0 : algo = GCRY_MD_SHA224;
720 0 : else if (has_option (line, "--hash=sha256"))
721 0 : algo = GCRY_MD_SHA256;
722 0 : else if (has_option (line, "--hash=sha384"))
723 0 : algo = GCRY_MD_SHA384;
724 0 : else if (has_option (line, "--hash=sha512"))
725 0 : algo = GCRY_MD_SHA512;
726 0 : else if (has_option (line, "--hash=rmd160"))
727 0 : algo = GCRY_MD_RMD160;
728 0 : else if (has_option (line, "--hash=md5"))
729 0 : algo = GCRY_MD_MD5;
730 0 : else if (has_option (line, "--hash=tls-md5sha1"))
731 0 : algo = MD_USER_TLS_MD5SHA1;
732 : else
733 0 : return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
734 : }
735 : else
736 141 : algo = 0;
737 :
738 141 : line = skip_options (line);
739 :
740 141 : if (!algo)
741 : {
742 : /* No hash option has been given: require an algo number instead */
743 141 : algo = (int)strtoul (line, &endp, 10);
744 141 : for (line = endp; *line == ' ' || *line == '\t'; line++)
745 : ;
746 141 : if (!algo || gcry_md_test_algo (algo))
747 0 : return set_error (GPG_ERR_UNSUPPORTED_ALGORITHM, NULL);
748 : }
749 141 : ctrl->digest.algo = algo;
750 141 : ctrl->digest.raw_value = 0;
751 :
752 : /* Parse the hash value. */
753 141 : n = 0;
754 141 : rc = parse_hexstring (ctx, line, &n);
755 141 : if (rc)
756 0 : return rc;
757 141 : n /= 2;
758 141 : if (algo == MD_USER_TLS_MD5SHA1 && n == 36)
759 : ;
760 141 : else if (n != 16 && n != 20 && n != 24
761 50 : && n != 28 && n != 32 && n != 48 && n != 64)
762 0 : return set_error (GPG_ERR_ASS_PARAMETER, "unsupported length of hash");
763 :
764 141 : if (n > MAX_DIGEST_LEN)
765 0 : return set_error (GPG_ERR_ASS_PARAMETER, "hash value to long");
766 :
767 141 : buf = ctrl->digest.value;
768 141 : ctrl->digest.valuelen = n;
769 3985 : for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
770 3844 : buf[n] = xtoi_2 (p);
771 141 : for (; n < ctrl->digest.valuelen; n++)
772 0 : buf[n] = 0;
773 141 : return 0;
774 : }
775 :
776 :
777 : static const char hlp_pksign[] =
778 : "PKSIGN [<options>] [<cache_nonce>]\n"
779 : "\n"
780 : "Perform the actual sign operation. Neither input nor output are\n"
781 : "sensitive to eavesdropping.";
782 : static gpg_error_t
783 141 : cmd_pksign (assuan_context_t ctx, char *line)
784 : {
785 : int rc;
786 141 : cache_mode_t cache_mode = CACHE_MODE_NORMAL;
787 141 : ctrl_t ctrl = assuan_get_pointer (ctx);
788 : membuf_t outbuf;
789 141 : char *cache_nonce = NULL;
790 : char *p;
791 :
792 141 : line = skip_options (line);
793 :
794 141 : p = line;
795 141 : for (p=line; *p && *p != ' ' && *p != '\t'; p++)
796 : ;
797 141 : *p = '\0';
798 141 : if (*line)
799 3 : cache_nonce = xtrystrdup (line);
800 :
801 141 : if (opt.ignore_cache_for_signing)
802 0 : cache_mode = CACHE_MODE_IGNORE;
803 141 : else if (!ctrl->server_local->use_cache_for_signing)
804 0 : cache_mode = CACHE_MODE_IGNORE;
805 :
806 141 : init_membuf (&outbuf, 512);
807 :
808 141 : rc = agent_pksign (ctrl, cache_nonce, ctrl->server_local->keydesc,
809 : &outbuf, cache_mode);
810 141 : if (rc)
811 0 : clear_outbuf (&outbuf);
812 : else
813 141 : rc = write_and_clear_outbuf (ctx, &outbuf);
814 :
815 141 : xfree (cache_nonce);
816 141 : xfree (ctrl->server_local->keydesc);
817 141 : ctrl->server_local->keydesc = NULL;
818 141 : return leave_cmd (ctx, rc);
819 : }
820 :
821 :
822 : static const char hlp_pkdecrypt[] =
823 : "PKDECRYPT [<options>]\n"
824 : "\n"
825 : "Perform the actual decrypt operation. Input is not\n"
826 : "sensitive to eavesdropping.";
827 : static gpg_error_t
828 262 : cmd_pkdecrypt (assuan_context_t ctx, char *line)
829 : {
830 : int rc;
831 262 : ctrl_t ctrl = assuan_get_pointer (ctx);
832 : unsigned char *value;
833 : size_t valuelen;
834 : membuf_t outbuf;
835 : int padding;
836 :
837 : (void)line;
838 :
839 : /* First inquire the data to decrypt */
840 262 : rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_CIPHERTEXT);
841 262 : if (!rc)
842 262 : rc = assuan_inquire (ctx, "CIPHERTEXT",
843 : &value, &valuelen, MAXLEN_CIPHERTEXT);
844 262 : if (rc)
845 0 : return rc;
846 :
847 262 : init_membuf (&outbuf, 512);
848 :
849 262 : rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc,
850 : value, valuelen, &outbuf, &padding);
851 262 : xfree (value);
852 262 : if (rc)
853 0 : clear_outbuf (&outbuf);
854 : else
855 : {
856 262 : if (padding != -1)
857 0 : rc = print_assuan_status (ctx, "PADDING", "%d", padding);
858 : else
859 262 : rc = 0;
860 262 : if (!rc)
861 262 : rc = write_and_clear_outbuf (ctx, &outbuf);
862 : }
863 262 : xfree (ctrl->server_local->keydesc);
864 262 : ctrl->server_local->keydesc = NULL;
865 262 : return leave_cmd (ctx, rc);
866 : }
867 :
868 :
869 : static const char hlp_genkey[] =
870 : "GENKEY [--no-protection] [--preset] [--inq-passwd]\n"
871 : " [--passwd-nonce=<s>] [<cache_nonce>]\n"
872 : "\n"
873 : "Generate a new key, store the secret part and return the public\n"
874 : "part. Here is an example transaction:\n"
875 : "\n"
876 : " C: GENKEY\n"
877 : " S: INQUIRE KEYPARAM\n"
878 : " C: D (genkey (rsa (nbits 2048)))\n"
879 : " C: END\n"
880 : " S: D (public-key\n"
881 : " S: D (rsa (n 326487324683264) (e 10001)))\n"
882 : " S: OK key created\n"
883 : "\n"
884 : "When the --preset option is used the passphrase for the generated\n"
885 : "key will be added to the cache. When --inq-passwd is used an inquire\n"
886 : "with the keyword NEWPASSWD is used to request the passphrase for the\n"
887 : "new key. When a --passwd-nonce is used, the corresponding cached\n"
888 : "passphrase is used to protect the new key.";
889 : static gpg_error_t
890 5 : cmd_genkey (assuan_context_t ctx, char *line)
891 : {
892 5 : ctrl_t ctrl = assuan_get_pointer (ctx);
893 : int rc;
894 : int no_protection;
895 : unsigned char *value;
896 : size_t valuelen;
897 5 : unsigned char *newpasswd = NULL;
898 : membuf_t outbuf;
899 5 : char *cache_nonce = NULL;
900 5 : char *passwd_nonce = NULL;
901 : int opt_preset;
902 : int opt_inq_passwd;
903 : size_t n;
904 : char *p, *pend;
905 : int c;
906 :
907 5 : if (ctrl->restricted)
908 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
909 :
910 5 : no_protection = has_option (line, "--no-protection");
911 5 : opt_preset = has_option (line, "--preset");
912 5 : opt_inq_passwd = has_option (line, "--inq-passwd");
913 5 : passwd_nonce = option_value (line, "--passwd-nonce");
914 5 : if (passwd_nonce)
915 : {
916 0 : for (pend = passwd_nonce; *pend && !spacep (pend); pend++)
917 : ;
918 0 : c = *pend;
919 0 : *pend = '\0';
920 0 : passwd_nonce = xtrystrdup (passwd_nonce);
921 0 : *pend = c;
922 0 : if (!passwd_nonce)
923 : {
924 0 : rc = gpg_error_from_syserror ();
925 0 : goto leave;
926 : }
927 : }
928 5 : line = skip_options (line);
929 :
930 5 : p = line;
931 5 : for (p=line; *p && *p != ' ' && *p != '\t'; p++)
932 : ;
933 5 : *p = '\0';
934 5 : if (*line)
935 1 : cache_nonce = xtrystrdup (line);
936 :
937 : /* First inquire the parameters */
938 5 : rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_KEYPARAM);
939 5 : if (!rc)
940 5 : rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
941 5 : if (rc)
942 0 : return rc;
943 :
944 5 : init_membuf (&outbuf, 512);
945 :
946 : /* If requested, ask for the password to be used for the key. If
947 : this is not used the regular Pinentry mechanism is used. */
948 5 : if (opt_inq_passwd && !no_protection)
949 : {
950 : /* (N is used as a dummy) */
951 0 : assuan_begin_confidential (ctx);
952 0 : rc = assuan_inquire (ctx, "NEWPASSWD", &newpasswd, &n, 256);
953 0 : assuan_end_confidential (ctx);
954 0 : if (rc)
955 0 : goto leave;
956 0 : if (!*newpasswd)
957 : {
958 : /* Empty password given - switch to no-protection mode. */
959 0 : xfree (newpasswd);
960 0 : newpasswd = NULL;
961 0 : no_protection = 1;
962 : }
963 :
964 : }
965 5 : else if (passwd_nonce)
966 0 : newpasswd = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
967 :
968 5 : rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection,
969 : newpasswd, opt_preset, &outbuf);
970 :
971 : leave:
972 5 : if (newpasswd)
973 : {
974 : /* Assuan_inquire does not allow us to read into secure memory
975 : thus we need to wipe it ourself. */
976 0 : wipememory (newpasswd, strlen (newpasswd));
977 0 : xfree (newpasswd);
978 : }
979 5 : xfree (value);
980 5 : if (rc)
981 0 : clear_outbuf (&outbuf);
982 : else
983 5 : rc = write_and_clear_outbuf (ctx, &outbuf);
984 5 : xfree (cache_nonce);
985 5 : xfree (passwd_nonce);
986 5 : return leave_cmd (ctx, rc);
987 : }
988 :
989 :
990 :
991 :
992 : static const char hlp_readkey[] =
993 : "READKEY <hexstring_with_keygrip>\n"
994 : " --card <keyid>\n"
995 : "\n"
996 : "Return the public key for the given keygrip or keyid.\n"
997 : "With --card, private key file with card information will be created.";
998 : static gpg_error_t
999 0 : cmd_readkey (assuan_context_t ctx, char *line)
1000 : {
1001 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1002 : int rc;
1003 : unsigned char grip[20];
1004 0 : gcry_sexp_t s_pkey = NULL;
1005 0 : unsigned char *pkbuf = NULL;
1006 0 : char *serialno = NULL;
1007 : size_t pkbuflen;
1008 : const char *opt_card;
1009 :
1010 0 : if (ctrl->restricted)
1011 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1012 :
1013 0 : opt_card = has_option_name (line, "--card");
1014 0 : line = skip_options (line);
1015 :
1016 0 : if (opt_card)
1017 : {
1018 0 : const char *keyid = opt_card;
1019 :
1020 0 : rc = agent_card_getattr (ctrl, "SERIALNO", &serialno);
1021 0 : if (rc)
1022 : {
1023 0 : log_error (_("error getting serial number of card: %s\n"),
1024 : gpg_strerror (rc));
1025 0 : goto leave;
1026 : }
1027 :
1028 0 : rc = agent_card_readkey (ctrl, keyid, &pkbuf);
1029 0 : if (rc)
1030 0 : goto leave;
1031 0 : pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
1032 0 : rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)pkbuf, pkbuflen);
1033 0 : if (rc)
1034 0 : goto leave;
1035 :
1036 0 : if (!gcry_pk_get_keygrip (s_pkey, grip))
1037 : {
1038 0 : rc = gcry_pk_testkey (s_pkey);
1039 0 : if (rc == 0)
1040 0 : rc = gpg_error (GPG_ERR_INTERNAL);
1041 :
1042 0 : goto leave;
1043 : }
1044 :
1045 0 : rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0);
1046 0 : if (rc)
1047 0 : goto leave;
1048 :
1049 0 : rc = assuan_send_data (ctx, pkbuf, pkbuflen);
1050 : }
1051 : else
1052 : {
1053 0 : rc = parse_keygrip (ctx, line, grip);
1054 0 : if (rc)
1055 0 : goto leave;
1056 :
1057 0 : rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
1058 0 : if (!rc)
1059 : {
1060 0 : pkbuflen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
1061 0 : log_assert (pkbuflen);
1062 0 : pkbuf = xtrymalloc (pkbuflen);
1063 0 : if (!pkbuf)
1064 0 : rc = gpg_error_from_syserror ();
1065 : else
1066 : {
1067 0 : gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, pkbuf, pkbuflen);
1068 0 : rc = assuan_send_data (ctx, pkbuf, pkbuflen);
1069 : }
1070 : }
1071 : }
1072 :
1073 : leave:
1074 0 : xfree (serialno);
1075 0 : xfree (pkbuf);
1076 0 : gcry_sexp_release (s_pkey);
1077 0 : return leave_cmd (ctx, rc);
1078 : }
1079 :
1080 :
1081 :
1082 : static const char hlp_keyinfo[] =
1083 : "KEYINFO [--[ssh-]list] [--data] [--ssh-fpr] [--with-ssh] <keygrip>\n"
1084 : "\n"
1085 : "Return information about the key specified by the KEYGRIP. If the\n"
1086 : "key is not available GPG_ERR_NOT_FOUND is returned. If the option\n"
1087 : "--list is given the keygrip is ignored and information about all\n"
1088 : "available keys are returned. If --ssh-list is given information\n"
1089 : "about all keys listed in the sshcontrol are returned. With --with-ssh\n"
1090 : "information from sshcontrol is always added to the info. Unless --data\n"
1091 : "is given, the information is returned as a status line using the format:\n"
1092 : "\n"
1093 : " KEYINFO <keygrip> <type> <serialno> <idstr> <cached> <protection> <fpr>\n"
1094 : "\n"
1095 : "KEYGRIP is the keygrip.\n"
1096 : "\n"
1097 : "TYPE is describes the type of the key:\n"
1098 : " 'D' - Regular key stored on disk,\n"
1099 : " 'T' - Key is stored on a smartcard (token),\n"
1100 : " 'X' - Unknown type,\n"
1101 : " '-' - Key is missing.\n"
1102 : "\n"
1103 : "SERIALNO is an ASCII string with the serial number of the\n"
1104 : " smartcard. If the serial number is not known a single\n"
1105 : " dash '-' is used instead.\n"
1106 : "\n"
1107 : "IDSTR is the IDSTR used to distinguish keys on a smartcard. If it\n"
1108 : " is not known a dash is used instead.\n"
1109 : "\n"
1110 : "CACHED is 1 if the passphrase for the key was found in the key cache.\n"
1111 : " If not, a '-' is used instead.\n"
1112 : "\n"
1113 : "PROTECTION describes the key protection type:\n"
1114 : " 'P' - The key is protected with a passphrase,\n"
1115 : " 'C' - The key is not protected,\n"
1116 : " '-' - Unknown protection.\n"
1117 : "\n"
1118 : "FPR returns the formatted ssh-style fingerprint of the key. It is only\n"
1119 : " printed if the option --ssh-fpr has been used. It defaults to '-'.\n"
1120 : "\n"
1121 : "TTL is the TTL in seconds for that key or '-' if n/a.\n"
1122 : "\n"
1123 : "FLAGS is a word consisting of one-letter flags:\n"
1124 : " 'D' - The key has been disabled,\n"
1125 : " 'S' - The key is listed in sshcontrol (requires --with-ssh),\n"
1126 : " 'c' - Use of the key needs to be confirmed,\n"
1127 : " '-' - No flags given.\n"
1128 : "\n"
1129 : "More information may be added in the future.";
1130 : static gpg_error_t
1131 60 : do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
1132 : int data, int with_ssh_fpr, int in_ssh,
1133 : int ttl, int disabled, int confirm)
1134 : {
1135 : gpg_error_t err;
1136 : char hexgrip[40+1];
1137 60 : char *fpr = NULL;
1138 : int keytype;
1139 60 : unsigned char *shadow_info = NULL;
1140 60 : char *serialno = NULL;
1141 60 : char *idstr = NULL;
1142 : const char *keytypestr;
1143 : const char *cached;
1144 : const char *protectionstr;
1145 : char *pw;
1146 60 : int missing_key = 0;
1147 : char ttlbuf[20];
1148 : char flagsbuf[5];
1149 :
1150 60 : err = agent_key_info_from_file (ctrl, grip, &keytype, &shadow_info);
1151 60 : if (err)
1152 : {
1153 0 : if (in_ssh && gpg_err_code (err) == GPG_ERR_NOT_FOUND)
1154 0 : missing_key = 1;
1155 : else
1156 : goto leave;
1157 : }
1158 :
1159 : /* Reformat the grip so that we use uppercase as good style. */
1160 60 : bin2hex (grip, 20, hexgrip);
1161 :
1162 60 : if (ttl > 0)
1163 0 : snprintf (ttlbuf, sizeof ttlbuf, "%d", ttl);
1164 : else
1165 60 : strcpy (ttlbuf, "-");
1166 :
1167 60 : *flagsbuf = 0;
1168 60 : if (disabled)
1169 0 : strcat (flagsbuf, "D");
1170 60 : if (in_ssh)
1171 0 : strcat (flagsbuf, "S");
1172 60 : if (confirm)
1173 0 : strcat (flagsbuf, "c");
1174 60 : if (!*flagsbuf)
1175 60 : strcpy (flagsbuf, "-");
1176 :
1177 :
1178 60 : if (missing_key)
1179 : {
1180 0 : protectionstr = "-"; keytypestr = "-";
1181 : }
1182 : else
1183 : {
1184 60 : switch (keytype)
1185 : {
1186 : case PRIVATE_KEY_CLEAR:
1187 : case PRIVATE_KEY_OPENPGP_NONE:
1188 20 : protectionstr = "C"; keytypestr = "D";
1189 20 : break;
1190 40 : case PRIVATE_KEY_PROTECTED: protectionstr = "P"; keytypestr = "D";
1191 40 : break;
1192 0 : case PRIVATE_KEY_SHADOWED: protectionstr = "-"; keytypestr = "T";
1193 0 : break;
1194 0 : default: protectionstr = "-"; keytypestr = "X";
1195 0 : break;
1196 : }
1197 : }
1198 :
1199 : /* Compute the ssh fingerprint if requested. */
1200 60 : if (with_ssh_fpr)
1201 : {
1202 : gcry_sexp_t key;
1203 :
1204 0 : if (!agent_raw_key_from_file (ctrl, grip, &key))
1205 : {
1206 0 : ssh_get_fingerprint_string (key, &fpr);
1207 0 : gcry_sexp_release (key);
1208 : }
1209 : }
1210 :
1211 : /* Here we have a little race by doing the cache check separately
1212 : from the retrieval function. Given that the cache flag is only a
1213 : hint, it should not really matter. */
1214 60 : pw = agent_get_cache (hexgrip, CACHE_MODE_NORMAL);
1215 60 : cached = pw ? "1" : "-";
1216 60 : xfree (pw);
1217 :
1218 60 : if (shadow_info)
1219 : {
1220 0 : err = parse_shadow_info (shadow_info, &serialno, &idstr, NULL);
1221 0 : if (err)
1222 0 : goto leave;
1223 : }
1224 :
1225 60 : if (!data)
1226 180 : err = agent_write_status (ctrl, "KEYINFO",
1227 : hexgrip,
1228 : keytypestr,
1229 60 : serialno? serialno : "-",
1230 60 : idstr? idstr : "-",
1231 : cached,
1232 : protectionstr,
1233 60 : fpr? fpr : "-",
1234 : ttlbuf,
1235 : flagsbuf,
1236 : NULL);
1237 : else
1238 : {
1239 : char *string;
1240 :
1241 0 : string = xtryasprintf ("%s %s %s %s %s %s %s %s %s\n",
1242 : hexgrip, keytypestr,
1243 0 : serialno? serialno : "-",
1244 0 : idstr? idstr : "-", cached, protectionstr,
1245 0 : fpr? fpr : "-",
1246 : ttlbuf,
1247 : flagsbuf);
1248 0 : if (!string)
1249 0 : err = gpg_error_from_syserror ();
1250 : else
1251 0 : err = assuan_send_data (ctx, string, strlen(string));
1252 0 : xfree (string);
1253 : }
1254 :
1255 : leave:
1256 60 : xfree (fpr);
1257 60 : xfree (shadow_info);
1258 60 : xfree (serialno);
1259 60 : xfree (idstr);
1260 60 : return err;
1261 : }
1262 :
1263 :
1264 : /* Entry int for the command KEYINFO. This function handles the
1265 : command option processing. For details see hlp_keyinfo above. */
1266 : static gpg_error_t
1267 60 : cmd_keyinfo (assuan_context_t ctx, char *line)
1268 : {
1269 60 : ctrl_t ctrl = assuan_get_pointer (ctx);
1270 : int err;
1271 : unsigned char grip[20];
1272 60 : DIR *dir = NULL;
1273 : int list_mode;
1274 : int opt_data, opt_ssh_fpr, opt_with_ssh;
1275 60 : ssh_control_file_t cf = NULL;
1276 : char hexgrip[41];
1277 : int disabled, ttl, confirm, is_ssh;
1278 :
1279 60 : if (ctrl->restricted)
1280 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1281 :
1282 60 : if (has_option (line, "--ssh-list"))
1283 0 : list_mode = 2;
1284 : else
1285 60 : list_mode = has_option (line, "--list");
1286 60 : opt_data = has_option (line, "--data");
1287 60 : opt_ssh_fpr = has_option (line, "--ssh-fpr");
1288 60 : opt_with_ssh = has_option (line, "--with-ssh");
1289 60 : line = skip_options (line);
1290 :
1291 60 : if (opt_with_ssh || list_mode == 2)
1292 0 : cf = ssh_open_control_file ();
1293 :
1294 60 : if (list_mode == 2)
1295 : {
1296 0 : if (cf)
1297 : {
1298 0 : while (!ssh_read_control_file (cf, hexgrip,
1299 : &disabled, &ttl, &confirm))
1300 : {
1301 0 : if (hex2bin (hexgrip, grip, 20) < 0 )
1302 0 : continue; /* Bad hex string. */
1303 0 : err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, 1,
1304 : ttl, disabled, confirm);
1305 0 : if (err)
1306 0 : goto leave;
1307 : }
1308 : }
1309 0 : err = 0;
1310 : }
1311 60 : else if (list_mode)
1312 : {
1313 : char *dirname;
1314 : struct dirent *dir_entry;
1315 :
1316 0 : dirname = make_filename_try (gnupg_homedir (),
1317 : GNUPG_PRIVATE_KEYS_DIR, NULL);
1318 0 : if (!dirname)
1319 : {
1320 0 : err = gpg_error_from_syserror ();
1321 0 : goto leave;
1322 : }
1323 0 : dir = opendir (dirname);
1324 0 : if (!dir)
1325 : {
1326 0 : err = gpg_error_from_syserror ();
1327 0 : xfree (dirname);
1328 0 : goto leave;
1329 : }
1330 0 : xfree (dirname);
1331 :
1332 0 : while ( (dir_entry = readdir (dir)) )
1333 : {
1334 0 : if (strlen (dir_entry->d_name) != 44
1335 0 : || strcmp (dir_entry->d_name + 40, ".key"))
1336 0 : continue;
1337 0 : strncpy (hexgrip, dir_entry->d_name, 40);
1338 0 : hexgrip[40] = 0;
1339 :
1340 0 : if ( hex2bin (hexgrip, grip, 20) < 0 )
1341 0 : continue; /* Bad hex string. */
1342 :
1343 0 : disabled = ttl = confirm = is_ssh = 0;
1344 0 : if (opt_with_ssh)
1345 : {
1346 0 : err = ssh_search_control_file (cf, hexgrip,
1347 : &disabled, &ttl, &confirm);
1348 0 : if (!err)
1349 0 : is_ssh = 1;
1350 0 : else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
1351 0 : goto leave;
1352 : }
1353 :
1354 0 : err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, is_ssh,
1355 : ttl, disabled, confirm);
1356 0 : if (err)
1357 0 : goto leave;
1358 : }
1359 0 : err = 0;
1360 : }
1361 : else
1362 : {
1363 60 : err = parse_keygrip (ctx, line, grip);
1364 60 : if (err)
1365 0 : goto leave;
1366 60 : disabled = ttl = confirm = is_ssh = 0;
1367 60 : if (opt_with_ssh)
1368 : {
1369 0 : err = ssh_search_control_file (cf, line,
1370 : &disabled, &ttl, &confirm);
1371 0 : if (!err)
1372 0 : is_ssh = 1;
1373 0 : else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
1374 0 : goto leave;
1375 : }
1376 :
1377 60 : err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, is_ssh,
1378 : ttl, disabled, confirm);
1379 : }
1380 :
1381 : leave:
1382 60 : ssh_close_control_file (cf);
1383 60 : if (dir)
1384 0 : closedir (dir);
1385 60 : if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
1386 0 : leave_cmd (ctx, err);
1387 60 : return err;
1388 : }
1389 :
1390 :
1391 :
1392 : /* Helper for cmd_get_passphrase. */
1393 : static int
1394 1 : send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
1395 : {
1396 : size_t n;
1397 : int rc;
1398 :
1399 1 : assuan_begin_confidential (ctx);
1400 1 : n = strlen (pw);
1401 1 : if (via_data)
1402 0 : rc = assuan_send_data (ctx, pw, n);
1403 : else
1404 : {
1405 1 : char *p = xtrymalloc_secure (n*2+1);
1406 1 : if (!p)
1407 0 : rc = gpg_error_from_syserror ();
1408 : else
1409 : {
1410 1 : bin2hex (pw, n, p);
1411 1 : rc = assuan_set_okay_line (ctx, p);
1412 1 : xfree (p);
1413 : }
1414 : }
1415 1 : return rc;
1416 : }
1417 :
1418 :
1419 : static const char hlp_get_passphrase[] =
1420 : "GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n"
1421 : " [--qualitybar] <cache_id>\n"
1422 : " [<error_message> <prompt> <description>]\n"
1423 : "\n"
1424 : "This function is usually used to ask for a passphrase to be used\n"
1425 : "for conventional encryption, but may also be used by programs which\n"
1426 : "need specal handling of passphrases. This command uses a syntax\n"
1427 : "which helps clients to use the agent with minimum effort. The\n"
1428 : "agent either returns with an error or with a OK followed by the hex\n"
1429 : "encoded passphrase. Note that the length of the strings is\n"
1430 : "implicitly limited by the maximum length of a command.\n"
1431 : "\n"
1432 : "If the option \"--data\" is used the passphrase is returned by usual\n"
1433 : "data lines and not on the okay line.\n"
1434 : "\n"
1435 : "If the option \"--check\" is used the passphrase constraints checks as\n"
1436 : "implemented by gpg-agent are applied. A check is not done if the\n"
1437 : "passphrase has been found in the cache.\n"
1438 : "\n"
1439 : "If the option \"--no-ask\" is used and the passphrase is not in the\n"
1440 : "cache the user will not be asked to enter a passphrase but the error\n"
1441 : "code GPG_ERR_NO_DATA is returned. \n"
1442 : "\n"
1443 : "If the option \"--qualitybar\" is used a visual indication of the\n"
1444 : "entered passphrase quality is shown. (Unless no minimum passphrase\n"
1445 : "length has been configured.)";
1446 : static gpg_error_t
1447 1 : cmd_get_passphrase (assuan_context_t ctx, char *line)
1448 : {
1449 1 : ctrl_t ctrl = assuan_get_pointer (ctx);
1450 : int rc;
1451 : char *pw;
1452 : char *response;
1453 1 : char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
1454 1 : const char *desc2 = _("Please re-enter this passphrase");
1455 : char *p;
1456 : int opt_data, opt_check, opt_no_ask, opt_qualbar;
1457 1 : int opt_repeat = 0;
1458 1 : char *entry_errtext = NULL;
1459 :
1460 1 : if (ctrl->restricted)
1461 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1462 :
1463 1 : opt_data = has_option (line, "--data");
1464 1 : opt_check = has_option (line, "--check");
1465 1 : opt_no_ask = has_option (line, "--no-ask");
1466 1 : if (has_option_name (line, "--repeat"))
1467 : {
1468 0 : p = option_value (line, "--repeat");
1469 0 : if (p)
1470 0 : opt_repeat = atoi (p);
1471 : else
1472 0 : opt_repeat = 1;
1473 : }
1474 1 : opt_qualbar = has_option (line, "--qualitybar");
1475 1 : line = skip_options (line);
1476 :
1477 1 : cacheid = line;
1478 1 : p = strchr (cacheid, ' ');
1479 1 : if (p)
1480 : {
1481 1 : *p++ = 0;
1482 2 : while (*p == ' ')
1483 0 : p++;
1484 1 : errtext = p;
1485 1 : p = strchr (errtext, ' ');
1486 1 : if (p)
1487 : {
1488 1 : *p++ = 0;
1489 2 : while (*p == ' ')
1490 0 : p++;
1491 1 : prompt = p;
1492 1 : p = strchr (prompt, ' ');
1493 1 : if (p)
1494 : {
1495 1 : *p++ = 0;
1496 2 : while (*p == ' ')
1497 0 : p++;
1498 1 : desc = p;
1499 1 : p = strchr (desc, ' ');
1500 1 : if (p)
1501 0 : *p = 0; /* Ignore trailing garbage. */
1502 : }
1503 : }
1504 : }
1505 1 : if (!*cacheid || strlen (cacheid) > 50)
1506 0 : return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
1507 1 : if (!desc)
1508 0 : return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
1509 :
1510 1 : if (!strcmp (cacheid, "X"))
1511 0 : cacheid = NULL;
1512 1 : if (!strcmp (errtext, "X"))
1513 1 : errtext = NULL;
1514 1 : if (!strcmp (prompt, "X"))
1515 1 : prompt = NULL;
1516 1 : if (!strcmp (desc, "X"))
1517 1 : desc = NULL;
1518 :
1519 1 : pw = cacheid ? agent_get_cache (cacheid, CACHE_MODE_USER) : NULL;
1520 1 : if (pw)
1521 : {
1522 1 : rc = send_back_passphrase (ctx, opt_data, pw);
1523 1 : xfree (pw);
1524 : }
1525 0 : else if (opt_no_ask)
1526 0 : rc = gpg_error (GPG_ERR_NO_DATA);
1527 : else
1528 : {
1529 : /* Note, that we only need to replace the + characters and
1530 : should leave the other escaping in place because the escaped
1531 : string is send verbatim to the pinentry which does the
1532 : unescaping (but not the + replacing) */
1533 0 : if (errtext)
1534 0 : plus_to_blank (errtext);
1535 0 : if (prompt)
1536 0 : plus_to_blank (prompt);
1537 0 : if (desc)
1538 0 : plus_to_blank (desc);
1539 :
1540 : next_try:
1541 0 : rc = agent_get_passphrase (ctrl, &response, desc, prompt,
1542 0 : entry_errtext? entry_errtext:errtext,
1543 : opt_qualbar, cacheid, CACHE_MODE_USER);
1544 0 : xfree (entry_errtext);
1545 0 : entry_errtext = NULL;
1546 0 : if (!rc)
1547 : {
1548 : int i;
1549 :
1550 0 : if (opt_check
1551 0 : && check_passphrase_constraints (ctrl, response, &entry_errtext))
1552 : {
1553 0 : xfree (response);
1554 0 : goto next_try;
1555 : }
1556 0 : for (i = 0; i < opt_repeat; i++)
1557 : {
1558 : char *response2;
1559 :
1560 0 : if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
1561 0 : break;
1562 :
1563 0 : rc = agent_get_passphrase (ctrl, &response2, desc2, prompt,
1564 : errtext, 0,
1565 : cacheid, CACHE_MODE_USER);
1566 0 : if (rc)
1567 0 : break;
1568 0 : if (strcmp (response2, response))
1569 : {
1570 0 : xfree (response2);
1571 0 : xfree (response);
1572 0 : entry_errtext = try_percent_escape
1573 0 : (_("does not match - try again"), NULL);
1574 0 : if (!entry_errtext)
1575 : {
1576 0 : rc = gpg_error_from_syserror ();
1577 0 : break;
1578 : }
1579 0 : goto next_try;
1580 : }
1581 0 : xfree (response2);
1582 : }
1583 0 : if (!rc)
1584 : {
1585 0 : if (cacheid)
1586 0 : agent_put_cache (cacheid, CACHE_MODE_USER, response, 0);
1587 0 : rc = send_back_passphrase (ctx, opt_data, response);
1588 : }
1589 0 : xfree (response);
1590 : }
1591 : }
1592 :
1593 1 : return leave_cmd (ctx, rc);
1594 : }
1595 :
1596 :
1597 : static const char hlp_clear_passphrase[] =
1598 : "CLEAR_PASSPHRASE [--mode=normal] <cache_id>\n"
1599 : "\n"
1600 : "may be used to invalidate the cache entry for a passphrase. The\n"
1601 : "function returns with OK even when there is no cached passphrase.\n"
1602 : "The --mode=normal option is used to clear an entry for a cacheid\n"
1603 : "added by the agent.\n";
1604 : static gpg_error_t
1605 0 : cmd_clear_passphrase (assuan_context_t ctx, char *line)
1606 : {
1607 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1608 0 : char *cacheid = NULL;
1609 : char *p;
1610 : int opt_normal;
1611 :
1612 0 : if (ctrl->restricted)
1613 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1614 :
1615 0 : opt_normal = has_option (line, "--mode=normal");
1616 0 : line = skip_options (line);
1617 :
1618 : /* parse the stuff */
1619 0 : for (p=line; *p == ' '; p++)
1620 : ;
1621 0 : cacheid = p;
1622 0 : p = strchr (cacheid, ' ');
1623 0 : if (p)
1624 0 : *p = 0; /* ignore garbage */
1625 0 : if (!*cacheid || strlen (cacheid) > 50)
1626 0 : return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
1627 :
1628 0 : agent_put_cache (cacheid, opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
1629 : NULL, 0);
1630 :
1631 0 : agent_clear_passphrase (ctrl, cacheid,
1632 : opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER);
1633 :
1634 0 : return 0;
1635 : }
1636 :
1637 :
1638 : static const char hlp_get_confirmation[] =
1639 : "GET_CONFIRMATION <description>\n"
1640 : "\n"
1641 : "This command may be used to ask for a simple confirmation.\n"
1642 : "DESCRIPTION is displayed along with a Okay and Cancel button. This\n"
1643 : "command uses a syntax which helps clients to use the agent with\n"
1644 : "minimum effort. The agent either returns with an error or with a\n"
1645 : "OK. Note, that the length of DESCRIPTION is implicitly limited by\n"
1646 : "the maximum length of a command. DESCRIPTION should not contain\n"
1647 : "any spaces, those must be encoded either percent escaped or simply\n"
1648 : "as '+'.";
1649 : static gpg_error_t
1650 0 : cmd_get_confirmation (assuan_context_t ctx, char *line)
1651 : {
1652 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1653 : int rc;
1654 0 : char *desc = NULL;
1655 : char *p;
1656 :
1657 0 : if (ctrl->restricted)
1658 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1659 :
1660 : /* parse the stuff */
1661 0 : for (p=line; *p == ' '; p++)
1662 : ;
1663 0 : desc = p;
1664 0 : p = strchr (desc, ' ');
1665 0 : if (p)
1666 0 : *p = 0; /* We ignore any garbage -may be later used for other args. */
1667 :
1668 0 : if (!*desc)
1669 0 : return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
1670 :
1671 0 : if (!strcmp (desc, "X"))
1672 0 : desc = NULL;
1673 :
1674 : /* Note, that we only need to replace the + characters and should
1675 : leave the other escaping in place because the escaped string is
1676 : send verbatim to the pinentry which does the unescaping (but not
1677 : the + replacing) */
1678 0 : if (desc)
1679 0 : plus_to_blank (desc);
1680 :
1681 0 : rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
1682 0 : return leave_cmd (ctx, rc);
1683 : }
1684 :
1685 :
1686 :
1687 : static const char hlp_learn[] =
1688 : "LEARN [--send] [--sendinfo] [--force]\n"
1689 : "\n"
1690 : "Learn something about the currently inserted smartcard. With\n"
1691 : "--sendinfo information about the card is returned; with --send\n"
1692 : "the available certificates are returned as D lines; with --force\n"
1693 : "private key storage will be updated by the result.";
1694 : static gpg_error_t
1695 0 : cmd_learn (assuan_context_t ctx, char *line)
1696 : {
1697 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1698 : gpg_error_t err;
1699 : int send, sendinfo, force;
1700 :
1701 0 : send = has_option (line, "--send");
1702 0 : sendinfo = send? 1 : has_option (line, "--sendinfo");
1703 0 : force = has_option (line, "--force");
1704 :
1705 0 : if (ctrl->restricted)
1706 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1707 :
1708 0 : err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
1709 0 : return leave_cmd (ctx, err);
1710 : }
1711 :
1712 :
1713 :
1714 : static const char hlp_passwd[] =
1715 : "PASSWD [--cache-nonce=<c>] [--passwd-nonce=<s>] [--preset]\n"
1716 : " [--verify] <hexkeygrip>\n"
1717 : "\n"
1718 : "Change the passphrase/PIN for the key identified by keygrip in LINE. If\n"
1719 : "--preset is used then the new passphrase will be added to the cache.\n"
1720 : "If --verify is used the command asks for the passphrase and verifies\n"
1721 : "that the passphrase valid.\n";
1722 : static gpg_error_t
1723 0 : cmd_passwd (assuan_context_t ctx, char *line)
1724 : {
1725 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1726 : gpg_error_t err;
1727 : int c;
1728 0 : char *cache_nonce = NULL;
1729 0 : char *passwd_nonce = NULL;
1730 : unsigned char grip[20];
1731 0 : gcry_sexp_t s_skey = NULL;
1732 0 : unsigned char *shadow_info = NULL;
1733 0 : char *passphrase = NULL;
1734 : char *pend;
1735 : int opt_preset, opt_verify;
1736 :
1737 0 : if (ctrl->restricted)
1738 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1739 :
1740 0 : opt_preset = has_option (line, "--preset");
1741 0 : cache_nonce = option_value (line, "--cache-nonce");
1742 0 : opt_verify = has_option (line, "--verify");
1743 0 : if (cache_nonce)
1744 : {
1745 0 : for (pend = cache_nonce; *pend && !spacep (pend); pend++)
1746 : ;
1747 0 : c = *pend;
1748 0 : *pend = '\0';
1749 0 : cache_nonce = xtrystrdup (cache_nonce);
1750 0 : *pend = c;
1751 0 : if (!cache_nonce)
1752 : {
1753 0 : err = gpg_error_from_syserror ();
1754 0 : goto leave;
1755 : }
1756 : }
1757 :
1758 0 : passwd_nonce = option_value (line, "--passwd-nonce");
1759 0 : if (passwd_nonce)
1760 : {
1761 0 : for (pend = passwd_nonce; *pend && !spacep (pend); pend++)
1762 : ;
1763 0 : c = *pend;
1764 0 : *pend = '\0';
1765 0 : passwd_nonce = xtrystrdup (passwd_nonce);
1766 0 : *pend = c;
1767 0 : if (!passwd_nonce)
1768 : {
1769 0 : err = gpg_error_from_syserror ();
1770 0 : goto leave;
1771 : }
1772 : }
1773 :
1774 0 : line = skip_options (line);
1775 :
1776 0 : err = parse_keygrip (ctx, line, grip);
1777 0 : if (err)
1778 0 : goto leave;
1779 :
1780 0 : ctrl->in_passwd++;
1781 0 : err = agent_key_from_file (ctrl,
1782 : opt_verify? NULL : cache_nonce,
1783 0 : ctrl->server_local->keydesc,
1784 : grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
1785 : &s_skey, &passphrase);
1786 0 : if (err)
1787 : ;
1788 0 : else if (shadow_info)
1789 : {
1790 0 : log_error ("changing a smartcard PIN is not yet supported\n");
1791 0 : err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1792 : }
1793 0 : else if (opt_verify)
1794 : {
1795 : /* All done. */
1796 0 : if (passphrase)
1797 : {
1798 0 : if (!passwd_nonce)
1799 : {
1800 : char buf[12];
1801 0 : gcry_create_nonce (buf, 12);
1802 0 : passwd_nonce = bin2hex (buf, 12, NULL);
1803 : }
1804 0 : if (passwd_nonce
1805 0 : && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
1806 : passphrase, CACHE_TTL_NONCE))
1807 : {
1808 0 : assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
1809 0 : xfree (ctrl->server_local->last_passwd_nonce);
1810 0 : ctrl->server_local->last_passwd_nonce = passwd_nonce;
1811 0 : passwd_nonce = NULL;
1812 : }
1813 : }
1814 : }
1815 : else
1816 : {
1817 0 : char *newpass = NULL;
1818 :
1819 0 : if (passwd_nonce)
1820 0 : newpass = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
1821 0 : err = agent_protect_and_store (ctrl, s_skey, &newpass);
1822 0 : if (!err && passphrase)
1823 : {
1824 : /* A passphrase existed on the old key and the change was
1825 : successful. Return a nonce for that old passphrase to
1826 : let the caller try to unprotect the other subkeys with
1827 : the same key. */
1828 0 : if (!cache_nonce)
1829 : {
1830 : char buf[12];
1831 0 : gcry_create_nonce (buf, 12);
1832 0 : cache_nonce = bin2hex (buf, 12, NULL);
1833 : }
1834 0 : if (cache_nonce
1835 0 : && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
1836 : passphrase, CACHE_TTL_NONCE))
1837 : {
1838 0 : assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
1839 0 : xfree (ctrl->server_local->last_cache_nonce);
1840 0 : ctrl->server_local->last_cache_nonce = cache_nonce;
1841 0 : cache_nonce = NULL;
1842 : }
1843 0 : if (newpass)
1844 : {
1845 : /* If we have a new passphrase (which might be empty) we
1846 : store it under a passwd nonce so that the caller may
1847 : send that nonce again to use it for another key. */
1848 0 : if (!passwd_nonce)
1849 : {
1850 : char buf[12];
1851 0 : gcry_create_nonce (buf, 12);
1852 0 : passwd_nonce = bin2hex (buf, 12, NULL);
1853 : }
1854 0 : if (passwd_nonce
1855 0 : && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
1856 : newpass, CACHE_TTL_NONCE))
1857 : {
1858 0 : assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
1859 0 : xfree (ctrl->server_local->last_passwd_nonce);
1860 0 : ctrl->server_local->last_passwd_nonce = passwd_nonce;
1861 0 : passwd_nonce = NULL;
1862 : }
1863 : }
1864 : }
1865 0 : if (!err && opt_preset)
1866 : {
1867 : char hexgrip[40+1];
1868 0 : bin2hex(grip, 20, hexgrip);
1869 0 : err = agent_put_cache (hexgrip, CACHE_MODE_ANY, newpass,
1870 : ctrl->cache_ttl_opt_preset);
1871 : }
1872 0 : xfree (newpass);
1873 : }
1874 0 : ctrl->in_passwd--;
1875 :
1876 0 : xfree (ctrl->server_local->keydesc);
1877 0 : ctrl->server_local->keydesc = NULL;
1878 :
1879 : leave:
1880 0 : xfree (passphrase);
1881 0 : gcry_sexp_release (s_skey);
1882 0 : xfree (shadow_info);
1883 0 : xfree (cache_nonce);
1884 0 : xfree (passwd_nonce);
1885 0 : return leave_cmd (ctx, err);
1886 : }
1887 :
1888 :
1889 : static const char hlp_preset_passphrase[] =
1890 : "PRESET_PASSPHRASE [--inquire] <string_or_keygrip> <timeout> [<hexstring>]\n"
1891 : "\n"
1892 : "Set the cached passphrase/PIN for the key identified by the keygrip\n"
1893 : "to passwd for the given time, where -1 means infinite and 0 means\n"
1894 : "the default (currently only a timeout of -1 is allowed, which means\n"
1895 : "to never expire it). If passwd is not provided, ask for it via the\n"
1896 : "pinentry module unless --inquire is passed in which case the passphrase\n"
1897 : "is retrieved from the client via a server inquire.\n";
1898 : static gpg_error_t
1899 135 : cmd_preset_passphrase (assuan_context_t ctx, char *line)
1900 : {
1901 135 : ctrl_t ctrl = assuan_get_pointer (ctx);
1902 : int rc;
1903 135 : char *grip_clear = NULL;
1904 135 : unsigned char *passphrase = NULL;
1905 : int ttl;
1906 : size_t len;
1907 : int opt_inquire;
1908 :
1909 135 : if (ctrl->restricted)
1910 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1911 :
1912 135 : if (!opt.allow_preset_passphrase)
1913 0 : return set_error (GPG_ERR_NOT_SUPPORTED, "no --allow-preset-passphrase");
1914 :
1915 135 : opt_inquire = has_option (line, "--inquire");
1916 135 : line = skip_options (line);
1917 135 : grip_clear = line;
1918 5637 : while (*line && (*line != ' ' && *line != '\t'))
1919 5367 : line++;
1920 135 : if (!*line)
1921 0 : return gpg_error (GPG_ERR_MISSING_VALUE);
1922 135 : *line = '\0';
1923 135 : line++;
1924 270 : while (*line && (*line == ' ' || *line == '\t'))
1925 0 : line++;
1926 :
1927 : /* Currently, only infinite timeouts are allowed. */
1928 135 : ttl = -1;
1929 135 : if (line[0] != '-' || line[1] != '1')
1930 0 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1931 135 : line++;
1932 135 : line++;
1933 405 : while (!(*line != ' ' && *line != '\t'))
1934 135 : line++;
1935 :
1936 : /* Syntax check the hexstring. */
1937 135 : len = 0;
1938 135 : rc = parse_hexstring (ctx, line, &len);
1939 135 : if (rc)
1940 0 : return rc;
1941 135 : line[len] = '\0';
1942 :
1943 : /* If there is a passphrase, use it. Currently, a passphrase is
1944 : required. */
1945 135 : if (*line)
1946 : {
1947 135 : if (opt_inquire)
1948 : {
1949 0 : rc = set_error (GPG_ERR_ASS_PARAMETER,
1950 : "both --inquire and passphrase specified");
1951 0 : goto leave;
1952 : }
1953 :
1954 : /* Do in-place conversion. */
1955 135 : passphrase = line;
1956 135 : if (!hex2str (passphrase, passphrase, strlen (passphrase)+1, NULL))
1957 0 : rc = set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
1958 : }
1959 0 : else if (opt_inquire)
1960 : {
1961 : /* Note that the passphrase will be truncated at any null byte and the
1962 : * limit is 480 characters. */
1963 0 : size_t maxlen = 480;
1964 :
1965 0 : rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%zu", maxlen);
1966 0 : if (!rc)
1967 0 : rc = assuan_inquire (ctx, "PASSPHRASE", &passphrase, &len, maxlen);
1968 : }
1969 : else
1970 0 : rc = set_error (GPG_ERR_NOT_IMPLEMENTED, "passphrase is required");
1971 :
1972 135 : if (!rc)
1973 : {
1974 135 : rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl);
1975 135 : if (opt_inquire)
1976 0 : xfree (passphrase);
1977 : }
1978 :
1979 : leave:
1980 135 : return leave_cmd (ctx, rc);
1981 : }
1982 :
1983 :
1984 :
1985 : static const char hlp_scd[] =
1986 : "SCD <commands to pass to the scdaemon>\n"
1987 : " \n"
1988 : "This is a general quote command to redirect everything to the\n"
1989 : "SCdaemon.";
1990 : static gpg_error_t
1991 0 : cmd_scd (assuan_context_t ctx, char *line)
1992 : {
1993 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1994 : int rc;
1995 :
1996 0 : if (ctrl->restricted)
1997 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
1998 :
1999 0 : rc = divert_generic_cmd (ctrl, line, ctx);
2000 :
2001 0 : return rc;
2002 : }
2003 :
2004 :
2005 :
2006 : static const char hlp_keywrap_key[] =
2007 : "KEYWRAP_KEY [--clear] <mode>\n"
2008 : "\n"
2009 : "Return a key to wrap another key. For now the key is returned\n"
2010 : "verbatim and and thus makes not much sense because an eavesdropper on\n"
2011 : "the gpg-agent connection will see the key as well as the wrapped key.\n"
2012 : "However, this function may either be equipped with a public key\n"
2013 : "mechanism or not used at all if the key is a pre-shared key. In any\n"
2014 : "case wrapping the import and export of keys is a requirement for\n"
2015 : "certain cryptographic validations and thus useful. The key persists\n"
2016 : "until a RESET command but may be cleared using the option --clear.\n"
2017 : "\n"
2018 : "Supported modes are:\n"
2019 : " --import - Return a key to import a key into gpg-agent\n"
2020 : " --export - Return a key to export a key from gpg-agent";
2021 : static gpg_error_t
2022 21 : cmd_keywrap_key (assuan_context_t ctx, char *line)
2023 : {
2024 21 : ctrl_t ctrl = assuan_get_pointer (ctx);
2025 21 : gpg_error_t err = 0;
2026 21 : int clearopt = has_option (line, "--clear");
2027 :
2028 21 : if (ctrl->restricted)
2029 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2030 :
2031 21 : assuan_begin_confidential (ctx);
2032 21 : if (has_option (line, "--import"))
2033 : {
2034 18 : xfree (ctrl->server_local->import_key);
2035 18 : if (clearopt)
2036 0 : ctrl->server_local->import_key = NULL;
2037 36 : else if (!(ctrl->server_local->import_key =
2038 18 : gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM)))
2039 0 : err = gpg_error_from_syserror ();
2040 : else
2041 18 : err = assuan_send_data (ctx, ctrl->server_local->import_key,
2042 : KEYWRAP_KEYSIZE);
2043 : }
2044 3 : else if (has_option (line, "--export"))
2045 : {
2046 3 : xfree (ctrl->server_local->export_key);
2047 3 : if (clearopt)
2048 0 : ctrl->server_local->export_key = NULL;
2049 6 : else if (!(ctrl->server_local->export_key =
2050 3 : gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM)))
2051 0 : err = gpg_error_from_syserror ();
2052 : else
2053 3 : err = assuan_send_data (ctx, ctrl->server_local->export_key,
2054 : KEYWRAP_KEYSIZE);
2055 : }
2056 : else
2057 0 : err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for MODE");
2058 21 : assuan_end_confidential (ctx);
2059 :
2060 21 : return leave_cmd (ctx, err);
2061 : }
2062 :
2063 :
2064 :
2065 : static const char hlp_import_key[] =
2066 : "IMPORT_KEY [--unattended] [--force] [<cache_nonce>]\n"
2067 : "\n"
2068 : "Import a secret key into the key store. The key is expected to be\n"
2069 : "encrypted using the current session's key wrapping key (cf. command\n"
2070 : "KEYWRAP_KEY) using the AESWRAP-128 algorithm. This function takes\n"
2071 : "no arguments but uses the inquiry \"KEYDATA\" to ask for the actual\n"
2072 : "key data. The unwrapped key must be a canonical S-expression. The\n"
2073 : "option --unattended tries to import the key as-is without any\n"
2074 : "re-encryption. Existing key can be overwritten with --force.";
2075 : static gpg_error_t
2076 33 : cmd_import_key (assuan_context_t ctx, char *line)
2077 : {
2078 33 : ctrl_t ctrl = assuan_get_pointer (ctx);
2079 : gpg_error_t err;
2080 : int opt_unattended;
2081 : int force;
2082 33 : unsigned char *wrappedkey = NULL;
2083 : size_t wrappedkeylen;
2084 33 : gcry_cipher_hd_t cipherhd = NULL;
2085 33 : unsigned char *key = NULL;
2086 : size_t keylen, realkeylen;
2087 33 : char *passphrase = NULL;
2088 33 : unsigned char *finalkey = NULL;
2089 : size_t finalkeylen;
2090 : unsigned char grip[20];
2091 33 : gcry_sexp_t openpgp_sexp = NULL;
2092 33 : char *cache_nonce = NULL;
2093 : char *p;
2094 :
2095 33 : if (ctrl->restricted)
2096 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2097 :
2098 33 : if (!ctrl->server_local->import_key)
2099 : {
2100 0 : err = gpg_error (GPG_ERR_MISSING_KEY);
2101 0 : goto leave;
2102 : }
2103 :
2104 33 : opt_unattended = has_option (line, "--unattended");
2105 33 : force = has_option (line, "--force");
2106 33 : line = skip_options (line);
2107 :
2108 33 : p = line;
2109 33 : for (p=line; *p && *p != ' ' && *p != '\t'; p++)
2110 : ;
2111 33 : *p = '\0';
2112 33 : if (*line)
2113 0 : cache_nonce = xtrystrdup (line);
2114 :
2115 33 : assuan_begin_confidential (ctx);
2116 33 : err = assuan_inquire (ctx, "KEYDATA",
2117 : &wrappedkey, &wrappedkeylen, MAXLEN_KEYDATA);
2118 33 : assuan_end_confidential (ctx);
2119 33 : if (err)
2120 0 : goto leave;
2121 33 : if (wrappedkeylen < 24)
2122 : {
2123 0 : err = gpg_error (GPG_ERR_INV_LENGTH);
2124 0 : goto leave;
2125 : }
2126 33 : keylen = wrappedkeylen - 8;
2127 33 : key = xtrymalloc_secure (keylen);
2128 33 : if (!key)
2129 : {
2130 0 : err = gpg_error_from_syserror ();
2131 0 : goto leave;
2132 : }
2133 :
2134 33 : err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
2135 : GCRY_CIPHER_MODE_AESWRAP, 0);
2136 33 : if (err)
2137 0 : goto leave;
2138 33 : err = gcry_cipher_setkey (cipherhd,
2139 33 : ctrl->server_local->import_key, KEYWRAP_KEYSIZE);
2140 33 : if (err)
2141 0 : goto leave;
2142 33 : err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen);
2143 33 : if (err)
2144 0 : goto leave;
2145 33 : gcry_cipher_close (cipherhd);
2146 33 : cipherhd = NULL;
2147 33 : xfree (wrappedkey);
2148 33 : wrappedkey = NULL;
2149 :
2150 33 : realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
2151 33 : if (!realkeylen)
2152 0 : goto leave; /* Invalid canonical encoded S-expression. */
2153 :
2154 33 : err = keygrip_from_canon_sexp (key, realkeylen, grip);
2155 33 : if (err)
2156 : {
2157 : /* This might be due to an unsupported S-expression format.
2158 : Check whether this is openpgp-private-key and trigger that
2159 : import code. */
2160 33 : if (!gcry_sexp_sscan (&openpgp_sexp, NULL, key, realkeylen))
2161 : {
2162 : const char *tag;
2163 : size_t taglen;
2164 :
2165 33 : tag = gcry_sexp_nth_data (openpgp_sexp, 0, &taglen);
2166 33 : if (tag && taglen == 19 && !memcmp (tag, "openpgp-private-key", 19))
2167 : ;
2168 : else
2169 : {
2170 0 : gcry_sexp_release (openpgp_sexp);
2171 0 : openpgp_sexp = NULL;
2172 : }
2173 : }
2174 33 : if (!openpgp_sexp)
2175 0 : goto leave; /* Note that ERR is still set. */
2176 : }
2177 :
2178 :
2179 33 : if (openpgp_sexp)
2180 : {
2181 : /* In most cases the key is encrypted and thus the conversion
2182 : function from the OpenPGP format to our internal format will
2183 : ask for a passphrase. That passphrase will be returned and
2184 : used to protect the key using the same code as for regular
2185 : key import. */
2186 :
2187 33 : xfree (key);
2188 33 : key = NULL;
2189 66 : err = convert_from_openpgp (ctrl, openpgp_sexp, force, grip,
2190 33 : ctrl->server_local->keydesc, cache_nonce,
2191 : &key, opt_unattended? NULL : &passphrase);
2192 33 : if (err)
2193 2 : goto leave;
2194 31 : realkeylen = gcry_sexp_canon_len (key, 0, NULL, &err);
2195 31 : if (!realkeylen)
2196 0 : goto leave; /* Invalid canonical encoded S-expression. */
2197 31 : if (passphrase)
2198 : {
2199 0 : assert (!opt_unattended);
2200 0 : if (!cache_nonce)
2201 : {
2202 : char buf[12];
2203 0 : gcry_create_nonce (buf, 12);
2204 0 : cache_nonce = bin2hex (buf, 12, NULL);
2205 : }
2206 0 : if (cache_nonce
2207 0 : && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
2208 : passphrase, CACHE_TTL_NONCE))
2209 0 : assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
2210 : }
2211 : }
2212 0 : else if (opt_unattended)
2213 : {
2214 0 : err = set_error (GPG_ERR_ASS_PARAMETER,
2215 : "\"--unattended\" may only be used with OpenPGP keys");
2216 0 : goto leave;
2217 : }
2218 : else
2219 : {
2220 0 : if (!force && !agent_key_available (grip))
2221 0 : err = gpg_error (GPG_ERR_EEXIST);
2222 : else
2223 : {
2224 0 : char *prompt = xtryasprintf
2225 0 : (_("Please enter the passphrase to protect the "
2226 : "imported object within the %s system."), GNUPG_NAME);
2227 0 : if (!prompt)
2228 0 : err = gpg_error_from_syserror ();
2229 : else
2230 0 : err = agent_ask_new_passphrase (ctrl, prompt, &passphrase);
2231 0 : xfree (prompt);
2232 : }
2233 0 : if (err)
2234 0 : goto leave;
2235 : }
2236 :
2237 31 : if (passphrase)
2238 : {
2239 0 : err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
2240 : ctrl->s2k_count, -1);
2241 0 : if (!err)
2242 0 : err = agent_write_private_key (grip, finalkey, finalkeylen, force);
2243 : }
2244 : else
2245 31 : err = agent_write_private_key (grip, key, realkeylen, force);
2246 :
2247 : leave:
2248 33 : gcry_sexp_release (openpgp_sexp);
2249 33 : xfree (finalkey);
2250 33 : xfree (passphrase);
2251 33 : xfree (key);
2252 33 : gcry_cipher_close (cipherhd);
2253 33 : xfree (wrappedkey);
2254 33 : xfree (cache_nonce);
2255 33 : xfree (ctrl->server_local->keydesc);
2256 33 : ctrl->server_local->keydesc = NULL;
2257 33 : return leave_cmd (ctx, err);
2258 : }
2259 :
2260 :
2261 :
2262 : static const char hlp_export_key[] =
2263 : "EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp] <hexstring_with_keygrip>\n"
2264 : "\n"
2265 : "Export a secret key from the key store. The key will be encrypted\n"
2266 : "using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
2267 : "using the AESWRAP-128 algorithm. The caller needs to retrieve that key\n"
2268 : "prior to using this command. The function takes the keygrip as argument.\n"
2269 : "\n"
2270 : "If --openpgp is used, the secret key material will be exported in RFC 4880\n"
2271 : "compatible passphrase-protected form. Without --openpgp, the secret key\n"
2272 : "material will be exported in the clear (after prompting the user to unlock\n"
2273 : "it, if needed).\n";
2274 : static gpg_error_t
2275 5 : cmd_export_key (assuan_context_t ctx, char *line)
2276 : {
2277 5 : ctrl_t ctrl = assuan_get_pointer (ctx);
2278 : gpg_error_t err;
2279 : unsigned char grip[20];
2280 5 : gcry_sexp_t s_skey = NULL;
2281 5 : unsigned char *key = NULL;
2282 : size_t keylen;
2283 5 : gcry_cipher_hd_t cipherhd = NULL;
2284 5 : unsigned char *wrappedkey = NULL;
2285 : size_t wrappedkeylen;
2286 : int openpgp;
2287 : char *cache_nonce;
2288 5 : char *passphrase = NULL;
2289 5 : unsigned char *shadow_info = NULL;
2290 : char *pend;
2291 : int c;
2292 :
2293 5 : if (ctrl->restricted)
2294 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2295 :
2296 5 : openpgp = has_option (line, "--openpgp");
2297 5 : cache_nonce = option_value (line, "--cache-nonce");
2298 5 : if (cache_nonce)
2299 : {
2300 1 : for (pend = cache_nonce; *pend && !spacep (pend); pend++)
2301 : ;
2302 1 : c = *pend;
2303 1 : *pend = '\0';
2304 1 : cache_nonce = xtrystrdup (cache_nonce);
2305 1 : *pend = c;
2306 1 : if (!cache_nonce)
2307 : {
2308 0 : err = gpg_error_from_syserror ();
2309 0 : goto leave;
2310 : }
2311 : }
2312 5 : line = skip_options (line);
2313 :
2314 5 : if (!ctrl->server_local->export_key)
2315 : {
2316 0 : err = set_error (GPG_ERR_MISSING_KEY, "did you run KEYWRAP_KEY ?");
2317 0 : goto leave;
2318 : }
2319 :
2320 5 : err = parse_keygrip (ctx, line, grip);
2321 5 : if (err)
2322 0 : goto leave;
2323 :
2324 5 : if (agent_key_available (grip))
2325 : {
2326 0 : err = gpg_error (GPG_ERR_NO_SECKEY);
2327 0 : goto leave;
2328 : }
2329 :
2330 : /* Get the key from the file. With the openpgp flag we also ask for
2331 : the passphrase so that we can use it to re-encrypt it. */
2332 10 : err = agent_key_from_file (ctrl, cache_nonce,
2333 5 : ctrl->server_local->keydesc, grip,
2334 : &shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
2335 : openpgp ? &passphrase : NULL);
2336 5 : if (err)
2337 0 : goto leave;
2338 5 : if (shadow_info)
2339 : {
2340 : /* Key is on a smartcard. */
2341 0 : err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
2342 0 : goto leave;
2343 : }
2344 :
2345 5 : if (openpgp)
2346 : {
2347 : /* The openpgp option changes the key format into the OpenPGP
2348 : key transfer format. The result is already a padded
2349 : canonical S-expression. */
2350 2 : if (!passphrase)
2351 : {
2352 0 : err = agent_ask_new_passphrase
2353 0 : (ctrl, _("This key (or subkey) is not protected with a passphrase."
2354 : " Please enter a new passphrase to export it."),
2355 : &passphrase);
2356 0 : if (err)
2357 0 : goto leave;
2358 : }
2359 2 : err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen);
2360 2 : if (!err && passphrase)
2361 : {
2362 2 : if (!cache_nonce)
2363 : {
2364 : char buf[12];
2365 1 : gcry_create_nonce (buf, 12);
2366 1 : cache_nonce = bin2hex (buf, 12, NULL);
2367 : }
2368 2 : if (cache_nonce
2369 2 : && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
2370 : passphrase, CACHE_TTL_NONCE))
2371 : {
2372 2 : assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
2373 2 : xfree (ctrl->server_local->last_cache_nonce);
2374 2 : ctrl->server_local->last_cache_nonce = cache_nonce;
2375 2 : cache_nonce = NULL;
2376 : }
2377 : }
2378 : }
2379 : else
2380 : {
2381 : /* Convert into a canonical S-expression and wrap that. */
2382 3 : err = make_canon_sexp_pad (s_skey, 1, &key, &keylen);
2383 : }
2384 5 : if (err)
2385 0 : goto leave;
2386 5 : gcry_sexp_release (s_skey);
2387 5 : s_skey = NULL;
2388 :
2389 5 : err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
2390 : GCRY_CIPHER_MODE_AESWRAP, 0);
2391 5 : if (err)
2392 0 : goto leave;
2393 5 : err = gcry_cipher_setkey (cipherhd,
2394 5 : ctrl->server_local->export_key, KEYWRAP_KEYSIZE);
2395 5 : if (err)
2396 0 : goto leave;
2397 :
2398 5 : wrappedkeylen = keylen + 8;
2399 5 : wrappedkey = xtrymalloc (wrappedkeylen);
2400 5 : if (!wrappedkey)
2401 : {
2402 0 : err = gpg_error_from_syserror ();
2403 0 : goto leave;
2404 : }
2405 :
2406 5 : err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen);
2407 5 : if (err)
2408 0 : goto leave;
2409 5 : xfree (key);
2410 5 : key = NULL;
2411 5 : gcry_cipher_close (cipherhd);
2412 5 : cipherhd = NULL;
2413 :
2414 5 : assuan_begin_confidential (ctx);
2415 5 : err = assuan_send_data (ctx, wrappedkey, wrappedkeylen);
2416 5 : assuan_end_confidential (ctx);
2417 :
2418 :
2419 : leave:
2420 5 : xfree (cache_nonce);
2421 5 : xfree (passphrase);
2422 5 : xfree (wrappedkey);
2423 5 : gcry_cipher_close (cipherhd);
2424 5 : xfree (key);
2425 5 : gcry_sexp_release (s_skey);
2426 5 : xfree (ctrl->server_local->keydesc);
2427 5 : ctrl->server_local->keydesc = NULL;
2428 5 : xfree (shadow_info);
2429 :
2430 5 : return leave_cmd (ctx, err);
2431 : }
2432 :
2433 :
2434 :
2435 : static const char hlp_delete_key[] =
2436 : "DELETE_KEY [--force] <hexstring_with_keygrip>\n"
2437 : "\n"
2438 : "Delete a secret key from the key store. If --force is used\n"
2439 : "and a loopback pinentry is allowed, the agent will not ask\n"
2440 : "the user for confirmation.";
2441 : static gpg_error_t
2442 0 : cmd_delete_key (assuan_context_t ctx, char *line)
2443 : {
2444 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2445 : gpg_error_t err;
2446 : int force;
2447 : unsigned char grip[20];
2448 :
2449 0 : if (ctrl->restricted)
2450 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2451 :
2452 0 : force = has_option (line, "--force");
2453 0 : line = skip_options (line);
2454 :
2455 : /* If the use of a loopback pinentry has been disabled, we assume
2456 : * that a silent deletion of keys shall also not be allowed. */
2457 0 : if (!opt.allow_loopback_pinentry)
2458 0 : force = 0;
2459 :
2460 0 : err = parse_keygrip (ctx, line, grip);
2461 0 : if (err)
2462 0 : goto leave;
2463 :
2464 0 : err = agent_delete_key (ctrl, ctrl->server_local->keydesc, grip, force );
2465 0 : if (err)
2466 0 : goto leave;
2467 :
2468 : leave:
2469 0 : xfree (ctrl->server_local->keydesc);
2470 0 : ctrl->server_local->keydesc = NULL;
2471 :
2472 0 : return leave_cmd (ctx, err);
2473 : }
2474 :
2475 :
2476 :
2477 : static const char hlp_keytocard[] =
2478 : "KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
2479 : "\n";
2480 : static gpg_error_t
2481 0 : cmd_keytocard (assuan_context_t ctx, char *line)
2482 : {
2483 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2484 : int force;
2485 0 : gpg_error_t err = 0;
2486 : unsigned char grip[20];
2487 0 : gcry_sexp_t s_skey = NULL;
2488 : unsigned char *keydata;
2489 : size_t keydatalen, timestamplen;
2490 : const char *serialno, *timestamp_str, *id;
2491 0 : unsigned char *shadow_info = NULL;
2492 : time_t timestamp;
2493 :
2494 0 : if (ctrl->restricted)
2495 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2496 :
2497 0 : force = has_option (line, "--force");
2498 0 : line = skip_options (line);
2499 :
2500 0 : err = parse_keygrip (ctx, line, grip);
2501 0 : if (err)
2502 0 : return err;
2503 :
2504 0 : if (agent_key_available (grip))
2505 0 : return gpg_error (GPG_ERR_NO_SECKEY);
2506 :
2507 0 : line += 40;
2508 0 : while (*line && (*line == ' ' || *line == '\t'))
2509 0 : line++;
2510 0 : serialno = line;
2511 0 : while (*line && (*line != ' ' && *line != '\t'))
2512 0 : line++;
2513 0 : if (!*line)
2514 0 : return gpg_error (GPG_ERR_MISSING_VALUE);
2515 0 : *line = '\0';
2516 0 : line++;
2517 0 : while (*line && (*line == ' ' || *line == '\t'))
2518 0 : line++;
2519 0 : id = line;
2520 0 : while (*line && (*line != ' ' && *line != '\t'))
2521 0 : line++;
2522 0 : if (!*line)
2523 0 : return gpg_error (GPG_ERR_MISSING_VALUE);
2524 0 : *line = '\0';
2525 0 : line++;
2526 0 : while (*line && (*line == ' ' || *line == '\t'))
2527 0 : line++;
2528 0 : timestamp_str = line;
2529 0 : while (*line && (*line != ' ' && *line != '\t'))
2530 0 : line++;
2531 0 : if (*line)
2532 0 : *line = '\0';
2533 0 : timestamplen = line - timestamp_str;
2534 0 : if (timestamplen != 15)
2535 0 : return gpg_error (GPG_ERR_INV_VALUE);
2536 :
2537 0 : err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
2538 : &shadow_info, CACHE_MODE_IGNORE, NULL,
2539 : &s_skey, NULL);
2540 0 : if (err)
2541 : {
2542 0 : xfree (shadow_info);
2543 0 : return err;
2544 : }
2545 0 : if (shadow_info)
2546 : {
2547 : /* Key is on a smartcard already. */
2548 0 : xfree (shadow_info);
2549 0 : gcry_sexp_release (s_skey);
2550 0 : return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
2551 : }
2552 :
2553 0 : keydatalen = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
2554 0 : keydata = xtrymalloc_secure (keydatalen + 30);
2555 0 : if (keydata == NULL)
2556 : {
2557 0 : gcry_sexp_release (s_skey);
2558 0 : return gpg_error_from_syserror ();
2559 : }
2560 :
2561 0 : gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
2562 0 : gcry_sexp_release (s_skey);
2563 0 : keydatalen--; /* Decrement for last '\0'. */
2564 : /* Add timestamp "created-at" in the private key */
2565 0 : timestamp = isotime2epoch (timestamp_str);
2566 0 : snprintf (keydata+keydatalen-1, 30, "(10:created-at10:%010lu))", timestamp);
2567 0 : keydatalen += 10 + 19 - 1;
2568 0 : err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
2569 0 : xfree (keydata);
2570 :
2571 0 : return leave_cmd (ctx, err);
2572 : }
2573 :
2574 :
2575 :
2576 : static const char hlp_getval[] =
2577 : "GETVAL <key>\n"
2578 : "\n"
2579 : "Return the value for KEY from the special environment as created by\n"
2580 : "PUTVAL.";
2581 : static gpg_error_t
2582 0 : cmd_getval (assuan_context_t ctx, char *line)
2583 : {
2584 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2585 0 : int rc = 0;
2586 0 : char *key = NULL;
2587 : char *p;
2588 : struct putval_item_s *vl;
2589 :
2590 0 : if (ctrl->restricted)
2591 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2592 :
2593 0 : for (p=line; *p == ' '; p++)
2594 : ;
2595 0 : key = p;
2596 0 : p = strchr (key, ' ');
2597 0 : if (p)
2598 : {
2599 0 : *p++ = 0;
2600 0 : for (; *p == ' '; p++)
2601 : ;
2602 0 : if (*p)
2603 0 : return set_error (GPG_ERR_ASS_PARAMETER, "too many arguments");
2604 : }
2605 0 : if (!*key)
2606 0 : return set_error (GPG_ERR_ASS_PARAMETER, "no key given");
2607 :
2608 :
2609 0 : for (vl=putval_list; vl; vl = vl->next)
2610 0 : if ( !strcmp (vl->d, key) )
2611 0 : break;
2612 :
2613 0 : if (vl) /* Got an entry. */
2614 0 : rc = assuan_send_data (ctx, vl->d+vl->off, vl->len);
2615 : else
2616 0 : return gpg_error (GPG_ERR_NO_DATA);
2617 :
2618 0 : return leave_cmd (ctx, rc);
2619 : }
2620 :
2621 :
2622 : static const char hlp_putval[] =
2623 : "PUTVAL <key> [<percent_escaped_value>]\n"
2624 : "\n"
2625 : "The gpg-agent maintains a kind of environment which may be used to\n"
2626 : "store key/value pairs in it, so that they can be retrieved later.\n"
2627 : "This may be used by helper daemons to daemonize themself on\n"
2628 : "invocation and register them with gpg-agent. Callers of the\n"
2629 : "daemon's service may now first try connect to get the information\n"
2630 : "for that service from gpg-agent through the GETVAL command and then\n"
2631 : "try to connect to that daemon. Only if that fails they may start\n"
2632 : "an own instance of the service daemon. \n"
2633 : "\n"
2634 : "KEY is an an arbitrary symbol with the same syntax rules as keys\n"
2635 : "for shell environment variables. PERCENT_ESCAPED_VALUE is the\n"
2636 : "corresponding value; they should be similar to the values of\n"
2637 : "envronment variables but gpg-agent does not enforce any\n"
2638 : "restrictions. If that value is not given any value under that KEY\n"
2639 : "is removed from this special environment.";
2640 : static gpg_error_t
2641 0 : cmd_putval (assuan_context_t ctx, char *line)
2642 : {
2643 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2644 0 : int rc = 0;
2645 0 : char *key = NULL;
2646 0 : char *value = NULL;
2647 0 : size_t valuelen = 0;
2648 : char *p;
2649 : struct putval_item_s *vl, *vlprev;
2650 :
2651 0 : if (ctrl->restricted)
2652 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2653 :
2654 0 : for (p=line; *p == ' '; p++)
2655 : ;
2656 0 : key = p;
2657 0 : p = strchr (key, ' ');
2658 0 : if (p)
2659 : {
2660 0 : *p++ = 0;
2661 0 : for (; *p == ' '; p++)
2662 : ;
2663 0 : if (*p)
2664 : {
2665 0 : value = p;
2666 0 : p = strchr (value, ' ');
2667 0 : if (p)
2668 0 : *p = 0;
2669 0 : valuelen = percent_plus_unescape_inplace (value, 0);
2670 : }
2671 : }
2672 0 : if (!*key)
2673 0 : return set_error (GPG_ERR_ASS_PARAMETER, "no key given");
2674 :
2675 :
2676 0 : for (vl=putval_list,vlprev=NULL; vl; vlprev=vl, vl = vl->next)
2677 0 : if ( !strcmp (vl->d, key) )
2678 0 : break;
2679 :
2680 0 : if (vl) /* Delete old entry. */
2681 : {
2682 0 : if (vlprev)
2683 0 : vlprev->next = vl->next;
2684 : else
2685 0 : putval_list = vl->next;
2686 0 : xfree (vl);
2687 : }
2688 :
2689 0 : if (valuelen) /* Add entry. */
2690 : {
2691 0 : vl = xtrymalloc (sizeof *vl + strlen (key) + valuelen);
2692 0 : if (!vl)
2693 0 : rc = gpg_error_from_syserror ();
2694 : else
2695 : {
2696 0 : vl->len = valuelen;
2697 0 : vl->off = strlen (key) + 1;
2698 0 : strcpy (vl->d, key);
2699 0 : memcpy (vl->d + vl->off, value, valuelen);
2700 0 : vl->next = putval_list;
2701 0 : putval_list = vl;
2702 : }
2703 : }
2704 :
2705 0 : return leave_cmd (ctx, rc);
2706 : }
2707 :
2708 :
2709 :
2710 :
2711 : static const char hlp_updatestartuptty[] =
2712 : "UPDATESTARTUPTTY\n"
2713 : "\n"
2714 : "Set startup TTY and X11 DISPLAY variables to the values of this\n"
2715 : "session. This command is useful to pull future pinentries to\n"
2716 : "another screen. It is only required because there is no way in the\n"
2717 : "ssh-agent protocol to convey this information.";
2718 : static gpg_error_t
2719 0 : cmd_updatestartuptty (assuan_context_t ctx, char *line)
2720 : {
2721 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2722 0 : gpg_error_t err = 0;
2723 : session_env_t se;
2724 0 : char *lc_ctype = NULL;
2725 0 : char *lc_messages = NULL;
2726 : int iterator;
2727 : const char *name;
2728 :
2729 : (void)line;
2730 :
2731 0 : if (ctrl->restricted)
2732 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2733 :
2734 0 : se = session_env_new ();
2735 0 : if (!se)
2736 0 : err = gpg_error_from_syserror ();
2737 :
2738 0 : iterator = 0;
2739 0 : while (!err && (name = session_env_list_stdenvnames (&iterator, NULL)))
2740 : {
2741 0 : const char *value = session_env_getenv (ctrl->session_env, name);
2742 0 : if (value)
2743 0 : err = session_env_setenv (se, name, value);
2744 : }
2745 :
2746 0 : if (!err && ctrl->lc_ctype)
2747 0 : if (!(lc_ctype = xtrystrdup (ctrl->lc_ctype)))
2748 0 : err = gpg_error_from_syserror ();
2749 :
2750 0 : if (!err && ctrl->lc_messages)
2751 0 : if (!(lc_messages = xtrystrdup (ctrl->lc_messages)))
2752 0 : err = gpg_error_from_syserror ();
2753 :
2754 0 : if (err)
2755 : {
2756 0 : session_env_release (se);
2757 0 : xfree (lc_ctype);
2758 0 : xfree (lc_messages);
2759 : }
2760 : else
2761 : {
2762 0 : session_env_release (opt.startup_env);
2763 0 : opt.startup_env = se;
2764 0 : xfree (opt.startup_lc_ctype);
2765 0 : opt.startup_lc_ctype = lc_ctype;
2766 0 : xfree (opt.startup_lc_messages);
2767 0 : opt.startup_lc_messages = lc_messages;
2768 : }
2769 :
2770 0 : return err;
2771 : }
2772 :
2773 :
2774 :
2775 : static const char hlp_killagent[] =
2776 : "KILLAGENT\n"
2777 : "\n"
2778 : "Stop the agent.";
2779 : static gpg_error_t
2780 46 : cmd_killagent (assuan_context_t ctx, char *line)
2781 : {
2782 46 : ctrl_t ctrl = assuan_get_pointer (ctx);
2783 :
2784 : (void)line;
2785 :
2786 46 : if (ctrl->restricted)
2787 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2788 :
2789 46 : ctrl->server_local->stopme = 1;
2790 46 : assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
2791 46 : return 0;
2792 : }
2793 :
2794 :
2795 : static const char hlp_reloadagent[] =
2796 : "RELOADAGENT\n"
2797 : "\n"
2798 : "This command is an alternative to SIGHUP\n"
2799 : "to reload the configuration.";
2800 : static gpg_error_t
2801 0 : cmd_reloadagent (assuan_context_t ctx, char *line)
2802 : {
2803 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2804 :
2805 : (void)line;
2806 :
2807 0 : if (ctrl->restricted)
2808 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
2809 :
2810 0 : agent_sighup_action ();
2811 0 : return 0;
2812 : }
2813 :
2814 :
2815 :
2816 : static const char hlp_getinfo[] =
2817 : "GETINFO <what>\n"
2818 : "\n"
2819 : "Multipurpose function to return a variety of information.\n"
2820 : "Supported values for WHAT are:\n"
2821 : "\n"
2822 : " version - Return the version of the program.\n"
2823 : " pid - Return the process id of the server.\n"
2824 : " socket_name - Return the name of the socket.\n"
2825 : " ssh_socket_name - Return the name of the ssh socket.\n"
2826 : " scd_running - Return OK if the SCdaemon is already running.\n"
2827 : " s2k_count - Return the calibrated S2K count.\n"
2828 : " std_env_names - List the names of the standard environment.\n"
2829 : " std_session_env - List the standard session environment.\n"
2830 : " std_startup_env - List the standard startup environment.\n"
2831 : " cmd_has_option\n"
2832 : " - Returns OK if the command CMD implements the option OPT.\n"
2833 : " connections - Return number of active connections.\n"
2834 : " restricted - Returns OK if the connection is in restricted mode.\n";
2835 : static gpg_error_t
2836 538 : cmd_getinfo (assuan_context_t ctx, char *line)
2837 : {
2838 538 : ctrl_t ctrl = assuan_get_pointer (ctx);
2839 538 : int rc = 0;
2840 :
2841 538 : if (!strcmp (line, "version"))
2842 : {
2843 535 : const char *s = VERSION;
2844 535 : rc = assuan_send_data (ctx, s, strlen (s));
2845 : }
2846 3 : else if (!strncmp (line, "cmd_has_option", 14)
2847 0 : && (line[14] == ' ' || line[14] == '\t' || !line[14]))
2848 0 : {
2849 : char *cmd, *cmdopt;
2850 0 : line += 14;
2851 0 : while (*line == ' ' || *line == '\t')
2852 0 : line++;
2853 0 : if (!*line)
2854 0 : rc = gpg_error (GPG_ERR_MISSING_VALUE);
2855 : else
2856 : {
2857 0 : cmd = line;
2858 0 : while (*line && (*line != ' ' && *line != '\t'))
2859 0 : line++;
2860 0 : if (!*line)
2861 0 : rc = gpg_error (GPG_ERR_MISSING_VALUE);
2862 : else
2863 : {
2864 0 : *line++ = 0;
2865 0 : while (*line == ' ' || *line == '\t')
2866 0 : line++;
2867 0 : if (!*line)
2868 0 : rc = gpg_error (GPG_ERR_MISSING_VALUE);
2869 : else
2870 : {
2871 0 : cmdopt = line;
2872 0 : if (!command_has_option (cmd, cmdopt))
2873 0 : rc = gpg_error (GPG_ERR_GENERAL);
2874 : }
2875 : }
2876 : }
2877 : }
2878 3 : else if (!strcmp (line, "s2k_count"))
2879 : {
2880 : char numbuf[50];
2881 :
2882 3 : snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
2883 3 : rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
2884 : }
2885 0 : else if (!strcmp (line, "restricted"))
2886 : {
2887 0 : rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_GENERAL);
2888 : }
2889 0 : else if (ctrl->restricted)
2890 : {
2891 0 : rc = gpg_error (GPG_ERR_FORBIDDEN);
2892 : }
2893 : /* All sub-commands below are not allowed in restricted mode. */
2894 0 : else if (!strcmp (line, "pid"))
2895 : {
2896 : char numbuf[50];
2897 :
2898 0 : snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
2899 0 : rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
2900 : }
2901 0 : else if (!strcmp (line, "socket_name"))
2902 : {
2903 0 : const char *s = get_agent_socket_name ();
2904 :
2905 0 : if (s)
2906 0 : rc = assuan_send_data (ctx, s, strlen (s));
2907 : else
2908 0 : rc = gpg_error (GPG_ERR_NO_DATA);
2909 : }
2910 0 : else if (!strcmp (line, "ssh_socket_name"))
2911 : {
2912 0 : const char *s = get_agent_ssh_socket_name ();
2913 :
2914 0 : if (s)
2915 0 : rc = assuan_send_data (ctx, s, strlen (s));
2916 : else
2917 0 : rc = gpg_error (GPG_ERR_NO_DATA);
2918 : }
2919 0 : else if (!strcmp (line, "scd_running"))
2920 : {
2921 0 : rc = agent_scd_check_running ()? 0 : gpg_error (GPG_ERR_GENERAL);
2922 : }
2923 0 : else if (!strcmp (line, "std_env_names"))
2924 : {
2925 : int iterator;
2926 : const char *name;
2927 :
2928 0 : iterator = 0;
2929 0 : while ((name = session_env_list_stdenvnames (&iterator, NULL)))
2930 : {
2931 0 : rc = assuan_send_data (ctx, name, strlen (name)+1);
2932 0 : if (!rc)
2933 0 : rc = assuan_send_data (ctx, NULL, 0);
2934 0 : if (rc)
2935 0 : break;
2936 : }
2937 : }
2938 0 : else if (!strcmp (line, "std_session_env")
2939 0 : || !strcmp (line, "std_startup_env"))
2940 0 : {
2941 : int iterator;
2942 : const char *name, *value;
2943 : char *string;
2944 :
2945 0 : iterator = 0;
2946 0 : while ((name = session_env_list_stdenvnames (&iterator, NULL)))
2947 : {
2948 0 : value = session_env_getenv_or_default
2949 0 : (line[5] == 't'? opt.startup_env:ctrl->session_env, name, NULL);
2950 0 : if (value)
2951 : {
2952 0 : string = xtryasprintf ("%s=%s", name, value);
2953 0 : if (!string)
2954 0 : rc = gpg_error_from_syserror ();
2955 : else
2956 : {
2957 0 : rc = assuan_send_data (ctx, string, strlen (string)+1);
2958 0 : if (!rc)
2959 0 : rc = assuan_send_data (ctx, NULL, 0);
2960 : }
2961 0 : if (rc)
2962 0 : break;
2963 : }
2964 : }
2965 : }
2966 0 : else if (!strcmp (line, "connections"))
2967 : {
2968 : char numbuf[20];
2969 :
2970 0 : snprintf (numbuf, sizeof numbuf, "%d",
2971 : get_agent_active_connection_count ());
2972 0 : rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
2973 : }
2974 : else
2975 0 : rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
2976 538 : return rc;
2977 : }
2978 :
2979 :
2980 :
2981 : /* This function is called by Libassuan to parse the OPTION command.
2982 : It has been registered similar to the other Assuan commands. */
2983 : static gpg_error_t
2984 3273 : option_handler (assuan_context_t ctx, const char *key, const char *value)
2985 : {
2986 3273 : ctrl_t ctrl = assuan_get_pointer (ctx);
2987 3273 : gpg_error_t err = 0;
2988 :
2989 3273 : if (!strcmp (key, "agent-awareness"))
2990 : {
2991 : /* The value is a version string telling us of which agent
2992 : version the caller is aware of. */
2993 1064 : ctrl->server_local->allow_fully_canceled =
2994 532 : gnupg_compare_version (value, "2.1.0");
2995 : }
2996 2741 : else if (ctrl->restricted)
2997 : {
2998 0 : err = gpg_error (GPG_ERR_FORBIDDEN);
2999 : }
3000 : /* All options below are not allowed in restricted mode. */
3001 2741 : else if (!strcmp (key, "putenv"))
3002 : {
3003 : /* Change the session's environment to be used for the
3004 : Pinentry. Valid values are:
3005 : <NAME> Delete envvar NAME
3006 : <KEY>= Set envvar NAME to the empty string
3007 : <KEY>=<VALUE> Set envvar NAME to VALUE
3008 : */
3009 624 : err = session_env_putenv (ctrl->session_env, value);
3010 : }
3011 2117 : else if (!strcmp (key, "display"))
3012 : {
3013 759 : err = session_env_setenv (ctrl->session_env, "DISPLAY", value);
3014 : }
3015 1358 : else if (!strcmp (key, "ttyname"))
3016 : {
3017 0 : if (!opt.keep_tty)
3018 0 : err = session_env_setenv (ctrl->session_env, "GPG_TTY", value);
3019 : }
3020 1358 : else if (!strcmp (key, "ttytype"))
3021 : {
3022 624 : if (!opt.keep_tty)
3023 624 : err = session_env_setenv (ctrl->session_env, "TERM", value);
3024 : }
3025 734 : else if (!strcmp (key, "lc-ctype"))
3026 : {
3027 0 : if (ctrl->lc_ctype)
3028 0 : xfree (ctrl->lc_ctype);
3029 0 : ctrl->lc_ctype = xtrystrdup (value);
3030 0 : if (!ctrl->lc_ctype)
3031 0 : return out_of_core ();
3032 : }
3033 734 : else if (!strcmp (key, "lc-messages"))
3034 : {
3035 0 : if (ctrl->lc_messages)
3036 0 : xfree (ctrl->lc_messages);
3037 0 : ctrl->lc_messages = xtrystrdup (value);
3038 0 : if (!ctrl->lc_messages)
3039 0 : return out_of_core ();
3040 : }
3041 734 : else if (!strcmp (key, "xauthority"))
3042 : {
3043 0 : err = session_env_setenv (ctrl->session_env, "XAUTHORITY", value);
3044 : }
3045 734 : else if (!strcmp (key, "pinentry-user-data"))
3046 : {
3047 67 : err = session_env_setenv (ctrl->session_env, "PINENTRY_USER_DATA", value);
3048 : }
3049 667 : else if (!strcmp (key, "use-cache-for-signing"))
3050 0 : ctrl->server_local->use_cache_for_signing = *value? !!atoi (value) : 0;
3051 667 : else if (!strcmp (key, "allow-pinentry-notify"))
3052 667 : ctrl->server_local->allow_pinentry_notify = 1;
3053 0 : else if (!strcmp (key, "pinentry-mode"))
3054 : {
3055 0 : int tmp = parse_pinentry_mode (value);
3056 0 : if (tmp == -1)
3057 0 : err = gpg_error (GPG_ERR_INV_VALUE);
3058 0 : else if (tmp == PINENTRY_MODE_LOOPBACK && !opt.allow_loopback_pinentry)
3059 0 : err = gpg_error (GPG_ERR_NOT_SUPPORTED);
3060 : else
3061 0 : ctrl->pinentry_mode = tmp;
3062 : }
3063 0 : else if (!strcmp (key, "cache-ttl-opt-preset"))
3064 : {
3065 0 : ctrl->cache_ttl_opt_preset = *value? atoi (value) : 0;
3066 : }
3067 0 : else if (!strcmp (key, "s2k-count"))
3068 : {
3069 0 : ctrl->s2k_count = *value? strtoul(value, NULL, 10) : 0;
3070 0 : if (ctrl->s2k_count && ctrl->s2k_count < 65536)
3071 : {
3072 0 : ctrl->s2k_count = 0;
3073 : }
3074 : }
3075 : else
3076 0 : err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
3077 :
3078 3273 : return err;
3079 : }
3080 :
3081 :
3082 :
3083 :
3084 : /* Called by libassuan after all commands. ERR is the error from the
3085 : last assuan operation and not the one returned from the command. */
3086 : static void
3087 7868 : post_cmd_notify (assuan_context_t ctx, gpg_error_t err)
3088 : {
3089 7868 : ctrl_t ctrl = assuan_get_pointer (ctx);
3090 :
3091 : (void)err;
3092 :
3093 : /* Switch off any I/O monitor controlled logging pausing. */
3094 7868 : ctrl->server_local->pause_io_logging = 0;
3095 7868 : }
3096 :
3097 :
3098 : /* This function is called by libassuan for all I/O. We use it here
3099 : to disable logging for the GETEVENTCOUNTER commands. This is so
3100 : that the debug output won't get cluttered by this primitive
3101 : command. */
3102 : static unsigned int
3103 26994 : io_monitor (assuan_context_t ctx, void *hook, int direction,
3104 : const char *line, size_t linelen)
3105 : {
3106 26994 : ctrl_t ctrl = assuan_get_pointer (ctx);
3107 :
3108 : (void) hook;
3109 :
3110 : /* We want to suppress all Assuan log messages for connections from
3111 : * self. However, assuan_get_pid works only after
3112 : * assuan_accept. Now, assuan_accept already logs a line ending with
3113 : * the process id. We use this hack here to get the peers pid so
3114 : * that we can compare it to our pid. We should add an assuan
3115 : * function to return the pid for a file descriptor and use that to
3116 : * detect connections to self. */
3117 26994 : if (ctx && !ctrl->server_local->greeting_seen
3118 759 : && direction == ASSUAN_IO_TO_PEER)
3119 : {
3120 759 : ctrl->server_local->greeting_seen = 1;
3121 759 : if (linelen > 32
3122 759 : && !strncmp (line, "OK Pleased to meet you, process ", 32)
3123 759 : && strtoul (line+32, NULL, 10) == getpid ())
3124 0 : return ASSUAN_IO_MONITOR_NOLOG;
3125 : }
3126 :
3127 :
3128 : /* Do not log self-connections. This makes the log cleaner because
3129 : * we won't see the check-our-own-socket calls. */
3130 26994 : if (ctx && ctrl->server_local->connect_from_self)
3131 0 : return ASSUAN_IO_MONITOR_NOLOG;
3132 :
3133 : /* Note that we only check for the uppercase name. This allows the user to
3134 : see the logging for debugging if using a non-upercase command
3135 : name. */
3136 26994 : if (ctx && direction == ASSUAN_IO_FROM_PEER
3137 8477 : && linelen >= 15
3138 6558 : && !strncmp (line, "GETEVENTCOUNTER", 15)
3139 0 : && (linelen == 15 || spacep (line+15)))
3140 : {
3141 0 : ctrl->server_local->pause_io_logging = 1;
3142 : }
3143 :
3144 26994 : return ctrl->server_local->pause_io_logging? ASSUAN_IO_MONITOR_NOLOG : 0;
3145 : }
3146 :
3147 :
3148 : /* Return true if the command CMD implements the option OPT. */
3149 : static int
3150 0 : command_has_option (const char *cmd, const char *cmdopt)
3151 : {
3152 0 : if (!strcmp (cmd, "GET_PASSPHRASE"))
3153 : {
3154 0 : if (!strcmp (cmdopt, "repeat"))
3155 0 : return 1;
3156 : }
3157 :
3158 0 : return 0;
3159 : }
3160 :
3161 :
3162 : /* Tell Libassuan about our commands. Also register the other Assuan
3163 : handlers. */
3164 : static int
3165 759 : register_commands (assuan_context_t ctx)
3166 : {
3167 : static struct {
3168 : const char *name;
3169 : assuan_handler_t handler;
3170 : const char * const help;
3171 : } table[] = {
3172 : { "GETEVENTCOUNTER",cmd_geteventcounter, hlp_geteventcounter },
3173 : { "ISTRUSTED", cmd_istrusted, hlp_istrusted },
3174 : { "HAVEKEY", cmd_havekey, hlp_havekey },
3175 : { "KEYINFO", cmd_keyinfo, hlp_keyinfo },
3176 : { "SIGKEY", cmd_sigkey, hlp_sigkey },
3177 : { "SETKEY", cmd_sigkey, hlp_sigkey },
3178 : { "SETKEYDESC", cmd_setkeydesc,hlp_setkeydesc },
3179 : { "SETHASH", cmd_sethash, hlp_sethash },
3180 : { "PKSIGN", cmd_pksign, hlp_pksign },
3181 : { "PKDECRYPT", cmd_pkdecrypt, hlp_pkdecrypt },
3182 : { "GENKEY", cmd_genkey, hlp_genkey },
3183 : { "READKEY", cmd_readkey, hlp_readkey },
3184 : { "GET_PASSPHRASE", cmd_get_passphrase, hlp_get_passphrase },
3185 : { "PRESET_PASSPHRASE", cmd_preset_passphrase, hlp_preset_passphrase },
3186 : { "CLEAR_PASSPHRASE", cmd_clear_passphrase, hlp_clear_passphrase },
3187 : { "GET_CONFIRMATION", cmd_get_confirmation, hlp_get_confirmation },
3188 : { "LISTTRUSTED", cmd_listtrusted, hlp_listtrusted },
3189 : { "MARKTRUSTED", cmd_marktrusted, hlp_martrusted },
3190 : { "LEARN", cmd_learn, hlp_learn },
3191 : { "PASSWD", cmd_passwd, hlp_passwd },
3192 : { "INPUT", NULL },
3193 : { "OUTPUT", NULL },
3194 : { "SCD", cmd_scd, hlp_scd },
3195 : { "KEYWRAP_KEY", cmd_keywrap_key, hlp_keywrap_key },
3196 : { "IMPORT_KEY", cmd_import_key, hlp_import_key },
3197 : { "EXPORT_KEY", cmd_export_key, hlp_export_key },
3198 : { "DELETE_KEY", cmd_delete_key, hlp_delete_key },
3199 : { "GETVAL", cmd_getval, hlp_getval },
3200 : { "PUTVAL", cmd_putval, hlp_putval },
3201 : { "UPDATESTARTUPTTY", cmd_updatestartuptty, hlp_updatestartuptty },
3202 : { "KILLAGENT", cmd_killagent, hlp_killagent },
3203 : { "RELOADAGENT", cmd_reloadagent,hlp_reloadagent },
3204 : { "GETINFO", cmd_getinfo, hlp_getinfo },
3205 : { "KEYTOCARD", cmd_keytocard, hlp_keytocard },
3206 : { NULL }
3207 : };
3208 : int i, rc;
3209 :
3210 26565 : for (i=0; table[i].name; i++)
3211 : {
3212 25806 : rc = assuan_register_command (ctx, table[i].name, table[i].handler,
3213 : table[i].help);
3214 25806 : if (rc)
3215 0 : return rc;
3216 : }
3217 759 : assuan_register_post_cmd_notify (ctx, post_cmd_notify);
3218 759 : assuan_register_reset_notify (ctx, reset_notify);
3219 759 : assuan_register_option_handler (ctx, option_handler);
3220 759 : return 0;
3221 : }
3222 :
3223 :
3224 : /* Startup the server. If LISTEN_FD and FD is given as -1, this is a
3225 : simple piper server, otherwise it is a regular server. CTRL is the
3226 : control structure for this connection; it has only the basic
3227 : initialization. */
3228 : void
3229 759 : start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
3230 : {
3231 : int rc;
3232 759 : assuan_context_t ctx = NULL;
3233 :
3234 759 : if (ctrl->restricted)
3235 : {
3236 0 : if (agent_copy_startup_env (ctrl))
3237 713 : return;
3238 : }
3239 :
3240 759 : rc = assuan_new (&ctx);
3241 759 : if (rc)
3242 : {
3243 0 : log_error ("failed to allocate assuan context: %s\n", gpg_strerror (rc));
3244 0 : agent_exit (2);
3245 : }
3246 :
3247 759 : if (listen_fd == GNUPG_INVALID_FD && fd == GNUPG_INVALID_FD)
3248 0 : {
3249 : assuan_fd_t filedes[2];
3250 :
3251 0 : filedes[0] = assuan_fdopen (0);
3252 0 : filedes[1] = assuan_fdopen (1);
3253 0 : rc = assuan_init_pipe_server (ctx, filedes);
3254 : }
3255 759 : else if (listen_fd != GNUPG_INVALID_FD)
3256 : {
3257 0 : rc = assuan_init_socket_server (ctx, listen_fd, 0);
3258 : /* FIXME: Need to call assuan_sock_set_nonce for Windows. But
3259 : this branch is currently not used. */
3260 : }
3261 : else
3262 : {
3263 759 : rc = assuan_init_socket_server (ctx, fd, ASSUAN_SOCKET_SERVER_ACCEPTED);
3264 : }
3265 759 : if (rc)
3266 : {
3267 0 : log_error ("failed to initialize the server: %s\n",
3268 : gpg_strerror(rc));
3269 0 : agent_exit (2);
3270 : }
3271 759 : rc = register_commands (ctx);
3272 759 : if (rc)
3273 : {
3274 0 : log_error ("failed to register commands with Assuan: %s\n",
3275 : gpg_strerror(rc));
3276 0 : agent_exit (2);
3277 : }
3278 :
3279 759 : assuan_set_pointer (ctx, ctrl);
3280 759 : ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
3281 759 : ctrl->server_local->assuan_ctx = ctx;
3282 759 : ctrl->server_local->use_cache_for_signing = 1;
3283 :
3284 759 : ctrl->digest.raw_value = 0;
3285 :
3286 759 : assuan_set_io_monitor (ctx, io_monitor, NULL);
3287 759 : agent_set_progress_cb (progress_cb, ctrl);
3288 :
3289 : for (;;)
3290 : {
3291 1518 : rc = assuan_accept (ctx);
3292 1518 : if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
3293 : {
3294 : break;
3295 : }
3296 759 : else if (rc)
3297 : {
3298 0 : log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
3299 0 : break;
3300 : }
3301 :
3302 759 : ctrl->server_local->connect_from_self = (assuan_get_pid (ctx)==getpid ());
3303 :
3304 759 : rc = assuan_process (ctx);
3305 759 : if (rc)
3306 : {
3307 0 : log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
3308 0 : continue;
3309 : }
3310 759 : }
3311 :
3312 : /* Reset the nonce caches. */
3313 759 : clear_nonce_cache (ctrl);
3314 :
3315 : /* Reset the SCD if needed. */
3316 759 : agent_reset_scd (ctrl);
3317 :
3318 : /* Reset the pinentry (in case of popup messages). */
3319 759 : agent_reset_query (ctrl);
3320 :
3321 : /* Cleanup. */
3322 759 : assuan_release (ctx);
3323 759 : xfree (ctrl->server_local->keydesc);
3324 759 : xfree (ctrl->server_local->import_key);
3325 759 : xfree (ctrl->server_local->export_key);
3326 759 : if (ctrl->server_local->stopme)
3327 46 : agent_exit (0);
3328 713 : xfree (ctrl->server_local);
3329 713 : ctrl->server_local = NULL;
3330 : }
3331 :
3332 :
3333 : /* Helper for the pinentry loopback mode. It merely passes the
3334 : parameters on to the client. */
3335 : gpg_error_t
3336 0 : pinentry_loopback(ctrl_t ctrl, const char *keyword,
3337 : unsigned char **buffer, size_t *size,
3338 : size_t max_length)
3339 : {
3340 : gpg_error_t rc;
3341 0 : assuan_context_t ctx = ctrl->server_local->assuan_ctx;
3342 :
3343 0 : rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%zu", max_length);
3344 0 : if (rc)
3345 0 : return rc;
3346 :
3347 0 : assuan_begin_confidential (ctx);
3348 0 : rc = assuan_inquire (ctx, keyword, buffer, size, max_length);
3349 0 : assuan_end_confidential (ctx);
3350 0 : return rc;
3351 : }
|