1
/* call-dirmngr.c - communication with the dromngr
2
* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
4
* This file is part of GnuPG.
6
* GnuPG is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* GnuPG is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
38
/* The name of the socket for a system daemon. */
39
#define DEFAULT_SOCKET_NAME "/var/run/dirmngr/socket"
50
static ASSUAN_CONTEXT dirmngr_ctx = NULL;
51
static int force_pipe_server = 0;
53
struct inq_certificate_parm_s {
56
ksba_cert_t issuer_cert;
59
struct isvalid_status_parm_s {
62
unsigned char fpr[20];
66
struct lookup_parm_s {
69
void (*cb)(void *, ksba_cert_t);
75
struct run_command_parm_s {
80
/* A simple implementation of a dynamic buffer. Use init_membuf() to
81
create a buffer, put_membuf to append bytes and get_membuf to
82
release and return the buffer. Allocation errors are detected but
83
only returned at the final get_membuf(), this helps not to clutter
84
the code with out of core checks. */
87
init_membuf (struct membuf *mb, int initiallen)
90
mb->size = initiallen;
92
mb->buf = xtrymalloc (initiallen);
98
put_membuf (struct membuf *mb, const void *buf, size_t len)
103
if (mb->len + len >= mb->size)
107
mb->size += len + 1024;
108
p = xtryrealloc (mb->buf, mb->size);
116
memcpy (mb->buf + mb->len, buf, len);
121
get_membuf (struct membuf *mb, size_t *len)
135
mb->out_of_core = 1; /* don't allow a reuse */
143
/* Try to connect to the agent via socket or fork it off and work by
144
pipes. Handle the server's initial greeting */
154
return 0; /* fixme: We need a context for each thread or serialize
155
the access to the dirmngr */
156
/* Note: if you change this to multiple connections, you also need
157
to take care of the implicit option sending caching. */
159
infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
160
if (opt.prefer_system_dirmngr && !force_pipe_server
161
&&(!infostr || !*infostr))
163
infostr = DEFAULT_SOCKET_NAME;
166
if (!infostr || !*infostr)
170
int no_close_list[3];
174
log_info (_("no running dirmngr - starting one\n"));
178
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
179
log_error ("error flushing pending output: %s\n", strerror (errno));
183
if (!opt.dirmngr_program || !*opt.dirmngr_program)
184
opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
185
if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
186
pgmname = opt.dirmngr_program;
191
argv[1] = "--server";
195
if (log_get_fd () != -1)
196
no_close_list[i++] = log_get_fd ();
197
no_close_list[i++] = fileno (stderr);
198
no_close_list[i] = -1;
200
/* connect to the agent and perform initial handshaking */
201
rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
209
infostr = xstrdup (infostr);
210
if (!try_default && *infostr)
212
if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
214
log_error (_("malformed DIRMNGR_INFO environment variable\n"));
216
force_pipe_server = 1;
217
return start_dirmngr ();
221
while (*p && *p != ':')
223
prot = *p? atoi (p+1) : 0;
226
log_error (_("dirmngr protocol version %d is not supported\n"),
229
force_pipe_server = 1;
230
return start_dirmngr ();
236
rc = assuan_socket_connect (&ctx, infostr, pid);
238
if (rc == ASSUAN_Connect_Failed)
240
log_error (_("can't connect to the dirmngr - trying fall back\n"));
241
force_pipe_server = 1;
242
return start_dirmngr ();
248
log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
249
return gpg_error (GPG_ERR_NO_DIRMNGR);
254
log_debug ("connection to dirmngr established\n");
260
/* Handle a SENDCERT inquiry. */
262
inq_certificate (void *opaque, const char *line)
264
struct inq_certificate_parm_s *parm = opaque;
266
const unsigned char *der;
270
if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
274
else if (!strncmp (line, "SENDISSUERCERT", 14)
275
&& (line[14] == ' ' || !line[14]))
282
log_error ("unsupported inquiry `%s'\n", line);
283
return ASSUAN_Inquire_Unknown;
287
{ /* Send the current certificate. */
288
der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
291
rc = ASSUAN_Inquire_Error;
293
rc = assuan_send_data (parm->ctx, der, derlen);
295
else if (issuer_mode)
297
log_error ("sending specific issuer certificate back "
298
"is not yet implemented\n");
299
rc = ASSUAN_Inquire_Error;
302
{ /* Send the given certificate. */
307
err = gpgsm_find_cert (line, &cert);
310
log_error ("certificate not found: %s\n", gpg_strerror (err));
311
rc = ASSUAN_Inquire_Error;
315
der = ksba_cert_get_image (cert, &derlen);
317
rc = ASSUAN_Inquire_Error;
319
rc = assuan_send_data (parm->ctx, der, derlen);
320
ksba_cert_release (cert);
328
/* Take a 20 byte hexencoded string and put it into the the provided
329
20 byte buffer FPR in binary format. */
331
unhexify_fpr (const char *hexstr, unsigned char *fpr)
336
for (s=hexstr, n=0; hexdigitp (s); s++, n++)
339
return 0; /* no fingerprint (invalid or wrong length). */
341
for (s=hexstr, n=0; *s; s += 2, n++)
347
static assuan_error_t
348
isvalid_status_cb (void *opaque, const char *line)
350
struct isvalid_status_parm_s *parm = opaque;
352
if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
356
for (line += 8; *line == ' '; line++)
358
if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
359
return ASSUAN_Canceled;
362
else if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
363
&& (line[24]==' ' || !line[24]))
366
if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
367
parm->seen++; /* Bumb it to indicate an error. */
375
/* Call the directory manager to check whether the certificate is valid
376
Returns 0 for valid or usually one of the errors:
378
GPG_ERR_CERTIFICATE_REVOKED
382
With USE_OCSP set to true, the dirmngr is asked to do an OCSP
386
gpgsm_dirmngr_isvalid (ctrl_t ctrl,
387
ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
389
static int did_options;
392
char line[ASSUAN_LINELENGTH];
393
struct inq_certificate_parm_s parm;
394
struct isvalid_status_parm_s stparm;
397
rc = start_dirmngr ();
403
certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
407
certid = gpgsm_get_certid (cert);
410
log_error ("error getting the certificate ID\n");
411
return gpg_error (GPG_ERR_GENERAL);
417
char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
418
log_info ("asking dirmngr about %s%s\n", fpr,
419
use_ocsp? " (using OCSP)":"");
423
parm.ctx = dirmngr_ctx;
425
parm.issuer_cert = issuer_cert;
429
memset (stparm.fpr, 0, 20);
431
/* FIXME: If --disable-crl-checks has been set, we should pass an
432
option to dirmngr, so that no fallback CRL check is done after an
435
/* It is sufficient to send the options only once because we have
436
one connection per process only. */
439
if (opt.force_crl_refresh)
440
assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
441
NULL, NULL, NULL, NULL, NULL, NULL);
444
snprintf (line, DIM(line)-1, "ISVALID %s", certid);
445
line[DIM(line)-1] = 0;
448
rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
449
inq_certificate, &parm,
450
isvalid_status_cb, &stparm);
452
log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
453
rc = map_assuan_err (rc);
455
if (!rc && stparm.seen)
457
/* Need to also check the certificate validity. */
458
if (stparm.seen != 1)
460
log_error ("communication problem with dirmngr detected\n");
461
rc = gpg_error (GPG_ERR_INV_CRL);
466
ksba_cert_t rspcert = NULL;
468
/* Fixme: First try to get the certificate from the
469
dirmngr's cache - it should be there. */
472
rc = gpg_error (GPG_ERR_ENOMEM);
474
rc = keydb_search_fpr (kh, stparm.fpr);
476
rc = keydb_get_cert (kh, &rspcert);
479
log_error ("unable to find the certificate used "
480
"by the dirmngr: %s\n", gpg_strerror (rc));
481
rc = gpg_error (GPG_ERR_INV_CRL);
487
rc = gpgsm_cert_use_ocsp_p (rspcert);
489
rc = gpg_error (GPG_ERR_INV_CRL);
492
/* Note, the flag = 1: This avoids checking this
493
certificate over and over again. */
494
rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1);
497
log_error ("invalid certificate used for CRL/OCSP: %s\n",
499
rc = gpg_error (GPG_ERR_INV_CRL);
503
ksba_cert_release (rspcert);
513
lookup_cb (void *opaque, const void *buffer, size_t length)
515
struct lookup_parm_s *parm = opaque;
526
put_membuf (&parm->data, buffer, length);
529
/* END encountered - process what we have */
530
buf = get_membuf (&parm->data, &len);
533
parm->error = gpg_error (GPG_ERR_ENOMEM);
537
rc = ksba_cert_new (&cert);
543
rc = ksba_cert_init_from_mem (cert, buf, len);
546
log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
550
parm->cb (parm->cb_value, cert);
553
ksba_cert_release (cert);
554
init_membuf (&parm->data, 4096);
558
/* Return a properly escaped pattern from NAMES. The only error
559
return is NULL to indicate a malloc failure. */
561
pattern_from_strlist (STRLIST names)
568
for (n=0, sl=names; sl; sl = sl->next)
570
for (s=sl->d; *s; s++, n++)
572
if (*s == '%' || *s == ' ' || *s == '+')
578
p = pattern = xtrymalloc (n+1);
582
for (n=0, sl=names; sl; sl = sl->next)
584
for (s=sl->d; *s; s++)
611
*pattern = 0; /* is empty */
613
p[-1] = '\0'; /* remove trailing blank */
619
lookup_status_cb (void *opaque, const char *line)
621
struct lookup_parm_s *parm = opaque;
623
if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
627
for (line += 8; *line == ' '; line++)
629
if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
630
return ASSUAN_Canceled;
633
else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
637
for (line +=9; *line == ' '; line++)
639
gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
646
/* Run the Directroy Managers lookup command using the pattern
647
compiled from the strings given in NAMES. The caller must provide
648
the callback CB which will be passed cert by cert. Note that CTRL
651
gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
652
void (*cb)(void*, ksba_cert_t), void *cb_value)
656
char line[ASSUAN_LINELENGTH];
657
struct lookup_parm_s parm;
660
rc = start_dirmngr ();
664
pattern = pattern_from_strlist (names);
666
return OUT_OF_CORE (errno);
667
snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
668
line[DIM(line)-1] = 0;
672
parm.ctx = dirmngr_ctx;
674
parm.cb_value = cb_value;
676
init_membuf (&parm.data, 4096);
678
rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
679
NULL, NULL, lookup_status_cb, &parm);
680
xfree (get_membuf (&parm.data, &len));
682
return map_assuan_err (rc);
688
/* Run Command helpers*/
690
/* Fairly simple callback to write all output of dirmngr to stdout. */
692
run_command_cb (void *opaque, const void *buffer, size_t length)
696
if ( fwrite (buffer, length, 1, stdout) != 1 )
697
log_error ("error writing to stdout: %s\n", strerror (errno));
702
/* Handle inquiries from the dirmngr COMMAND. */
704
run_command_inq_cb (void *opaque, const char *line)
706
struct run_command_parm_s *parm = opaque;
709
if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
710
{ /* send the given certificate */
713
const unsigned char *der;
718
return ASSUAN_Inquire_Error;
720
err = gpgsm_find_cert (line, &cert);
723
log_error ("certificate not found: %s\n", gpg_strerror (err));
724
rc = ASSUAN_Inquire_Error;
728
der = ksba_cert_get_image (cert, &derlen);
730
rc = ASSUAN_Inquire_Error;
732
rc = assuan_send_data (parm->ctx, der, derlen);
733
ksba_cert_release (cert);
736
else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
737
{ /* Simply show the message given in the argument. */
739
log_info ("dirmngr: %s\n", line);
743
log_error ("unsupported inquiry `%s'\n", line);
744
rc = ASSUAN_Inquire_Unknown;
751
run_command_status_cb (void *opaque, const char *line)
753
ctrl_t ctrl = opaque;
757
log_info ("dirmngr status: %s\n", line);
759
if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
763
for (line += 8; *line == ' '; line++)
765
if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
766
return ASSUAN_Canceled;
774
/* Pass COMMAND to dirmngr and print all output generated by Dirmngr
775
to stdout. A couple of inquiries are defined (see above). ARGC
776
arguments in ARGV are given to the Dirmngr. Spaces, plus and
777
percent characters within the argument strings are percent escaped
778
so that blanks can act as delimiters. */
780
gpgsm_dirmngr_run_command (CTRL ctrl, const char *command,
781
int argc, char **argv)
788
struct run_command_parm_s parm;
790
rc = start_dirmngr ();
794
parm.ctx = dirmngr_ctx;
796
len = strlen (command) + 1;
797
for (i=0; i < argc; i++)
798
len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
799
line = xtrymalloc (len);
801
return OUT_OF_CORE (errno);
803
p = stpcpy (line, command);
804
for (i=0; i < argc; i++)
807
for (s=argv[i]; *s; s++)
813
else if (!isprint (*s) || *s == '+')
815
sprintf (p, "%%%02X", *s);
824
rc = assuan_transact (dirmngr_ctx, line,
825
run_command_cb, NULL,
826
run_command_inq_cb, &parm,
827
run_command_status_cb, ctrl);
829
log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
830
return map_assuan_err (rc);