LCOV - code coverage report
Current view: top level - dirmngr - dirmngr-client.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 393 0.0 %
Date: 2016-09-12 12:29:17 Functions: 0 14 0.0 %

          Line data    Source code
       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           0 : init_asctobin (void)
     122             : {
     123             :   static int initialized;
     124             :   int i;
     125             :   unsigned char *s;
     126             : 
     127           0 :   if (initialized)
     128           0 :     return;
     129           0 :   initialized = 1;
     130             : 
     131           0 :   for (i=0; i < 256; i++ )
     132           0 :     asctobin[i] = 255; /* Used to detect invalid characters. */
     133           0 :   for (s=bintoasc, i=0; *s; s++, i++)
     134           0 :     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           0 : my_strusage (int level)
     156             : {
     157             :   const char *p;
     158             : 
     159           0 :   switch(level)
     160             :     {
     161           0 :     case 11: p = "dirmngr-client (@GNUPG@)";
     162           0 :       break;
     163           0 :     case 13: p = VERSION; break;
     164           0 :     case 17: p = PRINTABLE_OS_NAME; break;
     165           0 :     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
     166           0 :     case 49: p = PACKAGE_BUGREPORT; break;
     167             :     case 1:
     168           0 :     case 40: p =
     169             :                  _("Usage: dirmngr-client [options] "
     170             :                    "[certfile|pattern] (-h for help)\n");
     171           0 :       break;
     172           0 :     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           0 :       break;
     178             : 
     179           0 :     default: p = NULL;
     180             :     }
     181           0 :   return p;
     182             : }
     183             : 
     184             : 
     185             : 
     186             : int
     187           0 : 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           0 :   size_t certbuflen = 0;
     194           0 :   int cmd_ping = 0;
     195           0 :   int cmd_cache_cert = 0;
     196           0 :   int cmd_validate = 0;
     197           0 :   int cmd_lookup = 0;
     198           0 :   int cmd_loadcrl = 0;
     199           0 :   int cmd_squid_mode = 0;
     200             : 
     201           0 :   early_system_init ();
     202           0 :   set_strusage (my_strusage);
     203           0 :   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           0 :   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
     218           0 :   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
     219             : 
     220             :   /* Setup I18N. */
     221           0 :   i18n_init();
     222             : 
     223             :   /* Parse the command line.  */
     224           0 :   pargs.argc = &argc;
     225           0 :   pargs.argv = &argv;
     226           0 :   pargs.flags= 1;  /* Do not remove the args. */
     227           0 :   while (arg_parse (&pargs, opts) )
     228             :     {
     229           0 :       switch (pargs.r_opt)
     230             :         {
     231           0 :         case oVerbose: opt.verbose++; break;
     232           0 :         case oQuiet: opt.quiet++; break;
     233             : 
     234           0 :         case oOCSP: opt.use_ocsp++; break;
     235           0 :         case oPing: cmd_ping = 1; break;
     236           0 :         case oCacheCert: cmd_cache_cert = 1; break;
     237           0 :         case oValidate: cmd_validate = 1; break;
     238           0 :         case oLookup: cmd_lookup = 1; break;
     239           0 :         case oUrl: opt.url = 1; break;
     240           0 :         case oLocal: opt.local = 1; break;
     241           0 :         case oLoadCRL: cmd_loadcrl = 1; break;
     242           0 :         case oPEM: opt.pem = 1; break;
     243             :         case oSquidMode:
     244           0 :           opt.pem = 1;
     245           0 :           opt.escaped_pem = 1;
     246           0 :           cmd_squid_mode = 1;
     247           0 :           break;
     248           0 :         case oForceDefaultResponder: opt.force_default_responder = 1; break;
     249             : 
     250           0 :         default : pargs.err = 2; break;
     251             :         }
     252             :     }
     253           0 :   if (log_get_errorcount (0))
     254           0 :     exit (2);
     255             : 
     256           0 :   if (cmd_ping)
     257           0 :     err = 0;
     258           0 :   else if (cmd_lookup || cmd_loadcrl)
     259             :     {
     260           0 :       if (!argc)
     261           0 :         usage (1);
     262           0 :       err = 0;
     263             :     }
     264           0 :   else if (cmd_squid_mode)
     265             :     {
     266           0 :       err = 0;
     267           0 :       if (argc)
     268           0 :         usage (1);
     269             :     }
     270           0 :   else if (!argc)
     271             :     {
     272           0 :       err = read_certificate (NULL, &certbuf, &certbuflen);
     273           0 :       if (err)
     274           0 :         log_error (_("error reading certificate from stdin: %s\n"),
     275             :                    gpg_strerror (err));
     276             :     }
     277           0 :   else if (argc == 1)
     278             :     {
     279           0 :       err = read_certificate (*argv, &certbuf, &certbuflen);
     280           0 :       if (err)
     281           0 :         log_error (_("error reading certificate from '%s': %s\n"),
     282             :                    *argv, gpg_strerror (err));
     283             :     }
     284             :   else
     285             :     {
     286           0 :       err = 0;
     287           0 :       usage (1);
     288             :     }
     289             : 
     290           0 :   if (log_get_errorcount (0))
     291           0 :     exit (2);
     292             : 
     293           0 :   if (certbuflen > 20000)
     294             :     {
     295           0 :       log_error (_("certificate too large to make any sense\n"));
     296           0 :       exit (2);
     297             :     }
     298             : 
     299           0 :   err = start_new_dirmngr (&ctx,
     300             :                            GPG_ERR_SOURCE_DEFAULT,
     301           0 :                            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           0 :   if (err)
     309             :     {
     310           0 :       log_error (_("can't connect to the dirmngr: %s\n"), gpg_strerror (err));
     311           0 :       exit (2);
     312             :     }
     313             : 
     314           0 :   if (cmd_ping)
     315             :     ;
     316           0 :   else if (cmd_squid_mode)
     317             :     {
     318           0 :       while (!(err = squid_loop_body (ctx)))
     319             :         ;
     320           0 :       if (gpg_err_code (err) == GPG_ERR_EOF)
     321           0 :         err = 0;
     322             :     }
     323           0 :   else if (cmd_lookup)
     324             :     {
     325           0 :       int last_err = 0;
     326             : 
     327           0 :       for (; argc; argc--, argv++)
     328             :         {
     329           0 :           err = do_lookup (ctx, *argv);
     330           0 :           if (err)
     331             :             {
     332           0 :               log_error (_("lookup failed: %s\n"), gpg_strerror (err));
     333           0 :               last_err = err;
     334             :             }
     335             :         }
     336           0 :       err = last_err;
     337             :     }
     338           0 :   else if (cmd_loadcrl)
     339             :     {
     340           0 :       int last_err = 0;
     341             : 
     342           0 :       for (; argc; argc--, argv++)
     343             :         {
     344           0 :           err = do_loadcrl (ctx, *argv);
     345           0 :           if (err)
     346             :             {
     347           0 :               log_error (_("loading CRL '%s' failed: %s\n"),
     348             :                          *argv, gpg_strerror (err));
     349           0 :               last_err = err;
     350             :             }
     351             :         }
     352           0 :       err = last_err;
     353             :     }
     354           0 :   else if (cmd_cache_cert)
     355             :     {
     356           0 :       err = do_cache (ctx, certbuf, certbuflen);
     357           0 :       xfree (certbuf);
     358             :     }
     359           0 :   else if (cmd_validate)
     360             :     {
     361           0 :       err = do_validate (ctx, certbuf, certbuflen);
     362           0 :       xfree (certbuf);
     363             :     }
     364             :   else
     365             :     {
     366           0 :       err = do_check (ctx, certbuf, certbuflen);
     367           0 :       xfree (certbuf);
     368             :     }
     369             : 
     370           0 :   assuan_release (ctx);
     371             : 
     372           0 :   if (cmd_ping)
     373             :     {
     374           0 :       if (!opt.quiet)
     375           0 :         log_info (_("a dirmngr daemon is up and running\n"));
     376           0 :       return 0;
     377             :     }
     378           0 :   else if (cmd_lookup|| cmd_loadcrl || cmd_squid_mode)
     379           0 :     return err? 1:0;
     380           0 :   else if (cmd_cache_cert)
     381             :     {
     382           0 :       if (err && gpg_err_code (err) == GPG_ERR_DUP_VALUE )
     383             :         {
     384           0 :           if (!opt.quiet)
     385           0 :             log_info (_("certificate already cached\n"));
     386             :         }
     387           0 :       else if (err)
     388             :         {
     389           0 :           log_error (_("error caching certificate: %s\n"),
     390             :                      gpg_strerror (err));
     391           0 :           return 1;
     392             :         }
     393           0 :       return 0;
     394             :     }
     395           0 :   else if (cmd_validate && err)
     396             :     {
     397           0 :       log_error (_("validation of certificate failed: %s\n"),
     398             :                  gpg_strerror (err));
     399           0 :       return 1;
     400             :     }
     401           0 :   else if (!err)
     402             :     {
     403           0 :       if (!opt.quiet)
     404           0 :         log_info (_("certificate is valid\n"));
     405           0 :       return 0;
     406             :     }
     407           0 :   else if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED )
     408             :     {
     409           0 :       if (!opt.quiet)
     410           0 :         log_info (_("certificate has been revoked\n"));
     411           0 :       return 1;
     412             :     }
     413             :   else
     414             :     {
     415           0 :       log_error (_("certificate check failed: %s\n"), gpg_strerror (err));
     416           0 :       return 2;
     417             :     }
     418             : }
     419             : 
     420             : 
     421             : /* Print status line from the assuan protocol.  */
     422             : static gpg_error_t
     423           0 : status_cb (void *opaque, const char *line)
     424             : {
     425             :   (void)opaque;
     426             : 
     427           0 :   if (opt.verbose > 2)
     428           0 :     log_info (_("got status: '%s'\n"), line);
     429           0 :   return 0;
     430             : }
     431             : 
     432             : /* Print data as retrieved by the lookup function.  */
     433             : static gpg_error_t
     434           0 : data_cb (void *opaque, const void *buffer, size_t length)
     435             : {
     436             :   gpg_error_t err;
     437           0 :   struct b64state *state = opaque;
     438             : 
     439           0 :   if (buffer)
     440             :     {
     441           0 :       err = b64enc_write (state, buffer, length);
     442           0 :       if (err)
     443           0 :         log_error (_("error writing base64 encoding: %s\n"),
     444             :                    gpg_strerror (err));
     445             :     }
     446           0 :   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           0 : 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           0 :   } state = s_init;
     468             : 
     469           0 :   init_asctobin ();
     470             : 
     471           0 :   fp = fname? fopen (fname, "r") : stdin;
     472           0 :   if (!fp)
     473           0 :     return gpg_error_from_errno (errno);
     474             : 
     475           0 :   pos = 0;
     476           0 :   value = 0;
     477           0 :   bufsize = 8192;
     478           0 :   buf = xmalloc (bufsize);
     479           0 :   buflen = 0;
     480           0 :   while ((c=getc (fp)) != EOF)
     481             :     {
     482           0 :       int escaped_c = 0;
     483             : 
     484           0 :       if (opt.escaped_pem)
     485             :         {
     486           0 :           if (c == '%')
     487             :             {
     488             :               char tmp[2];
     489           0 :               if ((c = getc(fp)) == EOF)
     490           0 :                 break;
     491           0 :               tmp[0] = c;
     492           0 :               if ((c = getc(fp)) == EOF)
     493           0 :                 break;
     494           0 :               tmp[1] = c;
     495           0 :               if (!hexdigitp (tmp) || !hexdigitp (tmp+1))
     496             :                 {
     497           0 :                   log_error ("invalid percent escape sequence\n");
     498           0 :                   state = s_idle; /* Force an error. */
     499             :                   /* Skip to end of line.  */
     500           0 :                   while ( (c=getc (fp)) != EOF && c != '\n')
     501             :                     ;
     502           0 :                   goto ready;
     503             :                 }
     504           0 :               c = xtoi_2 (tmp);
     505           0 :               escaped_c = 1;
     506             :             }
     507           0 :           else if (c == '\n')
     508           0 :             goto ready; /* Ready.  */
     509             :         }
     510           0 :       switch (state)
     511             :         {
     512             :         case s_idle:
     513           0 :           if (c == '\n')
     514             :             {
     515           0 :               state = s_lfseen;
     516           0 :               pos = 0;
     517             :             }
     518           0 :           break;
     519             :         case s_init:
     520           0 :           state = s_lfseen;
     521             :         case s_lfseen:
     522           0 :           if (c != "-----BEGIN "[pos])
     523           0 :             state = s_idle;
     524           0 :           else if (pos == 10)
     525           0 :             state = s_begin;
     526             :           else
     527           0 :             pos++;
     528           0 :           break;
     529             :         case s_begin:
     530           0 :           if (c == '\n')
     531           0 :             state = s_b64_0;
     532           0 :           break;
     533             :         case s_b64_0:
     534             :         case s_b64_1:
     535             :         case s_b64_2:
     536             :         case s_b64_3:
     537             :           {
     538           0 :             if (buflen >= bufsize)
     539             :               {
     540           0 :                 bufsize += 8192;
     541           0 :                 buf = xrealloc (buf, bufsize);
     542             :               }
     543             : 
     544           0 :             if (c == '-')
     545           0 :               state = s_waitend;
     546           0 :             else if ((c = asctobin[c & 0xff]) == 255 )
     547             :               ; /* Just skip invalid base64 characters. */
     548           0 :             else if (state == s_b64_0)
     549             :               {
     550           0 :                 value = c << 2;
     551           0 :                 state = s_b64_1;
     552             :               }
     553           0 :             else if (state == s_b64_1)
     554             :               {
     555           0 :                 value |= (c>>4)&3;
     556           0 :                 buf[buflen++] = value;
     557           0 :                 value = (c<<4)&0xf0;
     558           0 :                 state = s_b64_2;
     559             :               }
     560           0 :             else if (state == s_b64_2)
     561             :               {
     562           0 :                 value |= (c>>2)&15;
     563           0 :                 buf[buflen++] = value;
     564           0 :                 value = (c<<6)&0xc0;
     565           0 :                 state = s_b64_3;
     566             :               }
     567             :             else
     568             :               {
     569           0 :                 value |= c&0x3f;
     570           0 :                 buf[buflen++] = value;
     571           0 :                 state = s_b64_0;
     572             :               }
     573             :           }
     574           0 :           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           0 :           if (c== '\n' && !escaped_c)
     581           0 :             goto ready;
     582           0 :           break;
     583             :         default:
     584           0 :           BUG();
     585             :         }
     586             :     }
     587             :  ready:
     588           0 :   if (fname)
     589           0 :     fclose (fp);
     590             : 
     591           0 :   if (state == s_init && c == EOF)
     592             :     {
     593           0 :       xfree (buf);
     594           0 :       return gpg_error (GPG_ERR_EOF);
     595             :     }
     596           0 :   else if (state != s_waitend)
     597             :     {
     598           0 :       log_error ("no certificate or invalid encoded\n");
     599           0 :       xfree (buf);
     600           0 :       return gpg_error (GPG_ERR_INV_ARMOR);
     601             :     }
     602             : 
     603           0 :   *rbuf = buf;
     604           0 :   *rbuflen = buflen;
     605           0 :   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           0 : 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           0 :   if (opt.pem)
     621           0 :     return read_pem_certificate (fname, rbuf, rbuflen);
     622           0 :   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           0 :       err = read_pem_certificate (fname, rbuf, rbuflen);
     628           0 :       if (! err)
     629           0 :         return 0;
     630             :     }
     631             : 
     632           0 :   fp = fname? fopen (fname, "rb") : stdin;
     633           0 :   if (!fp)
     634           0 :     return gpg_error_from_errno (errno);
     635             : 
     636           0 :   buf = NULL;
     637           0 :   bufsize = buflen = 0;
     638             : #define NCHUNK 8192
     639             :   do
     640             :     {
     641           0 :       bufsize += NCHUNK;
     642           0 :       if (!buf)
     643           0 :         buf = xmalloc (bufsize);
     644             :       else
     645           0 :         buf = xrealloc (buf, bufsize);
     646             : 
     647           0 :       nread = fread (buf+buflen, 1, NCHUNK, fp);
     648           0 :       if (nread < NCHUNK && ferror (fp))
     649             :         {
     650           0 :           err = gpg_error_from_errno (errno);
     651           0 :           xfree (buf);
     652           0 :           if (fname)
     653           0 :             fclose (fp);
     654           0 :           return err;
     655             :         }
     656           0 :       buflen += nread;
     657             :     }
     658           0 :   while (nread == NCHUNK);
     659             : #undef NCHUNK
     660           0 :   if (fname)
     661           0 :     fclose (fp);
     662           0 :   *rbuf = buf;
     663           0 :   *rbuflen = buflen;
     664           0 :   return 0;
     665             : }
     666             : 
     667             : 
     668             : /* Callback for the inquire fiunction to send back the certificate.  */
     669             : static gpg_error_t
     670           0 : inq_cert (void *opaque, const char *line)
     671             : {
     672           0 :   struct inq_cert_parm_s *parm = opaque;
     673             :   gpg_error_t err;
     674             : 
     675           0 :   if (!strncmp (line, "TARGETCERT", 10) && (line[10] == ' ' || !line[10]))
     676             :     {
     677           0 :       err = assuan_send_data (parm->ctx, parm->cert, parm->certlen);
     678             :     }
     679           0 :   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           0 :       err = assuan_send_data (parm->ctx, NULL, 0);
     684             :     }
     685           0 :   else if (!strncmp (line, "SENDCERT_SKI", 12)
     686           0 :            && (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           0 :       err = assuan_send_data (parm->ctx, NULL, 0);
     691             :     }
     692           0 :   else if (!strncmp (line, "SENDISSUERCERT", 14)
     693           0 :            && (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           0 :       err = assuan_send_data (parm->ctx, NULL, 0);
     698             :     }
     699             :   else
     700             :     {
     701           0 :       log_info (_("unsupported inquiry '%s'\n"), line);
     702           0 :       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           0 :   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           0 : 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           0 :   memset (&parm, 0, sizeof parm);
     722           0 :   parm.ctx = ctx;
     723           0 :   parm.cert = cert;
     724           0 :   parm.certlen = certlen;
     725             : 
     726           0 :   err = assuan_transact (ctx,
     727           0 :                          (opt.use_ocsp && opt.force_default_responder
     728             :                           ? "CHECKOCSP --force-default-responder"
     729           0 :                           : opt.use_ocsp? "CHECKOCSP" : "CHECKCRL"),
     730             :                          NULL, NULL, inq_cert, &parm, status_cb, NULL);
     731           0 :   if (opt.verbose > 1)
     732           0 :     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
     733           0 :   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           0 : 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           0 :   memset (&parm, 0, sizeof parm);
     745           0 :   parm.ctx = ctx;
     746           0 :   parm.cert = cert;
     747           0 :   parm.certlen = certlen;
     748             : 
     749           0 :   err = assuan_transact (ctx, "CACHECERT", NULL, NULL,
     750             :                         inq_cert, &parm,
     751             :                         status_cb, NULL);
     752           0 :   if (opt.verbose > 1)
     753           0 :     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
     754           0 :   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           0 : 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           0 :   memset (&parm, 0, sizeof parm);
     766           0 :   parm.ctx = ctx;
     767           0 :   parm.cert = cert;
     768           0 :   parm.certlen = certlen;
     769             : 
     770           0 :   err = assuan_transact (ctx, "VALIDATE", NULL, NULL,
     771             :                         inq_cert, &parm,
     772             :                         status_cb, NULL);
     773           0 :   if (opt.verbose > 1)
     774           0 :     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
     775           0 :   return err;
     776             : }
     777             : 
     778             : /* Load a CRL into the dirmngr.  */
     779             : static gpg_error_t
     780           0 : 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           0 :   if (opt.url)
     787           0 :     fname = xstrdup (filename);
     788             :   else
     789             :     {
     790             : #ifdef HAVE_CANONICALIZE_FILE_NAME
     791           0 :       fname = canonicalize_file_name (filename);
     792           0 :       if (!fname)
     793             :         {
     794           0 :           log_error ("error canonicalizing '%s': %s\n",
     795           0 :                      filename, strerror (errno));
     796           0 :           return gpg_error (GPG_ERR_GENERAL);
     797             :         }
     798             : #else
     799             :       fname = xstrdup (filename);
     800             : #endif
     801           0 :       if (*fname != '/')
     802             :         {
     803           0 :           log_error (_("absolute file name expected\n"));
     804           0 :           return gpg_error (GPG_ERR_GENERAL);
     805             :         }
     806             :     }
     807             : 
     808           0 :   line = xmalloc (8 + 6 + strlen (fname) * 3 + 1);
     809           0 :   p = stpcpy (line, "LOADCRL ");
     810           0 :   if (opt.url)
     811           0 :     p = stpcpy (p, "--url ");
     812           0 :   for (s = fname; *s; s++)
     813             :     {
     814           0 :       if (*s < ' ' || *s == '+')
     815             :         {
     816           0 :           sprintf (p, "%%%02X", *s);
     817           0 :           p += 3;
     818             :         }
     819           0 :       else if (*s == ' ')
     820           0 :         *p++ = '+';
     821             :       else
     822           0 :         *p++ = *s;
     823             :         }
     824           0 :   *p = 0;
     825             : 
     826           0 :   err = assuan_transact (ctx, line, NULL, NULL,
     827             :                         NULL, NULL,
     828             :                         status_cb, NULL);
     829           0 :   if (opt.verbose > 1)
     830           0 :     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
     831           0 :   xfree (line);
     832           0 :   xfree (fname);
     833           0 :   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           0 : 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           0 :   if (opt.verbose)
     848           0 :     log_info (_("looking up '%s'\n"), pattern);
     849             : 
     850           0 :   err = b64enc_start (&state, stdout, NULL);
     851           0 :   if (err)
     852           0 :     return err;
     853             : 
     854           0 :   line = xmalloc (10 + 6 + 13 + strlen (pattern)*3 + 1);
     855             : 
     856           0 :   p = stpcpy (line, "LOOKUP ");
     857           0 :   if (opt.url)
     858           0 :     p = stpcpy (p, "--url ");
     859           0 :   if (opt.local)
     860           0 :     p = stpcpy (p, "--cache-only ");
     861           0 :   for (s=pattern; *s; s++)
     862             :     {
     863           0 :       if (*s < ' ' || *s == '+')
     864             :         {
     865           0 :           sprintf (p, "%%%02X", *s);
     866           0 :           p += 3;
     867             :         }
     868           0 :       else if (*s == ' ')
     869           0 :         *p++ = '+';
     870             :       else
     871           0 :         *p++ = *s;
     872             :     }
     873           0 :   *p = 0;
     874             : 
     875             : 
     876           0 :   err = assuan_transact (ctx, line,
     877             :                          data_cb, &state,
     878             :                          NULL, NULL,
     879             :                          status_cb, NULL);
     880           0 :   if (opt.verbose > 1)
     881           0 :     log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
     882             : 
     883           0 :   err = b64enc_finish (&state);
     884             : 
     885           0 :   xfree (line);
     886           0 :   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           0 : squid_loop_body (assuan_context_t ctx)
     894             : {
     895             :   gpg_error_t err;
     896             :   unsigned char *certbuf;
     897           0 :   size_t certbuflen = 0;
     898             : 
     899           0 :   err = read_pem_certificate (NULL, &certbuf, &certbuflen);
     900           0 :   if (gpg_err_code (err) == GPG_ERR_EOF)
     901           0 :     return err;
     902           0 :   if (err)
     903             :     {
     904           0 :       log_error (_("error reading certificate from stdin: %s\n"),
     905             :                  gpg_strerror (err));
     906           0 :       puts ("ERROR");
     907           0 :       return 0;
     908             :     }
     909             : 
     910           0 :   err = do_check (ctx, certbuf, certbuflen);
     911           0 :   xfree (certbuf);
     912           0 :   if (!err)
     913             :     {
     914           0 :       if (opt.verbose)
     915           0 :         log_info (_("certificate is valid\n"));
     916           0 :       puts ("OK");
     917             :     }
     918             :   else
     919             :     {
     920           0 :       if (!opt.quiet)
     921             :         {
     922           0 :           if (gpg_err_code (err) == GPG_ERR_CERT_REVOKED )
     923           0 :             log_info (_("certificate has been revoked\n"));
     924             :           else
     925           0 :             log_error (_("certificate check failed: %s\n"),
     926             :                        gpg_strerror (err));
     927             :         }
     928           0 :       puts ("ERROR");
     929             :     }
     930             : 
     931           0 :   fflush (stdout);
     932             : 
     933           0 :   return 0;
     934             : }

Generated by: LCOV version 1.11