dirmngr: New option --resolver-timeout.
[gnupg.git] / dirmngr / dirmngr-client.c
1 /* dirmngr-client.c  -  A client for the dirmngr daemon
2  *      Copyright (C) 2004, 2007 g10 Code GmbH
3  *      Copyright (C) 2002, 2003 Free Software Foundation, Inc.
4  *
5  * This file is part of DirMngr.
6  *
7  * DirMngr is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * DirMngr is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <assert.h>
30
31 #include <gpg-error.h>
32 #include <assuan.h>
33
34 #include "../common/logging.h"
35 #include "../common/argparse.h"
36 #include "../common/stringhelp.h"
37 #include "../common/mischelp.h"
38 #include "../common/strlist.h"
39 #include "../common/asshelp.h"
40
41 #include "i18n.h"
42 #include "util.h"
43 #include "init.h"
44
45
46 /* Constants for the options.  */
47 enum
48   {
49     oQuiet        = 'q',
50     oVerbose      = 'v',
51     oLocal        = 'l',
52     oUrl          = 'u',
53
54     oOCSP         = 500,
55     oPing,
56     oCacheCert,
57     oValidate,
58     oLookup,
59     oLoadCRL,
60     oSquidMode,
61     oPEM,
62     oEscapedPEM,
63     oForceDefaultResponder
64   };
65
66
67 /* The list of options as used by the argparse.c code.  */
68 static ARGPARSE_OPTS opts[] = {
69   { oVerbose,  "verbose",   0, N_("verbose") },
70   { oQuiet,    "quiet",     0, N_("be somewhat more quiet") },
71   { oOCSP,     "ocsp",      0, N_("use OCSP instead of CRLs") },
72   { oPing,     "ping",      0, N_("check whether a dirmngr is running")},
73   { oCacheCert,"cache-cert",0, N_("add a certificate to the cache")},
74   { oValidate, "validate",  0, N_("validate a certificate")},
75   { oLookup,   "lookup",    0, N_("lookup a certificate")},
76   { oLocal,    "local",     0, N_("lookup only locally stored certificates")},
77   { oUrl,      "url",       0, N_("expect an URL for --lookup")},
78   { oLoadCRL,  "load-crl",  0, N_("load a CRL into the dirmngr")},
79   { oSquidMode,"squid-mode",0, N_("special mode for use by Squid")},
80   { oPEM,      "pem",       0, N_("expect certificates in PEM format")},
81   { oForceDefaultResponder, "force-default-responder", 0,
82     N_("force the use of the default OCSP responder")},
83   { 0, NULL, 0, NULL }
84 };
85
86
87 /* The usual structure for the program flags.  */
88 static struct
89 {
90   int quiet;
91   int verbose;
92   const char *dirmngr_program;
93   int force_default_responder;
94   int pem;
95   int escaped_pem; /* PEM is additional percent encoded.  */
96   int url;         /* Expect an URL.  */
97   int local;       /* Lookup up only local certificates.  */
98
99   int use_ocsp;
100 } opt;
101
102
103 /* Communication structure for the certificate inquire callback. */
104 struct inq_cert_parm_s
105 {
106   assuan_context_t ctx;
107   const unsigned char *cert;
108   size_t certlen;
109 };
110
111
112 /* Base64 conversion tables. */
113 static unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
114                                   "abcdefghijklmnopqrstuvwxyz"
115                                   "0123456789+/";
116 static unsigned char asctobin[256]; /* runtime initialized */
117
118
119 /* Build the helptable for radix64 to bin conversion. */
120 static void
121 init_asctobin (void)
122 {
123   static int initialized;
124   int i;
125   unsigned char *s;
126
127   if (initialized)
128     return;
129   initialized = 1;
130
131   for (i=0; i < 256; i++ )
132     asctobin[i] = 255; /* Used to detect invalid characters. */
133   for (s=bintoasc, i=0; *s; s++, i++)
134     asctobin[*s] = i;
135 }
136
137
138 /* Prototypes.  */
139 static gpg_error_t read_certificate (const char *fname,
140                                      unsigned char **rbuf, size_t *rbuflen);
141 static gpg_error_t do_check (assuan_context_t ctx,
142                              const unsigned char *cert, size_t certlen);
143 static gpg_error_t do_cache (assuan_context_t ctx,
144                              const unsigned char *cert, size_t certlen);
145 static gpg_error_t do_validate (assuan_context_t ctx,
146                                 const unsigned char *cert, size_t certlen);
147 static gpg_error_t do_loadcrl (assuan_context_t ctx, const char *filename);
148 static gpg_error_t do_lookup (assuan_context_t ctx, const char *pattern);
149 static gpg_error_t squid_loop_body (assuan_context_t ctx);
150
151
152
153 /* Function called by argparse.c to display information.  */
154 static const char *
155 my_strusage (int level)
156 {
157   const char *p;
158
159   switch(level)
160     {
161     case 11: p = "dirmngr-client (@GNUPG@)";
162       break;
163     case 13: p = VERSION; break;
164     case 17: p = PRINTABLE_OS_NAME; break;
165     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
166     case 49: p = PACKAGE_BUGREPORT; break;
167     case 1:
168     case 40: p =
169                  _("Usage: dirmngr-client [options] "
170                    "[certfile|pattern] (-h for help)\n");
171       break;
172     case 41: p =
173           _("Syntax: dirmngr-client [options] [certfile|pattern]\n"
174             "Test an X.509 certificate against a CRL or do an OCSP check\n"
175             "The process returns 0 if the certificate is valid, 1 if it is\n"
176             "not valid and other error codes for general failures\n");
177       break;
178
179     default: p = NULL;
180     }
181   return p;
182 }
183
184
185
186 int
187 main (int argc, char **argv )
188 {
189   ARGPARSE_ARGS pargs;
190   assuan_context_t ctx;
191   gpg_error_t err;
192   unsigned char *certbuf;
193   size_t certbuflen = 0;
194   int cmd_ping = 0;
195   int cmd_cache_cert = 0;
196   int cmd_validate = 0;
197   int cmd_lookup = 0;
198   int cmd_loadcrl = 0;
199   int cmd_squid_mode = 0;
200
201   early_system_init ();
202   set_strusage (my_strusage);
203   log_set_prefix ("dirmngr-client",
204                   GPGRT_LOG_WITH_PREFIX);
205
206   /* For W32 we need to initialize the socket subsystem.  Because we
207      don't use Pth we need to do this explicit. */
208 #ifdef HAVE_W32_SYSTEM
209  {
210    WSADATA wsadat;
211
212    WSAStartup (0x202, &wsadat);
213  }
214 #endif /*HAVE_W32_SYSTEM*/
215
216   /* Init Assuan.  */
217   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
218   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
219
220   /* Setup I18N. */
221   i18n_init();
222
223   /* Parse the command line.  */
224   pargs.argc = &argc;
225   pargs.argv = &argv;
226   pargs.flags= 1;  /* Do not remove the args. */
227   while (arg_parse (&pargs, opts) )
228     {
229       switch (pargs.r_opt)
230         {
231         case oVerbose: opt.verbose++; break;
232         case oQuiet: opt.quiet++; break;
233
234         case oOCSP: opt.use_ocsp++; break;
235         case oPing: cmd_ping = 1; break;
236         case oCacheCert: cmd_cache_cert = 1; break;
237         case oValidate: cmd_validate = 1; break;
238         case oLookup: cmd_lookup = 1; break;
239         case oUrl: opt.url = 1; break;
240         case oLocal: opt.local = 1; break;
241         case oLoadCRL: cmd_loadcrl = 1; break;
242         case oPEM: opt.pem = 1; break;
243         case oSquidMode:
244           opt.pem = 1;
245           opt.escaped_pem = 1;
246           cmd_squid_mode = 1;
247           break;
248         case oForceDefaultResponder: opt.force_default_responder = 1; break;
249
250         default : pargs.err = 2; break;
251         }
252     }
253   if (log_get_errorcount (0))
254     exit (2);
255
256   if (cmd_ping)
257     err = 0;
258   else if (cmd_lookup || cmd_loadcrl)
259     {
260       if (!argc)
261         usage (1);
262       err = 0;
263     }
264   else if (cmd_squid_mode)
265     {
266       err = 0;
267       if (argc)
268         usage (1);
269     }
270   else if (!argc)
271     {
272       err = read_certificate (NULL, &certbuf, &certbuflen);
273       if (err)
274         log_error (_("error reading certificate from stdin: %s\n"),
275                    gpg_strerror (err));
276     }
277   else if (argc == 1)
278     {
279       err = read_certificate (*argv, &certbuf, &certbuflen);
280       if (err)
281         log_error (_("error reading certificate from '%s': %s\n"),
282                    *argv, gpg_strerror (err));
283     }
284   else
285     {
286       err = 0;
287       usage (1);
288     }
289
290   if (log_get_errorcount (0))
291     exit (2);
292
293   if (certbuflen > 20000)
294     {
295       log_error (_("certificate too large to make any sense\n"));
296       exit (2);
297     }
298
299   err = start_new_dirmngr (&ctx,
300                            GPG_ERR_SOURCE_DEFAULT,
301                            opt.dirmngr_program
302                              ? opt.dirmngr_program
303                              : gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR),
304                            ! cmd_ping,
305                            opt.verbose,
306                            0,
307                            NULL, NULL);
308   if (err)
309     {
310       log_error (_("can't connect to the dirmngr: %s\n"), gpg_strerror (err));
311       exit (2);
312     }
313
314   if (cmd_ping)
315     ;
316   else if (cmd_squid_mode)
317     {
318       while (!(err = squid_loop_body (ctx)))
319         ;
320       if (gpg_err_code (err) == GPG_ERR_EOF)
321         err = 0;
322     }
323   else if (cmd_lookup)
324     {
325       int last_err = 0;
326
327       for (; argc; argc--, argv++)
328         {
329           err = do_lookup (ctx, *argv);
330           if (err)
331             {
332               log_error (_("lookup failed: %s\n"), gpg_strerror (err));
333               last_err = err;
334             }
335         }
336       err = last_err;
337     }
338   else if (cmd_loadcrl)
339     {
340       int last_err = 0;
341
342       for (; argc; argc--, argv++)
343         {
344           err = do_loadcrl (ctx, *argv);
345           if (err)
346             {
347               log_error (_("loading CRL '%s' failed: %s\n"),
348                          *argv, gpg_strerror (err));
349               last_err = err;
350             }
351         }
352       err = last_err;
353     }
354   else if (cmd_cache_cert)
355     {
356       err = do_cache (ctx, certbuf, certbuflen);
357       xfree (certbuf);
358     }
359   else if (cmd_validate)
360     {
361       err = do_validate (ctx, certbuf, certbuflen);
362       xfree (certbuf);
363     }
364   else
365     {
366       err = do_check (ctx, certbuf, certbuflen);
367       xfree (certbuf);
368     }
369
370   assuan_release (ctx);
371
372   if (cmd_ping)
373     {
374       if (!opt.quiet)
375         log_info (_("a dirmngr daemon is up and running\n"));
376       return 0;
377     }
378   else if (cmd_lookup|| cmd_loadcrl || cmd_squid_mode)
379     return err? 1:0;
380   else if (cmd_cache_cert)
381     {
382       if (err && gpg_err_code (err) == GPG_ERR_DUP_VALUE )
383         {
384           if (!opt.quiet)
385             log_info (_("certificate already cached\n"));
386         }
387       else if (err)
388         {
389           log_error (_("error caching certificate: %s\n"),
390                      gpg_strerror (err));
391           return 1;
392         }
393       return 0;
394     }
395   else if (cmd_validate && err)
396     {
397       log_error (_("validation of certificate failed: %s\n"),
398                  gpg_strerror (err));
399       return 1;
400     }
401   else if (!err)
402     {
403       if (!opt.quiet)
404         log_info (_("certificate is valid\n"));
405       return 0;
406     }
407   else if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED )
408     {
409       if (!opt.quiet)
410         log_info (_("certificate has been revoked\n"));
411       return 1;
412     }
413   else
414     {
415       log_error (_("certificate check failed: %s\n"), gpg_strerror (err));
416       return 2;
417     }
418 }
419
420
421 /* Print status line from the assuan protocol.  */
422 static gpg_error_t
423 status_cb (void *opaque, const char *line)
424 {
425   (void)opaque;
426
427   if (opt.verbose > 2)
428     log_info (_("got status: '%s'\n"), line);
429   return 0;
430 }
431
432 /* Print data as retrieved by the lookup function.  */
433 static gpg_error_t
434 data_cb (void *opaque, const void *buffer, size_t length)
435 {
436   gpg_error_t err;
437   struct b64state *state = opaque;
438
439   if (buffer)
440     {
441       err = b64enc_write (state, buffer, length);
442       if (err)
443         log_error (_("error writing base64 encoding: %s\n"),
444                    gpg_strerror (err));
445     }
446   return 0;
447 }
448
449
450 /* Read the first PEM certificate from the file FNAME.  If fname is
451    NULL the next certificate is read from stdin.  The certificate is
452    returned in an alloced buffer whose address will be returned in
453    RBUF and its length in RBUFLEN.  */
454 static gpg_error_t
455 read_pem_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
456 {
457   FILE *fp;
458   int c;
459   int pos;
460   int value;
461   unsigned char *buf;
462   size_t bufsize, buflen;
463   enum {
464     s_init, s_idle, s_lfseen, s_begin,
465     s_b64_0, s_b64_1, s_b64_2, s_b64_3,
466     s_waitend
467   } state = s_init;
468
469   init_asctobin ();
470
471   fp = fname? fopen (fname, "r") : stdin;
472   if (!fp)
473     return gpg_error_from_errno (errno);
474
475   pos = 0;
476   value = 0;
477   bufsize = 8192;
478   buf = xmalloc (bufsize);
479   buflen = 0;
480   while ((c=getc (fp)) != EOF)
481     {
482       int escaped_c = 0;
483
484       if (opt.escaped_pem)
485         {
486           if (c == '%')
487             {
488               char tmp[2];
489               if ((c = getc(fp)) == EOF)
490                 break;
491               tmp[0] = c;
492               if ((c = getc(fp)) == EOF)
493                 break;
494               tmp[1] = c;
495               if (!hexdigitp (tmp) || !hexdigitp (tmp+1))
496                 {
497                   log_error ("invalid percent escape sequence\n");
498                   state = s_idle; /* Force an error. */
499                   /* Skip to end of line.  */
500                   while ( (c=getc (fp)) != EOF && c != '\n')
501                     ;
502                   goto ready;
503                 }
504               c = xtoi_2 (tmp);
505               escaped_c = 1;
506             }
507           else if (c == '\n')
508             goto ready; /* Ready.  */
509         }
510       switch (state)
511         {
512         case s_idle:
513           if (c == '\n')
514             {
515               state = s_lfseen;
516               pos = 0;
517             }
518           break;
519         case s_init:
520           state = s_lfseen;
521         case s_lfseen:
522           if (c != "-----BEGIN "[pos])
523             state = s_idle;
524           else if (pos == 10)
525             state = s_begin;
526           else
527             pos++;
528           break;
529         case s_begin:
530           if (c == '\n')
531             state = s_b64_0;
532           break;
533         case s_b64_0:
534         case s_b64_1:
535         case s_b64_2:
536         case s_b64_3:
537           {
538             if (buflen >= bufsize)
539               {
540                 bufsize += 8192;
541                 buf = xrealloc (buf, bufsize);
542               }
543
544             if (c == '-')
545               state = s_waitend;
546             else if ((c = asctobin[c & 0xff]) == 255 )
547               ; /* Just skip invalid base64 characters. */
548             else if (state == s_b64_0)
549               {
550                 value = c << 2;
551                 state = s_b64_1;
552               }
553             else if (state == s_b64_1)
554               {
555                 value |= (c>>4)&3;
556                 buf[buflen++] = value;
557                 value = (c<<4)&0xf0;
558                 state = s_b64_2;
559               }
560             else if (state == s_b64_2)
561               {
562                 value |= (c>>2)&15;
563                 buf[buflen++] = value;
564                 value = (c<<6)&0xc0;
565                 state = s_b64_3;
566               }
567             else
568               {
569                 value |= c&0x3f;
570                 buf[buflen++] = value;
571                 state = s_b64_0;
572               }
573           }
574           break;
575         case s_waitend:
576           /* Note that we do not check that the base64 decoder has
577              been left in the expected state.  We assume that the PEM
578              header is just fine.  However we need to wait for the
579              real LF and not a trailing percent escaped one. */
580           if (c== '\n' && !escaped_c)
581             goto ready;
582           break;
583         default:
584           BUG();
585         }
586     }
587  ready:
588   if (fname)
589     fclose (fp);
590
591   if (state == s_init && c == EOF)
592     {
593       xfree (buf);
594       return gpg_error (GPG_ERR_EOF);
595     }
596   else if (state != s_waitend)
597     {
598       log_error ("no certificate or invalid encoded\n");
599       xfree (buf);
600       return gpg_error (GPG_ERR_INV_ARMOR);
601     }
602
603   *rbuf = buf;
604   *rbuflen = buflen;
605   return 0;
606 }
607
608 /* Read a binary certificate from the file FNAME.  If fname is NULL the
609    file is read from stdin.  The certificate is returned in an alloced
610    buffer whose address will be returned in RBUF and its length in
611    RBUFLEN.  */
612 static gpg_error_t
613 read_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
614 {
615   gpg_error_t err;
616   FILE *fp;
617   unsigned char *buf;
618   size_t nread, bufsize, buflen;
619
620   if (opt.pem)
621     return read_pem_certificate (fname, rbuf, rbuflen);
622   else if (fname)
623     {
624       /* A filename has been given.  Let's just assume it is in PEM
625          format and decode it, and fall back to interpreting it as
626          binary certificate if that fails.  */
627       err = read_pem_certificate (fname, rbuf, rbuflen);
628       if (! err)
629         return 0;
630     }
631
632   fp = fname? fopen (fname, "rb") : stdin;
633   if (!fp)
634     return gpg_error_from_errno (errno);
635
636   buf = NULL;
637   bufsize = buflen = 0;
638 #define NCHUNK 8192
639   do
640     {
641       bufsize += NCHUNK;
642       if (!buf)
643         buf = xmalloc (bufsize);
644       else
645         buf = xrealloc (buf, bufsize);
646
647       nread = fread (buf+buflen, 1, NCHUNK, fp);
648       if (nread < NCHUNK && ferror (fp))
649         {
650           err = gpg_error_from_errno (errno);
651           xfree (buf);
652           if (fname)
653             fclose (fp);
654           return err;
655         }
656       buflen += nread;
657     }
658   while (nread == NCHUNK);
659 #undef NCHUNK
660   if (fname)
661     fclose (fp);
662   *rbuf = buf;
663   *rbuflen = buflen;
664   return 0;
665 }
666
667
668 /* Callback for the inquire fiunction to send back the certificate.  */
669 static gpg_error_t
670 inq_cert (void *opaque, const char *line)
671 {
672   struct inq_cert_parm_s *parm = opaque;
673   gpg_error_t err;
674
675   if (!strncmp (line, "TARGETCERT", 10) && (line[10] == ' ' || !line[10]))
676     {
677       err = assuan_send_data (parm->ctx, parm->cert, parm->certlen);
678     }
679   else if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
680     {
681       /* We don't support this but dirmngr might ask for it.  So
682          simply ignore it by sending back and empty value. */
683       err = assuan_send_data (parm->ctx, NULL, 0);
684     }
685   else if (!strncmp (line, "SENDCERT_SKI", 12)
686            && (line[12]==' ' || !line[12]))
687     {
688       /* We don't support this but dirmngr might ask for it.  So
689          simply ignore it by sending back an empty value. */
690       err = assuan_send_data (parm->ctx, NULL, 0);
691     }
692   else if (!strncmp (line, "SENDISSUERCERT", 14)
693            && (line[14] == ' ' || !line[14]))
694     {
695       /* We don't support this but dirmngr might ask for it.  So
696          simply ignore it by sending back an empty value. */
697       err = assuan_send_data (parm->ctx, NULL, 0);
698     }
699   else
700     {
701       log_info (_("unsupported inquiry '%s'\n"), line);
702       err = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
703       /* Note that this error will let assuan_transact terminate
704          immediately instead of return the error to the caller.  It is
705          not clear whether this is the desired behaviour - it may
706          change in future. */
707     }
708
709   return err;
710 }
711
712
713 /* Check the certificate CERT,CERTLEN for validity using a CRL or OCSP.
714    Return a proper error code. */
715 static gpg_error_t
716 do_check (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
717 {
718   gpg_error_t err;
719   struct inq_cert_parm_s parm;
720
721   memset (&parm, 0, sizeof parm);
722   parm.ctx = ctx;
723   parm.cert = cert;
724   parm.certlen = certlen;
725
726   err = assuan_transact (ctx,
727                          (opt.use_ocsp && opt.force_default_responder
728                           ? "CHECKOCSP --force-default-responder"
729                           : opt.use_ocsp? "CHECKOCSP" : "CHECKCRL"),
730                          NULL, NULL, inq_cert, &parm, status_cb, NULL);
731   if (opt.verbose > 1)
732     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
733   return err;
734 }
735
736 /* Check the certificate CERT,CERTLEN for validity using a CRL or OCSP.
737    Return a proper error code. */
738 static gpg_error_t
739 do_cache (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
740 {
741   gpg_error_t err;
742   struct inq_cert_parm_s parm;
743
744   memset (&parm, 0, sizeof parm);
745   parm.ctx = ctx;
746   parm.cert = cert;
747   parm.certlen = certlen;
748
749   err = assuan_transact (ctx, "CACHECERT", NULL, NULL,
750                         inq_cert, &parm,
751                         status_cb, NULL);
752   if (opt.verbose > 1)
753     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
754   return err;
755 }
756
757 /* Check the certificate CERT,CERTLEN for validity using dirmngrs
758    internal validate feature.  Return a proper error code. */
759 static gpg_error_t
760 do_validate (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
761 {
762   gpg_error_t err;
763   struct inq_cert_parm_s parm;
764
765   memset (&parm, 0, sizeof parm);
766   parm.ctx = ctx;
767   parm.cert = cert;
768   parm.certlen = certlen;
769
770   err = assuan_transact (ctx, "VALIDATE", NULL, NULL,
771                         inq_cert, &parm,
772                         status_cb, NULL);
773   if (opt.verbose > 1)
774     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
775   return err;
776 }
777
778 /* Load a CRL into the dirmngr.  */
779 static gpg_error_t
780 do_loadcrl (assuan_context_t ctx, const char *filename)
781 {
782   gpg_error_t err;
783   const char *s;
784   char *fname, *line, *p;
785
786   if (opt.url)
787     fname = xstrdup (filename);
788   else
789     {
790 #ifdef HAVE_CANONICALIZE_FILE_NAME
791       fname = canonicalize_file_name (filename);
792       if (!fname)
793         {
794           log_error ("error canonicalizing '%s': %s\n",
795                      filename, strerror (errno));
796           return gpg_error (GPG_ERR_GENERAL);
797         }
798 #else
799       fname = xstrdup (filename);
800 #endif
801       if (*fname != '/')
802         {
803           log_error (_("absolute file name expected\n"));
804           return gpg_error (GPG_ERR_GENERAL);
805         }
806     }
807
808   line = xmalloc (8 + 6 + strlen (fname) * 3 + 1);
809   p = stpcpy (line, "LOADCRL ");
810   if (opt.url)
811     p = stpcpy (p, "--url ");
812   for (s = fname; *s; s++)
813     {
814       if (*s < ' ' || *s == '+')
815         {
816           sprintf (p, "%%%02X", *s);
817           p += 3;
818         }
819       else if (*s == ' ')
820         *p++ = '+';
821       else
822         *p++ = *s;
823         }
824   *p = 0;
825
826   err = assuan_transact (ctx, line, NULL, NULL,
827                         NULL, NULL,
828                         status_cb, NULL);
829   if (opt.verbose > 1)
830     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
831   xfree (line);
832   xfree (fname);
833   return err;
834 }
835
836
837 /* Do a LDAP lookup using PATTERN and print the result in a base-64
838    encoded format.  */
839 static gpg_error_t
840 do_lookup (assuan_context_t ctx, const char *pattern)
841 {
842   gpg_error_t err;
843   const unsigned char *s;
844   char *line, *p;
845   struct b64state state;
846
847   if (opt.verbose)
848     log_info (_("looking up '%s'\n"), pattern);
849
850   err = b64enc_start (&state, stdout, NULL);
851   if (err)
852     return err;
853
854   line = xmalloc (10 + 6 + 13 + strlen (pattern)*3 + 1);
855
856   p = stpcpy (line, "LOOKUP ");
857   if (opt.url)
858     p = stpcpy (p, "--url ");
859   if (opt.local)
860     p = stpcpy (p, "--cache-only ");
861   for (s=pattern; *s; s++)
862     {
863       if (*s < ' ' || *s == '+')
864         {
865           sprintf (p, "%%%02X", *s);
866           p += 3;
867         }
868       else if (*s == ' ')
869         *p++ = '+';
870       else
871         *p++ = *s;
872     }
873   *p = 0;
874
875
876   err = assuan_transact (ctx, line,
877                          data_cb, &state,
878                          NULL, NULL,
879                          status_cb, NULL);
880   if (opt.verbose > 1)
881     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
882
883   err = b64enc_finish (&state);
884
885   xfree (line);
886   return err;
887 }
888
889 /* The body of an endless loop: Read a line from stdin, retrieve the
890    certificate from it, validate it and print "ERR" or "OK" to stdout.
891    Continue.  */
892 static gpg_error_t
893 squid_loop_body (assuan_context_t ctx)
894 {
895   gpg_error_t err;
896   unsigned char *certbuf;
897   size_t certbuflen = 0;
898
899   err = read_pem_certificate (NULL, &certbuf, &certbuflen);
900   if (gpg_err_code (err) == GPG_ERR_EOF)
901     return err;
902   if (err)
903     {
904       log_error (_("error reading certificate from stdin: %s\n"),
905                  gpg_strerror (err));
906       puts ("ERROR");
907       return 0;
908     }
909
910   err = do_check (ctx, certbuf, certbuflen);
911   xfree (certbuf);
912   if (!err)
913     {
914       if (opt.verbose)
915         log_info (_("certificate is valid\n"));
916       puts ("OK");
917     }
918   else
919     {
920       if (!opt.quiet)
921         {
922           if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED )
923             log_info (_("certificate has been revoked\n"));
924           else
925             log_error (_("certificate check failed: %s\n"),
926                        gpg_strerror (err));
927         }
928       puts ("ERROR");
929     }
930
931   fflush (stdout);
932
933   return 0;
934 }