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
);