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