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