Line data Source code
1 : /* server.c - LDAP and Keyserver access server
2 : * Copyright (C) 2002 Klarälvdalens Datakonsult AB
3 : * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011, 2015 g10 Code GmbH
4 : * Copyright (C) 2014, 2015, 2016 Werner Koch
5 : *
6 : * This file is part of GnuPG.
7 : *
8 : * GnuPG is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 3 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * GnuPG is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License
19 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include <config.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <stddef.h>
26 : #include <string.h>
27 : #include <assert.h>
28 : #include <sys/types.h>
29 : #include <sys/stat.h>
30 : #include <unistd.h>
31 : #include <errno.h>
32 :
33 : #include "dirmngr.h"
34 : #include <assuan.h>
35 :
36 : #include "crlcache.h"
37 : #include "crlfetch.h"
38 : #if USE_LDAP
39 : # include "ldapserver.h"
40 : #endif
41 : #include "ocsp.h"
42 : #include "certcache.h"
43 : #include "validate.h"
44 : #include "misc.h"
45 : #if USE_LDAP
46 : # include "ldap-wrapper.h"
47 : #endif
48 : #include "ks-action.h"
49 : #include "ks-engine.h" /* (ks_hkp_print_hosttable) */
50 : #if USE_LDAP
51 : # include "ldap-parse-uri.h"
52 : #endif
53 : #include "dns-stuff.h"
54 : #include "mbox-util.h"
55 : #include "zb32.h"
56 : #include "server-help.h"
57 :
58 : /* To avoid DoS attacks we limit the size of a certificate to
59 : something reasonable. The DoS was actually only an issue back when
60 : Dirmngr was a system service and not a user service. */
61 : #define MAX_CERT_LENGTH (16*1024)
62 :
63 : /* The same goes for OpenPGP keyblocks, but here we need to allow for
64 : much longer blocks; a 200k keyblock is not too unusual for keys
65 : with a lot of signatures (e.g. 0x5b0358a2). 9C31503C6D866396 even
66 : has 770 KiB as of 2015-08-23. To avoid adding a runtime option we
67 : now use 20MiB which should really be enough. Well, a key with
68 : several pictures could be larger (the parser as a 18MiB limit for
69 : attribute packets) but it won't be nice to the keyservers to send
70 : them such large blobs. */
71 : #define MAX_KEYBLOCK_LENGTH (20*1024*1024)
72 :
73 :
74 : #define PARM_ERROR(t) assuan_set_error (ctx, \
75 : gpg_error (GPG_ERR_ASS_PARAMETER), (t))
76 : #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
77 :
78 :
79 :
80 : /* Control structure per connection. */
81 : struct server_local_s
82 : {
83 : /* Data used to associate an Assuan context with local server data */
84 : assuan_context_t assuan_ctx;
85 :
86 : /* Per-session LDAP servers. */
87 : ldap_server_t ldapservers;
88 :
89 : /* Per-session list of keyservers. */
90 : uri_item_t keyservers;
91 :
92 : /* If this flag is set to true this dirmngr process will be
93 : terminated after the end of this session. */
94 : int stopme;
95 :
96 : /* State variable private to is_tor_running. */
97 : int tor_state;
98 :
99 : /* If the first both flags are set the assuan logging of data lines
100 : * is suppressed. The count variable is used to show the number of
101 : * non-logged bytes. */
102 : size_t inhibit_data_logging_count;
103 : unsigned int inhibit_data_logging : 1;
104 : unsigned int inhibit_data_logging_now : 1;
105 : };
106 :
107 :
108 : /* Cookie definition for assuan data line output. */
109 : static gpgrt_ssize_t data_line_cookie_write (void *cookie,
110 : const void *buffer, size_t size);
111 : static int data_line_cookie_close (void *cookie);
112 : static es_cookie_io_functions_t data_line_cookie_functions =
113 : {
114 : NULL,
115 : data_line_cookie_write,
116 : NULL,
117 : data_line_cookie_close
118 : };
119 :
120 :
121 :
122 :
123 :
124 : /* Accessor for the local ldapservers variable. */
125 : ldap_server_t
126 0 : get_ldapservers_from_ctrl (ctrl_t ctrl)
127 : {
128 0 : if (ctrl && ctrl->server_local)
129 0 : return ctrl->server_local->ldapservers;
130 : else
131 0 : return NULL;
132 : }
133 :
134 : /* Release an uri_item_t list. */
135 : static void
136 0 : release_uri_item_list (uri_item_t list)
137 : {
138 0 : while (list)
139 : {
140 0 : uri_item_t tmp = list->next;
141 0 : http_release_parsed_uri (list->parsed_uri);
142 0 : xfree (list);
143 0 : list = tmp;
144 : }
145 0 : }
146 :
147 : /* Release all configured keyserver info from CTRL. */
148 : void
149 0 : release_ctrl_keyservers (ctrl_t ctrl)
150 : {
151 0 : if (! ctrl->server_local)
152 0 : return;
153 :
154 0 : release_uri_item_list (ctrl->server_local->keyservers);
155 0 : ctrl->server_local->keyservers = NULL;
156 : }
157 :
158 :
159 :
160 : /* Helper to print a message while leaving a command. */
161 : static gpg_error_t
162 0 : leave_cmd (assuan_context_t ctx, gpg_error_t err)
163 : {
164 0 : if (err)
165 : {
166 0 : const char *name = assuan_get_command_name (ctx);
167 0 : if (!name)
168 0 : name = "?";
169 0 : if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
170 0 : log_error ("command '%s' failed: %s\n", name,
171 : gpg_strerror (err));
172 : else
173 0 : log_error ("command '%s' failed: %s <%s>\n", name,
174 : gpg_strerror (err), gpg_strsource (err));
175 : }
176 0 : return err;
177 : }
178 :
179 :
180 : /* This is a wrapper around assuan_send_data which makes debugging the
181 : output in verbose mode easier. */
182 : static gpg_error_t
183 0 : data_line_write (assuan_context_t ctx, const void *buffer_arg, size_t size)
184 : {
185 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
186 0 : const char *buffer = buffer_arg;
187 : gpg_error_t err;
188 :
189 : /* If we do not want logging, enable it it here. */
190 0 : if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
191 0 : ctrl->server_local->inhibit_data_logging_now = 1;
192 :
193 0 : if (opt.verbose && buffer && size)
194 0 : {
195 : /* Ease reading of output by sending a physical line at each LF. */
196 : const char *p;
197 : size_t n, nbytes;
198 :
199 0 : nbytes = size;
200 : do
201 : {
202 0 : p = memchr (buffer, '\n', nbytes);
203 0 : n = p ? (p - buffer) + 1 : nbytes;
204 0 : err = assuan_send_data (ctx, buffer, n);
205 0 : if (err)
206 : {
207 0 : gpg_err_set_errno (EIO);
208 0 : goto leave;
209 : }
210 0 : buffer += n;
211 0 : nbytes -= n;
212 0 : if (nbytes && (err=assuan_send_data (ctx, NULL, 0))) /* Flush line. */
213 : {
214 0 : gpg_err_set_errno (EIO);
215 0 : goto leave;
216 : }
217 : }
218 0 : while (nbytes);
219 : }
220 : else
221 : {
222 0 : err = assuan_send_data (ctx, buffer, size);
223 0 : if (err)
224 : {
225 0 : gpg_err_set_errno (EIO); /* For use by data_line_cookie_write. */
226 0 : goto leave;
227 : }
228 : }
229 :
230 : leave:
231 0 : if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
232 : {
233 0 : ctrl->server_local->inhibit_data_logging_now = 0;
234 0 : ctrl->server_local->inhibit_data_logging_count += size;
235 : }
236 :
237 0 : return err;
238 : }
239 :
240 :
241 : /* A write handler used by es_fopencookie to write assuan data
242 : lines. */
243 : static gpgrt_ssize_t
244 0 : data_line_cookie_write (void *cookie, const void *buffer, size_t size)
245 : {
246 0 : assuan_context_t ctx = cookie;
247 :
248 0 : if (data_line_write (ctx, buffer, size))
249 0 : return -1;
250 0 : return (gpgrt_ssize_t)size;
251 : }
252 :
253 :
254 : static int
255 0 : data_line_cookie_close (void *cookie)
256 : {
257 0 : assuan_context_t ctx = cookie;
258 :
259 0 : if (DBG_IPC)
260 : {
261 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
262 :
263 0 : if (ctrl && ctrl->server_local
264 0 : && ctrl->server_local->inhibit_data_logging
265 0 : && ctrl->server_local->inhibit_data_logging_count)
266 0 : log_debug ("(%zu bytes sent via D lines not shown)\n",
267 0 : ctrl->server_local->inhibit_data_logging_count);
268 : }
269 0 : if (assuan_send_data (ctx, NULL, 0))
270 : {
271 0 : gpg_err_set_errno (EIO);
272 0 : return -1;
273 : }
274 :
275 0 : return 0;
276 : }
277 :
278 :
279 : /* Copy the % and + escaped string S into the buffer D and replace the
280 : escape sequences. Note, that it is sufficient to allocate the
281 : target string D as long as the source string S, i.e.: strlen(s)+1.
282 : Note further that if S contains an escaped binary Nul the resulting
283 : string D will contain the 0 as well as all other characters but it
284 : will be impossible to know whether this is the original EOS or a
285 : copied Nul. */
286 : static void
287 0 : strcpy_escaped_plus (char *d, const unsigned char *s)
288 : {
289 0 : while (*s)
290 : {
291 0 : if (*s == '%' && s[1] && s[2])
292 : {
293 0 : s++;
294 0 : *d++ = xtoi_2 ( s);
295 0 : s += 2;
296 : }
297 0 : else if (*s == '+')
298 0 : *d++ = ' ', s++;
299 : else
300 0 : *d++ = *s++;
301 : }
302 0 : *d = 0;
303 0 : }
304 :
305 :
306 : /* This function returns true if a Tor server is running. The sattus
307 : is cached for the current connection. */
308 : static int
309 0 : is_tor_running (ctrl_t ctrl)
310 : {
311 : /* Check whether we can connect to the proxy. */
312 :
313 0 : if (!ctrl || !ctrl->server_local)
314 0 : return 0; /* Ooops. */
315 :
316 0 : if (!ctrl->server_local->tor_state)
317 : {
318 : assuan_fd_t sock;
319 :
320 0 : sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
321 0 : if (sock == ASSUAN_INVALID_FD)
322 0 : ctrl->server_local->tor_state = -1; /* Not running. */
323 : else
324 : {
325 0 : assuan_sock_close (sock);
326 0 : ctrl->server_local->tor_state = 1; /* Running. */
327 : }
328 : }
329 0 : return (ctrl->server_local->tor_state > 0);
330 : }
331 :
332 :
333 : /* Return an error if the assuan context does not belong to the owner
334 : of the process or to root. On error FAILTEXT is set as Assuan
335 : error string. */
336 : static gpg_error_t
337 0 : check_owner_permission (assuan_context_t ctx, const char *failtext)
338 : {
339 : #ifdef HAVE_W32_SYSTEM
340 : /* Under Windows the dirmngr is always run under the control of the
341 : user. */
342 : (void)ctx;
343 : (void)failtext;
344 : #else
345 : gpg_err_code_t ec;
346 : assuan_peercred_t cred;
347 :
348 0 : ec = gpg_err_code (assuan_get_peercred (ctx, &cred));
349 0 : if (!ec && cred->uid && cred->uid != getuid ())
350 0 : ec = GPG_ERR_EPERM;
351 0 : if (ec)
352 0 : return set_error (ec, failtext);
353 : #endif
354 0 : return 0;
355 : }
356 :
357 :
358 :
359 : /* Common code for get_cert_local and get_issuer_cert_local. */
360 : static ksba_cert_t
361 0 : do_get_cert_local (ctrl_t ctrl, const char *name, const char *command)
362 : {
363 : unsigned char *value;
364 : size_t valuelen;
365 : int rc;
366 : char *buf;
367 : ksba_cert_t cert;
368 :
369 0 : if (name)
370 : {
371 0 : buf = xmalloc ( strlen (command) + 1 + strlen(name) + 1);
372 0 : strcpy (stpcpy (stpcpy (buf, command), " "), name);
373 : }
374 : else
375 0 : buf = xstrdup (command);
376 :
377 0 : rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
378 : &value, &valuelen, MAX_CERT_LENGTH);
379 0 : xfree (buf);
380 0 : if (rc)
381 : {
382 0 : log_error (_("assuan_inquire(%s) failed: %s\n"),
383 : command, gpg_strerror (rc));
384 0 : return NULL;
385 : }
386 :
387 0 : if (!valuelen)
388 : {
389 0 : xfree (value);
390 0 : return NULL;
391 : }
392 :
393 0 : rc = ksba_cert_new (&cert);
394 0 : if (!rc)
395 : {
396 0 : rc = ksba_cert_init_from_mem (cert, value, valuelen);
397 0 : if (rc)
398 : {
399 0 : ksba_cert_release (cert);
400 0 : cert = NULL;
401 : }
402 : }
403 0 : xfree (value);
404 0 : return cert;
405 : }
406 :
407 :
408 :
409 : /* Ask back to return a certificate for name, given as a regular
410 : gpgsm certificate indentificates (e.g. fingerprint or one of the
411 : other methods). Alternatively, NULL may be used for NAME to
412 : return the current target certificate. Either return the certificate
413 : in a KSBA object or NULL if it is not available.
414 : */
415 : ksba_cert_t
416 0 : get_cert_local (ctrl_t ctrl, const char *name)
417 : {
418 0 : if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
419 : {
420 0 : if (opt.debug)
421 0 : log_debug ("get_cert_local called w/o context\n");
422 0 : return NULL;
423 : }
424 0 : return do_get_cert_local (ctrl, name, "SENDCERT");
425 :
426 : }
427 :
428 : /* Ask back to return the issuing certificate for name, given as a
429 : regular gpgsm certificate indentificates (e.g. fingerprint or one
430 : of the other methods). Alternatively, NULL may be used for NAME to
431 : return thecurrent target certificate. Either return the certificate
432 : in a KSBA object or NULL if it is not available.
433 :
434 : */
435 : ksba_cert_t
436 0 : get_issuing_cert_local (ctrl_t ctrl, const char *name)
437 : {
438 0 : if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
439 : {
440 0 : if (opt.debug)
441 0 : log_debug ("get_issuing_cert_local called w/o context\n");
442 0 : return NULL;
443 : }
444 0 : return do_get_cert_local (ctrl, name, "SENDISSUERCERT");
445 : }
446 :
447 : /* Ask back to return a certificate with subject NAME and a
448 : subjectKeyIdentifier of KEYID. */
449 : ksba_cert_t
450 0 : get_cert_local_ski (ctrl_t ctrl, const char *name, ksba_sexp_t keyid)
451 : {
452 : unsigned char *value;
453 : size_t valuelen;
454 : int rc;
455 : char *buf;
456 : ksba_cert_t cert;
457 : char *hexkeyid;
458 :
459 0 : if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
460 : {
461 0 : if (opt.debug)
462 0 : log_debug ("get_cert_local_ski called w/o context\n");
463 0 : return NULL;
464 : }
465 0 : if (!name || !keyid)
466 : {
467 0 : log_debug ("get_cert_local_ski called with insufficient arguments\n");
468 0 : return NULL;
469 : }
470 :
471 0 : hexkeyid = serial_hex (keyid);
472 0 : if (!hexkeyid)
473 : {
474 0 : log_debug ("serial_hex() failed\n");
475 0 : return NULL;
476 : }
477 :
478 0 : buf = xtrymalloc (15 + strlen (hexkeyid) + 2 + strlen(name) + 1);
479 0 : if (!buf)
480 : {
481 :
482 0 : log_error ("can't allocate enough memory: %s\n", strerror (errno));
483 0 : xfree (hexkeyid);
484 0 : return NULL;
485 : }
486 0 : strcpy (stpcpy (stpcpy (stpcpy (buf, "SENDCERT_SKI "), hexkeyid)," /"),name);
487 0 : xfree (hexkeyid);
488 :
489 0 : rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
490 : &value, &valuelen, MAX_CERT_LENGTH);
491 0 : xfree (buf);
492 0 : if (rc)
493 : {
494 0 : log_error (_("assuan_inquire(%s) failed: %s\n"), "SENDCERT_SKI",
495 : gpg_strerror (rc));
496 0 : return NULL;
497 : }
498 :
499 0 : if (!valuelen)
500 : {
501 0 : xfree (value);
502 0 : return NULL;
503 : }
504 :
505 0 : rc = ksba_cert_new (&cert);
506 0 : if (!rc)
507 : {
508 0 : rc = ksba_cert_init_from_mem (cert, value, valuelen);
509 0 : if (rc)
510 : {
511 0 : ksba_cert_release (cert);
512 0 : cert = NULL;
513 : }
514 : }
515 0 : xfree (value);
516 0 : return cert;
517 : }
518 :
519 :
520 : /* Ask the client via an inquiry to check the istrusted status of the
521 : certificate specified by the hexified fingerprint HEXFPR. Returns
522 : 0 if the certificate is trusted by the client or an error code. */
523 : gpg_error_t
524 0 : get_istrusted_from_client (ctrl_t ctrl, const char *hexfpr)
525 : {
526 : unsigned char *value;
527 : size_t valuelen;
528 : int rc;
529 : char request[100];
530 :
531 0 : if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx
532 0 : || !hexfpr)
533 0 : return gpg_error (GPG_ERR_INV_ARG);
534 :
535 0 : snprintf (request, sizeof request, "ISTRUSTED %s", hexfpr);
536 0 : rc = assuan_inquire (ctrl->server_local->assuan_ctx, request,
537 : &value, &valuelen, 100);
538 0 : if (rc)
539 : {
540 0 : log_error (_("assuan_inquire(%s) failed: %s\n"),
541 : request, gpg_strerror (rc));
542 0 : return rc;
543 : }
544 : /* The expected data is: "1" or "1 cruft" (not a C-string). */
545 0 : if (valuelen && *value == '1' && (valuelen == 1 || spacep (value+1)))
546 0 : rc = 0;
547 : else
548 0 : rc = gpg_error (GPG_ERR_NOT_TRUSTED);
549 0 : xfree (value);
550 0 : return rc;
551 : }
552 :
553 :
554 :
555 :
556 : /* Ask the client to return the certificate associated with the
557 : current command. This is sometimes needed because the client usually
558 : sends us just the cert ID, assuming that the request can be
559 : satisfied from the cache, where the cert ID is used as key. */
560 : static int
561 0 : inquire_cert_and_load_crl (assuan_context_t ctx)
562 : {
563 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
564 : gpg_error_t err;
565 0 : unsigned char *value = NULL;
566 : size_t valuelen;
567 0 : ksba_cert_t cert = NULL;
568 :
569 0 : err = assuan_inquire( ctx, "SENDCERT", &value, &valuelen, 0);
570 0 : if (err)
571 0 : return err;
572 :
573 : /* { */
574 : /* FILE *fp = fopen ("foo.der", "r"); */
575 : /* value = xmalloc (2000); */
576 : /* valuelen = fread (value, 1, 2000, fp); */
577 : /* fclose (fp); */
578 : /* } */
579 :
580 0 : if (!valuelen) /* No data returned; return a comprehensible error. */
581 0 : return gpg_error (GPG_ERR_MISSING_CERT);
582 :
583 0 : err = ksba_cert_new (&cert);
584 0 : if (err)
585 0 : goto leave;
586 0 : err = ksba_cert_init_from_mem (cert, value, valuelen);
587 0 : if(err)
588 0 : goto leave;
589 0 : xfree (value); value = NULL;
590 :
591 0 : err = crl_cache_reload_crl (ctrl, cert);
592 :
593 : leave:
594 0 : ksba_cert_release (cert);
595 0 : xfree (value);
596 0 : return err;
597 : }
598 :
599 :
600 : /* Handle OPTION commands. */
601 : static gpg_error_t
602 0 : option_handler (assuan_context_t ctx, const char *key, const char *value)
603 : {
604 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
605 0 : gpg_error_t err = 0;
606 :
607 0 : if (!strcmp (key, "force-crl-refresh"))
608 : {
609 0 : int i = *value? atoi (value) : 0;
610 0 : ctrl->force_crl_refresh = i;
611 : }
612 0 : else if (!strcmp (key, "audit-events"))
613 : {
614 0 : int i = *value? atoi (value) : 0;
615 0 : ctrl->audit_events = i;
616 : }
617 0 : else if (!strcmp (key, "http-proxy"))
618 : {
619 0 : xfree (ctrl->http_proxy);
620 0 : if (!*value || !strcmp (value, "none"))
621 0 : ctrl->http_proxy = NULL;
622 0 : else if (!(ctrl->http_proxy = xtrystrdup (value)))
623 0 : err = gpg_error_from_syserror ();
624 : }
625 0 : else if (!strcmp (key, "honor-keyserver-url-used"))
626 : {
627 : /* Return an error if we are running in Tor mode. */
628 0 : if (opt.use_tor)
629 0 : err = gpg_error (GPG_ERR_FORBIDDEN);
630 : }
631 : else
632 0 : err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
633 :
634 0 : return err;
635 : }
636 :
637 :
638 :
639 : static const char hlp_dns_cert[] =
640 : "DNS_CERT <subtype> <name>\n"
641 : "DNS_CERT --pka <user_id>\n"
642 : "DNS_CERT --dane <user_id>\n"
643 : "\n"
644 : "Return the CERT record for <name>. <subtype> is one of\n"
645 : " * Return the first record of any supported subtype\n"
646 : " PGP Return the first record of subtype PGP (3)\n"
647 : " IPGP Return the first record of subtype IPGP (6)\n"
648 : "If the content of a certificate is available (PGP) it is returned\n"
649 : "by data lines. Fingerprints and URLs are returned via status lines.\n"
650 : "In --pka mode the fingerprint and if available an URL is returned.\n"
651 : "In --dane mode the key is returned from RR type 61";
652 : static gpg_error_t
653 0 : cmd_dns_cert (assuan_context_t ctx, char *line)
654 : {
655 : /* ctrl_t ctrl = assuan_get_pointer (ctx); */
656 0 : gpg_error_t err = 0;
657 : int pka_mode, dane_mode;
658 0 : char *mbox = NULL;
659 0 : char *namebuf = NULL;
660 0 : char *encodedhash = NULL;
661 : const char *name;
662 : int certtype;
663 : char *p;
664 0 : void *key = NULL;
665 : size_t keylen;
666 0 : unsigned char *fpr = NULL;
667 : size_t fprlen;
668 0 : char *url = NULL;
669 :
670 0 : pka_mode = has_option (line, "--pka");
671 0 : dane_mode = has_option (line, "--dane");
672 0 : line = skip_options (line);
673 :
674 0 : if (pka_mode && dane_mode)
675 : {
676 0 : err = PARM_ERROR ("either --pka or --dane may be given");
677 0 : goto leave;
678 : }
679 :
680 0 : if (pka_mode || dane_mode)
681 : ; /* No need to parse here - we do this later. */
682 : else
683 : {
684 0 : p = strchr (line, ' ');
685 0 : if (!p)
686 : {
687 0 : err = PARM_ERROR ("missing arguments");
688 0 : goto leave;
689 : }
690 0 : *p++ = 0;
691 0 : if (!strcmp (line, "*"))
692 0 : certtype = DNS_CERTTYPE_ANY;
693 0 : else if (!strcmp (line, "IPGP"))
694 0 : certtype = DNS_CERTTYPE_IPGP;
695 0 : else if (!strcmp (line, "PGP"))
696 0 : certtype = DNS_CERTTYPE_PGP;
697 : else
698 : {
699 0 : err = PARM_ERROR ("unknown subtype");
700 0 : goto leave;
701 : }
702 0 : while (spacep (p))
703 0 : p++;
704 0 : line = p;
705 0 : if (!*line)
706 : {
707 0 : err = PARM_ERROR ("name missing");
708 0 : goto leave;
709 : }
710 : }
711 :
712 0 : if (opt.use_tor && (err = enable_dns_tormode (0)))
713 : {
714 : /* Tor mode is requested but the DNS code can't enable it. */
715 0 : assuan_set_error (ctx, err, "error enabling Tor mode");
716 0 : goto leave;
717 : }
718 :
719 0 : if (pka_mode || dane_mode)
720 0 : {
721 : char *domain; /* Points to mbox. */
722 : char hashbuf[32]; /* For SHA-1 and SHA-256. */
723 :
724 : /* We lowercase ascii characters but the DANE I-D does not allow
725 : this. FIXME: Check after the release of the RFC whether to
726 : change this. */
727 0 : mbox = mailbox_from_userid (line);
728 0 : if (!mbox || !(domain = strchr (mbox, '@')))
729 : {
730 0 : err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
731 0 : goto leave;
732 : }
733 0 : *domain++ = 0;
734 :
735 0 : if (pka_mode)
736 : {
737 0 : gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
738 0 : encodedhash = zb32_encode (hashbuf, 8*20);
739 0 : if (!encodedhash)
740 : {
741 0 : err = gpg_error_from_syserror ();
742 0 : goto leave;
743 : }
744 0 : namebuf = strconcat (encodedhash, "._pka.", domain, NULL);
745 0 : if (!namebuf)
746 : {
747 0 : err = gpg_error_from_syserror ();
748 0 : goto leave;
749 : }
750 0 : name = namebuf;
751 0 : certtype = DNS_CERTTYPE_IPGP;
752 : }
753 : else
754 : {
755 : /* Note: The hash is truncated to 28 bytes and we lowercase
756 : the result only for aesthetic reasons. */
757 0 : gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, mbox, strlen (mbox));
758 0 : encodedhash = bin2hex (hashbuf, 28, NULL);
759 0 : if (!encodedhash)
760 : {
761 0 : err = gpg_error_from_syserror ();
762 0 : goto leave;
763 : }
764 0 : ascii_strlwr (encodedhash);
765 0 : namebuf = strconcat (encodedhash, "._openpgpkey.", domain, NULL);
766 0 : if (!namebuf)
767 : {
768 0 : err = gpg_error_from_syserror ();
769 0 : goto leave;
770 : }
771 0 : name = namebuf;
772 0 : certtype = DNS_CERTTYPE_RR61;
773 : }
774 : }
775 : else
776 0 : name = line;
777 :
778 0 : err = get_dns_cert (name, certtype, &key, &keylen, &fpr, &fprlen, &url);
779 0 : if (err)
780 0 : goto leave;
781 :
782 0 : if (key)
783 : {
784 0 : err = data_line_write (ctx, key, keylen);
785 0 : if (err)
786 0 : goto leave;
787 : }
788 :
789 0 : if (fpr)
790 : {
791 : char *tmpstr;
792 :
793 0 : tmpstr = bin2hex (fpr, fprlen, NULL);
794 0 : if (!tmpstr)
795 0 : err = gpg_error_from_syserror ();
796 : else
797 : {
798 0 : err = assuan_write_status (ctx, "FPR", tmpstr);
799 0 : xfree (tmpstr);
800 : }
801 0 : if (err)
802 0 : goto leave;
803 : }
804 :
805 0 : if (url)
806 : {
807 0 : err = assuan_write_status (ctx, "URL", url);
808 0 : if (err)
809 0 : goto leave;
810 : }
811 :
812 :
813 : leave:
814 0 : xfree (key);
815 0 : xfree (fpr);
816 0 : xfree (url);
817 0 : xfree (mbox);
818 0 : xfree (namebuf);
819 0 : xfree (encodedhash);
820 0 : return leave_cmd (ctx, err);
821 : }
822 :
823 :
824 :
825 : static const char hlp_wkd_get[] =
826 : "WKD_GET [--submission-address|--policy-flags] <user_id>\n"
827 : "\n"
828 : "Return the key or other info for <user_id>\n"
829 : "from the Web Key Directory.";
830 : static gpg_error_t
831 0 : cmd_wkd_get (assuan_context_t ctx, char *line)
832 : {
833 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
834 0 : gpg_error_t err = 0;
835 0 : char *mbox = NULL;
836 : char *domain; /* Points to mbox. */
837 : char sha1buf[20];
838 0 : char *uri = NULL;
839 0 : char *encodedhash = NULL;
840 : int opt_submission_addr;
841 : int opt_policy_flags;
842 0 : int no_log = 0;
843 :
844 0 : opt_submission_addr = has_option (line, "--submission-address");
845 0 : opt_policy_flags = has_option (line, "--policy-flags");
846 0 : line = skip_options (line);
847 :
848 0 : mbox = mailbox_from_userid (line);
849 0 : if (!mbox || !(domain = strchr (mbox, '@')))
850 : {
851 0 : err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
852 0 : goto leave;
853 : }
854 0 : *domain++ = 0;
855 :
856 0 : gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, mbox, strlen (mbox));
857 0 : encodedhash = zb32_encode (sha1buf, 8*20);
858 0 : if (!encodedhash)
859 : {
860 0 : err = gpg_error_from_syserror ();
861 0 : goto leave;
862 : }
863 :
864 0 : if (opt_submission_addr)
865 : {
866 0 : uri = strconcat ("https://",
867 : domain,
868 : "/.well-known/openpgpkey/submission-address",
869 : NULL);
870 : }
871 0 : else if (opt_policy_flags)
872 : {
873 0 : uri = strconcat ("https://",
874 : domain,
875 : "/.well-known/openpgpkey/policy",
876 : NULL);
877 : }
878 : else
879 : {
880 0 : uri = strconcat ("https://",
881 : domain,
882 : "/.well-known/openpgpkey/hu/",
883 : encodedhash,
884 : NULL);
885 0 : no_log = 1;
886 : }
887 0 : if (!uri)
888 : {
889 0 : err = gpg_error_from_syserror ();
890 0 : goto leave;
891 : }
892 :
893 : /* Setup an output stream and perform the get. */
894 : {
895 : estream_t outfp;
896 :
897 0 : outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
898 0 : if (!outfp)
899 0 : err = set_error (GPG_ERR_ASS_GENERAL,
900 : "error setting up a data stream");
901 : else
902 : {
903 0 : if (no_log)
904 0 : ctrl->server_local->inhibit_data_logging = 1;
905 0 : ctrl->server_local->inhibit_data_logging_now = 0;
906 0 : ctrl->server_local->inhibit_data_logging_count = 0;
907 0 : err = ks_action_fetch (ctrl, uri, outfp);
908 0 : es_fclose (outfp);
909 0 : ctrl->server_local->inhibit_data_logging = 0;
910 : }
911 : }
912 :
913 : leave:
914 0 : xfree (uri);
915 0 : xfree (encodedhash);
916 0 : xfree (mbox);
917 0 : return leave_cmd (ctx, err);
918 : }
919 :
920 :
921 :
922 : static const char hlp_ldapserver[] =
923 : "LDAPSERVER <data>\n"
924 : "\n"
925 : "Add a new LDAP server to the list of configured LDAP servers.\n"
926 : "DATA is in the same format as expected in the configure file.";
927 : static gpg_error_t
928 0 : cmd_ldapserver (assuan_context_t ctx, char *line)
929 : {
930 : #if USE_LDAP
931 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
932 : ldap_server_t server;
933 : ldap_server_t *last_next_p;
934 :
935 0 : while (spacep (line))
936 0 : line++;
937 0 : if (*line == '\0')
938 0 : return leave_cmd (ctx, PARM_ERROR (_("ldapserver missing")));
939 :
940 0 : server = ldapserver_parse_one (line, "", 0);
941 0 : if (! server)
942 0 : return leave_cmd (ctx, gpg_error (GPG_ERR_INV_ARG));
943 :
944 0 : last_next_p = &ctrl->server_local->ldapservers;
945 0 : while (*last_next_p)
946 0 : last_next_p = &(*last_next_p)->next;
947 0 : *last_next_p = server;
948 0 : return leave_cmd (ctx, 0);
949 : #else
950 : (void)line;
951 : return leave_cmd (ctx, gpg_error (GPG_ERR_NOT_IMPLEMENTED));
952 : #endif
953 : }
954 :
955 :
956 : static const char hlp_isvalid[] =
957 : "ISVALID [--only-ocsp] [--force-default-responder]"
958 : " <certificate_id>|<certificate_fpr>\n"
959 : "\n"
960 : "This command checks whether the certificate identified by the\n"
961 : "certificate_id is valid. This is done by consulting CRLs or\n"
962 : "whatever has been configured. Note, that the returned error codes\n"
963 : "are from gpg-error.h. The command may callback using the inquire\n"
964 : "function. See the manual for details.\n"
965 : "\n"
966 : "The CERTIFICATE_ID is a hex encoded string consisting of two parts,\n"
967 : "delimited by a single dot. The first part is the SHA-1 hash of the\n"
968 : "issuer name and the second part the serial number.\n"
969 : "\n"
970 : "Alternatively the certificate's fingerprint may be given in which\n"
971 : "case an OCSP request is done before consulting the CRL.\n"
972 : "\n"
973 : "If the option --only-ocsp is given, no fallback to a CRL check will\n"
974 : "be used.\n"
975 : "\n"
976 : "If the option --force-default-responder is given, only the default\n"
977 : "OCSP responder will be used and any other methods of obtaining an\n"
978 : "OCSP responder URL won't be used.";
979 : static gpg_error_t
980 0 : cmd_isvalid (assuan_context_t ctx, char *line)
981 : {
982 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
983 : char *issuerhash, *serialno;
984 : gpg_error_t err;
985 0 : int did_inquire = 0;
986 0 : int ocsp_mode = 0;
987 : int only_ocsp;
988 : int force_default_responder;
989 :
990 0 : only_ocsp = has_option (line, "--only-ocsp");
991 0 : force_default_responder = has_option (line, "--force-default-responder");
992 0 : line = skip_options (line);
993 :
994 0 : issuerhash = xstrdup (line); /* We need to work on a copy of the
995 : line because that same Assuan
996 : context may be used for an inquiry.
997 : That is because Assuan reuses its
998 : line buffer.
999 : */
1000 :
1001 0 : serialno = strchr (issuerhash, '.');
1002 0 : if (serialno)
1003 0 : *serialno++ = 0;
1004 : else
1005 : {
1006 0 : char *endp = strchr (issuerhash, ' ');
1007 0 : if (endp)
1008 0 : *endp = 0;
1009 0 : if (strlen (issuerhash) != 40)
1010 : {
1011 0 : xfree (issuerhash);
1012 0 : return leave_cmd (ctx, PARM_ERROR (_("serialno missing in cert ID")));
1013 : }
1014 0 : ocsp_mode = 1;
1015 : }
1016 :
1017 :
1018 : again:
1019 0 : if (ocsp_mode)
1020 : {
1021 : /* Note, that we ignore the given issuer hash and instead rely
1022 : on the current certificate semantics used with this
1023 : command. */
1024 0 : if (!opt.allow_ocsp)
1025 0 : err = gpg_error (GPG_ERR_NOT_SUPPORTED);
1026 : else
1027 0 : err = ocsp_isvalid (ctrl, NULL, NULL, force_default_responder);
1028 : /* Fixme: If we got no ocsp response and --only-ocsp is not used
1029 : we should fall back to CRL mode. Thus we need to clear
1030 : OCSP_MODE, get the issuerhash and the serialno from the
1031 : current certificate and jump to again. */
1032 : }
1033 0 : else if (only_ocsp)
1034 0 : err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1035 : else
1036 : {
1037 0 : switch (crl_cache_isvalid (ctrl,
1038 : issuerhash, serialno,
1039 : ctrl->force_crl_refresh))
1040 : {
1041 : case CRL_CACHE_VALID:
1042 0 : err = 0;
1043 0 : break;
1044 : case CRL_CACHE_INVALID:
1045 0 : err = gpg_error (GPG_ERR_CERT_REVOKED);
1046 0 : break;
1047 : case CRL_CACHE_DONTKNOW:
1048 0 : if (did_inquire)
1049 0 : err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1050 0 : else if (!(err = inquire_cert_and_load_crl (ctx)))
1051 : {
1052 0 : did_inquire = 1;
1053 0 : goto again;
1054 : }
1055 0 : break;
1056 : case CRL_CACHE_CANTUSE:
1057 0 : err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
1058 0 : break;
1059 : default:
1060 0 : log_fatal ("crl_cache_isvalid returned invalid code\n");
1061 : }
1062 : }
1063 :
1064 0 : xfree (issuerhash);
1065 0 : return leave_cmd (ctx, err);
1066 : }
1067 :
1068 :
1069 : /* If the line contains a SHA-1 fingerprint as the first argument,
1070 : return the FPR vuffer on success. The function checks that the
1071 : fingerprint consists of valid characters and prints and error
1072 : message if it does not and returns NULL. Fingerprints are
1073 : considered optional and thus no explicit error is returned. NULL is
1074 : also returned if there is no fingerprint at all available.
1075 : FPR must be a caller provided buffer of at least 20 bytes.
1076 :
1077 : Note that colons within the fingerprint are allowed to separate 2
1078 : hex digits; this allows for easier cutting and pasting using the
1079 : usual fingerprint rendering.
1080 : */
1081 : static unsigned char *
1082 0 : get_fingerprint_from_line (const char *line, unsigned char *fpr)
1083 : {
1084 : const char *s;
1085 : int i;
1086 :
1087 0 : for (s=line, i=0; *s && *s != ' '; s++ )
1088 : {
1089 0 : if ( hexdigitp (s) && hexdigitp (s+1) )
1090 : {
1091 0 : if ( i >= 20 )
1092 0 : return NULL; /* Fingerprint too long. */
1093 0 : fpr[i++] = xtoi_2 (s);
1094 0 : s++;
1095 : }
1096 0 : else if ( *s != ':' )
1097 0 : return NULL; /* Invalid. */
1098 : }
1099 0 : if ( i != 20 )
1100 0 : return NULL; /* Fingerprint to short. */
1101 0 : return fpr;
1102 : }
1103 :
1104 :
1105 :
1106 : static const char hlp_checkcrl[] =
1107 : "CHECKCRL [<fingerprint>]\n"
1108 : "\n"
1109 : "Check whether the certificate with FINGERPRINT (SHA-1 hash of the\n"
1110 : "entire X.509 certificate blob) is valid or not by consulting the\n"
1111 : "CRL responsible for this certificate. If the fingerprint has not\n"
1112 : "been given or the certificate is not known, the function \n"
1113 : "inquires the certificate using an\n"
1114 : "\n"
1115 : " INQUIRE TARGETCERT\n"
1116 : "\n"
1117 : "and the caller is expected to return the certificate for the\n"
1118 : "request (which should match FINGERPRINT) as a binary blob.\n"
1119 : "Processing then takes place without further interaction; in\n"
1120 : "particular dirmngr tries to locate other required certificate by\n"
1121 : "its own mechanism which includes a local certificate store as well\n"
1122 : "as a list of trusted root certificates.\n"
1123 : "\n"
1124 : "The return value is the usual gpg-error code or 0 for ducesss;\n"
1125 : "i.e. the certificate validity has been confirmed by a valid CRL.";
1126 : static gpg_error_t
1127 0 : cmd_checkcrl (assuan_context_t ctx, char *line)
1128 : {
1129 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1130 : gpg_error_t err;
1131 : unsigned char fprbuffer[20], *fpr;
1132 : ksba_cert_t cert;
1133 :
1134 0 : fpr = get_fingerprint_from_line (line, fprbuffer);
1135 0 : cert = fpr? get_cert_byfpr (fpr) : NULL;
1136 :
1137 0 : if (!cert)
1138 : {
1139 : /* We do not have this certificate yet or the fingerprint has
1140 : not been given. Inquire it from the client. */
1141 0 : unsigned char *value = NULL;
1142 : size_t valuelen;
1143 :
1144 0 : err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1145 : &value, &valuelen, MAX_CERT_LENGTH);
1146 0 : if (err)
1147 : {
1148 0 : log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1149 0 : goto leave;
1150 : }
1151 :
1152 0 : if (!valuelen) /* No data returned; return a comprehensible error. */
1153 0 : err = gpg_error (GPG_ERR_MISSING_CERT);
1154 : else
1155 : {
1156 0 : err = ksba_cert_new (&cert);
1157 0 : if (!err)
1158 0 : err = ksba_cert_init_from_mem (cert, value, valuelen);
1159 : }
1160 0 : xfree (value);
1161 0 : if(err)
1162 0 : goto leave;
1163 : }
1164 :
1165 0 : assert (cert);
1166 :
1167 0 : err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
1168 0 : if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
1169 : {
1170 0 : err = crl_cache_reload_crl (ctrl, cert);
1171 0 : if (!err)
1172 0 : err = crl_cache_cert_isvalid (ctrl, cert, 0);
1173 : }
1174 :
1175 : leave:
1176 0 : ksba_cert_release (cert);
1177 0 : return leave_cmd (ctx, err);
1178 : }
1179 :
1180 :
1181 : static const char hlp_checkocsp[] =
1182 : "CHECKOCSP [--force-default-responder] [<fingerprint>]\n"
1183 : "\n"
1184 : "Check whether the certificate with FINGERPRINT (SHA-1 hash of the\n"
1185 : "entire X.509 certificate blob) is valid or not by asking an OCSP\n"
1186 : "responder responsible for this certificate. The optional\n"
1187 : "fingerprint may be used for a quick check in case an OCSP check has\n"
1188 : "been done for this certificate recently (we always cache OCSP\n"
1189 : "responses for a couple of minutes). If the fingerprint has not been\n"
1190 : "given or there is no cached result, the function inquires the\n"
1191 : "certificate using an\n"
1192 : "\n"
1193 : " INQUIRE TARGETCERT\n"
1194 : "\n"
1195 : "and the caller is expected to return the certificate for the\n"
1196 : "request (which should match FINGERPRINT) as a binary blob.\n"
1197 : "Processing then takes place without further interaction; in\n"
1198 : "particular dirmngr tries to locate other required certificates by\n"
1199 : "its own mechanism which includes a local certificate store as well\n"
1200 : "as a list of trusted root certificates.\n"
1201 : "\n"
1202 : "If the option --force-default-responder is given, only the default\n"
1203 : "OCSP responder will be used and any other methods of obtaining an\n"
1204 : "OCSP responder URL won't be used.\n"
1205 : "\n"
1206 : "The return value is the usual gpg-error code or 0 for ducesss;\n"
1207 : "i.e. the certificate validity has been confirmed by a valid CRL.";
1208 : static gpg_error_t
1209 0 : cmd_checkocsp (assuan_context_t ctx, char *line)
1210 : {
1211 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1212 : gpg_error_t err;
1213 : unsigned char fprbuffer[20], *fpr;
1214 : ksba_cert_t cert;
1215 : int force_default_responder;
1216 :
1217 0 : force_default_responder = has_option (line, "--force-default-responder");
1218 0 : line = skip_options (line);
1219 :
1220 0 : fpr = get_fingerprint_from_line (line, fprbuffer);
1221 0 : cert = fpr? get_cert_byfpr (fpr) : NULL;
1222 :
1223 0 : if (!cert)
1224 : {
1225 : /* We do not have this certificate yet or the fingerprint has
1226 : not been given. Inquire it from the client. */
1227 0 : unsigned char *value = NULL;
1228 : size_t valuelen;
1229 :
1230 0 : err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1231 : &value, &valuelen, MAX_CERT_LENGTH);
1232 0 : if (err)
1233 : {
1234 0 : log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1235 0 : goto leave;
1236 : }
1237 :
1238 0 : if (!valuelen) /* No data returned; return a comprehensible error. */
1239 0 : err = gpg_error (GPG_ERR_MISSING_CERT);
1240 : else
1241 : {
1242 0 : err = ksba_cert_new (&cert);
1243 0 : if (!err)
1244 0 : err = ksba_cert_init_from_mem (cert, value, valuelen);
1245 : }
1246 0 : xfree (value);
1247 0 : if(err)
1248 0 : goto leave;
1249 : }
1250 :
1251 0 : assert (cert);
1252 :
1253 0 : if (!opt.allow_ocsp)
1254 0 : err = gpg_error (GPG_ERR_NOT_SUPPORTED);
1255 : else
1256 0 : err = ocsp_isvalid (ctrl, cert, NULL, force_default_responder);
1257 :
1258 : leave:
1259 0 : ksba_cert_release (cert);
1260 0 : return leave_cmd (ctx, err);
1261 : }
1262 :
1263 :
1264 :
1265 : static int
1266 0 : lookup_cert_by_url (assuan_context_t ctx, const char *url)
1267 : {
1268 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1269 0 : gpg_error_t err = 0;
1270 0 : unsigned char *value = NULL;
1271 : size_t valuelen;
1272 :
1273 : /* Fetch single certificate given it's URL. */
1274 0 : err = fetch_cert_by_url (ctrl, url, &value, &valuelen);
1275 0 : if (err)
1276 : {
1277 0 : log_error (_("fetch_cert_by_url failed: %s\n"), gpg_strerror (err));
1278 0 : goto leave;
1279 : }
1280 :
1281 : /* Send the data, flush the buffer and then send an END. */
1282 0 : err = assuan_send_data (ctx, value, valuelen);
1283 0 : if (!err)
1284 0 : err = assuan_send_data (ctx, NULL, 0);
1285 0 : if (!err)
1286 0 : err = assuan_write_line (ctx, "END");
1287 0 : if (err)
1288 : {
1289 0 : log_error (_("error sending data: %s\n"), gpg_strerror (err));
1290 0 : goto leave;
1291 : }
1292 :
1293 : leave:
1294 :
1295 0 : return err;
1296 : }
1297 :
1298 :
1299 : /* Send the certificate, flush the buffer and then send an END. */
1300 : static gpg_error_t
1301 0 : return_one_cert (void *opaque, ksba_cert_t cert)
1302 : {
1303 0 : assuan_context_t ctx = opaque;
1304 : gpg_error_t err;
1305 : const unsigned char *der;
1306 : size_t derlen;
1307 :
1308 0 : der = ksba_cert_get_image (cert, &derlen);
1309 0 : if (!der)
1310 0 : err = gpg_error (GPG_ERR_INV_CERT_OBJ);
1311 : else
1312 : {
1313 0 : err = assuan_send_data (ctx, der, derlen);
1314 0 : if (!err)
1315 0 : err = assuan_send_data (ctx, NULL, 0);
1316 0 : if (!err)
1317 0 : err = assuan_write_line (ctx, "END");
1318 : }
1319 0 : if (err)
1320 0 : log_error (_("error sending data: %s\n"), gpg_strerror (err));
1321 0 : return err;
1322 : }
1323 :
1324 :
1325 : /* Lookup certificates from the internal cache or using the ldap
1326 : servers. */
1327 : static int
1328 0 : lookup_cert_by_pattern (assuan_context_t ctx, char *line,
1329 : int single, int cache_only)
1330 : {
1331 0 : gpg_error_t err = 0;
1332 : char *p;
1333 0 : strlist_t sl, list = NULL;
1334 0 : int truncated = 0, truncation_forced = 0;
1335 0 : int count = 0;
1336 0 : int local_count = 0;
1337 : #if USE_LDAP
1338 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1339 0 : unsigned char *value = NULL;
1340 : size_t valuelen;
1341 : struct ldapserver_iter ldapserver_iter;
1342 : cert_fetch_context_t fetch_context;
1343 : #endif /*USE_LDAP*/
1344 0 : int any_no_data = 0;
1345 :
1346 : /* Break the line down into an STRLIST */
1347 0 : for (p=line; *p; line = p)
1348 : {
1349 0 : while (*p && *p != ' ')
1350 0 : p++;
1351 0 : if (*p)
1352 0 : *p++ = 0;
1353 :
1354 0 : if (*line)
1355 : {
1356 0 : sl = xtrymalloc (sizeof *sl + strlen (line));
1357 0 : if (!sl)
1358 : {
1359 0 : err = gpg_error_from_errno (errno);
1360 0 : goto leave;
1361 : }
1362 0 : memset (sl, 0, sizeof *sl);
1363 0 : strcpy_escaped_plus (sl->d, line);
1364 0 : sl->next = list;
1365 0 : list = sl;
1366 : }
1367 : }
1368 :
1369 : /* First look through the internal cache. The certifcates returned
1370 : here are not counted towards the truncation limit. */
1371 0 : if (single && !cache_only)
1372 : ; /* Do not read from the local cache in this case. */
1373 : else
1374 : {
1375 0 : for (sl=list; sl; sl = sl->next)
1376 : {
1377 0 : err = get_certs_bypattern (sl->d, return_one_cert, ctx);
1378 0 : if (!err)
1379 0 : local_count++;
1380 0 : if (!err && single)
1381 0 : goto ready;
1382 :
1383 0 : if (gpg_err_code (err) == GPG_ERR_NO_DATA)
1384 : {
1385 0 : err = 0;
1386 0 : if (cache_only)
1387 0 : any_no_data = 1;
1388 : }
1389 0 : else if (gpg_err_code (err) == GPG_ERR_INV_NAME && !cache_only)
1390 : {
1391 : /* No real fault because the internal pattern lookup
1392 : can't yet cope with all types of pattern. */
1393 0 : err = 0;
1394 : }
1395 0 : if (err)
1396 0 : goto ready;
1397 : }
1398 : }
1399 :
1400 : /* Loop over all configured servers unless we want only the
1401 : certificates from the cache. */
1402 : #if USE_LDAP
1403 0 : for (ldapserver_iter_begin (&ldapserver_iter, ctrl);
1404 0 : !cache_only && !ldapserver_iter_end_p (&ldapserver_iter)
1405 0 : && ldapserver_iter.server->host && !truncation_forced;
1406 0 : ldapserver_iter_next (&ldapserver_iter))
1407 : {
1408 0 : ldap_server_t ldapserver = ldapserver_iter.server;
1409 :
1410 0 : if (DBG_LOOKUP)
1411 0 : log_debug ("cmd_lookup: trying %s:%d base=%s\n",
1412 : ldapserver->host, ldapserver->port,
1413 0 : ldapserver->base?ldapserver->base : "[default]");
1414 :
1415 : /* Fetch certificates matching pattern */
1416 0 : err = start_cert_fetch (ctrl, &fetch_context, list, ldapserver);
1417 0 : if ( gpg_err_code (err) == GPG_ERR_NO_DATA )
1418 : {
1419 0 : if (DBG_LOOKUP)
1420 0 : log_debug ("cmd_lookup: no data\n");
1421 0 : err = 0;
1422 0 : any_no_data = 1;
1423 0 : continue;
1424 : }
1425 0 : if (err)
1426 : {
1427 0 : log_error (_("start_cert_fetch failed: %s\n"), gpg_strerror (err));
1428 0 : goto leave;
1429 : }
1430 :
1431 : /* Fetch the certificates for this query. */
1432 0 : while (!truncation_forced)
1433 : {
1434 0 : xfree (value); value = NULL;
1435 0 : err = fetch_next_cert (fetch_context, &value, &valuelen);
1436 0 : if (gpg_err_code (err) == GPG_ERR_NO_DATA )
1437 : {
1438 0 : err = 0;
1439 0 : any_no_data = 1;
1440 0 : break; /* Ready. */
1441 : }
1442 0 : if (gpg_err_code (err) == GPG_ERR_TRUNCATED)
1443 : {
1444 0 : truncated = 1;
1445 0 : err = 0;
1446 0 : break; /* Ready. */
1447 : }
1448 0 : if (gpg_err_code (err) == GPG_ERR_EOF)
1449 : {
1450 0 : err = 0;
1451 0 : break; /* Ready. */
1452 : }
1453 0 : if (!err && !value)
1454 : {
1455 0 : err = gpg_error (GPG_ERR_BUG);
1456 0 : goto leave;
1457 : }
1458 0 : if (err)
1459 : {
1460 0 : log_error (_("fetch_next_cert failed: %s\n"),
1461 : gpg_strerror (err));
1462 0 : end_cert_fetch (fetch_context);
1463 0 : goto leave;
1464 : }
1465 :
1466 0 : if (DBG_LOOKUP)
1467 0 : log_debug ("cmd_lookup: returning one cert%s\n",
1468 : truncated? " (truncated)":"");
1469 :
1470 : /* Send the data, flush the buffer and then send an END line
1471 : as a certificate delimiter. */
1472 0 : err = assuan_send_data (ctx, value, valuelen);
1473 0 : if (!err)
1474 0 : err = assuan_send_data (ctx, NULL, 0);
1475 0 : if (!err)
1476 0 : err = assuan_write_line (ctx, "END");
1477 0 : if (err)
1478 : {
1479 0 : log_error (_("error sending data: %s\n"), gpg_strerror (err));
1480 0 : end_cert_fetch (fetch_context);
1481 0 : goto leave;
1482 : }
1483 :
1484 0 : if (++count >= opt.max_replies )
1485 : {
1486 0 : truncation_forced = 1;
1487 0 : log_info (_("max_replies %d exceeded\n"), opt.max_replies );
1488 : }
1489 0 : if (single)
1490 0 : break;
1491 : }
1492 :
1493 0 : end_cert_fetch (fetch_context);
1494 : }
1495 : #endif /*USE_LDAP*/
1496 :
1497 : ready:
1498 0 : if (truncated || truncation_forced)
1499 : {
1500 : char str[50];
1501 :
1502 0 : sprintf (str, "%d", count);
1503 0 : assuan_write_status (ctx, "TRUNCATED", str);
1504 : }
1505 :
1506 0 : if (!err && !count && !local_count && any_no_data)
1507 0 : err = gpg_error (GPG_ERR_NO_DATA);
1508 :
1509 : leave:
1510 0 : free_strlist (list);
1511 0 : return err;
1512 : }
1513 :
1514 :
1515 : static const char hlp_lookup[] =
1516 : "LOOKUP [--url] [--single] [--cache-only] <pattern>\n"
1517 : "\n"
1518 : "Lookup certificates matching PATTERN. With --url the pattern is\n"
1519 : "expected to be one URL.\n"
1520 : "\n"
1521 : "If --url is not given: To allow for multiple patterns (which are ORed)\n"
1522 : "quoting is required: Spaces are translated to \"+\" or \"%20\";\n"
1523 : "obviously this requires that the usual escape quoting rules are applied.\n"
1524 : "\n"
1525 : "If --url is given no special escaping is required because URLs are\n"
1526 : "already escaped this way.\n"
1527 : "\n"
1528 : "If --single is given the first and only the first match will be\n"
1529 : "returned. If --cache-only is _not_ given, no local query will be\n"
1530 : "done.\n"
1531 : "\n"
1532 : "If --cache-only is given no external lookup is done so that only\n"
1533 : "certificates from the cache may get returned.";
1534 : static gpg_error_t
1535 0 : cmd_lookup (assuan_context_t ctx, char *line)
1536 : {
1537 : gpg_error_t err;
1538 : int lookup_url, single, cache_only;
1539 :
1540 0 : lookup_url = has_leading_option (line, "--url");
1541 0 : single = has_leading_option (line, "--single");
1542 0 : cache_only = has_leading_option (line, "--cache-only");
1543 0 : line = skip_options (line);
1544 :
1545 0 : if (lookup_url && cache_only)
1546 0 : err = gpg_error (GPG_ERR_NOT_FOUND);
1547 0 : else if (lookup_url && single)
1548 0 : err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1549 0 : else if (lookup_url)
1550 0 : err = lookup_cert_by_url (ctx, line);
1551 : else
1552 0 : err = lookup_cert_by_pattern (ctx, line, single, cache_only);
1553 :
1554 0 : return leave_cmd (ctx, err);
1555 : }
1556 :
1557 :
1558 : static const char hlp_loadcrl[] =
1559 : "LOADCRL [--url] <filename|url>\n"
1560 : "\n"
1561 : "Load the CRL in the file with name FILENAME into our cache. Note\n"
1562 : "that FILENAME should be given with an absolute path because\n"
1563 : "Dirmngrs cwd is not known. With --url the CRL is directly loaded\n"
1564 : "from the given URL.\n"
1565 : "\n"
1566 : "This command is usually used by gpgsm using the invocation \"gpgsm\n"
1567 : "--call-dirmngr loadcrl <filename>\". A direct invocation of Dirmngr\n"
1568 : "is not useful because gpgsm might need to callback gpgsm to ask for\n"
1569 : "the CA's certificate.";
1570 : static gpg_error_t
1571 0 : cmd_loadcrl (assuan_context_t ctx, char *line)
1572 : {
1573 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1574 0 : gpg_error_t err = 0;
1575 0 : int use_url = has_leading_option (line, "--url");
1576 :
1577 0 : line = skip_options (line);
1578 :
1579 0 : if (use_url)
1580 : {
1581 : ksba_reader_t reader;
1582 :
1583 0 : err = crl_fetch (ctrl, line, &reader);
1584 0 : if (err)
1585 0 : log_error (_("fetching CRL from '%s' failed: %s\n"),
1586 : line, gpg_strerror (err));
1587 : else
1588 : {
1589 0 : err = crl_cache_insert (ctrl, line, reader);
1590 0 : if (err)
1591 0 : log_error (_("processing CRL from '%s' failed: %s\n"),
1592 : line, gpg_strerror (err));
1593 0 : crl_close_reader (reader);
1594 : }
1595 : }
1596 : else
1597 : {
1598 : char *buf;
1599 :
1600 0 : buf = xtrymalloc (strlen (line)+1);
1601 0 : if (!buf)
1602 0 : err = gpg_error_from_syserror ();
1603 : else
1604 : {
1605 0 : strcpy_escaped_plus (buf, line);
1606 0 : err = crl_cache_load (ctrl, buf);
1607 0 : xfree (buf);
1608 : }
1609 : }
1610 :
1611 0 : return leave_cmd (ctx, err);
1612 : }
1613 :
1614 :
1615 : static const char hlp_listcrls[] =
1616 : "LISTCRLS\n"
1617 : "\n"
1618 : "List the content of all CRLs in a readable format. This command is\n"
1619 : "usually used by gpgsm using the invocation \"gpgsm --call-dirmngr\n"
1620 : "listcrls\". It may also be used directly using \"dirmngr\n"
1621 : "--list-crls\".";
1622 : static gpg_error_t
1623 0 : cmd_listcrls (assuan_context_t ctx, char *line)
1624 : {
1625 : gpg_error_t err;
1626 : estream_t fp;
1627 :
1628 : (void)line;
1629 :
1630 0 : fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
1631 0 : if (!fp)
1632 0 : err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
1633 : else
1634 : {
1635 0 : err = crl_cache_list (fp);
1636 0 : es_fclose (fp);
1637 : }
1638 0 : return leave_cmd (ctx, err);
1639 : }
1640 :
1641 :
1642 : static const char hlp_cachecert[] =
1643 : "CACHECERT\n"
1644 : "\n"
1645 : "Put a certificate into the internal cache. This command might be\n"
1646 : "useful if a client knows in advance certificates required for a\n"
1647 : "test and wants to make sure they get added to the internal cache.\n"
1648 : "It is also helpful for debugging. To get the actual certificate,\n"
1649 : "this command immediately inquires it using\n"
1650 : "\n"
1651 : " INQUIRE TARGETCERT\n"
1652 : "\n"
1653 : "and the caller is expected to return the certificate for the\n"
1654 : "request as a binary blob.";
1655 : static gpg_error_t
1656 0 : cmd_cachecert (assuan_context_t ctx, char *line)
1657 : {
1658 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1659 : gpg_error_t err;
1660 0 : ksba_cert_t cert = NULL;
1661 0 : unsigned char *value = NULL;
1662 : size_t valuelen;
1663 :
1664 : (void)line;
1665 :
1666 0 : err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1667 : &value, &valuelen, MAX_CERT_LENGTH);
1668 0 : if (err)
1669 : {
1670 0 : log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1671 0 : goto leave;
1672 : }
1673 :
1674 0 : if (!valuelen) /* No data returned; return a comprehensible error. */
1675 0 : err = gpg_error (GPG_ERR_MISSING_CERT);
1676 : else
1677 : {
1678 0 : err = ksba_cert_new (&cert);
1679 0 : if (!err)
1680 0 : err = ksba_cert_init_from_mem (cert, value, valuelen);
1681 : }
1682 0 : xfree (value);
1683 0 : if(err)
1684 0 : goto leave;
1685 :
1686 0 : err = cache_cert (cert);
1687 :
1688 : leave:
1689 0 : ksba_cert_release (cert);
1690 0 : return leave_cmd (ctx, err);
1691 : }
1692 :
1693 :
1694 : static const char hlp_validate[] =
1695 : "VALIDATE\n"
1696 : "\n"
1697 : "Validate a certificate using the certificate validation function\n"
1698 : "used internally by dirmngr. This command is only useful for\n"
1699 : "debugging. To get the actual certificate, this command immediately\n"
1700 : "inquires it using\n"
1701 : "\n"
1702 : " INQUIRE TARGETCERT\n"
1703 : "\n"
1704 : "and the caller is expected to return the certificate for the\n"
1705 : "request as a binary blob.";
1706 : static gpg_error_t
1707 0 : cmd_validate (assuan_context_t ctx, char *line)
1708 : {
1709 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1710 : gpg_error_t err;
1711 0 : ksba_cert_t cert = NULL;
1712 0 : unsigned char *value = NULL;
1713 : size_t valuelen;
1714 :
1715 : (void)line;
1716 :
1717 0 : err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1718 : &value, &valuelen, MAX_CERT_LENGTH);
1719 0 : if (err)
1720 : {
1721 0 : log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1722 0 : goto leave;
1723 : }
1724 :
1725 0 : if (!valuelen) /* No data returned; return a comprehensible error. */
1726 0 : err = gpg_error (GPG_ERR_MISSING_CERT);
1727 : else
1728 : {
1729 0 : err = ksba_cert_new (&cert);
1730 0 : if (!err)
1731 0 : err = ksba_cert_init_from_mem (cert, value, valuelen);
1732 : }
1733 0 : xfree (value);
1734 0 : if(err)
1735 0 : goto leave;
1736 :
1737 : /* If we have this certificate already in our cache, use the cached
1738 : version for validation because this will take care of any cached
1739 : results. */
1740 : {
1741 : unsigned char fpr[20];
1742 : ksba_cert_t tmpcert;
1743 :
1744 0 : cert_compute_fpr (cert, fpr);
1745 0 : tmpcert = get_cert_byfpr (fpr);
1746 0 : if (tmpcert)
1747 : {
1748 0 : ksba_cert_release (cert);
1749 0 : cert = tmpcert;
1750 : }
1751 : }
1752 :
1753 0 : err = validate_cert_chain (ctrl, cert, NULL, VALIDATE_MODE_CERT, NULL);
1754 :
1755 : leave:
1756 0 : ksba_cert_release (cert);
1757 0 : return leave_cmd (ctx, err);
1758 : }
1759 :
1760 :
1761 :
1762 : /* Parse an keyserver URI and store it in a new uri item which is
1763 : returned at R_ITEM. On error return an error code. */
1764 : static gpg_error_t
1765 0 : make_keyserver_item (const char *uri, uri_item_t *r_item)
1766 : {
1767 : gpg_error_t err;
1768 : uri_item_t item;
1769 :
1770 0 : *r_item = NULL;
1771 0 : item = xtrymalloc (sizeof *item + strlen (uri));
1772 0 : if (!item)
1773 0 : return gpg_error_from_syserror ();
1774 :
1775 0 : item->next = NULL;
1776 0 : item->parsed_uri = NULL;
1777 0 : strcpy (item->uri, uri);
1778 :
1779 : #if USE_LDAP
1780 0 : if (ldap_uri_p (item->uri))
1781 0 : err = ldap_parse_uri (&item->parsed_uri, uri);
1782 : else
1783 : #endif
1784 : {
1785 0 : err = http_parse_uri (&item->parsed_uri, uri, 1);
1786 : }
1787 :
1788 0 : if (err)
1789 0 : xfree (item);
1790 : else
1791 0 : *r_item = item;
1792 0 : return err;
1793 : }
1794 :
1795 :
1796 : /* If no keyserver is stored in CTRL but a global keyserver has been
1797 : set, put that global keyserver into CTRL. We need use this
1798 : function to help migrate from the old gpg based keyserver
1799 : configuration to the new dirmngr based configuration. */
1800 : static gpg_error_t
1801 0 : ensure_keyserver (ctrl_t ctrl)
1802 : {
1803 : gpg_error_t err;
1804 : uri_item_t item;
1805 0 : uri_item_t onion_items = NULL;
1806 0 : uri_item_t plain_items = NULL;
1807 : uri_item_t ui;
1808 : strlist_t sl;
1809 :
1810 0 : if (ctrl->server_local->keyservers)
1811 0 : return 0; /* Already set for this session. */
1812 0 : if (!opt.keyserver)
1813 : {
1814 : /* No global option set. Fall back to default: */
1815 0 : return make_keyserver_item (DIRMNGR_DEFAULT_KEYSERVER,
1816 0 : &ctrl->server_local->keyservers);
1817 : }
1818 :
1819 0 : for (sl = opt.keyserver; sl; sl = sl->next)
1820 : {
1821 0 : err = make_keyserver_item (sl->d, &item);
1822 0 : if (err)
1823 0 : goto leave;
1824 0 : if (item->parsed_uri->onion)
1825 : {
1826 0 : item->next = onion_items;
1827 0 : onion_items = item;
1828 : }
1829 : else
1830 : {
1831 0 : item->next = plain_items;
1832 0 : plain_items = item;
1833 : }
1834 : }
1835 :
1836 : /* Decide which to use. Note that the sesssion has no keyservers
1837 : yet set. */
1838 0 : if (onion_items && !onion_items->next && plain_items && !plain_items->next)
1839 : {
1840 : /* If there is just one onion and one plain keyserver given, we take
1841 : only one depending on whether Tor is running or not. */
1842 0 : if (is_tor_running (ctrl))
1843 : {
1844 0 : ctrl->server_local->keyservers = onion_items;
1845 0 : onion_items = NULL;
1846 : }
1847 : else
1848 : {
1849 0 : ctrl->server_local->keyservers = plain_items;
1850 0 : plain_items = NULL;
1851 : }
1852 : }
1853 0 : else if (!is_tor_running (ctrl))
1854 : {
1855 : /* Tor is not running. It does not make sense to add Onion
1856 : addresses. */
1857 0 : ctrl->server_local->keyservers = plain_items;
1858 0 : plain_items = NULL;
1859 : }
1860 : else
1861 : {
1862 : /* In all other cases add all keyservers. */
1863 0 : ctrl->server_local->keyservers = onion_items;
1864 0 : onion_items = NULL;
1865 0 : for (ui = ctrl->server_local->keyservers; ui && ui->next; ui = ui->next)
1866 : ;
1867 0 : if (ui)
1868 0 : ui->next = plain_items;
1869 : else
1870 0 : ctrl->server_local->keyservers = plain_items;
1871 0 : plain_items = NULL;
1872 : }
1873 :
1874 : leave:
1875 0 : release_uri_item_list (onion_items);
1876 0 : release_uri_item_list (plain_items);
1877 :
1878 0 : return err;
1879 : }
1880 :
1881 :
1882 : static const char hlp_keyserver[] =
1883 : "KEYSERVER [<options>] [<uri>|<host>]\n"
1884 : "Options are:\n"
1885 : " --help\n"
1886 : " --clear Remove all configured keyservers\n"
1887 : " --resolve Resolve HKP host names and rotate\n"
1888 : " --hosttable Print table of known hosts and pools\n"
1889 : " --dead Mark <host> as dead\n"
1890 : " --alive Mark <host> as alive\n"
1891 : "\n"
1892 : "If called without arguments list all configured keyserver URLs.\n"
1893 : "If called with an URI add this as keyserver. Note that keyservers\n"
1894 : "are configured on a per-session base. A default keyserver may already be\n"
1895 : "present, thus the \"--clear\" option must be used to get full control.\n"
1896 : "If \"--clear\" and an URI are used together the clear command is\n"
1897 : "obviously executed first. A RESET command does not change the list\n"
1898 : "of configured keyservers.";
1899 : static gpg_error_t
1900 0 : cmd_keyserver (assuan_context_t ctx, char *line)
1901 : {
1902 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1903 0 : gpg_error_t err = 0;
1904 : int clear_flag, add_flag, help_flag, host_flag, resolve_flag;
1905 : int dead_flag, alive_flag;
1906 0 : uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it
1907 : is always initialized. */
1908 :
1909 0 : clear_flag = has_option (line, "--clear");
1910 0 : help_flag = has_option (line, "--help");
1911 0 : resolve_flag = has_option (line, "--resolve");
1912 0 : host_flag = has_option (line, "--hosttable");
1913 0 : dead_flag = has_option (line, "--dead");
1914 0 : alive_flag = has_option (line, "--alive");
1915 0 : line = skip_options (line);
1916 0 : add_flag = !!*line;
1917 :
1918 0 : if (help_flag)
1919 : {
1920 0 : err = ks_action_help (ctrl, line);
1921 0 : goto leave;
1922 : }
1923 :
1924 0 : if (resolve_flag)
1925 : {
1926 0 : err = ensure_keyserver (ctrl);
1927 0 : if (!err)
1928 0 : err = ks_action_resolve (ctrl, ctrl->server_local->keyservers);
1929 0 : if (err)
1930 0 : goto leave;
1931 : }
1932 :
1933 0 : if (alive_flag && dead_flag)
1934 : {
1935 0 : err = set_error (GPG_ERR_ASS_PARAMETER, "no support for zombies");
1936 0 : goto leave;
1937 : }
1938 0 : if (dead_flag)
1939 : {
1940 0 : err = check_owner_permission (ctx, "no permission to use --dead");
1941 0 : if (err)
1942 0 : goto leave;
1943 : }
1944 0 : if (alive_flag || dead_flag)
1945 : {
1946 0 : if (!*line)
1947 : {
1948 0 : err = set_error (GPG_ERR_ASS_PARAMETER, "name of host missing");
1949 0 : goto leave;
1950 : }
1951 :
1952 0 : err = ks_hkp_mark_host (ctrl, line, alive_flag);
1953 0 : if (err)
1954 0 : goto leave;
1955 : }
1956 :
1957 0 : if (host_flag)
1958 : {
1959 0 : err = ks_hkp_print_hosttable (ctrl);
1960 0 : if (err)
1961 0 : goto leave;
1962 : }
1963 0 : if (resolve_flag || host_flag || alive_flag || dead_flag)
1964 : goto leave;
1965 :
1966 0 : if (add_flag)
1967 : {
1968 0 : err = make_keyserver_item (line, &item);
1969 0 : if (err)
1970 0 : goto leave;
1971 : }
1972 0 : if (clear_flag)
1973 0 : release_ctrl_keyservers (ctrl);
1974 0 : if (add_flag)
1975 : {
1976 0 : item->next = ctrl->server_local->keyservers;
1977 0 : ctrl->server_local->keyservers = item;
1978 : }
1979 :
1980 0 : if (!add_flag && !clear_flag && !help_flag)
1981 : {
1982 : /* List configured keyservers. However, we first add a global
1983 : keyserver. */
1984 : uri_item_t u;
1985 :
1986 0 : err = ensure_keyserver (ctrl);
1987 0 : if (err)
1988 : {
1989 0 : assuan_set_error (ctx, err,
1990 : "Bad keyserver configuration in dirmngr.conf");
1991 0 : goto leave;
1992 : }
1993 :
1994 0 : for (u=ctrl->server_local->keyservers; u; u = u->next)
1995 0 : dirmngr_status (ctrl, "KEYSERVER", u->uri, NULL);
1996 : }
1997 0 : err = 0;
1998 :
1999 : leave:
2000 0 : return leave_cmd (ctx, err);
2001 : }
2002 :
2003 :
2004 :
2005 : static const char hlp_ks_search[] =
2006 : "KS_SEARCH {<pattern>}\n"
2007 : "\n"
2008 : "Search the configured OpenPGP keyservers (see command KEYSERVER)\n"
2009 : "for keys matching PATTERN";
2010 : static gpg_error_t
2011 0 : cmd_ks_search (assuan_context_t ctx, char *line)
2012 : {
2013 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2014 : gpg_error_t err;
2015 : strlist_t list, sl;
2016 : char *p;
2017 : estream_t outfp;
2018 :
2019 : /* No options for now. */
2020 0 : line = skip_options (line);
2021 :
2022 : /* Break the line down into an strlist. Each pattern is
2023 : percent-plus escaped. */
2024 0 : list = NULL;
2025 0 : for (p=line; *p; line = p)
2026 : {
2027 0 : while (*p && *p != ' ')
2028 0 : p++;
2029 0 : if (*p)
2030 0 : *p++ = 0;
2031 0 : if (*line)
2032 : {
2033 0 : sl = xtrymalloc (sizeof *sl + strlen (line));
2034 0 : if (!sl)
2035 : {
2036 0 : err = gpg_error_from_syserror ();
2037 0 : goto leave;
2038 : }
2039 0 : sl->flags = 0;
2040 0 : strcpy_escaped_plus (sl->d, line);
2041 0 : sl->next = list;
2042 0 : list = sl;
2043 : }
2044 : }
2045 :
2046 0 : err = ensure_keyserver (ctrl);
2047 0 : if (err)
2048 0 : goto leave;
2049 :
2050 : /* Setup an output stream and perform the search. */
2051 0 : outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2052 0 : if (!outfp)
2053 0 : err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2054 : else
2055 : {
2056 0 : err = ks_action_search (ctrl, ctrl->server_local->keyservers,
2057 : list, outfp);
2058 0 : es_fclose (outfp);
2059 : }
2060 :
2061 : leave:
2062 0 : free_strlist (list);
2063 0 : return leave_cmd (ctx, err);
2064 : }
2065 :
2066 :
2067 :
2068 : static const char hlp_ks_get[] =
2069 : "KS_GET {<pattern>}\n"
2070 : "\n"
2071 : "Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
2072 : "(see command KEYSERVER). Each pattern should be a keyid, a fingerprint,\n"
2073 : "or an exact name indicated by the '=' prefix.";
2074 : static gpg_error_t
2075 0 : cmd_ks_get (assuan_context_t ctx, char *line)
2076 : {
2077 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2078 : gpg_error_t err;
2079 : strlist_t list, sl;
2080 : char *p;
2081 : estream_t outfp;
2082 :
2083 : /* No options for now. */
2084 0 : line = skip_options (line);
2085 :
2086 : /* Break the line into a strlist. Each pattern is by
2087 : definition percent-plus escaped. However we only support keyids
2088 : and fingerprints and thus the client has no need to apply the
2089 : escaping. */
2090 0 : list = NULL;
2091 0 : for (p=line; *p; line = p)
2092 : {
2093 0 : while (*p && *p != ' ')
2094 0 : p++;
2095 0 : if (*p)
2096 0 : *p++ = 0;
2097 0 : if (*line)
2098 : {
2099 0 : sl = xtrymalloc (sizeof *sl + strlen (line));
2100 0 : if (!sl)
2101 : {
2102 0 : err = gpg_error_from_syserror ();
2103 0 : goto leave;
2104 : }
2105 0 : sl->flags = 0;
2106 0 : strcpy_escaped_plus (sl->d, line);
2107 0 : sl->next = list;
2108 0 : list = sl;
2109 : }
2110 : }
2111 :
2112 0 : err = ensure_keyserver (ctrl);
2113 0 : if (err)
2114 0 : goto leave;
2115 :
2116 : /* Setup an output stream and perform the get. */
2117 0 : outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2118 0 : if (!outfp)
2119 0 : err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2120 : else
2121 : {
2122 0 : ctrl->server_local->inhibit_data_logging = 1;
2123 0 : ctrl->server_local->inhibit_data_logging_now = 0;
2124 0 : ctrl->server_local->inhibit_data_logging_count = 0;
2125 0 : err = ks_action_get (ctrl, ctrl->server_local->keyservers, list, outfp);
2126 0 : es_fclose (outfp);
2127 0 : ctrl->server_local->inhibit_data_logging = 0;
2128 : }
2129 :
2130 : leave:
2131 0 : free_strlist (list);
2132 0 : return leave_cmd (ctx, err);
2133 : }
2134 :
2135 :
2136 : static const char hlp_ks_fetch[] =
2137 : "KS_FETCH <URL>\n"
2138 : "\n"
2139 : "Get the key(s) from URL.";
2140 : static gpg_error_t
2141 0 : cmd_ks_fetch (assuan_context_t ctx, char *line)
2142 : {
2143 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2144 : gpg_error_t err;
2145 : estream_t outfp;
2146 :
2147 : /* No options for now. */
2148 0 : line = skip_options (line);
2149 :
2150 0 : err = ensure_keyserver (ctrl); /* FIXME: Why do we needs this here? */
2151 0 : if (err)
2152 0 : goto leave;
2153 :
2154 : /* Setup an output stream and perform the get. */
2155 0 : outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
2156 0 : if (!outfp)
2157 0 : err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
2158 : else
2159 : {
2160 0 : ctrl->server_local->inhibit_data_logging = 1;
2161 0 : ctrl->server_local->inhibit_data_logging_now = 0;
2162 0 : ctrl->server_local->inhibit_data_logging_count = 0;
2163 0 : err = ks_action_fetch (ctrl, line, outfp);
2164 0 : es_fclose (outfp);
2165 0 : ctrl->server_local->inhibit_data_logging = 0;
2166 : }
2167 :
2168 : leave:
2169 0 : return leave_cmd (ctx, err);
2170 : }
2171 :
2172 :
2173 :
2174 : static const char hlp_ks_put[] =
2175 : "KS_PUT\n"
2176 : "\n"
2177 : "Send a key to the configured OpenPGP keyservers. The actual key material\n"
2178 : "is then requested by Dirmngr using\n"
2179 : "\n"
2180 : " INQUIRE KEYBLOCK\n"
2181 : "\n"
2182 : "The client shall respond with a binary version of the keyblock (e.g.,\n"
2183 : "the output of `gpg --export KEYID'). For LDAP\n"
2184 : "keyservers Dirmngr may ask for meta information of the provided keyblock\n"
2185 : "using:\n"
2186 : "\n"
2187 : " INQUIRE KEYBLOCK_INFO\n"
2188 : "\n"
2189 : "The client shall respond with a colon delimited info lines (the output\n"
2190 : "of 'for x in keys sigs; do gpg --list-$x --with-colons KEYID; done').\n";
2191 : static gpg_error_t
2192 0 : cmd_ks_put (assuan_context_t ctx, char *line)
2193 : {
2194 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2195 : gpg_error_t err;
2196 0 : unsigned char *value = NULL;
2197 : size_t valuelen;
2198 0 : unsigned char *info = NULL;
2199 : size_t infolen;
2200 :
2201 : /* No options for now. */
2202 0 : line = skip_options (line);
2203 :
2204 0 : err = ensure_keyserver (ctrl);
2205 0 : if (err)
2206 0 : goto leave;
2207 :
2208 : /* Ask for the key material. */
2209 0 : err = assuan_inquire (ctx, "KEYBLOCK",
2210 : &value, &valuelen, MAX_KEYBLOCK_LENGTH);
2211 0 : if (err)
2212 : {
2213 0 : log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
2214 0 : goto leave;
2215 : }
2216 :
2217 0 : if (!valuelen) /* No data returned; return a comprehensible error. */
2218 : {
2219 0 : err = gpg_error (GPG_ERR_MISSING_CERT);
2220 0 : goto leave;
2221 : }
2222 :
2223 : /* Ask for the key meta data. Not actually needed for HKP servers
2224 : but we do it anyway to test the client implementaion. */
2225 0 : err = assuan_inquire (ctx, "KEYBLOCK_INFO",
2226 : &info, &infolen, MAX_KEYBLOCK_LENGTH);
2227 0 : if (err)
2228 : {
2229 0 : log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
2230 0 : goto leave;
2231 : }
2232 :
2233 : /* Send the key. */
2234 0 : err = ks_action_put (ctrl, ctrl->server_local->keyservers,
2235 : value, valuelen, info, infolen);
2236 :
2237 : leave:
2238 0 : xfree (info);
2239 0 : xfree (value);
2240 0 : return leave_cmd (ctx, err);
2241 : }
2242 :
2243 :
2244 :
2245 : static const char hlp_loadswdb[] =
2246 : "LOADSWDB [--force]\n"
2247 : "\n"
2248 : "Load and verify the swdb.lst from the Net.";
2249 : static gpg_error_t
2250 0 : cmd_loadswdb (assuan_context_t ctx, char *line)
2251 : {
2252 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2253 : gpg_error_t err;
2254 :
2255 0 : err = dirmngr_load_swdb (ctrl, has_option (line, "--force"));
2256 :
2257 0 : return leave_cmd (ctx, err);
2258 : }
2259 :
2260 :
2261 :
2262 : static const char hlp_getinfo[] =
2263 : "GETINFO <what>\n"
2264 : "\n"
2265 : "Multi purpose command to return certain information. \n"
2266 : "Supported values of WHAT are:\n"
2267 : "\n"
2268 : "version - Return the version of the program.\n"
2269 : "pid - Return the process id of the server.\n"
2270 : "tor - Return OK if running in Tor mode\n"
2271 : "dnsinfo - Return info about the DNS resolver\n"
2272 : "socket_name - Return the name of the socket.\n";
2273 : static gpg_error_t
2274 0 : cmd_getinfo (assuan_context_t ctx, char *line)
2275 : {
2276 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2277 : gpg_error_t err;
2278 :
2279 0 : if (!strcmp (line, "version"))
2280 : {
2281 0 : const char *s = VERSION;
2282 0 : err = assuan_send_data (ctx, s, strlen (s));
2283 : }
2284 0 : else if (!strcmp (line, "pid"))
2285 : {
2286 : char numbuf[50];
2287 :
2288 0 : snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
2289 0 : err = assuan_send_data (ctx, numbuf, strlen (numbuf));
2290 : }
2291 0 : else if (!strcmp (line, "socket_name"))
2292 : {
2293 0 : const char *s = dirmngr_get_current_socket_name ();
2294 0 : err = assuan_send_data (ctx, s, strlen (s));
2295 : }
2296 0 : else if (!strcmp (line, "tor"))
2297 : {
2298 0 : if (opt.use_tor)
2299 : {
2300 0 : if (!is_tor_running (ctrl))
2301 0 : err = assuan_write_status (ctx, "NO_TOR", "Tor not running");
2302 : else
2303 0 : err = 0;
2304 0 : if (!err)
2305 0 : assuan_set_okay_line (ctx, "- Tor mode is enabled");
2306 : }
2307 : else
2308 0 : err = set_error (GPG_ERR_FALSE, "Tor mode is NOT enabled");
2309 : }
2310 0 : else if (!strcmp (line, "dnsinfo"))
2311 : {
2312 : #if USE_ADNS && HAVE_ADNS_IF_TORMODE
2313 : assuan_set_okay_line (ctx, "- ADNS with Tor support");
2314 : #elif USE_ADNS
2315 0 : assuan_set_okay_line (ctx, "- ADNS w/o Tor support");
2316 : #else
2317 : assuan_set_okay_line (ctx, "- System resolver w/o Tor support");
2318 : #endif
2319 0 : err = 0;
2320 : }
2321 : else
2322 0 : err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
2323 :
2324 0 : return leave_cmd (ctx, err);
2325 : }
2326 :
2327 :
2328 :
2329 : static const char hlp_killdirmngr[] =
2330 : "KILLDIRMNGR\n"
2331 : "\n"
2332 : "This command allows a user - given sufficient permissions -\n"
2333 : "to kill this dirmngr process.\n";
2334 : static gpg_error_t
2335 0 : cmd_killdirmngr (assuan_context_t ctx, char *line)
2336 : {
2337 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2338 :
2339 : (void)line;
2340 :
2341 0 : ctrl->server_local->stopme = 1;
2342 0 : assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
2343 0 : return gpg_error (GPG_ERR_EOF);
2344 : }
2345 :
2346 :
2347 : static const char hlp_reloaddirmngr[] =
2348 : "RELOADDIRMNGR\n"
2349 : "\n"
2350 : "This command is an alternative to SIGHUP\n"
2351 : "to reload the configuration.";
2352 : static gpg_error_t
2353 0 : cmd_reloaddirmngr (assuan_context_t ctx, char *line)
2354 : {
2355 : (void)ctx;
2356 : (void)line;
2357 :
2358 0 : dirmngr_sighup_action ();
2359 0 : return 0;
2360 : }
2361 :
2362 :
2363 :
2364 : /* Tell the assuan library about our commands. */
2365 : static int
2366 0 : register_commands (assuan_context_t ctx)
2367 : {
2368 : static struct {
2369 : const char *name;
2370 : assuan_handler_t handler;
2371 : const char * const help;
2372 : } table[] = {
2373 : { "DNS_CERT", cmd_dns_cert, hlp_dns_cert },
2374 : { "WKD_GET", cmd_wkd_get, hlp_wkd_get },
2375 : { "LDAPSERVER", cmd_ldapserver, hlp_ldapserver },
2376 : { "ISVALID", cmd_isvalid, hlp_isvalid },
2377 : { "CHECKCRL", cmd_checkcrl, hlp_checkcrl },
2378 : { "CHECKOCSP", cmd_checkocsp, hlp_checkocsp },
2379 : { "LOOKUP", cmd_lookup, hlp_lookup },
2380 : { "LOADCRL", cmd_loadcrl, hlp_loadcrl },
2381 : { "LISTCRLS", cmd_listcrls, hlp_listcrls },
2382 : { "CACHECERT", cmd_cachecert, hlp_cachecert },
2383 : { "VALIDATE", cmd_validate, hlp_validate },
2384 : { "KEYSERVER", cmd_keyserver, hlp_keyserver },
2385 : { "KS_SEARCH", cmd_ks_search, hlp_ks_search },
2386 : { "KS_GET", cmd_ks_get, hlp_ks_get },
2387 : { "KS_FETCH", cmd_ks_fetch, hlp_ks_fetch },
2388 : { "KS_PUT", cmd_ks_put, hlp_ks_put },
2389 : { "GETINFO", cmd_getinfo, hlp_getinfo },
2390 : { "LOADSWDB", cmd_loadswdb, hlp_loadswdb },
2391 : { "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
2392 : { "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },
2393 : { NULL, NULL }
2394 : };
2395 : int i, j, rc;
2396 :
2397 0 : for (i=j=0; table[i].name; i++)
2398 : {
2399 0 : rc = assuan_register_command (ctx, table[i].name, table[i].handler,
2400 : table[i].help);
2401 0 : if (rc)
2402 0 : return rc;
2403 : }
2404 0 : return 0;
2405 : }
2406 :
2407 :
2408 : /* Note that we do not reset the list of configured keyservers. */
2409 : static gpg_error_t
2410 0 : reset_notify (assuan_context_t ctx, char *line)
2411 : {
2412 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2413 : (void)line;
2414 :
2415 : #if USE_LDAP
2416 0 : ldapserver_list_free (ctrl->server_local->ldapservers);
2417 : #endif /*USE_LDAP*/
2418 0 : ctrl->server_local->ldapservers = NULL;
2419 0 : return 0;
2420 : }
2421 :
2422 :
2423 : /* This function is called by our assuan log handler to test whether a
2424 : * log message shall really be printed. The function must return
2425 : * false to inhibit the logging of MSG. CAT gives the requested log
2426 : * category. MSG might be NULL. */
2427 : int
2428 0 : dirmngr_assuan_log_monitor (assuan_context_t ctx, unsigned int cat,
2429 : const char *msg)
2430 : {
2431 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
2432 :
2433 : (void)cat;
2434 : (void)msg;
2435 :
2436 0 : if (!ctrl || !ctrl->server_local)
2437 0 : return 1; /* Can't decide - allow logging. */
2438 :
2439 0 : if (!ctrl->server_local->inhibit_data_logging)
2440 0 : return 1; /* Not requested - allow logging. */
2441 :
2442 : /* Disallow logging if *_now is true. */
2443 0 : return !ctrl->server_local->inhibit_data_logging_now;
2444 : }
2445 :
2446 :
2447 : /* Startup the server and run the main command loop. With FD = -1,
2448 : use stdin/stdout. */
2449 : void
2450 0 : start_command_handler (assuan_fd_t fd)
2451 : {
2452 : static const char hello[] = "Dirmngr " VERSION " at your service";
2453 : static char *hello_line;
2454 : int rc;
2455 : assuan_context_t ctx;
2456 : ctrl_t ctrl;
2457 :
2458 0 : ctrl = xtrycalloc (1, sizeof *ctrl);
2459 0 : if (ctrl)
2460 0 : ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
2461 0 : if (!ctrl || !ctrl->server_local)
2462 : {
2463 0 : log_error (_("can't allocate control structure: %s\n"),
2464 0 : strerror (errno));
2465 0 : xfree (ctrl);
2466 0 : return;
2467 : }
2468 :
2469 0 : dirmngr_init_default_ctrl (ctrl);
2470 :
2471 0 : rc = assuan_new (&ctx);
2472 0 : if (rc)
2473 : {
2474 0 : log_error (_("failed to allocate assuan context: %s\n"),
2475 : gpg_strerror (rc));
2476 0 : dirmngr_exit (2);
2477 : }
2478 :
2479 0 : if (fd == ASSUAN_INVALID_FD)
2480 : {
2481 : assuan_fd_t filedes[2];
2482 :
2483 0 : filedes[0] = assuan_fdopen (0);
2484 0 : filedes[1] = assuan_fdopen (1);
2485 0 : rc = assuan_init_pipe_server (ctx, filedes);
2486 : }
2487 : else
2488 : {
2489 0 : rc = assuan_init_socket_server (ctx, fd, ASSUAN_SOCKET_SERVER_ACCEPTED);
2490 : }
2491 :
2492 0 : if (rc)
2493 : {
2494 0 : assuan_release (ctx);
2495 0 : log_error (_("failed to initialize the server: %s\n"),
2496 : gpg_strerror(rc));
2497 0 : dirmngr_exit (2);
2498 : }
2499 :
2500 0 : rc = register_commands (ctx);
2501 0 : if (rc)
2502 : {
2503 0 : log_error (_("failed to the register commands with Assuan: %s\n"),
2504 : gpg_strerror(rc));
2505 0 : dirmngr_exit (2);
2506 : }
2507 :
2508 :
2509 0 : if (!hello_line)
2510 : {
2511 0 : hello_line = xtryasprintf
2512 : ("Home: %s\n"
2513 : "Config: %s\n"
2514 : "%s",
2515 : gnupg_homedir (),
2516 0 : opt.config_filename? opt.config_filename : "[none]",
2517 : hello);
2518 : }
2519 :
2520 0 : ctrl->server_local->assuan_ctx = ctx;
2521 0 : assuan_set_pointer (ctx, ctrl);
2522 :
2523 0 : assuan_set_hello_line (ctx, hello_line);
2524 0 : assuan_register_option_handler (ctx, option_handler);
2525 0 : assuan_register_reset_notify (ctx, reset_notify);
2526 :
2527 : for (;;)
2528 : {
2529 0 : rc = assuan_accept (ctx);
2530 0 : if (rc == -1)
2531 0 : break;
2532 0 : if (rc)
2533 : {
2534 0 : log_info (_("Assuan accept problem: %s\n"), gpg_strerror (rc));
2535 0 : break;
2536 : }
2537 :
2538 : #ifndef HAVE_W32_SYSTEM
2539 0 : if (opt.verbose)
2540 : {
2541 : assuan_peercred_t peercred;
2542 :
2543 0 : if (!assuan_get_peercred (ctx, &peercred))
2544 0 : log_info ("connection from process %ld (%ld:%ld)\n",
2545 0 : (long)peercred->pid, (long)peercred->uid,
2546 0 : (long)peercred->gid);
2547 : }
2548 : #endif
2549 :
2550 0 : rc = assuan_process (ctx);
2551 0 : if (rc)
2552 : {
2553 0 : log_info (_("Assuan processing failed: %s\n"), gpg_strerror (rc));
2554 0 : continue;
2555 : }
2556 0 : }
2557 :
2558 :
2559 : #if USE_LDAP
2560 0 : ldap_wrapper_connection_cleanup (ctrl);
2561 :
2562 0 : ldapserver_list_free (ctrl->server_local->ldapservers);
2563 : #endif /*USE_LDAP*/
2564 0 : ctrl->server_local->ldapservers = NULL;
2565 :
2566 0 : release_ctrl_keyservers (ctrl);
2567 :
2568 0 : ctrl->server_local->assuan_ctx = NULL;
2569 0 : assuan_release (ctx);
2570 :
2571 0 : if (ctrl->server_local->stopme)
2572 0 : dirmngr_exit (0);
2573 :
2574 0 : if (ctrl->refcount)
2575 0 : log_error ("oops: connection control structure still referenced (%d)\n",
2576 : ctrl->refcount);
2577 : else
2578 : {
2579 0 : release_ctrl_ocsp_certs (ctrl);
2580 0 : xfree (ctrl->server_local);
2581 0 : dirmngr_deinit_default_ctrl (ctrl);
2582 0 : xfree (ctrl);
2583 : }
2584 : }
2585 :
2586 :
2587 : /* Send a status line back to the client. KEYWORD is the status
2588 : keyword, the optional string arguments are blank separated added to
2589 : the line, the last argument must be a NULL. */
2590 : gpg_error_t
2591 0 : dirmngr_status (ctrl_t ctrl, const char *keyword, ...)
2592 : {
2593 0 : gpg_error_t err = 0;
2594 : va_list arg_ptr;
2595 : const char *text;
2596 :
2597 0 : va_start (arg_ptr, keyword);
2598 :
2599 0 : if (ctrl->server_local)
2600 : {
2601 0 : assuan_context_t ctx = ctrl->server_local->assuan_ctx;
2602 : char buf[950], *p;
2603 : size_t n;
2604 :
2605 0 : p = buf;
2606 0 : n = 0;
2607 0 : while ( (text = va_arg (arg_ptr, const char *)) )
2608 : {
2609 0 : if (n)
2610 : {
2611 0 : *p++ = ' ';
2612 0 : n++;
2613 : }
2614 0 : for ( ; *text && n < DIM (buf)-2; n++)
2615 0 : *p++ = *text++;
2616 : }
2617 0 : *p = 0;
2618 0 : err = assuan_write_status (ctx, keyword, buf);
2619 : }
2620 :
2621 0 : va_end (arg_ptr);
2622 0 : return err;
2623 : }
2624 :
2625 :
2626 : /* Print a help status line. TEXTLEN gives the length of the text
2627 : from TEXT to be printed. The function splits text at LFs. */
2628 : gpg_error_t
2629 0 : dirmngr_status_help (ctrl_t ctrl, const char *text)
2630 : {
2631 0 : gpg_error_t err = 0;
2632 :
2633 0 : if (ctrl->server_local)
2634 : {
2635 0 : assuan_context_t ctx = ctrl->server_local->assuan_ctx;
2636 : char buf[950], *p;
2637 : size_t n;
2638 :
2639 : do
2640 : {
2641 0 : p = buf;
2642 0 : n = 0;
2643 0 : for ( ; *text && *text != '\n' && n < DIM (buf)-2; n++)
2644 0 : *p++ = *text++;
2645 0 : if (*text == '\n')
2646 0 : text++;
2647 0 : *p = 0;
2648 0 : err = assuan_write_status (ctx, "#", buf);
2649 : }
2650 0 : while (!err && *text);
2651 : }
2652 :
2653 0 : return err;
2654 : }
2655 :
2656 : /* Send a tick progress indicator back. Fixme: This is only done for
2657 : the currently active channel. */
2658 : gpg_error_t
2659 0 : dirmngr_tick (ctrl_t ctrl)
2660 : {
2661 : static time_t next_tick = 0;
2662 0 : gpg_error_t err = 0;
2663 0 : time_t now = time (NULL);
2664 :
2665 0 : if (!next_tick)
2666 : {
2667 0 : next_tick = now + 1;
2668 : }
2669 0 : else if ( now > next_tick )
2670 : {
2671 0 : if (ctrl)
2672 : {
2673 0 : err = dirmngr_status (ctrl, "PROGRESS", "tick", "? 0 0", NULL);
2674 0 : if (err)
2675 : {
2676 : /* Take this as in indication for a cancel request. */
2677 0 : err = gpg_error (GPG_ERR_CANCELED);
2678 : }
2679 0 : now = time (NULL);
2680 : }
2681 :
2682 0 : next_tick = now + 1;
2683 : }
2684 0 : return err;
2685 : }
|