dirmngr (17 files)

cvs user wk cvs at cvs.gnupg.org
Tue Nov 23 14:14:07 CET 2004


    Date: Tuesday, November 23, 2004 @ 14:20:44
  Author: wk
    Path: /cvs/dirmngr/dirmngr

   Added: src/b64enc.c
Modified: TODO src/ChangeLog src/Makefile.am src/certcache.c
          src/crlfetch.c src/dirmngr-client.c src/dirmngr_ldap.c
          src/ldap.c src/misc.c src/misc.h src/no-libgcrypt.c
          src/no-libgcrypt.h src/ocsp.c src/ocsp.h src/server.c src/util.h

* dirmngr-client.c (do_lookup): New.
(main): New option --lookup.
(data_cb): New.
* b64enc.c: New. Taken from GnuPG 1.9.
* no-libgcrypt.c (gcry_strdup): Added.

* ocsp.c (ocsp_isvalid): New arg CERT and lookup the issuer
certificate using the standard methods.

* server.c (cmd_lookup): Truncation is now also an indication for
error.
(cmd_checkocsp): Implemented.

* dirmngr_ldap.c (fetch_ldap): Write an error marker for a
truncated search.
* ldap.c (add_server_to_servers): Reactivated.
(url_fetch_ldap): Call it here and try all configured servers in
case of a a failed lookup.
(fetch_next_cert_ldap): Detect the truncation error flag.

* misc.c (host_and_port_from_url, remove_percent_escapes): New.


----------------------+
 TODO                 |   12 --
 src/ChangeLog        |   24 +++++
 src/Makefile.am      |    2 
 src/b64enc.c         |  213 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/certcache.c      |    6 -
 src/crlfetch.c       |   31 -------
 src/dirmngr-client.c |  106 ++++++++++++++++++++++--
 src/dirmngr_ldap.c   |   13 ++
 src/ldap.c           |  104 ++++++++++++++++++-----
 src/misc.c           |  104 +++++++++++++++++++++++
 src/misc.h           |    5 -
 src/no-libgcrypt.c   |    6 +
 src/no-libgcrypt.h   |    1 
 src/ocsp.c           |   56 ++++++++----
 src/ocsp.h           |    3 
 src/server.c         |   49 ++++++++++-
 src/util.h           |   17 +++
 17 files changed, 644 insertions(+), 108 deletions(-)


Index: dirmngr/TODO
diff -u dirmngr/TODO:1.14 dirmngr/TODO:1.15
--- dirmngr/TODO:1.14	Tue Nov 16 19:24:36 2004
+++ dirmngr/TODO	Tue Nov 23 14:20:44 2004
@@ -2,9 +2,6 @@
 
 * Audit the code!
 
-* Dirmngr as system daemon 
-  We need to limit the length of inquires etc.
-
 * Write a useful README
 
 * Map LDAP error codes
@@ -15,15 +12,6 @@
    This is the server where a baseDN has been given and that baseDN is
    contained in the search pattern.
 
-* Properly parse LDAP attributes from the URL and remove the bad hack in crl_fetch.
-
-* Add --honor-http-proxy
-
 * Properly use locks in crlcache.c
 
-* truncated
-  Need to updated the code in ldap.c
-
-* In daemon mode we should put the cache files into /var/cache/dirmngr
-
 
Index: dirmngr/src/ChangeLog
diff -u dirmngr/src/ChangeLog:1.25 dirmngr/src/ChangeLog:1.26
--- dirmngr/src/ChangeLog:1.25	Mon Nov 22 22:30:50 2004
+++ dirmngr/src/ChangeLog	Tue Nov 23 14:20:44 2004
@@ -1,3 +1,27 @@
+2004-11-23  Werner Koch  <wk at g10code.com>
+
+	* dirmngr-client.c (do_lookup): New.
+	(main): New option --lookup.
+	(data_cb): New.
+	* b64enc.c: New. Taken from GnuPG 1.9.
+	* no-libgcrypt.c (gcry_strdup): Added.
+
+	* ocsp.c (ocsp_isvalid): New arg CERT and lookup the issuer
+	certificate using the standard methods.
+
+	* server.c (cmd_lookup): Truncation is now also an indication for
+	error.
+	(cmd_checkocsp): Implemented.
+
+	* dirmngr_ldap.c (fetch_ldap): Write an error marker for a
+	truncated search.
+	* ldap.c (add_server_to_servers): Reactivated.
+	(url_fetch_ldap): Call it here and try all configured servers in
+	case of a a failed lookup.
+	(fetch_next_cert_ldap): Detect the truncation error flag.
+
+	* misc.c (host_and_port_from_url, remove_percent_escapes): New.
+
 2004-11-22  Werner Koch  <wk at g10code.com>
 
 	* dirmngr_ldap.c (main): New option --proxy.
Index: dirmngr/src/Makefile.am
diff -u dirmngr/src/Makefile.am:1.19 dirmngr/src/Makefile.am:1.20
--- dirmngr/src/Makefile.am:1.19	Mon Nov 22 22:30:50 2004
+++ dirmngr/src/Makefile.am	Tue Nov 23 14:20:44 2004
@@ -56,7 +56,7 @@
 		    $(LDAP_LIBS)
 
 
-dirmngr_client_SOURCES = dirmngr-client.c i18n.h util.h maperror.c \
+dirmngr_client_SOURCES = dirmngr-client.c i18n.h util.h b64enc.c maperror.c \
                          no-libgcrypt.c no-libgcrypt.h 
 dirmngr_client_LDADD = ../jnlib/libjnlib.a $(LIBOBJS) $(LIBASSUAN_LIBS) \
 	               $(GPG_ERROR_LIBS)
Index: dirmngr/src/b64enc.c
diff -u /dev/null dirmngr/src/b64enc.c:1.1
--- /dev/null	Tue Nov 23 14:20:45 2004
+++ dirmngr/src/b64enc.c	Tue Nov 23 14:20:44 2004
@@ -0,0 +1,213 @@
+/* b64enc.c - Simple Base64 encoder.
+ *	Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "i18n.h"
+#include "util.h"
+
+#define B64ENC_DID_HEADER   1
+#define B64ENC_DID_TRAILER  2
+#define B64ENC_NO_LINEFEEDS 16
+
+
+/* The base-64 character list */
+static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
+                                    "abcdefghijklmnopqrstuvwxyz" 
+                                    "0123456789+/"; 
+
+/* Prepare for base-64 writing to the stream FP.  If TITLE is not NULL
+   and not an empty string, this string will be used as the title for
+   the armor lines, with TITLE being an empty string, we don't write
+   the header lines and furthermore even don't write any linefeeds.
+   With TITLE beeing NULL, we merely don't write header but make sure
+   that lines are not too long. Note, that we don't write any output
+   unless at least one byte get written using b64enc_write. */
+gpg_error_t
+b64enc_start (struct b64state *state, FILE *fp, const char *title)
+{
+  memset (state, 0, sizeof *state);
+  state->fp = fp;
+  if (title && !*title)
+    state->flags |= B64ENC_NO_LINEFEEDS;
+  else if (title)
+    {
+      state->title = xtrystrdup (title);
+      if (!state->title)
+        return  gpg_error_from_errno (errno);
+    }
+  return 0;
+}
+
+
+/* Write NBYTES from BUFFER to the Base 64 stream identified by
+   STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
+   stream. */
+gpg_error_t
+b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
+{
+  unsigned char radbuf[4];
+  int idx, quad_count;
+  const unsigned char *p;
+  FILE *fp = state->fp;
+
+
+  if (!nbytes)
+    {
+      if (buffer && fflush (fp))
+        goto write_error;
+      return 0;
+    }
+
+  if (!(state->flags & B64ENC_DID_HEADER))
+    {
+      if (state->title)
+        {
+          if ( fputs ("-----BEGIN ", fp) == EOF
+               || fputs (state->title, fp) == EOF
+               || fputs ("-----\n", fp) == EOF)
+            goto write_error;
+        }
+      state->flags |= B64ENC_DID_HEADER;
+    }
+
+  idx = state->idx;
+  quad_count = state->quad_count;
+  assert (idx < 4);
+  memcpy (radbuf, state->radbuf, idx);
+  
+  for (p=buffer; nbytes; p++, nbytes--)
+    {
+      radbuf[idx++] = *p;
+      if (idx > 2)
+        {
+          char tmp[4];
+
+          tmp[0] = bintoasc[(*radbuf >> 2) & 077];
+          tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
+          tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
+          tmp[3] = bintoasc[radbuf[2]&077];
+          for (idx=0; idx < 4; idx++)
+            putc (tmp[idx], fp);
+          idx = 0;
+          if (ferror (fp))
+            goto write_error;
+          if (++quad_count >= (64/4)) 
+            {
+              quad_count = 0;
+              if (!(state->flags & B64ENC_NO_LINEFEEDS)
+                  && fputs ("\n", fp) == EOF)
+                goto write_error;
+            }
+        }
+    }
+  memcpy (state->radbuf, radbuf, idx);
+  state->idx = idx;
+  state->quad_count = quad_count;
+  return 0;
+
+ write_error:
+  return gpg_error_from_errno (errno);
+}
+
+gpg_error_t
+b64enc_finish (struct b64state *state)
+{
+  gpg_error_t err = 0;
+  unsigned char radbuf[4];
+  int idx, quad_count;
+  FILE *fp;
+
+  if (!(state->flags & B64ENC_DID_HEADER))
+    goto cleanup;
+
+  /* Flush the base64 encoding */
+  fp = state->fp;
+  idx = state->idx;
+  quad_count = state->quad_count;
+  assert (idx < 4);
+  memcpy (radbuf, state->radbuf, idx);
+
+  if (idx)
+    {
+      char tmp[4];
+      
+      tmp[0] = bintoasc[(*radbuf>>2)&077];
+      if (idx == 1)
+        {
+          tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
+          tmp[2] = '=';
+          tmp[3] = '=';
+        }
+      else 
+        { 
+          tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
+          tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
+          tmp[3] = '=';
+        }
+      for (idx=0; idx < 4; idx++)
+        putc (tmp[idx], fp);
+      idx = 0;
+      if (ferror (fp))
+        goto write_error;
+      
+      if (++quad_count >= (64/4)) 
+        {
+          quad_count = 0;
+          if (!(state->flags & B64ENC_NO_LINEFEEDS)
+              && fputs ("\n", fp) == EOF)
+            goto write_error;
+        }
+    }
+
+  /* Finish the last line and write the trailer. */
+  if (quad_count
+      && !(state->flags & B64ENC_NO_LINEFEEDS)
+      && fputs ("\n", fp) == EOF)
+    goto write_error;
+
+  if (state->title)
+    {
+      if ( fputs ("-----END ", fp) == EOF
+           || fputs (state->title, fp) == EOF
+           || fputs ("-----\n", fp) == EOF)
+        goto write_error;
+    }
+
+  goto cleanup;
+
+ write_error:
+  err = gpg_error_from_errno (errno);
+
+ cleanup:
+  if (state->title)
+    {
+      xfree (state->title);
+      state->title = NULL;
+    }
+  state->fp = NULL;
+  return err;
+}
+
Index: dirmngr/src/certcache.c
diff -u dirmngr/src/certcache.c:1.5 dirmngr/src/certcache.c:1.6
--- dirmngr/src/certcache.c:1.5	Mon Nov 22 22:30:50 2004
+++ dirmngr/src/certcache.c	Tue Nov 23 14:20:44 2004
@@ -709,9 +709,3 @@
   return err;
 }
 
-
-
-
-
-
-
Index: dirmngr/src/crlfetch.c
diff -u dirmngr/src/crlfetch.c:1.21 dirmngr/src/crlfetch.c:1.22
--- dirmngr/src/crlfetch.c:1.21	Mon Nov 22 22:30:50 2004
+++ dirmngr/src/crlfetch.c	Tue Nov 23 14:20:44 2004
@@ -111,8 +111,6 @@
     }
   else /* Let the LDAP code try other schemes. */
     {
-      const char *s;
-
       if (opt.disable_ldap)
         {
           log_error (_("CRL access not possible due to disabled %s\n"),
@@ -121,35 +119,6 @@
         }
       else
         err = url_fetch_ldap (ctrl, url, NULL, 0, reader);
-
-/*       if (err) */
-/*         { */
-/*           /\* If the function failed we try again using our default */
-/*              host.  *\/ */
-/*           ldap_server_t server; */
-/*           char *savehost; */
-/*           int saveport; */
-      
-/*           if (DBG_LOOKUP) */
-/*             log_debug ("no hostname in URL or query failed; " */
-/*                        "trying all default hostnames\n"); */
-/*           savehost = ludp->lud_host; */
-/*           saveport = ludp->lud_port; */
-/*           for (server = opt.ldapservers; server; server = server->next) */
-/*             { */
-/*               ludp->lud_host = server->host; */
-/*               ludp->lud_port = server->port; */
-/*               err = url_fetch_ldap_internal (ludp, attr, value, valuelen); */
-/*               if (!err) */
-/*                 break; */
-/*             } */
-/*           ludp->lud_host = savehost; */
-/*           ludp->lud_port = saveport; */
-/*                 if (opt.add_new_ldapservers) */
-/* 	add_server_to_servers (ludp->lud_host, ludp->lud_port); */
-
-/*         } */
-
     }
   if (free_this)
     xfree (free_this);
Index: dirmngr/src/dirmngr-client.c
diff -u dirmngr/src/dirmngr-client.c:1.3 dirmngr/src/dirmngr-client.c:1.4
--- dirmngr/src/dirmngr-client.c:1.3	Fri Nov 19 16:27:28 2004
+++ dirmngr/src/dirmngr-client.c	Tue Nov 23 14:20:44 2004
@@ -54,6 +54,7 @@
     oPing,
     oCacheCert,
     oValidate,
+    oLookup,
     oUseDaemon,
     oDummy
   };
@@ -68,6 +69,7 @@
   { oPing,     "ping",      0, N_("check whether a dirmngr is running")},
   { oCacheCert,"cache-cert",0, N_("add a certificate to the cache")},
   { oValidate, "validate",  0, N_("validate a certificate")},
+  { oLookup,   "lookup",    0, N_("lookup a certificate")},
   {0}
 };
  
@@ -105,6 +107,7 @@
                              const unsigned char *cert, size_t certlen);
 static gpg_error_t do_validate (assuan_context_t ctx,
                                 const unsigned char *cert, size_t certlen);
+static gpg_error_t do_lookup (assuan_context_t ctx, const char *pattern);
 
 
 
@@ -116,7 +119,7 @@
     
   switch(level)
     {
-    case 11: p = "dirmngr-client";
+    case 11: p = "dirmngr-client (dirmngr)";
       break;
     case 13: p = VERSION; break;
     case 14: p = "Copyright (C) 2004 g10 Code GmbH"; break;
@@ -126,10 +129,11 @@
       break;
     case 1:
     case 40: p =
-               _("Usage: dirmngr-client [options] [certfile] (-h for help)\n");
+                 _("Usage: dirmngr-client [options] "
+                   "[certfile|pattern] (-h for help)\n");
       break;
     case 41: p =
-          _("Syntax: dirmngr-client [options] [certfile]\n"
+          _("Syntax: dirmngr-client [options] [certfile|pattern]\n"
             "Test an X.509 certificate against a CRL or do an OCSP check\n"
             "The process returns 0 if the certificate is valid, 1 if it is\n"
             "not valid and other error codes for general failures\n");
@@ -163,11 +167,11 @@
   assuan_context_t ctx;
   gpg_error_t err;
   unsigned char *certbuf;
-  size_t certbuflen;
+  size_t certbuflen = 0;
   int cmd_ping = 0;
-  int use_daemon = 0;
   int cmd_cache_cert = 0;
   int cmd_validate = 0;
+  int cmd_lookup = 0;
 
   set_strusage (my_strusage);
   log_set_prefix ("dirmngr-client",
@@ -190,12 +194,12 @@
         {
         case oVerbose: opt.verbose++; break;
         case oQuiet: opt.quiet++; break;
-        case oUseDaemon: use_daemon = 1; break;
           
         case oOCSP: opt.use_ocsp++; break;
         case oPing: cmd_ping = 1; break;
         case oCacheCert: cmd_cache_cert = 1; break;
         case oValidate: cmd_validate = 1; break;
+        case oLookup: cmd_lookup = 1; break;
 
         default : pargs.err = 2; break;
 	}
@@ -205,6 +209,12 @@
 
   if (cmd_ping)
     err = 0;
+  else if (cmd_lookup)
+    {
+      if (!argc)
+        usage (1);
+      err = 0;
+    }
   else if (!argc)
     {
       err = read_certificate (NULL, &certbuf, &certbuflen);
@@ -234,12 +244,27 @@
       exit (2);
     }
 
-  ctx = start_dirmngr (cmd_ping || use_daemon);
+  ctx = start_dirmngr (1);
   if (!ctx)
     exit (2);
 
   if (cmd_ping)
     ;
+  else if (cmd_lookup)
+    {
+      int last_err = 0;
+
+      for (; argc; argc--, argv++)
+        {
+          err = do_lookup (ctx, *argv);
+          if (err)
+            {
+              log_error (_("lookup failed: %s\n"), gpg_strerror (err));
+              last_err = err;
+            }
+        }
+      err = last_err;
+    }
   else if (cmd_cache_cert)
     {
       err = do_cache (ctx, certbuf, certbuflen);
@@ -264,6 +289,8 @@
         log_info (_("a dirmngr daemon is up and running\n"));
       return 0;
     }
+  else if (cmd_lookup)
+    return err? 1:0;
   else if (cmd_cache_cert)
     {
       if (err && gpg_err_code (err) == GPG_ERR_DUP_VALUE )
@@ -314,6 +341,24 @@
   return 0;
 }
 
+/* Print data as retrieved by the lookup function.  */
+static assuan_error_t
+data_cb (void *opaque, const void *buffer, size_t length)
+{
+  gpg_error_t err;
+  struct b64state *state = opaque;
+
+  if (buffer)
+    {
+      err = b64enc_write (state, buffer, length);
+      if (err)
+        log_error (_("error writing base64 encoding: %s\n"),
+                   gpg_strerror (err));
+    }
+  return 0;
+}
+  
+
 /* Try to connect to the dirmngr via socket or fork it off and work by
    pipes.  Handle the server's initial greeting */
 static assuan_context_t
@@ -569,3 +614,50 @@
     log_info ("response of dirmngr: %s\n", ae? assuan_strerror (ae): "okay");
   return map_assuan_err (ae);
 }
+
+static gpg_error_t
+do_lookup (assuan_context_t ctx, const char *pattern)
+{
+  gpg_error_t err;
+  assuan_error_t ae;
+  const unsigned char *s;
+  char *line, *p;
+  struct b64state state;
+
+  if (opt.verbose)
+    log_info (_("looking up `%s'\n"), pattern);
+
+  err = b64enc_start (&state, stdout, NULL);
+  if (err)
+    return err;
+
+  line = xmalloc (10 + strlen (pattern)*3 + 1);
+
+  p = stpcpy (line, "LOOKUP ");
+  for (s=pattern; *s; s++)
+    {
+      if (*s < ' ' || *s == '+')
+        {
+          sprintf (p, "%%%02X", *s);
+          p += 3;
+        }
+      else if (*s == ' ')
+        *p++ = '+';
+      else
+        *p++ = *s;
+    }
+  *p = 0;
+
+
+  ae = assuan_transact (ctx, line,
+                        data_cb, &state,
+                        NULL, NULL,
+                        status_cb, NULL);
+  if (opt.verbose > 1)
+    log_info ("response of dirmngr: %s\n", ae? assuan_strerror (ae): "okay");
+
+  err = b64enc_finish (&state);
+
+  xfree (line);
+  return ae? map_assuan_err (ae) : err;
+}
Index: dirmngr/src/dirmngr_ldap.c
diff -u dirmngr/src/dirmngr_ldap.c:1.3 dirmngr/src/dirmngr_ldap.c:1.4
--- dirmngr/src/dirmngr_ldap.c:1.3	Mon Nov 22 22:30:50 2004
+++ dirmngr/src/dirmngr_ldap.c	Tue Nov 23 14:20:44 2004
@@ -125,7 +125,7 @@
     
   switch(level)
     {
-    case 11: p = "dirmngr_ldap";
+    case 11: p = "dirmngr_ldap (dirmngr)";
       break;
     case 13: p = VERSION; break;
     case 14: p = "Copyright (C) 2004 g10 Code GmbH"; break;
@@ -466,7 +466,16 @@
                        ludp->lud_attrs:attrs,
                        0,
                        &opt.timeout, &msg);
-  if (rc)
+  if (rc == LDAP_SIZELIMIT_EXCEEDED && opt.multi)
+    {
+      if (fwrite ("E\0\0\0\x09truncated", 14, 1, stdout) != 1)
+        {
+          log_error (_("error writing to stdout: %s\n"),
+                     strerror (errno));
+          return -1;
+        }
+    }
+  else if (rc)
     {
       log_error (_("searching `%s' failed: %s\n"), 
                  url, ldap_err2string (rc));
Index: dirmngr/src/ldap.c
diff -u dirmngr/src/ldap.c:1.36 dirmngr/src/ldap.c:1.37
--- dirmngr/src/ldap.c:1.36	Mon Nov 22 22:30:50 2004
+++ dirmngr/src/ldap.c	Tue Nov 23 14:20:44 2004
@@ -58,6 +58,7 @@
   ksba_reader_t reader;  /* The reader used (shallow copy). */
   unsigned char *tmpbuf; /* Helper buffer.  */
   size_t tmpbufsize;     /* Allocated size of tmpbuf.  */
+  int truncated;         /* Flag to indicate a truncated output.  */
 };
 
 
@@ -91,7 +92,7 @@
 static struct wrapper_context_s *wrapper_list;
 
 
-#if 0
+
 /* Add HOST and PORT to our list of LDAP servers.  Fixme: We should
    better use an extra list of servers. */
 static void
@@ -101,6 +102,9 @@
   ldap_server_t last = NULL;
   const char *s;
 
+  if (!port)
+    port = 389;
+
   for (server=opt.ldapservers; server; server = server->next)
     {
       if (!strcmp (server->host, host) && server->port == port)
@@ -116,21 +120,25 @@
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                  "01234567890.-", *s))
       {
-        log_error (_("invalid char 0x%02x in host name"
-                   " - not added\n"), *s);
+        log_error (_("invalid char 0x%02x in host name - not added\n"), *s);
         return;
       }
 
   log_info (_("adding `%s:%d' to the ldap server list\n"), host, port);
-  server = xcalloc (1, sizeof *s);
-  server->host = xstrdup (host);
-  server->port = port;
-  if (last)
-    last->next = server;
+  server = xtrycalloc (1, sizeof *s);
+  if (!server)
+    log_error (_("malloc failed: %s\n"), strerror (errno));
   else
-    opt.ldapservers = server;
+    {
+      server->host = xstrdup (host);
+      server->port = port;
+      if (last)
+        last->next = server;
+      else
+        opt.ldapservers = server;
+    }
 }
-#endif
+
 
 /* Release the wrapper context and kill a running wrapper process. */
 static void
@@ -745,13 +753,46 @@
                           NULL, NULL, NULL, url,
                           reader);
 
-  return err;
   /* FIXME: This option might be used for DoS attacks.  Becuase it
      will enlarge the list of servers to consult without a limit and
      all LDAP queries w/o a host are will then try each host in
-     turn.  */
-/*   if (opt.add_new_ldapservers) */
-/*     add_server_to_servers (ludp->lud_host, ludp->lud_port); */
+     turn. */
+  if (!err && opt.add_new_ldapservers && !opt.ldap_proxy) 
+    {
+      if (host)
+        add_server_to_servers (host, port);
+      else if (url)
+        {
+          char *tmp = host_and_port_from_url (url, &port);
+          add_server_to_servers (host, port);
+          xfree (tmp);
+        }
+    }
+
+  /* If the lookup failed and we are not only using the proxy, we try
+     again using our default list of servers.  */
+  if (err && !(opt.ldap_proxy && opt.only_ldap_proxy))
+    {
+      ldap_server_t server;
+      
+      if (DBG_LOOKUP)
+        log_debug ("no hostname in URL or query failed; "
+                   "trying all default hostnames\n");
+      
+      for (server = opt.ldapservers; err && server; server = server->next)
+        {
+          err = run_ldap_wrapper (ctrl,
+                                  NULL,
+                                  server->host, server->port,
+                                  NULL, NULL,
+                                  NULL, NULL, NULL, url,
+                                  reader);
+          if (!err)
+            break;
+        }
+    }
+
+  return err;
 }
 
 
@@ -766,6 +807,9 @@
   gpg_error_t err = gpg_error (GPG_ERR_CONFIGURATION);
 
   *reader = NULL;
+
+  /* FIXME; we might want to look at the Base SN to try matching
+     servers first. */
   for (server = opt.ldapservers; server; server = server->next)
     {
       err = run_ldap_wrapper (ctrl,
@@ -1087,9 +1131,10 @@
 }
 
 
-/* Fetch the next certificate. Return 0 on success, GPG_ERR_EOF
-   if no (more) certificates are available or any other error
-   code. */
+/* Fetch the next certificate. Return 0 on success, GPG_ERR_EOF if no
+   (more) certificates are available or any other error
+   code. GPG_ERR_TRUNCATED may be returned to indicate tha the result
+   has been truncated. */
 gpg_error_t
 fetch_next_cert_ldap (cert_fetch_context_t context,
   unsigned char **value, size_t *valuelen)
@@ -1099,7 +1144,6 @@
   char *p, *pend;
   int n;
   int okay = 0;
-  int truncated = 0;
 
   *value = NULL;
   *valuelen = 0;
@@ -1164,23 +1208,33 @@
                   okay = 0;
                 }
             }
+          else if (*hdr == 'E')
+            {
+              p = context->tmpbuf;
+              p[n] = 0; /*(we allocated one extra byte for this.)*/
+              if (!strcmp (p, "truncated"))
+                {
+                  context->truncated = 1;
+                  log_info (_("ldap_search hit the size limit of"
+                              " the server\n"));
+                }
+            }
         }
     }
-  
+
   if (err)
     {
       xfree (*value);
       *value = NULL;
       *valuelen = 0;
+      if (gpg_err_code (err) == GPG_ERR_EOF && context->truncated)
+        {
+          context->truncated = 0; /* So that the next call would return EOF. */
+          err = gpg_error (GPG_ERR_TRUNCATED);
+        }
     }
 
   return err;
-
-  
-/*    if (rc == LDAP_SIZELIMIT_EXCEEDED) */
-/*    { */
-  /*     truncated = 1; */
-/*       log_info (_("ldap_search hit the size limit of the server\n")); */
 }
 
 
Index: dirmngr/src/misc.c
diff -u dirmngr/src/misc.c:1.8 dirmngr/src/misc.c:1.9
--- dirmngr/src/misc.c:1.8	Tue Nov 16 19:24:35 2004
+++ dirmngr/src/misc.c	Tue Nov 23 14:20:44 2004
@@ -24,7 +24,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <errno.h>
 
+#include "util.h"
 #include "misc.h"
 #include "dirmngr.h"
 
@@ -569,3 +571,105 @@
     }
   log_debug ("END Certificate\n");
 }
+
+
+/****************
+ * Remove all %xx escapes; this is done inplace.
+ * Returns: New length of the string.
+ */
+static int
+remove_percent_escapes (unsigned char *string)
+{
+  int n = 0;
+  unsigned char *p, *s;
+
+  for (p = s = string; *s; s++)
+    {
+      if (*s == '%')
+        {
+          if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
+            {
+              s++;
+              *p = xtoi_2 (s);
+              s++;
+              p++;
+              n++;
+            }
+          else
+            {
+              *p++ = *s++;
+              if (*s)
+                *p++ = *s++;
+              if (*s)
+                *p++ = *s++;
+              if (*s)
+                *p = 0;
+              return -1;   /* Bad URI. */
+            }
+        }
+      else
+        {
+          *p++ = *s;
+          n++;
+        }
+    }
+  *p = 0;  /* Always keep a string terminator. */
+  return n;
+}
+
+
+/* Return the host name and the port (0 if none was given) from the
+   URL.  Return NULL on error or if host is not included in the
+   URL.  */
+char *
+host_and_port_from_url (const char *url, int *port)
+{
+  const char *s, *s2;
+  char *buf, *p;
+  int n;
+
+  s = url;
+
+  *port = 0;
+
+  /* Find the scheme */
+  if ( !(s2 = strchr (s, ':')) || s2 == s )
+    return NULL;  /* No scheme given. */
+  s = s2+1;
+
+  /* Find the hostname */
+  if (*s != '/')
+    return NULL; /* Does not start with a slash. */
+
+  s++;
+  if (*s != '/')
+    return NULL; /* No host name.  */
+  s++;
+
+  buf = xtrystrdup (s);
+  if (!buf)
+    {
+      log_error (_("malloc failed: %s\n"), strerror (errno));
+      return NULL;
+    }
+  if ((p = strchr (buf, '/')))
+    *p++ = 0;
+  strlwr (buf);
+  if ((p = strchr (p, ':')))
+    {
+      *p++ = 0;
+      *port = atoi (p);
+    }
+
+  /* Remove quotes and make sure that no Nul has been encoded. */
+  if ((n = remove_percent_escapes (buf)) < 0
+      || n != strlen (p) )
+    {
+      log_error (_("bad URL encoding detected\n"));
+      xfree (buf);
+      return NULL;
+    }
+
+  return buf;
+}
+
Index: dirmngr/src/misc.h
diff -u dirmngr/src/misc.h:1.8 dirmngr/src/misc.h:1.9
--- dirmngr/src/misc.h:1.8	Tue Nov 16 19:24:35 2004
+++ dirmngr/src/misc.h	Tue Nov 23 14:20:44 2004
@@ -100,7 +100,10 @@
    TEXT.  This is used for debugging. */
 void dump_cert (const char *text, ksba_cert_t cert);
 
-
+/* Return the host name and the port (0 if none was given) from the
+   URL.  Return NULL on error or if host is not included in the
+   URL.  */
+char *host_and_port_from_url (const char *url, int *port);
 
 
 #ifdef HAVE_FOPENCOOKIE
Index: dirmngr/src/no-libgcrypt.c
diff -u dirmngr/src/no-libgcrypt.c:1.1 dirmngr/src/no-libgcrypt.c:1.2
--- dirmngr/src/no-libgcrypt.c:1.1	Tue Nov 16 19:24:35 2004
+++ dirmngr/src/no-libgcrypt.c	Tue Nov 23 14:20:44 2004
@@ -90,6 +90,12 @@
 
 
 char *
+gcry_strdup (const char *string)
+{
+  return strdup (string);
+}
+
+char *
 gcry_xstrdup (const char *string)
 {
   void *p = malloc (strlen (string)+1);
Index: dirmngr/src/no-libgcrypt.h
diff -u dirmngr/src/no-libgcrypt.h:1.1 dirmngr/src/no-libgcrypt.h:1.2
--- dirmngr/src/no-libgcrypt.h:1.1	Tue Nov 16 19:24:35 2004
+++ dirmngr/src/no-libgcrypt.h	Tue Nov 23 14:20:44 2004
@@ -27,6 +27,7 @@
 void *gcry_xrealloc (void *a, size_t n);
 void *gcry_calloc (size_t n, size_t m);
 void *gcry_xcalloc (size_t n, size_t m);
+char *gcry_strdup (const char *string);
 char *gcry_xstrdup (const char *string);
 void gcry_free (void *a);
 
Index: dirmngr/src/ocsp.c
diff -u dirmngr/src/ocsp.c:1.10 dirmngr/src/ocsp.c:1.11
--- dirmngr/src/ocsp.c:1.10	Mon Nov 22 22:30:50 2004
+++ dirmngr/src/ocsp.c	Tue Nov 23 14:20:44 2004
@@ -28,6 +28,7 @@
 #include "misc.h"
 #include "http.h"
 #include "validate.h"
+#include "certcache.h"
 
 #include "ocsp.h"
 
@@ -386,12 +387,14 @@
 }
 
 
+/* Check whether the certificate either given by fingerprint CERT_FPR
+   or directly through a the CERT object is valid by running an OCSP
+   transaction.  */
 gpg_error_t
-ocsp_isvalid (ctrl_t ctrl, const char *cert_fpr)
+ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr)
 {
   gpg_error_t err;
   ksba_ocsp_t ocsp = NULL;
-  ksba_cert_t cert = NULL;
   ksba_cert_t issuer_cert = NULL;
   ksba_sexp_t sigval = NULL;
   gcry_sexp_t s_sig = NULL;
@@ -407,6 +410,38 @@
   ksba_name_t name;
   const char *default_signer = NULL;
 
+  /* Get the certificate.  */
+  if (cert)
+    {
+      ksba_cert_ref (cert);
+
+      err = find_issuing_cert (ctrl, cert, &issuer_cert);
+      if (err)
+        {
+          log_error (_("issuer certificate not found: %s\n"), 
+                     gpg_strerror (err));
+          goto leave;
+        }
+    }
+  else
+    {
+      cert = get_cert_local (ctrl, cert_fpr);
+      if (!cert)
+        {
+          log_error (_("caller did not return the target certificate\n"));
+          err = gpg_error (GPG_ERR_GENERAL);
+          goto leave;
+        }
+      issuer_cert = get_issuing_cert_local (ctrl, NULL);
+      if (!issuer_cert)
+        {
+          log_error (_("caller did not return the issuing certificate\n"));
+          err = gpg_error (GPG_ERR_GENERAL);
+          goto leave;
+        }
+    }
+
+  /* Create an OCSP instance.  */
   err = ksba_ocsp_new (&ocsp);
   if (err)
     {
@@ -415,22 +450,7 @@
       goto leave;
     }
 
-  /* We don't have any caching yet implemented thus we need to get the
-     certificate right now. */
-  cert = get_cert_local (ctrl, cert_fpr);
-  if (!cert)
-    {
-      log_error (_("caller did not return the target certificate\n"));
-      err = gpg_error (GPG_ERR_GENERAL);
-      goto leave;
-    }
-  issuer_cert = get_issuing_cert_local (ctrl, NULL);
-  if (!issuer_cert)
-    {
-      log_error (_("caller did not return the issuing certificate\n"));
-      err = gpg_error (GPG_ERR_GENERAL);
-      goto leave;
-    }
+
 
   /* Figure out the OCSP responder to use. 
      1. Try to get the reponder from the certificate.
Index: dirmngr/src/ocsp.h
diff -u dirmngr/src/ocsp.h:1.1 dirmngr/src/ocsp.h:1.2
--- dirmngr/src/ocsp.h:1.1	Thu Dec 11 12:25:25 2003
+++ dirmngr/src/ocsp.h	Tue Nov 23 14:20:44 2004
@@ -21,7 +21,6 @@
 #ifndef OCSP_H
 #define OCSP_H
 
-gpg_error_t ocsp_isvalid (ctrl_t ctrl, const char *cert_fpr);
-
+gpg_error_t ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr);
 
 #endif /*OCSP_H*/
Index: dirmngr/src/server.c
diff -u dirmngr/src/server.c:1.46 dirmngr/src/server.c:1.47
--- dirmngr/src/server.c:1.46	Mon Nov 22 22:30:50 2004
+++ dirmngr/src/server.c	Tue Nov 23 14:20:44 2004
@@ -313,7 +313,7 @@
       if (!opt.allow_ocsp)
         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
       else
-        err = ocsp_isvalid (ctrl, NULL);
+        err = ocsp_isvalid (ctrl, NULL, NULL);
       /* Fixme: If we got no ocsp response we should fall back to CRL
          mode.  Thus we need to clear OCSP_MODE, get the issuerhash
          and the serialno from the current certificate and jump to
@@ -497,13 +497,55 @@
 static int
 cmd_checkocsp (assuan_context_t ctx, char *line)
 {
-/*   ctrl_t ctrl = assuan_get_pointer (ctx); */
+  ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
+  unsigned char fprbuffer[20], *fpr;
+  ksba_cert_t cert;
 
-  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  fpr = get_fingerprint_from_line (line, fprbuffer);
+  cert = fpr? get_cert_byfpr (fpr) : NULL;
+  
+  if (!cert)
+    {
+      /* We do not have this certificate yet or the fingerprint has
+         not been given.  Inquire it from the client.  */
+      assuan_error_t ae;
+      unsigned char *value = NULL;
+      size_t valuelen; 
+      
+      ae = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
+                           &value, &valuelen, MAX_CERT_LENGTH);
+      if (ae)
+        {
+          log_error (_("assuan_inquire failed: %s\n"), assuan_strerror (ae));
+          err = map_assuan_err (ae);
+          goto leave;
+        }
+  
+      if (!valuelen) /* No data returned; return a comprehensible error. */
+        err = gpg_error (GPG_ERR_MISSING_CERT);
+      else
+        {
+          err = ksba_cert_new (&cert);
+          if (!err)
+            err = ksba_cert_init_from_mem (cert, value, valuelen);
+        }
+      xfree (value);
+      if(err)
+        goto leave;
+    }
+
+  assert (cert);
+
+  if (!opt.allow_ocsp)
+    err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+  else
+    err = ocsp_isvalid (ctrl, cert, NULL);
 
+ leave:
   if (err)
     log_error (_("command %s failed: %s\n"), "CHECKOCSP", gpg_strerror (err));
+  ksba_cert_release (cert);
   return map_to_assuan_status (err);
 }
 
@@ -583,6 +625,7 @@
             {
               truncated = 1;
               err = 0;
+              break;  /* Ready.  */
             }
           if (gpg_err_code (err) == GPG_ERR_EOF)
             {
Index: dirmngr/src/util.h
diff -u dirmngr/src/util.h:1.1 dirmngr/src/util.h:1.2
--- dirmngr/src/util.h:1.1	Tue Nov 16 19:24:35 2004
+++ dirmngr/src/util.h	Tue Nov 23 14:20:44 2004
@@ -23,6 +23,23 @@
 
 #include <gpg-error.h>
 
+/*-- b64enc.c --*/
+struct b64state 
+{ 
+  unsigned int flags;
+  int idx;
+  int quad_count;
+  FILE *fp;
+  char *title;
+  unsigned char radbuf[4];
+};
+gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title);
+gpg_error_t b64enc_write (struct b64state *state,
+                          const void *buffer, size_t nbytes);
+gpg_error_t b64enc_finish (struct b64state *state);
+
+
+
 /*-- maperror.c --*/
 gpg_error_t map_assuan_err (int err);
 




More information about the Gnupg-commits mailing list