g10: Fix signature checking.
[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 <http://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                            default_homedir (),
302                            opt.dirmngr_program
303                              ? opt.dirmngr_program
304                              : gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR),
305                            ! cmd_ping,
306                            opt.verbose,
307                            0,
308                            NULL, NULL);
309   if (err)
310     {
311       log_error (_("can't connect to the dirmngr: %s\n"), gpg_strerror (err));
312       exit (2);
313     }
314
315   if (cmd_ping)
316     ;
317   else if (cmd_squid_mode)
318     {
319       while (!(err = squid_loop_body (ctx)))
320         ;
321       if (gpg_err_code (err) == GPG_ERR_EOF)
322         err = 0;
323     }
324   else if (cmd_lookup)
325     {
326       int last_err = 0;
327
328       for (; argc; argc--, argv++)
329         {
330           err = do_lookup (ctx, *argv);
331           if (err)
332             {
333               log_error (_("lookup failed: %s\n"), gpg_strerror (err));
334               last_err = err;
335             }
336         }
337       err = last_err;
338     }
339   else if (cmd_loadcrl)
340     {
341       int last_err = 0;
342
343       for (; argc; argc--, argv++)
344         {
345           err = do_loadcrl (ctx, *argv);
346           if (err)
347             {
348               log_error (_("loading CRL '%s' failed: %s\n"),
349                          *argv, gpg_strerror (err));
350               last_err = err;
351             }
352         }
353       err = last_err;
354     }
355   else if (cmd_cache_cert)
356     {
357       err = do_cache (ctx, certbuf, certbuflen);
358       xfree (certbuf);
359     }
360   else if (cmd_validate)
361     {
362       err = do_validate (ctx, certbuf, certbuflen);
363       xfree (certbuf);
364     }
365   else
366     {
367       err = do_check (ctx, certbuf, certbuflen);
368       xfree (certbuf);
369     }
370
371   assuan_release (ctx);
372
373   if (cmd_ping)
374     {
375       if (!opt.quiet)
376         log_info (_("a dirmngr daemon is up and running\n"));
377       return 0;
378     }
379   else if (cmd_lookup|| cmd_loadcrl || cmd_squid_mode)
380     return err? 1:0;
381   else if (cmd_cache_cert)
382     {
383       if (err && gpg_err_code (err) == GPG_ERR_DUP_VALUE )
384         {
385           if (!opt.quiet)
386             log_info (_("certificate already cached\n"));
387         }
388       else if (err)
389         {
390           log_error (_("error caching certificate: %s\n"),
391                      gpg_strerror (err));
392           return 1;
393         }
394       return 0;
395     }
396   else if (cmd_validate && err)
397     {
398       log_error (_("validation of certificate failed: %s\n"),
399                  gpg_strerror (err));
400       return 1;
401     }
402   else if (!err)
403     {
404       if (!opt.quiet)
405         log_info (_("certificate is valid\n"));
406       return 0;
407     }
408   else if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED )
409     {
410       if (!opt.quiet)
411         log_info (_("certificate has been revoked\n"));
412       return 1;
413     }
414   else
415     {
416       log_error (_("certificate check failed: %s\n"), gpg_strerror (err));
417       return 2;
418     }
419 }
420
421
422 /* Print status line from the assuan protocol.  */
423 static gpg_error_t
424 status_cb (void *opaque, const char *line)
425 {
426   (void)opaque;
427
428   if (opt.verbose > 2)
429     log_info (_("got status: '%s'\n"), line);
430   return 0;
431 }
432
433 /* Print data as retrieved by the lookup function.  */
434 static gpg_error_t
435 data_cb (void *opaque, const void *buffer, size_t length)
436 {
437   gpg_error_t err;
438   struct b64state *state = opaque;
439
440   if (buffer)
441     {
442       err = b64enc_write (state, buffer, length);
443       if (err)
444         log_error (_("error writing base64 encoding: %s\n"),
445                    gpg_strerror (err));
446     }
447   return 0;
448 }
449
450
451 /* Read the first PEM certificate from the file FNAME.  If fname is
452    NULL the next certificate is read from stdin.  The certificate is
453    returned in an alloced buffer whose address will be returned in
454    RBUF and its length in RBUFLEN.  */
455 static gpg_error_t
456 read_pem_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
457 {
458   FILE *fp;
459   int c;
460   int pos;
461   int value;
462   unsigned char *buf;
463   size_t bufsize, buflen;
464   enum {
465     s_init, s_idle, s_lfseen, s_begin,
466     s_b64_0, s_b64_1, s_b64_2, s_b64_3,
467     s_waitend
468   } state = s_init;
469
470   init_asctobin ();
471
472   fp = fname? fopen (fname, "r") : stdin;
473   if (!fp)
474     return gpg_error_from_errno (errno);
475
476   pos = 0;
477   value = 0;
478   bufsize = 8192;
479   buf = xmalloc (bufsize);
480   buflen = 0;
481   while ((c=getc (fp)) != EOF)
482     {
483       int escaped_c = 0;
484
485       if (opt.escaped_pem)
486         {
487           if (c == '%')
488             {
489               char tmp[2];
490               if ((c = getc(fp)) == EOF)
491                 break;
492               tmp[0] = c;
493               if ((c = getc(fp)) == EOF)
494                 break;
495               tmp[1] = c;
496               if (!hexdigitp (tmp) || !hexdigitp (tmp+1))
497                 {
498                   log_error ("invalid percent escape sequence\n");
499                   state = s_idle; /* Force an error. */
500                   /* Skip to end of line.  */
501                   while ( (c=getc (fp)) != EOF && c != '\n')
502                     ;
503                   goto ready;
504                 }
505               c = xtoi_2 (tmp);
506               escaped_c = 1;
507             }
508           else if (c == '\n')
509             goto ready; /* Ready.  */
510         }
511       switch (state)
512         {
513         case s_idle:
514           if (c == '\n')
515             {
516               state = s_lfseen;
517               pos = 0;
518             }
519           break;
520         case s_init:
521           state = s_lfseen;
522         case s_lfseen:
523           if (c != "-----BEGIN "[pos])
524             state = s_idle;
525           else if (pos == 10)
526             state = s_begin;
527           else
528             pos++;
529           break;
530         case s_begin:
531           if (c == '\n')
532             state = s_b64_0;
533           break;
534         case s_b64_0:
535         case s_b64_1:
536         case s_b64_2:
537         case s_b64_3:
538           {
539             if (buflen >= bufsize)
540               {
541                 bufsize += 8192;
542                 buf = xrealloc (buf, bufsize);
543               }
544
545             if (c == '-')
546               state = s_waitend;
547             else if ((c = asctobin[c & 0xff]) == 255 )
548               ; /* Just skip invalid base64 characters. */
549             else if (state == s_b64_0)
550               {
551                 value = c << 2;
552                 state = s_b64_1;
553               }
554             else if (state == s_b64_1)
555               {
556                 value |= (c>>4)&3;
557                 buf[buflen++] = value;
558                 value = (c<<4)&0xf0;
559                 state = s_b64_2;
560               }
561             else if (state == s_b64_2)
562               {
563                 value |= (c>>2)&15;
564                 buf[buflen++] = value;
565                 value = (c<<6)&0xc0;
566                 state = s_b64_3;
567               }
568             else
569               {
570                 value |= c&0x3f;
571                 buf[buflen++] = value;
572                 state = s_b64_0;
573               }
574           }
575           break;
576         case s_waitend:
577           /* Note that we do not check that the base64 decoder has
578              been left in the expected state.  We assume that the PEM
579              header is just fine.  However we need to wait for the
580              real LF and not a trailing percent escaped one. */
581           if (c== '\n' && !escaped_c)
582             goto ready;
583           break;
584         default:
585           BUG();
586         }
587     }
588  ready:
589   if (fname)
590     fclose (fp);
591
592   if (state == s_init && c == EOF)
593     {
594       xfree (buf);
595       return gpg_error (GPG_ERR_EOF);
596     }
597   else if (state != s_waitend)
598     {
599       log_error ("no certificate or invalid encoded\n");
600       xfree (buf);
601       return gpg_error (GPG_ERR_INV_ARMOR);
602     }
603
604   *rbuf = buf;
605   *rbuflen = buflen;
606   return 0;
607 }
608
609 /* Read a binary certificate from the file FNAME.  If fname is NULL the
610    file is read from stdin.  The certificate is returned in an alloced
611    buffer whose address will be returned in RBUF and its length in
612    RBUFLEN.  */
613 static gpg_error_t
614 read_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
615 {
616   gpg_error_t err;
617   FILE *fp;
618   unsigned char *buf;
619   size_t nread, bufsize, buflen;
620
621   if (opt.pem)
622     return read_pem_certificate (fname, rbuf, rbuflen);
623   else if (fname)
624     {
625       /* A filename has been given.  Let's just assume it is in PEM
626          format and decode it, and fall back to interpreting it as
627          binary certificate if that fails.  */
628       err = read_pem_certificate (fname, rbuf, rbuflen);
629       if (! err)
630         return 0;
631     }
632
633   fp = fname? fopen (fname, "rb") : stdin;
634   if (!fp)
635     return gpg_error_from_errno (errno);
636
637   buf = NULL;
638   bufsize = buflen = 0;
639 #define NCHUNK 8192
640   do
641     {
642       bufsize += NCHUNK;
643       if (!buf)
644         buf = xmalloc (bufsize);
645       else
646         buf = xrealloc (buf, bufsize);
647
648       nread = fread (buf+buflen, 1, NCHUNK, fp);
649       if (nread < NCHUNK && ferror (fp))
650         {
651           err = gpg_error_from_errno (errno);
652           xfree (buf);
653           if (fname)
654             fclose (fp);
655           return err;
656         }
657       buflen += nread;
658     }
659   while (nread == NCHUNK);
660 #undef NCHUNK
661   if (fname)
662     fclose (fp);
663   *rbuf = buf;
664   *rbuflen = buflen;
665   return 0;
666 }
667
668
669 /* Callback for the inquire fiunction to send back the certificate.  */
670 static gpg_error_t
671 inq_cert (void *opaque, const char *line)
672 {
673   struct inq_cert_parm_s *parm = opaque;
674   gpg_error_t err;
675
676   if (!strncmp (line, "TARGETCERT", 10) && (line[10] == ' ' || !line[10]))
677     {
678       err = assuan_send_data (parm->ctx, parm->cert, parm->certlen);
679     }
680   else if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
681     {
682       /* We don't support this but dirmngr might ask for it.  So
683          simply ignore it by sending back and empty value. */
684       err = assuan_send_data (parm->ctx, NULL, 0);
685     }
686   else if (!strncmp (line, "SENDCERT_SKI", 12)
687            && (line[12]==' ' || !line[12]))
688     {
689       /* We don't support this but dirmngr might ask for it.  So
690          simply ignore it by sending back an empty value. */
691       err = assuan_send_data (parm->ctx, NULL, 0);
692     }
693   else if (!strncmp (line, "SENDISSUERCERT", 14)
694            && (line[14] == ' ' || !line[14]))
695     {
696       /* We don't support this but dirmngr might ask for it.  So
697          simply ignore it by sending back an empty value. */
698       err = assuan_send_data (parm->ctx, NULL, 0);
699     }
700   else
701     {
702       log_info (_("unsupported inquiry '%s'\n"), line);
703       err = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
704       /* Note that this error will let assuan_transact terminate
705          immediately instead of return the error to the caller.  It is
706          not clear whether this is the desired behaviour - it may
707          change in future. */
708     }
709
710   return err;
711 }
712
713
714 /* Check the certificate CERT,CERTLEN for validity using a CRL or OCSP.
715    Return a proper error code. */
716 static gpg_error_t
717 do_check (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
718 {
719   gpg_error_t err;
720   struct inq_cert_parm_s parm;
721
722   memset (&parm, 0, sizeof parm);
723   parm.ctx = ctx;
724   parm.cert = cert;
725   parm.certlen = certlen;
726
727   err = assuan_transact (ctx,
728                          (opt.use_ocsp && opt.force_default_responder
729                           ? "CHECKOCSP --force-default-responder"
730                           : opt.use_ocsp? "CHECKOCSP" : "CHECKCRL"),
731                          NULL, NULL, inq_cert, &parm, status_cb, NULL);
732   if (opt.verbose > 1)
733     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
734   return err;
735 }
736
737 /* Check the certificate CERT,CERTLEN for validity using a CRL or OCSP.
738    Return a proper error code. */
739 static gpg_error_t
740 do_cache (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
741 {
742   gpg_error_t err;
743   struct inq_cert_parm_s parm;
744
745   memset (&parm, 0, sizeof parm);
746   parm.ctx = ctx;
747   parm.cert = cert;
748   parm.certlen = certlen;
749
750   err = assuan_transact (ctx, "CACHECERT", NULL, NULL,
751                         inq_cert, &parm,
752                         status_cb, NULL);
753   if (opt.verbose > 1)
754     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
755   return err;
756 }
757
758 /* Check the certificate CERT,CERTLEN for validity using dirmngrs
759    internal validate feature.  Return a proper error code. */
760 static gpg_error_t
761 do_validate (assuan_context_t ctx, const unsigned char *cert, size_t certlen)
762 {
763   gpg_error_t err;
764   struct inq_cert_parm_s parm;
765
766   memset (&parm, 0, sizeof parm);
767   parm.ctx = ctx;
768   parm.cert = cert;
769   parm.certlen = certlen;
770
771   err = assuan_transact (ctx, "VALIDATE", NULL, NULL,
772                         inq_cert, &parm,
773                         status_cb, NULL);
774   if (opt.verbose > 1)
775     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
776   return err;
777 }
778
779 /* Load a CRL into the dirmngr.  */
780 static gpg_error_t
781 do_loadcrl (assuan_context_t ctx, const char *filename)
782 {
783   gpg_error_t err;
784   const char *s;
785   char *fname, *line, *p;
786
787   if (opt.url)
788     fname = xstrdup (filename);
789   else
790     {
791 #ifdef HAVE_CANONICALIZE_FILE_NAME
792       fname = canonicalize_file_name (filename);
793       if (!fname)
794         {
795           log_error ("error canonicalizing '%s': %s\n",
796                      filename, strerror (errno));
797           return gpg_error (GPG_ERR_GENERAL);
798         }
799 #else
800       fname = xstrdup (filename);
801 #endif
802       if (*fname != '/')
803         {
804           log_error (_("absolute file name expected\n"));
805           return gpg_error (GPG_ERR_GENERAL);
806         }
807     }
808
809   line = xmalloc (8 + 6 + strlen (fname) * 3 + 1);
810   p = stpcpy (line, "LOADCRL ");
811   if (opt.url)
812     p = stpcpy (p, "--url ");
813   for (s = fname; *s; s++)
814     {
815       if (*s < ' ' || *s == '+')
816         {
817           sprintf (p, "%%%02X", *s);
818           p += 3;
819         }
820       else if (*s == ' ')
821         *p++ = '+';
822       else
823         *p++ = *s;
824         }
825   *p = 0;
826
827   err = assuan_transact (ctx, line, NULL, NULL,
828                         NULL, NULL,
829                         status_cb, NULL);
830   if (opt.verbose > 1)
831     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
832   xfree (line);
833   xfree (fname);
834   return err;
835 }
836
837
838 /* Do a LDAP lookup using PATTERN and print the result in a base-64
839    encoded format.  */
840 static gpg_error_t
841 do_lookup (assuan_context_t ctx, const char *pattern)
842 {
843   gpg_error_t err;
844   const unsigned char *s;
845   char *line, *p;
846   struct b64state state;
847
848   if (opt.verbose)
849     log_info (_("looking up '%s'\n"), pattern);
850
851   err = b64enc_start (&state, stdout, NULL);
852   if (err)
853     return err;
854
855   line = xmalloc (10 + 6 + 13 + strlen (pattern)*3 + 1);
856
857   p = stpcpy (line, "LOOKUP ");
858   if (opt.url)
859     p = stpcpy (p, "--url ");
860   if (opt.local)
861     p = stpcpy (p, "--cache-only ");
862   for (s=pattern; *s; s++)
863     {
864       if (*s < ' ' || *s == '+')
865         {
866           sprintf (p, "%%%02X", *s);
867           p += 3;
868         }
869       else if (*s == ' ')
870         *p++ = '+';
871       else
872         *p++ = *s;
873     }
874   *p = 0;
875
876
877   err = assuan_transact (ctx, line,
878                          data_cb, &state,
879                          NULL, NULL,
880                          status_cb, NULL);
881   if (opt.verbose > 1)
882     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
883
884   err = b64enc_finish (&state);
885
886   xfree (line);
887   return err;
888 }
889
890 /* The body of an endless loop: Read a line from stdin, retrieve the
891    certificate from it, validate it and print "ERR" or "OK" to stdout.
892    Continue.  */
893 static gpg_error_t
894 squid_loop_body (assuan_context_t ctx)
895 {
896   gpg_error_t err;
897   unsigned char *certbuf;
898   size_t certbuflen = 0;
899
900   err = read_pem_certificate (NULL, &certbuf, &certbuflen);
901   if (gpg_err_code (err) == GPG_ERR_EOF)
902     return err;
903   if (err)
904     {
905       log_error (_("error reading certificate from stdin: %s\n"),
906                  gpg_strerror (err));
907       puts ("ERROR");
908       return 0;
909     }
910
911   err = do_check (ctx, certbuf, certbuflen);
912   xfree (certbuf);
913   if (!err)
914     {
915       if (opt.verbose)
916         log_info (_("certificate is valid\n"));
917       puts ("OK");
918     }
919   else
920     {
921       if (!opt.quiet)
922         {
923           if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED )
924             log_info (_("certificate has been revoked\n"));
925           else
926             log_error (_("certificate check failed: %s\n"),
927                        gpg_strerror (err));
928         }
929       puts ("ERROR");
930     }
931
932   fflush (stdout);
933
934   return 0;
935 }