1 /* call-dirmngr.c - communication with the dromngr
2 * Copyright (C) 2002, 2003, 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
39 /* The name of the socket for a system daemon. */
40 #define DEFAULT_SOCKET_NAME "/var/run/dirmngr/socket"
51 static assuan_context_t dirmngr_ctx
= NULL
;
52 static int force_pipe_server
= 0;
54 struct inq_certificate_parm_s
{
57 ksba_cert_t issuer_cert
;
60 struct isvalid_status_parm_s
{
63 unsigned char fpr
[20];
67 struct lookup_parm_s
{
70 void (*cb
)(void *, ksba_cert_t
);
76 struct run_command_parm_s
{
81 /* A simple implementation of a dynamic buffer. Use init_membuf() to
82 create a buffer, put_membuf to append bytes and get_membuf to
83 release and return the buffer. Allocation errors are detected but
84 only returned at the final get_membuf(), this helps not to clutter
85 the code with out of core checks. */
88 init_membuf (struct membuf
*mb
, int initiallen
)
91 mb
->size
= initiallen
;
93 mb
->buf
= xtrymalloc (initiallen
);
99 put_membuf (struct membuf
*mb
, const void *buf
, size_t len
)
104 if (mb
->len
+ len
>= mb
->size
)
108 mb
->size
+= len
+ 1024;
109 p
= xtryrealloc (mb
->buf
, mb
->size
);
117 memcpy (mb
->buf
+ mb
->len
, buf
, len
);
122 get_membuf (struct membuf
*mb
, size_t *len
)
136 mb
->out_of_core
= 1; /* don't allow a reuse */
144 /* Try to connect to the agent via socket or fork it off and work by
145 pipes. Handle the server's initial greeting */
151 assuan_context_t ctx
;
155 return 0; /* fixme: We need a context for each thread or serialize
156 the access to the dirmngr */
157 /* Note: if you change this to multiple connections, you also need
158 to take care of the implicit option sending caching. */
160 infostr
= force_pipe_server
? NULL
: getenv ("DIRMNGR_INFO");
161 if (opt
.prefer_system_dirmngr
&& !force_pipe_server
162 &&(!infostr
|| !*infostr
))
164 infostr
= DEFAULT_SOCKET_NAME
;
167 if (!infostr
|| !*infostr
)
171 int no_close_list
[3];
174 if (!opt
.dirmngr_program
|| !*opt
.dirmngr_program
)
175 opt
.dirmngr_program
= GNUPG_DEFAULT_DIRMNGR
;
176 if ( !(pgmname
= strrchr (opt
.dirmngr_program
, '/')))
177 pgmname
= opt
.dirmngr_program
;
182 log_info (_("no running dirmngr - starting `%s'\n"),
183 opt
.dirmngr_program
);
187 gpg_error_t tmperr
= gpg_error (gpg_err_code_from_errno (errno
));
188 log_error ("error flushing pending output: %s\n", strerror (errno
));
193 argv
[1] = "--server";
197 if (log_get_fd () != -1)
198 no_close_list
[i
++] = log_get_fd ();
199 no_close_list
[i
++] = fileno (stderr
);
200 no_close_list
[i
] = -1;
202 /* connect to the agent and perform initial handshaking */
203 rc
= assuan_pipe_connect (&ctx
, opt
.dirmngr_program
, argv
,
211 infostr
= xstrdup (infostr
);
212 if (!try_default
&& *infostr
)
214 if ( !(p
= strchr (infostr
, PATHSEP_C
)) || p
== infostr
)
216 log_error (_("malformed DIRMNGR_INFO environment variable\n"));
218 force_pipe_server
= 1;
219 return start_dirmngr ();
223 while (*p
&& *p
!= PATHSEP_C
)
225 prot
= *p
? atoi (p
+1) : 0;
228 log_error (_("dirmngr protocol version %d is not supported\n"),
231 force_pipe_server
= 1;
232 return start_dirmngr ();
238 rc
= assuan_socket_connect (&ctx
, infostr
, pid
);
240 if (gpg_err_code (rc
) == GPG_ERR_ASS_CONNECT_FAILED
)
242 log_error (_("can't connect to the dirmngr - trying fall back\n"));
243 force_pipe_server
= 1;
244 return start_dirmngr ();
250 log_error ("can't connect to the dirmngr: %s\n", gpg_strerror (rc
));
251 return gpg_error (GPG_ERR_NO_DIRMNGR
);
256 log_debug ("connection to dirmngr established\n");
262 /* Handle a SENDCERT inquiry. */
264 inq_certificate (void *opaque
, const char *line
)
266 struct inq_certificate_parm_s
*parm
= opaque
;
268 const unsigned char *der
;
271 ksba_sexp_t ski
= NULL
;
273 if (!strncmp (line
, "SENDCERT", 8) && (line
[8] == ' ' || !line
[8]))
277 else if (!strncmp (line
, "SENDCERT_SKI", 12) && (line
[12]==' ' || !line
[12]))
281 /* Send a certificate where a sourceKeyIdentifier is included. */
285 ski
= make_simple_sexp_from_hexstr (line
, &n
);
290 else if (!strncmp (line
, "SENDISSUERCERT", 14)
291 && (line
[14] == ' ' || !line
[14]))
298 log_error ("unsupported inquiry `%s'\n", line
);
299 return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE
);
303 { /* Send the current certificate. */
304 der
= ksba_cert_get_image (issuer_mode
? parm
->issuer_cert
: parm
->cert
,
307 rc
= gpg_error (GPG_ERR_INV_CERT_OBJ
);
309 rc
= assuan_send_data (parm
->ctx
, der
, derlen
);
311 else if (issuer_mode
)
313 log_error ("sending specific issuer certificate back "
314 "is not yet implemented\n");
315 rc
= gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE
);
318 { /* Send the given certificate. */
323 err
= gpgsm_find_cert (line
, ski
, &cert
);
326 log_error ("certificate not found: %s\n", gpg_strerror (err
));
327 rc
= gpg_error (GPG_ERR_NOT_FOUND
);
331 der
= ksba_cert_get_image (cert
, &derlen
);
333 rc
= gpg_error (GPG_ERR_INV_CERT_OBJ
);
335 rc
= assuan_send_data (parm
->ctx
, der
, derlen
);
336 ksba_cert_release (cert
);
345 /* Take a 20 byte hexencoded string and put it into the the provided
346 20 byte buffer FPR in binary format. */
348 unhexify_fpr (const char *hexstr
, unsigned char *fpr
)
353 for (s
=hexstr
, n
=0; hexdigitp (s
); s
++, n
++)
356 return 0; /* no fingerprint (invalid or wrong length). */
358 for (s
=hexstr
, n
=0; *s
; s
+= 2, n
++)
364 static assuan_error_t
365 isvalid_status_cb (void *opaque
, const char *line
)
367 struct isvalid_status_parm_s
*parm
= opaque
;
369 if (!strncmp (line
, "PROGRESS", 8) && (line
[8]==' ' || !line
[8]))
373 for (line
+= 8; *line
== ' '; line
++)
375 if (gpgsm_status (parm
->ctrl
, STATUS_PROGRESS
, line
))
376 return gpg_error (GPG_ERR_ASS_CANCELED
);
379 else if (!strncmp (line
, "ONLY_VALID_IF_CERT_VALID", 24)
380 && (line
[24]==' ' || !line
[24]))
383 if (!line
[24] || !unhexify_fpr (line
+25, parm
->fpr
))
384 parm
->seen
++; /* Bumb it to indicate an error. */
392 /* Call the directory manager to check whether the certificate is valid
393 Returns 0 for valid or usually one of the errors:
395 GPG_ERR_CERTIFICATE_REVOKED
399 With USE_OCSP set to true, the dirmngr is asked to do an OCSP
403 gpgsm_dirmngr_isvalid (ctrl_t ctrl
,
404 ksba_cert_t cert
, ksba_cert_t issuer_cert
, int use_ocsp
)
406 static int did_options
;
409 char line
[ASSUAN_LINELENGTH
];
410 struct inq_certificate_parm_s parm
;
411 struct isvalid_status_parm_s stparm
;
414 rc
= start_dirmngr ();
420 certid
= gpgsm_get_fingerprint_hexstring (cert
, GCRY_MD_SHA1
);
424 certid
= gpgsm_get_certid (cert
);
427 log_error ("error getting the certificate ID\n");
428 return gpg_error (GPG_ERR_GENERAL
);
434 char *fpr
= gpgsm_get_fingerprint_string (cert
, GCRY_MD_SHA1
);
435 log_info ("asking dirmngr about %s%s\n", fpr
,
436 use_ocsp
? " (using OCSP)":"");
440 parm
.ctx
= dirmngr_ctx
;
442 parm
.issuer_cert
= issuer_cert
;
446 memset (stparm
.fpr
, 0, 20);
448 /* FIXME: If --disable-crl-checks has been set, we should pass an
449 option to dirmngr, so that no fallback CRL check is done after an
452 /* It is sufficient to send the options only once because we have
453 one connection per process only. */
456 if (opt
.force_crl_refresh
)
457 assuan_transact (dirmngr_ctx
, "OPTION force-crl-refresh=1",
458 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
461 snprintf (line
, DIM(line
)-1, "ISVALID %s", certid
);
462 line
[DIM(line
)-1] = 0;
465 rc
= assuan_transact (dirmngr_ctx
, line
, NULL
, NULL
,
466 inq_certificate
, &parm
,
467 isvalid_status_cb
, &stparm
);
469 log_info ("response of dirmngr: %s\n", rc
? gpg_strerror (rc
): "okay");
472 if (!rc
&& stparm
.seen
)
474 /* Need to also check the certificate validity. */
475 if (stparm
.seen
!= 1)
477 log_error ("communication problem with dirmngr detected\n");
478 rc
= gpg_error (GPG_ERR_INV_CRL
);
483 ksba_cert_t rspcert
= NULL
;
485 /* Fixme: First try to get the certificate from the
486 dirmngr's cache - it should be there. */
489 rc
= gpg_error (GPG_ERR_ENOMEM
);
491 rc
= keydb_search_fpr (kh
, stparm
.fpr
);
493 rc
= keydb_get_cert (kh
, &rspcert
);
496 log_error ("unable to find the certificate used "
497 "by the dirmngr: %s\n", gpg_strerror (rc
));
498 rc
= gpg_error (GPG_ERR_INV_CRL
);
504 rc
= gpgsm_cert_use_ocsp_p (rspcert
);
506 rc
= gpg_error (GPG_ERR_INV_CRL
);
509 /* Note, the flag = 1: This avoids checking this
510 certificate over and over again. */
511 rc
= gpgsm_validate_chain (ctrl
, rspcert
, NULL
, 0, NULL
, 1);
514 log_error ("invalid certificate used for CRL/OCSP: %s\n",
516 rc
= gpg_error (GPG_ERR_INV_CRL
);
520 ksba_cert_release (rspcert
);
530 lookup_cb (void *opaque
, const void *buffer
, size_t length
)
532 struct lookup_parm_s
*parm
= opaque
;
543 put_membuf (&parm
->data
, buffer
, length
);
546 /* END encountered - process what we have */
547 buf
= get_membuf (&parm
->data
, &len
);
550 parm
->error
= gpg_error (GPG_ERR_ENOMEM
);
554 rc
= ksba_cert_new (&cert
);
560 rc
= ksba_cert_init_from_mem (cert
, buf
, len
);
563 log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc
));
567 parm
->cb (parm
->cb_value
, cert
);
570 ksba_cert_release (cert
);
571 init_membuf (&parm
->data
, 4096);
575 /* Return a properly escaped pattern from NAMES. The only error
576 return is NULL to indicate a malloc failure. */
578 pattern_from_strlist (strlist_t names
)
585 for (n
=0, sl
=names
; sl
; sl
= sl
->next
)
587 for (s
=sl
->d
; *s
; s
++, n
++)
589 if (*s
== '%' || *s
== ' ' || *s
== '+')
595 p
= pattern
= xtrymalloc (n
+1);
599 for (n
=0, sl
=names
; sl
; sl
= sl
->next
)
601 for (s
=sl
->d
; *s
; s
++)
628 *pattern
= 0; /* is empty */
630 p
[-1] = '\0'; /* remove trailing blank */
636 lookup_status_cb (void *opaque
, const char *line
)
638 struct lookup_parm_s
*parm
= opaque
;
640 if (!strncmp (line
, "PROGRESS", 8) && (line
[8]==' ' || !line
[8]))
644 for (line
+= 8; *line
== ' '; line
++)
646 if (gpgsm_status (parm
->ctrl
, STATUS_PROGRESS
, line
))
647 return gpg_error (GPG_ERR_ASS_CANCELED
);
650 else if (!strncmp (line
, "TRUNCATED", 9) && (line
[9]==' ' || !line
[9]))
654 for (line
+=9; *line
== ' '; line
++)
656 gpgsm_status (parm
->ctrl
, STATUS_TRUNCATED
, line
);
663 /* Run the Directroy Managers lookup command using the pattern
664 compiled from the strings given in NAMES. The caller must provide
665 the callback CB which will be passed cert by cert. Note that CTRL
668 gpgsm_dirmngr_lookup (ctrl_t ctrl
, strlist_t names
,
669 void (*cb
)(void*, ksba_cert_t
), void *cb_value
)
673 char line
[ASSUAN_LINELENGTH
];
674 struct lookup_parm_s parm
;
677 rc
= start_dirmngr ();
681 pattern
= pattern_from_strlist (names
);
683 return out_of_core ();
684 snprintf (line
, DIM(line
)-1, "LOOKUP %s", pattern
);
685 line
[DIM(line
)-1] = 0;
689 parm
.ctx
= dirmngr_ctx
;
691 parm
.cb_value
= cb_value
;
693 init_membuf (&parm
.data
, 4096);
695 rc
= assuan_transact (dirmngr_ctx
, line
, lookup_cb
, &parm
,
696 NULL
, NULL
, lookup_status_cb
, &parm
);
697 xfree (get_membuf (&parm
.data
, &len
));
705 /* Run Command helpers*/
707 /* Fairly simple callback to write all output of dirmngr to stdout. */
709 run_command_cb (void *opaque
, const void *buffer
, size_t length
)
713 if ( fwrite (buffer
, length
, 1, stdout
) != 1 )
714 log_error ("error writing to stdout: %s\n", strerror (errno
));
719 /* Handle inquiries from the dirmngr COMMAND. */
721 run_command_inq_cb (void *opaque
, const char *line
)
723 struct run_command_parm_s
*parm
= opaque
;
726 if ( !strncmp (line
, "SENDCERT", 8) && (line
[8] == ' ' || !line
[8]) )
727 { /* send the given certificate */
730 const unsigned char *der
;
735 return gpg_error (GPG_ERR_ASS_PARAMETER
);
737 err
= gpgsm_find_cert (line
, NULL
, &cert
);
740 log_error ("certificate not found: %s\n", gpg_strerror (err
));
741 rc
= gpg_error (GPG_ERR_NOT_FOUND
);
745 der
= ksba_cert_get_image (cert
, &derlen
);
747 rc
= gpg_error (GPG_ERR_INV_CERT_OBJ
);
749 rc
= assuan_send_data (parm
->ctx
, der
, derlen
);
750 ksba_cert_release (cert
);
753 else if ( !strncmp (line
, "PRINTINFO", 9) && (line
[9] == ' ' || !line
[9]) )
754 { /* Simply show the message given in the argument. */
756 log_info ("dirmngr: %s\n", line
);
760 log_error ("unsupported inquiry `%s'\n", line
);
761 rc
= gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE
);
768 run_command_status_cb (void *opaque
, const char *line
)
770 ctrl_t ctrl
= opaque
;
774 log_info ("dirmngr status: %s\n", line
);
776 if (!strncmp (line
, "PROGRESS", 8) && (line
[8]==' ' || !line
[8]))
780 for (line
+= 8; *line
== ' '; line
++)
782 if (gpgsm_status (ctrl
, STATUS_PROGRESS
, line
))
783 return gpg_error (GPG_ERR_ASS_CANCELED
);
791 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
792 to stdout. A couple of inquiries are defined (see above). ARGC
793 arguments in ARGV are given to the Dirmngr. Spaces, plus and
794 percent characters within the argument strings are percent escaped
795 so that blanks can act as delimiters. */
797 gpgsm_dirmngr_run_command (ctrl_t ctrl
, const char *command
,
798 int argc
, char **argv
)
805 struct run_command_parm_s parm
;
807 rc
= start_dirmngr ();
811 parm
.ctx
= dirmngr_ctx
;
813 len
= strlen (command
) + 1;
814 for (i
=0; i
< argc
; i
++)
815 len
+= 1 + 3*strlen (argv
[i
]); /* enough space for percent escaping */
816 line
= xtrymalloc (len
);
818 return out_of_core ();
820 p
= stpcpy (line
, command
);
821 for (i
=0; i
< argc
; i
++)
824 for (s
=argv
[i
]; *s
; s
++)
830 else if (!isprint (*s
) || *s
== '+')
832 sprintf (p
, "%%%02X", *(const unsigned char *)s
);
841 rc
= assuan_transact (dirmngr_ctx
, line
,
842 run_command_cb
, NULL
,
843 run_command_inq_cb
, &parm
,
844 run_command_status_cb
, ctrl
);
846 log_info ("response of dirmngr: %s\n", rc
? gpg_strerror (rc
): "okay");