LCOV - code coverage report
Current view: top level - sm - call-dirmngr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 415 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 23 0.0 %

          Line data    Source code
       1             : /* call-dirmngr.c - Communication with the dirmngr
       2             :  * Copyright (C) 2002, 2003, 2005, 2007, 2008,
       3             :  *               2010  Free Software Foundation, Inc.
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG 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 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * GnuPG 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             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : #include <errno.h>
      26             : #include <unistd.h>
      27             : #include <time.h>
      28             : #include <assert.h>
      29             : #include <ctype.h>
      30             : 
      31             : #include "gpgsm.h"
      32             : #include <gcrypt.h>
      33             : #include <assuan.h>
      34             : 
      35             : #include "i18n.h"
      36             : #include "keydb.h"
      37             : #include "asshelp.h"
      38             : 
      39             : 
      40             : struct membuf {
      41             :   size_t len;
      42             :   size_t size;
      43             :   char *buf;
      44             :   int out_of_core;
      45             : };
      46             : 
      47             : 
      48             : 
      49             : /* fixme: We need a context for each thread or serialize the access to
      50             :    the dirmngr.  */
      51             : static assuan_context_t dirmngr_ctx = NULL;
      52             : static assuan_context_t dirmngr2_ctx = NULL;
      53             : 
      54             : static int dirmngr_ctx_locked;
      55             : static int dirmngr2_ctx_locked;
      56             : 
      57             : struct inq_certificate_parm_s {
      58             :   ctrl_t ctrl;
      59             :   assuan_context_t ctx;
      60             :   ksba_cert_t cert;
      61             :   ksba_cert_t issuer_cert;
      62             : };
      63             : 
      64             : struct isvalid_status_parm_s {
      65             :   ctrl_t ctrl;
      66             :   int seen;
      67             :   unsigned char fpr[20];
      68             : };
      69             : 
      70             : 
      71             : struct lookup_parm_s {
      72             :   ctrl_t ctrl;
      73             :   assuan_context_t ctx;
      74             :   void (*cb)(void *, ksba_cert_t);
      75             :   void *cb_value;
      76             :   struct membuf data;
      77             :   int error;
      78             : };
      79             : 
      80             : struct run_command_parm_s {
      81             :   assuan_context_t ctx;
      82             : };
      83             : 
      84             : 
      85             : 
      86             : static gpg_error_t get_cached_cert (assuan_context_t ctx,
      87             :                                     const unsigned char *fpr,
      88             :                                     ksba_cert_t *r_cert);
      89             : 
      90             : 
      91             : 
      92             : /* A simple implementation of a dynamic buffer.  Use init_membuf() to
      93             :    create a buffer, put_membuf to append bytes and get_membuf to
      94             :    release and return the buffer.  Allocation errors are detected but
      95             :    only returned at the final get_membuf(), this helps not to clutter
      96             :    the code with out of core checks.  */
      97             : 
      98             : static void
      99           0 : init_membuf (struct membuf *mb, int initiallen)
     100             : {
     101           0 :   mb->len = 0;
     102           0 :   mb->size = initiallen;
     103           0 :   mb->out_of_core = 0;
     104           0 :   mb->buf = xtrymalloc (initiallen);
     105           0 :   if (!mb->buf)
     106           0 :       mb->out_of_core = 1;
     107           0 : }
     108             : 
     109             : static void
     110           0 : put_membuf (struct membuf *mb, const void *buf, size_t len)
     111             : {
     112           0 :   if (mb->out_of_core)
     113           0 :     return;
     114             : 
     115           0 :   if (mb->len + len >= mb->size)
     116             :     {
     117             :       char *p;
     118             : 
     119           0 :       mb->size += len + 1024;
     120           0 :       p = xtryrealloc (mb->buf, mb->size);
     121           0 :       if (!p)
     122             :         {
     123           0 :           mb->out_of_core = 1;
     124           0 :           return;
     125             :         }
     126           0 :       mb->buf = p;
     127             :     }
     128           0 :   memcpy (mb->buf + mb->len, buf, len);
     129           0 :   mb->len += len;
     130             : }
     131             : 
     132             : static void *
     133           0 : get_membuf (struct membuf *mb, size_t *len)
     134             : {
     135             :   char *p;
     136             : 
     137           0 :   if (mb->out_of_core)
     138             :     {
     139           0 :       xfree (mb->buf);
     140           0 :       mb->buf = NULL;
     141           0 :       return NULL;
     142             :     }
     143             : 
     144           0 :   p = mb->buf;
     145           0 :   *len = mb->len;
     146           0 :   mb->buf = NULL;
     147           0 :   mb->out_of_core = 1; /* don't allow a reuse */
     148           0 :   return p;
     149             : }
     150             : 
     151             : 
     152             : /* This function prepares the dirmngr for a new session.  The
     153             :    audit-events option is used so that other dirmngr clients won't get
     154             :    disturbed by such events.  */
     155             : static void
     156           0 : prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err)
     157             : {
     158             :   struct keyserver_spec *server;
     159             : 
     160           0 :   if (!err)
     161             :     {
     162           0 :       err = assuan_transact (ctx, "OPTION audit-events=1",
     163             :                              NULL, NULL, NULL, NULL, NULL, NULL);
     164           0 :       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
     165           0 :         err = 0;  /* Allow the use of old dirmngr versions.  */
     166             :     }
     167           0 :   audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err);
     168             : 
     169           0 :   if (!ctx || err)
     170           0 :     return;
     171             : 
     172           0 :   server = opt.keyserver;
     173           0 :   while (server)
     174             :     {
     175             :       char line[ASSUAN_LINELENGTH];
     176           0 :       char *user = server->user ? server->user : "";
     177           0 :       char *pass = server->pass ? server->pass : "";
     178           0 :       char *base = server->base ? server->base : "";
     179             : 
     180           0 :       snprintf (line, DIM (line) - 1, "LDAPSERVER %s:%i:%s:%s:%s",
     181             :                 server->host, server->port, user, pass, base);
     182           0 :       line[DIM (line) - 1] = 0;
     183             : 
     184           0 :       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
     185           0 :       if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD)
     186           0 :         err = 0;  /* Allow the use of old dirmngr versions.  */
     187             : 
     188           0 :       server = server->next;
     189             :     }
     190             : }
     191             : 
     192             : 
     193             : 
     194             : /* Return a new assuan context for a Dirmngr connection.  */
     195             : static gpg_error_t
     196           0 : start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
     197             : {
     198             :   gpg_error_t err;
     199             :   assuan_context_t ctx;
     200             : 
     201           0 :   if (opt.disable_dirmngr || ctrl->offline)
     202           0 :     return gpg_error (GPG_ERR_NO_DIRMNGR);
     203             : 
     204           0 :   if (*ctx_r)
     205           0 :     return 0;
     206             : 
     207             :   /* Note: if you change this to multiple connections, you also need
     208             :      to take care of the implicit option sending caching. */
     209             : 
     210           0 :   err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT,
     211             :                            opt.homedir, opt.dirmngr_program,
     212           0 :                            opt.autostart, opt.verbose, DBG_IPC,
     213             :                            gpgsm_status2, ctrl);
     214           0 :   if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
     215             :     {
     216             :       static int shown;
     217             : 
     218           0 :       if (!shown)
     219             :         {
     220           0 :           shown = 1;
     221           0 :           log_info (_("no dirmngr running in this session\n"));
     222             :         }
     223             :     }
     224           0 :   prepare_dirmngr (ctrl, ctx, err);
     225           0 :   if (err)
     226           0 :     return err;
     227             : 
     228           0 :   *ctx_r = ctx;
     229           0 :   return 0;
     230             : }
     231             : 
     232             : 
     233             : static int
     234           0 : start_dirmngr (ctrl_t ctrl)
     235             : {
     236             :   gpg_error_t err;
     237             : 
     238           0 :   assert (! dirmngr_ctx_locked);
     239           0 :   dirmngr_ctx_locked = 1;
     240             : 
     241           0 :   err = start_dirmngr_ext (ctrl, &dirmngr_ctx);
     242             :   /* We do not check ERR but the existance of a context because the
     243             :      error might come from a failed command send to the dirmngr.
     244             :      Fixme: Why don't we close the drimngr context if we encountered
     245             :      an error in prepare_dirmngr?  */
     246           0 :   if (!dirmngr_ctx)
     247           0 :     dirmngr_ctx_locked = 0;
     248           0 :   return err;
     249             : }
     250             : 
     251             : 
     252             : static void
     253           0 : release_dirmngr (ctrl_t ctrl)
     254             : {
     255             :   (void)ctrl;
     256             : 
     257           0 :   if (!dirmngr_ctx_locked)
     258           0 :     log_error ("WARNING: trying to release a non-locked dirmngr ctx\n");
     259           0 :   dirmngr_ctx_locked = 0;
     260           0 : }
     261             : 
     262             : 
     263             : static int
     264           0 : start_dirmngr2 (ctrl_t ctrl)
     265             : {
     266             :   gpg_error_t err;
     267             : 
     268           0 :   assert (! dirmngr2_ctx_locked);
     269           0 :   dirmngr2_ctx_locked = 1;
     270             : 
     271           0 :   err = start_dirmngr_ext (ctrl, &dirmngr2_ctx);
     272           0 :   if (!dirmngr2_ctx)
     273           0 :     dirmngr2_ctx_locked = 0;
     274           0 :   return err;
     275             : }
     276             : 
     277             : 
     278             : static void
     279           0 : release_dirmngr2 (ctrl_t ctrl)
     280             : {
     281             :   (void)ctrl;
     282             : 
     283           0 :   if (!dirmngr2_ctx_locked)
     284           0 :     log_error ("WARNING: trying to release a non-locked dirmngr2 ctx\n");
     285           0 :   dirmngr2_ctx_locked = 0;
     286           0 : }
     287             : 
     288             : 
     289             : 
     290             : /* Handle a SENDCERT inquiry. */
     291             : static gpg_error_t
     292           0 : inq_certificate (void *opaque, const char *line)
     293             : {
     294           0 :   struct inq_certificate_parm_s *parm = opaque;
     295             :   const char *s;
     296             :   int rc;
     297             :   size_t n;
     298             :   const unsigned char *der;
     299             :   size_t derlen;
     300           0 :   int issuer_mode = 0;
     301           0 :   ksba_sexp_t ski = NULL;
     302             : 
     303           0 :   if ((s = has_leading_keyword (line, "SENDCERT")))
     304             :     {
     305           0 :       line = s;
     306             :     }
     307           0 :   else if ((s = has_leading_keyword (line, "SENDCERT_SKI")))
     308             :     {
     309             :       /* Send a certificate where a sourceKeyIdentifier is included. */
     310           0 :       line = s;
     311           0 :       ski = make_simple_sexp_from_hexstr (line, &n);
     312           0 :       line += n;
     313           0 :       while (*line == ' ')
     314           0 :         line++;
     315             :     }
     316           0 :   else if ((s = has_leading_keyword (line, "SENDISSUERCERT")))
     317             :     {
     318           0 :       line = s;
     319           0 :       issuer_mode = 1;
     320             :     }
     321           0 :   else if ((s = has_leading_keyword (line, "ISTRUSTED")))
     322             :     {
     323             :       /* The server is asking us whether the certificate is a trusted
     324             :          root certificate.  */
     325             :       char fpr[41];
     326             :       struct rootca_flags_s rootca_flags;
     327             : 
     328           0 :       line = s;
     329             : 
     330           0 :       for (s=line,n=0; hexdigitp (s); s++, n++)
     331             :         ;
     332           0 :       if (*s || n != 40)
     333           0 :         return gpg_error (GPG_ERR_ASS_PARAMETER);
     334           0 :       for (s=line, n=0; n < 40; s++, n++)
     335           0 :         fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
     336           0 :       fpr[n] = 0;
     337             : 
     338           0 :       if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
     339           0 :         rc = assuan_send_data (parm->ctx, "1", 1);
     340             :       else
     341           0 :         rc = 0;
     342           0 :       return rc;
     343             :     }
     344             :   else
     345             :     {
     346           0 :       log_error ("unsupported inquiry '%s'\n", line);
     347           0 :       return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
     348             :     }
     349             : 
     350           0 :   if (!*line)
     351             :     { /* Send the current certificate. */
     352           0 :       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
     353             :                                  &derlen);
     354           0 :       if (!der)
     355           0 :         rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
     356             :       else
     357           0 :         rc = assuan_send_data (parm->ctx, der, derlen);
     358             :     }
     359           0 :   else if (issuer_mode)
     360             :     {
     361           0 :       log_error ("sending specific issuer certificate back "
     362             :                  "is not yet implemented\n");
     363           0 :       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
     364             :     }
     365             :   else
     366             :     { /* Send the given certificate. */
     367             :       int err;
     368             :       ksba_cert_t cert;
     369             : 
     370             : 
     371           0 :       err = gpgsm_find_cert (line, ski, &cert);
     372           0 :       if (err)
     373             :         {
     374           0 :           log_error ("certificate not found: %s\n", gpg_strerror (err));
     375           0 :           rc = gpg_error (GPG_ERR_NOT_FOUND);
     376             :         }
     377             :       else
     378             :         {
     379           0 :           der = ksba_cert_get_image (cert, &derlen);
     380           0 :           if (!der)
     381           0 :             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
     382             :           else
     383           0 :             rc = assuan_send_data (parm->ctx, der, derlen);
     384           0 :           ksba_cert_release (cert);
     385             :         }
     386             :     }
     387             : 
     388           0 :   xfree (ski);
     389           0 :   return rc;
     390             : }
     391             : 
     392             : 
     393             : /* Take a 20 byte hexencoded string and put it into the the provided
     394             :    20 byte buffer FPR in binary format. */
     395             : static int
     396           0 : unhexify_fpr (const char *hexstr, unsigned char *fpr)
     397             : {
     398             :   const char *s;
     399             :   int n;
     400             : 
     401           0 :   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
     402             :     ;
     403           0 :   if (*s || (n != 40))
     404           0 :     return 0; /* no fingerprint (invalid or wrong length). */
     405           0 :   n /= 2;
     406           0 :   for (s=hexstr, n=0; *s; s += 2, n++)
     407           0 :     fpr[n] = xtoi_2 (s);
     408           0 :   return 1; /* okay */
     409             : }
     410             : 
     411             : 
     412             : static gpg_error_t
     413           0 : isvalid_status_cb (void *opaque, const char *line)
     414             : {
     415           0 :   struct isvalid_status_parm_s *parm = opaque;
     416             :   const char *s;
     417             : 
     418           0 :   if ((s = has_leading_keyword (line, "PROGRESS")))
     419             :     {
     420           0 :       if (parm->ctrl)
     421             :         {
     422           0 :           line = s;
     423           0 :           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
     424           0 :             return gpg_error (GPG_ERR_ASS_CANCELED);
     425             :         }
     426             :     }
     427           0 :   else if ((s = has_leading_keyword (line, "ONLY_VALID_IF_CERT_VALID")))
     428             :     {
     429           0 :       parm->seen++;
     430           0 :       if (!*s || !unhexify_fpr (s, parm->fpr))
     431           0 :         parm->seen++; /* Bumb it to indicate an error. */
     432             :     }
     433           0 :   return 0;
     434             : }
     435             : 
     436             : 
     437             : 
     438             : 
     439             : /* Call the directory manager to check whether the certificate is valid
     440             :    Returns 0 for valid or usually one of the errors:
     441             : 
     442             :   GPG_ERR_CERTIFICATE_REVOKED
     443             :   GPG_ERR_NO_CRL_KNOWN
     444             :   GPG_ERR_CRL_TOO_OLD
     445             : 
     446             :   Values for USE_OCSP:
     447             :      0 = Do CRL check.
     448             :      1 = Do an OCSP check.
     449             :      2 = Do an OCSP check using only the default responder.
     450             :  */
     451             : int
     452           0 : gpgsm_dirmngr_isvalid (ctrl_t ctrl,
     453             :                        ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
     454             : {
     455             :   static int did_options;
     456             :   int rc;
     457             :   char *certid;
     458             :   char line[ASSUAN_LINELENGTH];
     459             :   struct inq_certificate_parm_s parm;
     460             :   struct isvalid_status_parm_s stparm;
     461             : 
     462           0 :   rc = start_dirmngr (ctrl);
     463           0 :   if (rc)
     464           0 :     return rc;
     465             : 
     466           0 :   if (use_ocsp)
     467             :     {
     468           0 :       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
     469             :     }
     470             :   else
     471             :     {
     472           0 :       certid = gpgsm_get_certid (cert);
     473           0 :       if (!certid)
     474             :         {
     475           0 :           log_error ("error getting the certificate ID\n");
     476           0 :           release_dirmngr (ctrl);
     477           0 :           return gpg_error (GPG_ERR_GENERAL);
     478             :         }
     479             :     }
     480             : 
     481           0 :   if (opt.verbose > 1)
     482             :     {
     483           0 :       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
     484           0 :       log_info ("asking dirmngr about %s%s\n", fpr,
     485             :                 use_ocsp? " (using OCSP)":"");
     486           0 :       xfree (fpr);
     487             :     }
     488             : 
     489           0 :   parm.ctx = dirmngr_ctx;
     490           0 :   parm.ctrl = ctrl;
     491           0 :   parm.cert = cert;
     492           0 :   parm.issuer_cert = issuer_cert;
     493             : 
     494           0 :   stparm.ctrl = ctrl;
     495           0 :   stparm.seen = 0;
     496           0 :   memset (stparm.fpr, 0, 20);
     497             : 
     498             :   /* FIXME: If --disable-crl-checks has been set, we should pass an
     499             :      option to dirmngr, so that no fallback CRL check is done after an
     500             :      ocsp check.  It is not a problem right now as dirmngr does not
     501             :      fallback to CRL checking.  */
     502             : 
     503             :   /* It is sufficient to send the options only once because we have
     504             :      one connection per process only. */
     505           0 :   if (!did_options)
     506             :     {
     507           0 :       if (opt.force_crl_refresh)
     508           0 :         assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
     509             :                          NULL, NULL, NULL, NULL, NULL, NULL);
     510           0 :       did_options = 1;
     511             :     }
     512           0 :   snprintf (line, DIM(line)-1, "ISVALID%s %s",
     513             :             use_ocsp == 2? " --only-ocsp --force-default-responder":"",
     514             :             certid);
     515           0 :   line[DIM(line)-1] = 0;
     516           0 :   xfree (certid);
     517             : 
     518           0 :   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
     519             :                         inq_certificate, &parm,
     520             :                         isvalid_status_cb, &stparm);
     521           0 :   if (opt.verbose > 1)
     522           0 :     log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
     523           0 :   rc = rc;
     524             : 
     525           0 :   if (!rc && stparm.seen)
     526             :     {
     527             :       /* Need to also check the certificate validity. */
     528           0 :       if (stparm.seen != 1)
     529             :         {
     530           0 :           log_error ("communication problem with dirmngr detected\n");
     531           0 :           rc = gpg_error (GPG_ERR_INV_CRL);
     532             :         }
     533             :       else
     534             :         {
     535           0 :           ksba_cert_t rspcert = NULL;
     536             : 
     537           0 :           if (get_cached_cert (dirmngr_ctx, stparm.fpr, &rspcert))
     538             :             {
     539             :               /* Ooops: Something went wrong getting the certificate
     540             :                  from the dirmngr.  Try our own cert store now.  */
     541             :               KEYDB_HANDLE kh;
     542             : 
     543           0 :               kh = keydb_new (0);
     544           0 :               if (!kh)
     545           0 :                 rc = gpg_error (GPG_ERR_ENOMEM);
     546           0 :               if (!rc)
     547           0 :                 rc = keydb_search_fpr (kh, stparm.fpr);
     548           0 :               if (!rc)
     549           0 :                 rc = keydb_get_cert (kh, &rspcert);
     550           0 :               if (rc)
     551             :                 {
     552           0 :                   log_error ("unable to find the certificate used "
     553             :                              "by the dirmngr: %s\n", gpg_strerror (rc));
     554           0 :                   rc = gpg_error (GPG_ERR_INV_CRL);
     555             :                 }
     556           0 :               keydb_release (kh);
     557             :             }
     558             : 
     559           0 :           if (!rc)
     560             :             {
     561           0 :               rc = gpgsm_cert_use_ocsp_p (rspcert);
     562           0 :               if (rc)
     563           0 :                 rc = gpg_error (GPG_ERR_INV_CRL);
     564             :               else
     565             :                 {
     566             :                   /* Note the no_dirmngr flag: This avoids checking
     567             :                      this certificate over and over again. */
     568           0 :                   rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL,
     569             :                                              VALIDATE_FLAG_NO_DIRMNGR, NULL);
     570           0 :                   if (rc)
     571             :                     {
     572           0 :                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
     573             :                                  gpg_strerror (rc));
     574           0 :                       rc = gpg_error (GPG_ERR_INV_CRL);
     575             :                     }
     576             :                 }
     577             :             }
     578           0 :           ksba_cert_release (rspcert);
     579             :         }
     580             :     }
     581           0 :   release_dirmngr (ctrl);
     582           0 :   return rc;
     583             : }
     584             : 
     585             : 
     586             : 
     587             : /* Lookup helpers*/
     588             : static gpg_error_t
     589           0 : lookup_cb (void *opaque, const void *buffer, size_t length)
     590             : {
     591           0 :   struct lookup_parm_s *parm = opaque;
     592             :   size_t len;
     593             :   char *buf;
     594             :   ksba_cert_t cert;
     595             :   int rc;
     596             : 
     597           0 :   if (parm->error)
     598           0 :     return 0;
     599             : 
     600           0 :   if (buffer)
     601             :     {
     602           0 :       put_membuf (&parm->data, buffer, length);
     603           0 :       return 0;
     604             :     }
     605             :   /* END encountered - process what we have */
     606           0 :   buf = get_membuf (&parm->data, &len);
     607           0 :   if (!buf)
     608             :     {
     609           0 :       parm->error = gpg_error (GPG_ERR_ENOMEM);
     610           0 :       return 0;
     611             :     }
     612             : 
     613           0 :   rc = ksba_cert_new (&cert);
     614           0 :   if (rc)
     615             :     {
     616           0 :       parm->error = rc;
     617           0 :       return 0;
     618             :     }
     619           0 :   rc = ksba_cert_init_from_mem (cert, buf, len);
     620           0 :   if (rc)
     621             :     {
     622           0 :       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
     623             :     }
     624             :   else
     625             :     {
     626           0 :       parm->cb (parm->cb_value, cert);
     627             :     }
     628             : 
     629           0 :   ksba_cert_release (cert);
     630           0 :   init_membuf (&parm->data, 4096);
     631           0 :   return 0;
     632             : }
     633             : 
     634             : /* Return a properly escaped pattern from NAMES.  The only error
     635             :    return is NULL to indicate a malloc failure. */
     636             : static char *
     637           0 : pattern_from_strlist (strlist_t names)
     638             : {
     639             :   strlist_t sl;
     640             :   int n;
     641             :   const char *s;
     642             :   char *pattern, *p;
     643             : 
     644           0 :   for (n=0, sl=names; sl; sl = sl->next)
     645             :     {
     646           0 :       for (s=sl->d; *s; s++, n++)
     647             :         {
     648           0 :           if (*s == '%' || *s == ' ' || *s == '+')
     649           0 :             n += 2;
     650             :         }
     651           0 :       n++;
     652             :     }
     653             : 
     654           0 :   p = pattern = xtrymalloc (n+1);
     655           0 :   if (!pattern)
     656           0 :     return NULL;
     657             : 
     658           0 :   for (sl=names; sl; sl = sl->next)
     659             :     {
     660           0 :       for (s=sl->d; *s; s++)
     661             :         {
     662           0 :           switch (*s)
     663             :             {
     664             :             case '%':
     665           0 :               *p++ = '%';
     666           0 :               *p++ = '2';
     667           0 :               *p++ = '5';
     668           0 :               break;
     669             :             case ' ':
     670           0 :               *p++ = '%';
     671           0 :               *p++ = '2';
     672           0 :               *p++ = '0';
     673           0 :               break;
     674             :             case '+':
     675           0 :               *p++ = '%';
     676           0 :               *p++ = '2';
     677           0 :               *p++ = 'B';
     678           0 :               break;
     679             :             default:
     680           0 :               *p++ = *s;
     681           0 :               break;
     682             :             }
     683             :         }
     684           0 :       *p++ = ' ';
     685             :     }
     686           0 :   if (p == pattern)
     687           0 :     *pattern = 0; /* is empty */
     688             :   else
     689           0 :     p[-1] = '\0'; /* remove trailing blank */
     690             : 
     691           0 :   return pattern;
     692             : }
     693             : 
     694             : static gpg_error_t
     695           0 : lookup_status_cb (void *opaque, const char *line)
     696             : {
     697           0 :   struct lookup_parm_s *parm = opaque;
     698             :   const char *s;
     699             : 
     700           0 :   if ((s = has_leading_keyword (line, "PROGRESS")))
     701             :     {
     702           0 :       if (parm->ctrl)
     703             :         {
     704           0 :           line = s;
     705           0 :           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
     706           0 :             return gpg_error (GPG_ERR_ASS_CANCELED);
     707             :         }
     708             :     }
     709           0 :   else if ((s = has_leading_keyword (line, "TRUNCATED")))
     710             :     {
     711           0 :       if (parm->ctrl)
     712             :         {
     713           0 :           line = s;
     714           0 :           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
     715             :         }
     716             :     }
     717           0 :   return 0;
     718             : }
     719             : 
     720             : 
     721             : /* Run the Directory Manager's lookup command using the pattern
     722             :    compiled from the strings given in NAMES.  The caller must provide
     723             :    the callback CB which will be passed cert by cert.  Note that CTRL
     724             :    is optional.  With CACHE_ONLY the dirmngr will search only its own
     725             :    key cache. */
     726             : int
     727           0 : gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only,
     728             :                       void (*cb)(void*, ksba_cert_t), void *cb_value)
     729             : {
     730             :   int rc;
     731             :   char *pattern;
     732             :   char line[ASSUAN_LINELENGTH];
     733             :   struct lookup_parm_s parm;
     734             :   size_t len;
     735             :   assuan_context_t ctx;
     736             : 
     737             :   /* The lookup function can be invoked from the callback of a lookup
     738             :      function, for example to walk the chain.  */
     739           0 :   if (!dirmngr_ctx_locked)
     740             :     {
     741           0 :       rc = start_dirmngr (ctrl);
     742           0 :       if (rc)
     743           0 :         return rc;
     744           0 :       ctx = dirmngr_ctx;
     745             :     }
     746           0 :   else if (!dirmngr2_ctx_locked)
     747             :     {
     748           0 :       rc = start_dirmngr2 (ctrl);
     749           0 :       if (rc)
     750           0 :         return rc;
     751           0 :       ctx = dirmngr2_ctx;
     752             :     }
     753             :   else
     754             :     {
     755           0 :       log_fatal ("both dirmngr contexts are in use\n");
     756             :     }
     757             : 
     758           0 :   pattern = pattern_from_strlist (names);
     759           0 :   if (!pattern)
     760             :     {
     761           0 :       if (ctx == dirmngr_ctx)
     762           0 :         release_dirmngr (ctrl);
     763             :       else
     764           0 :         release_dirmngr2 (ctrl);
     765             : 
     766           0 :       return out_of_core ();
     767             :     }
     768           0 :   snprintf (line, DIM(line)-1, "LOOKUP%s %s",
     769             :             cache_only? " --cache-only":"", pattern);
     770           0 :   line[DIM(line)-1] = 0;
     771           0 :   xfree (pattern);
     772             : 
     773           0 :   parm.ctrl = ctrl;
     774           0 :   parm.ctx = ctx;
     775           0 :   parm.cb = cb;
     776           0 :   parm.cb_value = cb_value;
     777           0 :   parm.error = 0;
     778           0 :   init_membuf (&parm.data, 4096);
     779             : 
     780           0 :   rc = assuan_transact (ctx, line, lookup_cb, &parm,
     781             :                         NULL, NULL, lookup_status_cb, &parm);
     782           0 :   xfree (get_membuf (&parm.data, &len));
     783             : 
     784           0 :   if (ctx == dirmngr_ctx)
     785           0 :     release_dirmngr (ctrl);
     786             :   else
     787           0 :     release_dirmngr2 (ctrl);
     788             : 
     789           0 :   if (rc)
     790           0 :       return rc;
     791           0 :   return parm.error;
     792             : }
     793             : 
     794             : 
     795             : 
     796             : static gpg_error_t
     797           0 : get_cached_cert_data_cb (void *opaque, const void *buffer, size_t length)
     798             : {
     799           0 :   struct membuf *mb = opaque;
     800             : 
     801           0 :   if (buffer)
     802           0 :     put_membuf (mb, buffer, length);
     803           0 :   return 0;
     804             : }
     805             : 
     806             : /* Return a certificate from the Directory Manager's cache.  This
     807             :    function only returns one certificate which must be specified using
     808             :    the fingerprint FPR and will be stored at R_CERT.  On error NULL is
     809             :    stored at R_CERT and an error code returned.  Note that the caller
     810             :    must provide the locked dirmngr context CTX. */
     811             : static gpg_error_t
     812           0 : get_cached_cert (assuan_context_t ctx,
     813             :                  const unsigned char *fpr, ksba_cert_t *r_cert)
     814             : {
     815             :   gpg_error_t err;
     816             :   char line[ASSUAN_LINELENGTH];
     817             :   char hexfpr[2*20+1];
     818             :   struct membuf mb;
     819             :   char *buf;
     820           0 :   size_t buflen = 0;
     821             :   ksba_cert_t cert;
     822             : 
     823           0 :   *r_cert = NULL;
     824             : 
     825           0 :   bin2hex (fpr, 20, hexfpr);
     826           0 :   snprintf (line, DIM(line)-1, "LOOKUP --single --cache-only 0x%s", hexfpr);
     827             : 
     828           0 :   init_membuf (&mb, 4096);
     829           0 :   err = assuan_transact (ctx, line, get_cached_cert_data_cb, &mb,
     830             :                          NULL, NULL, NULL, NULL);
     831           0 :   buf = get_membuf (&mb, &buflen);
     832           0 :   if (err)
     833             :     {
     834           0 :       xfree (buf);
     835           0 :       return err;
     836             :     }
     837           0 :   if (!buf)
     838           0 :     return gpg_error (GPG_ERR_ENOMEM);
     839             : 
     840           0 :   err = ksba_cert_new (&cert);
     841           0 :   if (err)
     842             :     {
     843           0 :       xfree (buf);
     844           0 :       return err;
     845             :     }
     846           0 :   err = ksba_cert_init_from_mem (cert, buf, buflen);
     847           0 :   xfree (buf);
     848           0 :   if (err)
     849             :     {
     850           0 :       log_error ("failed to parse a certificate: %s\n", gpg_strerror (err));
     851           0 :       ksba_cert_release (cert);
     852           0 :       return err;
     853             :     }
     854             : 
     855           0 :   *r_cert = cert;
     856           0 :   return 0;
     857             : }
     858             : 
     859             : 
     860             : 
     861             : /* Run Command helpers*/
     862             : 
     863             : /* Fairly simple callback to write all output of dirmngr to stdout. */
     864             : static gpg_error_t
     865           0 : run_command_cb (void *opaque, const void *buffer, size_t length)
     866             : {
     867             :   (void)opaque;
     868             : 
     869           0 :   if (buffer)
     870             :     {
     871           0 :       if ( fwrite (buffer, length, 1, stdout) != 1 )
     872           0 :         log_error ("error writing to stdout: %s\n", strerror (errno));
     873             :     }
     874           0 :   return 0;
     875             : }
     876             : 
     877             : /* Handle inquiries from the dirmngr COMMAND. */
     878             : static gpg_error_t
     879           0 : run_command_inq_cb (void *opaque, const char *line)
     880             : {
     881           0 :   struct run_command_parm_s *parm = opaque;
     882             :   const char *s;
     883           0 :   int rc = 0;
     884             : 
     885           0 :   if ((s = has_leading_keyword (line, "SENDCERT")))
     886             :     { /* send the given certificate */
     887             :       int err;
     888             :       ksba_cert_t cert;
     889             :       const unsigned char *der;
     890             :       size_t derlen;
     891             : 
     892           0 :       line = s;
     893           0 :       if (!*line)
     894           0 :         return gpg_error (GPG_ERR_ASS_PARAMETER);
     895             : 
     896           0 :       err = gpgsm_find_cert (line, NULL, &cert);
     897           0 :       if (err)
     898             :         {
     899           0 :           log_error ("certificate not found: %s\n", gpg_strerror (err));
     900           0 :           rc = gpg_error (GPG_ERR_NOT_FOUND);
     901             :         }
     902             :       else
     903             :         {
     904           0 :           der = ksba_cert_get_image (cert, &derlen);
     905           0 :           if (!der)
     906           0 :             rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
     907             :           else
     908           0 :             rc = assuan_send_data (parm->ctx, der, derlen);
     909           0 :           ksba_cert_release (cert);
     910             :         }
     911             :     }
     912           0 :   else if ((s = has_leading_keyword (line, "PRINTINFO")))
     913             :     { /* Simply show the message given in the argument. */
     914           0 :       line = s;
     915           0 :       log_info ("dirmngr: %s\n", line);
     916             :     }
     917             :   else
     918             :     {
     919           0 :       log_error ("unsupported inquiry '%s'\n", line);
     920           0 :       rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
     921             :     }
     922             : 
     923           0 :   return rc;
     924             : }
     925             : 
     926             : static gpg_error_t
     927           0 : run_command_status_cb (void *opaque, const char *line)
     928             : {
     929           0 :   ctrl_t ctrl = opaque;
     930             :   const char *s;
     931             : 
     932           0 :   if (opt.verbose)
     933             :     {
     934           0 :       log_info ("dirmngr status: %s\n", line);
     935             :     }
     936           0 :   if ((s = has_leading_keyword (line, "PROGRESS")))
     937             :     {
     938           0 :       if (ctrl)
     939             :         {
     940           0 :           line = s;
     941           0 :           if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
     942           0 :             return gpg_error (GPG_ERR_ASS_CANCELED);
     943             :         }
     944             :     }
     945           0 :   return 0;
     946             : }
     947             : 
     948             : 
     949             : 
     950             : /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
     951             :    to stdout.  A couple of inquiries are defined (see above).  ARGC
     952             :    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
     953             :    percent characters within the argument strings are percent escaped
     954             :    so that blanks can act as delimiters. */
     955             : int
     956           0 : gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command,
     957             :                            int argc, char **argv)
     958             : {
     959             :   int rc;
     960             :   int i;
     961             :   const char *s;
     962             :   char *line, *p;
     963             :   size_t len;
     964             :   struct run_command_parm_s parm;
     965             : 
     966           0 :   rc = start_dirmngr (ctrl);
     967           0 :   if (rc)
     968           0 :     return rc;
     969             : 
     970           0 :   parm.ctx = dirmngr_ctx;
     971             : 
     972           0 :   len = strlen (command) + 1;
     973           0 :   for (i=0; i < argc; i++)
     974           0 :     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
     975           0 :   line = xtrymalloc (len);
     976           0 :   if (!line)
     977             :     {
     978           0 :       release_dirmngr (ctrl);
     979           0 :       return out_of_core ();
     980             :     }
     981             : 
     982           0 :   p = stpcpy (line, command);
     983           0 :   for (i=0; i < argc; i++)
     984             :     {
     985           0 :       *p++ = ' ';
     986           0 :       for (s=argv[i]; *s; s++)
     987             :         {
     988           0 :           if (!isascii (*s))
     989           0 :             *p++ = *s;
     990           0 :           else if (*s == ' ')
     991           0 :             *p++ = '+';
     992           0 :           else if (!isprint (*s) || *s == '+')
     993             :             {
     994           0 :               sprintf (p, "%%%02X", *(const unsigned char *)s);
     995           0 :               p += 3;
     996             :             }
     997             :           else
     998           0 :             *p++ = *s;
     999             :         }
    1000             :     }
    1001           0 :   *p = 0;
    1002             : 
    1003           0 :   rc = assuan_transact (dirmngr_ctx, line,
    1004             :                         run_command_cb, NULL,
    1005             :                         run_command_inq_cb, &parm,
    1006             :                         run_command_status_cb, ctrl);
    1007           0 :   xfree (line);
    1008           0 :   log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
    1009           0 :   release_dirmngr (ctrl);
    1010           0 :   return rc;
    1011             : }

Generated by: LCOV version 1.11