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