LCOV - code coverage report
Current view: top level - dirmngr - ldap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 353 0.0 %
Date: 2016-09-12 13:01:59 Functions: 0 12 0.0 %

          Line data    Source code
       1             : /* ldap.c - LDAP access
       2             :  * Copyright (C) 2002 Klarälvdalens Datakonsult AB
       3             :  * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2010 g10 Code GmbH
       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, write to the Free Software
      19             :  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
      20             :  */
      21             : 
      22             : #include <config.h>
      23             : 
      24             : #include <stdio.h>
      25             : #include <stdlib.h>
      26             : #include <string.h>
      27             : #include <errno.h>
      28             : #include <unistd.h>
      29             : #include <fcntl.h>
      30             : #include <time.h>
      31             : #include <npth.h>
      32             : 
      33             : #include "dirmngr.h"
      34             : #include "exechelp.h"
      35             : #include "crlfetch.h"
      36             : #include "ldapserver.h"
      37             : #include "misc.h"
      38             : #include "ldap-wrapper.h"
      39             : #include "host2net.h"
      40             : 
      41             : 
      42             : #define UNENCODED_URL_CHARS "abcdefghijklmnopqrstuvwxyz"   \
      43             :                             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
      44             :                             "01234567890"                  \
      45             :                             "$-_.+!*'(),"
      46             : #define USERCERTIFICATE "userCertificate"
      47             : #define CACERTIFICATE   "caCertificate"
      48             : #define X509CACERT      "x509caCert"
      49             : #define USERSMIMECERTIFICATE "userSMIMECertificate"
      50             : 
      51             : 
      52             : /* Definition for the context of the cert fetch functions. */
      53             : struct cert_fetch_context_s
      54             : {
      55             :   ksba_reader_t reader;  /* The reader used (shallow copy). */
      56             :   unsigned char *tmpbuf; /* Helper buffer.  */
      57             :   size_t tmpbufsize;     /* Allocated size of tmpbuf.  */
      58             :   int truncated;         /* Flag to indicate a truncated output.  */
      59             : };
      60             : 
      61             : 
      62             : 
      63             : 
      64             : /* Add HOST and PORT to our list of LDAP servers.  Fixme: We should
      65             :    better use an extra list of servers. */
      66             : static void
      67           0 : add_server_to_servers (const char *host, int port)
      68             : {
      69             :   ldap_server_t server;
      70           0 :   ldap_server_t last = NULL;
      71             :   const char *s;
      72             : 
      73           0 :   if (!port)
      74           0 :     port = 389;
      75             : 
      76           0 :   for (server=opt.ldapservers; server; server = server->next)
      77             :     {
      78           0 :       if (!strcmp (server->host, host) && server->port == port)
      79           0 :           return; /* already in list... */
      80           0 :       last = server;
      81             :     }
      82             : 
      83             :   /* We assume that the host names are all supplied by our
      84             :      configuration files and thus are sane.  To keep this assumption
      85             :      we must reject all invalid host names. */
      86           0 :   for (s=host; *s; s++)
      87           0 :     if (!strchr ("abcdefghijklmnopqrstuvwxyz"
      88             :                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      89           0 :                  "01234567890.-", *s))
      90             :       {
      91           0 :         log_error (_("invalid char 0x%02x in host name - not added\n"), *s);
      92           0 :         return;
      93             :       }
      94             : 
      95           0 :   log_info (_("adding '%s:%d' to the ldap server list\n"), host, port);
      96           0 :   server = xtrycalloc (1, sizeof *s);
      97           0 :   if (!server)
      98           0 :     log_error (_("malloc failed: %s\n"), strerror (errno));
      99             :   else
     100             :     {
     101           0 :       server->host = xstrdup (host);
     102           0 :       server->port = port;
     103           0 :       if (last)
     104           0 :         last->next = server;
     105             :       else
     106           0 :         opt.ldapservers = server;
     107             :     }
     108             : }
     109             : 
     110             : 
     111             : 
     112             : 
     113             : /* Perform an LDAP query.  Returns an gpg error code or 0 on success.
     114             :    The function returns a new reader object at READER. */
     115             : static gpg_error_t
     116           0 : run_ldap_wrapper (ctrl_t ctrl,
     117             :                   int ignore_timeout,
     118             :                   int multi_mode,
     119             :                   const char *proxy,
     120             :                   const char *host, int port,
     121             :                   const char *user, const char *pass,
     122             :                   const char *dn, const char *filter, const char *attr,
     123             :                   const char *url,
     124             :                   ksba_reader_t *reader)
     125             : {
     126             :   const char *argv[40];
     127             :   int argc;
     128             :   char portbuf[30], timeoutbuf[30];
     129             : 
     130             : 
     131           0 :   *reader = NULL;
     132             : 
     133           0 :   argc = 0;
     134           0 :   if (pass)  /* Note, that the password must be the first item.  */
     135             :     {
     136           0 :       argv[argc++] = "--pass";
     137           0 :       argv[argc++] = pass;
     138             :     }
     139           0 :   if (opt.verbose)
     140           0 :     argv[argc++] = "-vv";
     141           0 :   argv[argc++] = "--log-with-pid";
     142           0 :   if (multi_mode)
     143           0 :     argv[argc++] = "--multi";
     144           0 :   if (opt.ldaptimeout)
     145             :     {
     146           0 :       sprintf (timeoutbuf, "%u", opt.ldaptimeout);
     147           0 :       argv[argc++] = "--timeout";
     148           0 :       argv[argc++] = timeoutbuf;
     149           0 :       if (ignore_timeout)
     150           0 :         argv[argc++] = "--only-search-timeout";
     151             :     }
     152           0 :   if (proxy)
     153             :     {
     154           0 :       argv[argc++] = "--proxy";
     155           0 :       argv[argc++] = proxy;
     156             :     }
     157           0 :   if (host)
     158             :     {
     159           0 :       argv[argc++] = "--host";
     160           0 :       argv[argc++] = host;
     161             :     }
     162           0 :   if (port)
     163             :     {
     164           0 :       sprintf (portbuf, "%d", port);
     165           0 :       argv[argc++] = "--port";
     166           0 :       argv[argc++] = portbuf;
     167             :     }
     168           0 :   if (user)
     169             :     {
     170           0 :       argv[argc++] = "--user";
     171           0 :       argv[argc++] = user;
     172             :     }
     173           0 :   if (dn)
     174             :     {
     175           0 :       argv[argc++] = "--dn";
     176           0 :       argv[argc++] = dn;
     177             :     }
     178           0 :   if (filter)
     179             :     {
     180           0 :       argv[argc++] = "--filter";
     181           0 :       argv[argc++] = filter;
     182             :     }
     183           0 :   if (attr)
     184             :     {
     185           0 :       argv[argc++] = "--attr";
     186           0 :       argv[argc++] = attr;
     187             :     }
     188           0 :   argv[argc++] = url? url : "ldap://";
     189           0 :   argv[argc] = NULL;
     190             : 
     191           0 :   return ldap_wrapper (ctrl, reader, argv);
     192             : }
     193             : 
     194             : 
     195             : 
     196             : 
     197             : /* Perform a LDAP query using a given URL. On success a new ksba
     198             :    reader is returned.  If HOST or PORT are not 0, they are used to
     199             :    override the values from the URL. */
     200             : gpg_error_t
     201           0 : url_fetch_ldap (ctrl_t ctrl, const char *url, const char *host, int port,
     202             :                 ksba_reader_t *reader)
     203             : {
     204             :   gpg_error_t err;
     205             : 
     206           0 :   err = run_ldap_wrapper (ctrl,
     207             :                           1, /* Ignore explicit timeout because CRLs
     208             :                                 might be very large. */
     209             :                           0,
     210             :                           opt.ldap_proxy,
     211             :                           host, port,
     212             :                           NULL, NULL,
     213             :                           NULL, NULL, NULL, url,
     214             :                           reader);
     215             : 
     216             :   /* FIXME: This option might be used for DoS attacks.  Because it
     217             :      will enlarge the list of servers to consult without a limit and
     218             :      all LDAP queries w/o a host are will then try each host in
     219             :      turn. */
     220           0 :   if (!err && opt.add_new_ldapservers && !opt.ldap_proxy)
     221             :     {
     222           0 :       if (host)
     223           0 :         add_server_to_servers (host, port);
     224           0 :       else if (url)
     225             :         {
     226           0 :           char *tmp = host_and_port_from_url (url, &port);
     227           0 :           if (tmp)
     228             :             {
     229           0 :               add_server_to_servers (tmp, port);
     230           0 :               xfree (tmp);
     231             :             }
     232             :         }
     233             :     }
     234             : 
     235             :   /* If the lookup failed and we are not only using the proxy, we try
     236             :      again using our default list of servers.  */
     237           0 :   if (err && !(opt.ldap_proxy && opt.only_ldap_proxy))
     238             :     {
     239             :       struct ldapserver_iter iter;
     240             : 
     241           0 :       if (DBG_LOOKUP)
     242           0 :         log_debug ("no hostname in URL or query failed; "
     243             :                    "trying all default hostnames\n");
     244             : 
     245           0 :       for (ldapserver_iter_begin (&iter, ctrl);
     246           0 :            err && ! ldapserver_iter_end_p (&iter);
     247           0 :            ldapserver_iter_next (&iter))
     248             :         {
     249           0 :           ldap_server_t server = iter.server;
     250             : 
     251           0 :           err = run_ldap_wrapper (ctrl,
     252             :                                   0,
     253             :                                   0,
     254             :                                   NULL,
     255           0 :                                   server->host, server->port,
     256             :                                   NULL, NULL,
     257             :                                   NULL, NULL, NULL, url,
     258             :                                   reader);
     259           0 :           if (!err)
     260           0 :             break;
     261             :         }
     262             :     }
     263             : 
     264           0 :   return err;
     265             : }
     266             : 
     267             : 
     268             : 
     269             : /* Perform an LDAP query on all configured servers.  On error the
     270             :    error code of the last try is returned.  */
     271             : gpg_error_t
     272           0 : attr_fetch_ldap (ctrl_t ctrl,
     273             :                  const char *dn, const char *attr, ksba_reader_t *reader)
     274             : {
     275           0 :   gpg_error_t err = gpg_error (GPG_ERR_CONFIGURATION);
     276             :   struct ldapserver_iter iter;
     277             : 
     278           0 :   *reader = NULL;
     279             : 
     280             :   /* FIXME; we might want to look at the Base SN to try matching
     281             :      servers first. */
     282           0 :   for (ldapserver_iter_begin (&iter, ctrl); ! ldapserver_iter_end_p (&iter);
     283           0 :        ldapserver_iter_next (&iter))
     284             :     {
     285           0 :       ldap_server_t server = iter.server;
     286             : 
     287           0 :       err = run_ldap_wrapper (ctrl,
     288             :                               0,
     289             :                               0,
     290             :                               opt.ldap_proxy,
     291           0 :                               server->host, server->port,
     292           0 :                               server->user, server->pass,
     293             :                               dn, "objectClass=*", attr, NULL,
     294             :                               reader);
     295           0 :       if (!err)
     296           0 :         break; /* Probably found a result. Ready. */
     297             :     }
     298           0 :   return err;
     299             : }
     300             : 
     301             : 
     302             : /* Parse PATTERN and return a new strlist to be used for the actual
     303             :    LDAP query.  Bit 0 of the flags field is set if that pattern is
     304             :    actually a base specification.  Caller must release the returned
     305             :    strlist.  NULL is returned on error.
     306             : 
     307             :  * Possible patterns:
     308             :  *
     309             :  *   KeyID
     310             :  *   Fingerprint
     311             :  *   OpenPGP userid
     312             :  * x Email address  Indicated by a left angle bracket.
     313             :  *   Exact word match in user id or subj. name
     314             :  * x Subj. DN  indicated bu a leading slash
     315             :  *   Issuer DN
     316             :  *   Serial number + subj. DN
     317             :  * x Substring match indicated by a leading '*; is also the default.
     318             :  */
     319             : 
     320             : strlist_t
     321           0 : parse_one_pattern (const char *pattern)
     322             : {
     323           0 :   strlist_t result = NULL;
     324             :   char *p;
     325             : 
     326           0 :   switch (*pattern)
     327             :     {
     328             :     case '<':                        /* Email. */
     329             :       {
     330           0 :         pattern++;
     331           0 :         result = xmalloc (sizeof *result + 5 + strlen (pattern));
     332           0 :         result->next = NULL;
     333           0 :         result->flags = 0;
     334           0 :         p = stpcpy (stpcpy (result->d, "mail="), pattern);
     335           0 :         if (p[-1] == '>')
     336           0 :           *--p = 0;
     337           0 :         if (!*result->d) /* Error. */
     338             :           {
     339           0 :             xfree (result);
     340           0 :             result = NULL;
     341             :           }
     342           0 :         break;
     343             :       }
     344             :     case '/':                   /* Subject DN. */
     345           0 :       pattern++;
     346           0 :       if (*pattern)
     347             :         {
     348           0 :           result = xmalloc (sizeof *result + strlen (pattern));
     349           0 :           result->next = NULL;
     350           0 :           result->flags = 1; /* Base spec. */
     351           0 :           strcpy (result->d, pattern);
     352             :         }
     353           0 :       break;
     354             :     case '#':                   /* Issuer DN. */
     355           0 :       pattern++;
     356           0 :       if (*pattern == '/')  /* Just issuer DN. */
     357             :         {
     358           0 :           pattern++;
     359             :         }
     360             :       else  /* Serial number + issuer DN */
     361             :         {
     362             :         }
     363           0 :       break;
     364             :     case '*':
     365           0 :       pattern++;
     366             :     default:                    /* Take as substring match. */
     367             :       {
     368           0 :         const char format[] = "(|(sn=*%s*)(|(cn=*%s*)(mail=*%s*)))";
     369             : 
     370           0 :         if (*pattern)
     371             :           {
     372           0 :             result = xmalloc (sizeof *result
     373             :                               + strlen (format) + 3 * strlen (pattern));
     374           0 :             result->next = NULL;
     375           0 :             result->flags = 0;
     376           0 :             sprintf (result->d, format, pattern, pattern, pattern);
     377             :           }
     378             :       }
     379           0 :       break;
     380             :     }
     381             : 
     382           0 :   return result;
     383             : }
     384             : 
     385             : /* Take the string STRING and escape it according to the URL rules.
     386             :    Retun a newly allocated string. */
     387             : static char *
     388           0 : escape4url (const char *string)
     389             : {
     390             :   const char *s;
     391             :   char *buf, *p;
     392             :   size_t n;
     393             : 
     394           0 :   if (!string)
     395           0 :     string = "";
     396             : 
     397           0 :   for (s=string,n=0; *s; s++)
     398           0 :     if (strchr (UNENCODED_URL_CHARS, *s))
     399           0 :       n++;
     400             :     else
     401           0 :       n += 3;
     402             : 
     403           0 :   buf = malloc (n+1);
     404           0 :   if (!buf)
     405           0 :     return NULL;
     406             : 
     407           0 :   for (s=string,p=buf; *s; s++)
     408           0 :     if (strchr (UNENCODED_URL_CHARS, *s))
     409           0 :       *p++ = *s;
     410             :     else
     411             :       {
     412           0 :         sprintf (p, "%%%02X", *(const unsigned char *)s);
     413           0 :         p += 3;
     414             :       }
     415           0 :   *p = 0;
     416             : 
     417           0 :   return buf;
     418             : }
     419             : 
     420             : 
     421             : 
     422             : /* Create a LDAP URL from DN and FILTER and return it in URL.  We don't
     423             :    need the host and port because this will be specified using the
     424             :    override options. */
     425             : static gpg_error_t
     426           0 : make_url (char **url, const char *dn, const char *filter)
     427             : {
     428             :   gpg_error_t err;
     429             :   char *u_dn, *u_filter;
     430           0 :   char const attrs[] = (USERCERTIFICATE ","
     431             : /*                         USERSMIMECERTIFICATE "," */
     432             :                         CACERTIFICATE ","
     433             :                         X509CACERT );
     434             : 
     435           0 :   *url = NULL;
     436             : 
     437           0 :   u_dn = escape4url (dn);
     438           0 :   if (!u_dn)
     439           0 :       return gpg_error_from_errno (errno);
     440             : 
     441           0 :   u_filter = escape4url (filter);
     442           0 :   if (!u_filter)
     443             :     {
     444           0 :       err = gpg_error_from_errno (errno);
     445           0 :       xfree (u_dn);
     446           0 :       return err;
     447             :     }
     448           0 :   *url = malloc ( 8 + strlen (u_dn)
     449           0 :                  + 1 + strlen (attrs)
     450           0 :                  + 5 + strlen (u_filter) + 1 );
     451           0 :   if (!*url)
     452             :     {
     453           0 :       err = gpg_error_from_errno (errno);
     454           0 :       xfree (u_dn);
     455           0 :       xfree (u_filter);
     456           0 :       return err;
     457             :     }
     458             : 
     459           0 :   stpcpy (stpcpy (stpcpy (stpcpy (stpcpy (stpcpy (*url, "ldap:///"),
     460             :                                           u_dn),
     461             :                                   "?"),
     462             :                           attrs),
     463             :                   "?sub?"),
     464             :           u_filter);
     465           0 :   xfree (u_dn);
     466           0 :   xfree (u_filter);
     467           0 :   return 0;
     468             : }
     469             : 
     470             : 
     471             : /* Prepare an LDAP query to return the attribute ATTR for the DN.  All
     472             :    configured default servers are queried until one responds.  This
     473             :    function returns an error code or 0 and a CONTEXT on success. */
     474             : gpg_error_t
     475           0 : start_default_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
     476             :                           const char *dn, const char *attr)
     477             : {
     478             :   gpg_error_t err;
     479             :   struct ldapserver_iter iter;
     480             : 
     481           0 :   *context = xtrycalloc (1, sizeof **context);
     482           0 :   if (!*context)
     483           0 :     return gpg_error_from_errno (errno);
     484             : 
     485             :   /* FIXME; we might want to look at the Base SN to try matching
     486             :      servers first. */
     487           0 :   err = gpg_error (GPG_ERR_CONFIGURATION);
     488             : 
     489           0 :   for (ldapserver_iter_begin (&iter, ctrl); ! ldapserver_iter_end_p (&iter);
     490           0 :        ldapserver_iter_next (&iter))
     491             :     {
     492           0 :       ldap_server_t server = iter.server;
     493             : 
     494           0 :       err = run_ldap_wrapper (ctrl,
     495             :                               0,
     496             :                               1,
     497             :                               opt.ldap_proxy,
     498           0 :                               server->host, server->port,
     499           0 :                               server->user, server->pass,
     500             :                               dn, "objectClass=*", attr, NULL,
     501           0 :                               &(*context)->reader);
     502           0 :       if (!err)
     503           0 :         break; /* Probably found a result. */
     504             :     }
     505             : 
     506           0 :   if (err)
     507             :     {
     508           0 :       xfree (*context);
     509           0 :       *context = NULL;
     510             :     }
     511           0 :   return err;
     512             : }
     513             : 
     514             : 
     515             : /* Prepare an LDAP query to return certificates matching PATTERNS using
     516             :    the SERVER.  This function returns an error code or 0 and a CONTEXT
     517             :    on success. */
     518             : gpg_error_t
     519           0 : start_cert_fetch_ldap (ctrl_t ctrl, cert_fetch_context_t *context,
     520             :                        strlist_t patterns, const ldap_server_t server)
     521             : {
     522             :   gpg_error_t err;
     523           0 :   char *proxy = NULL;
     524           0 :   char *host = NULL;
     525             :   int port;
     526           0 :   char *user = NULL;
     527           0 :   char *pass = NULL;
     528             :   const char *base;
     529             :   char *argv[50];
     530           0 :   int argc = 0;
     531           0 :   int argc_malloced = 0;
     532             :   char portbuf[30], timeoutbuf[30];
     533             : 
     534             : 
     535           0 :   *context = NULL;
     536             : 
     537           0 :   if (opt.ldap_proxy && !(proxy = xtrystrdup (opt.ldap_proxy)))
     538             :     {
     539           0 :       err = gpg_error_from_syserror ();
     540           0 :       goto leave;
     541             :     }
     542             : 
     543           0 :   if (server)
     544             :     {
     545           0 :       if (server->host && !(host = xtrystrdup (server->host)))
     546             :         {
     547           0 :           err = gpg_error_from_syserror ();
     548           0 :           goto leave;
     549             :         }
     550           0 :       port = server->port;
     551           0 :       if (server->user && !(user = xtrystrdup (server->user)))
     552             :         {
     553           0 :           err = gpg_error_from_syserror ();
     554           0 :           goto leave;
     555             :         }
     556           0 :       if (server->pass && !(pass = xtrystrdup (server->pass)))
     557             :         {
     558           0 :           err = gpg_error_from_syserror ();
     559           0 :           goto leave;
     560             :         }
     561           0 :       base = server->base;
     562             : 
     563             :     }
     564             :   else /* Use a default server. */
     565           0 :     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     566             : 
     567             : 
     568           0 :   if (!base)
     569           0 :     base = "";
     570             : 
     571           0 :   if (pass) /* Note: Must be the first item. */
     572             :     {
     573           0 :       argv[argc++] = "--pass";
     574           0 :       argv[argc++] = pass;
     575             :     }
     576           0 :   if (opt.verbose)
     577           0 :     argv[argc++] = "-vv";
     578           0 :   argv[argc++] = "--log-with-pid";
     579           0 :   argv[argc++] = "--multi";
     580           0 :   if (opt.ldaptimeout)
     581             :     {
     582           0 :       snprintf (timeoutbuf, sizeof timeoutbuf, "%u", opt.ldaptimeout);
     583           0 :       argv[argc++] = "--timeout";
     584           0 :       argv[argc++] = timeoutbuf;
     585             :     }
     586           0 :   if (opt.ldap_proxy)
     587             :     {
     588           0 :       argv[argc++] = "--proxy";
     589           0 :       argv[argc++] = proxy;
     590             :     }
     591           0 :   if (host)
     592             :     {
     593           0 :       argv[argc++] = "--host";
     594           0 :       argv[argc++] = host;
     595             :     }
     596           0 :   if (port)
     597             :     {
     598           0 :       snprintf (portbuf, sizeof portbuf, "%d", port);
     599           0 :       argv[argc++] = "--port";
     600           0 :       argv[argc++] = portbuf;
     601             :     }
     602           0 :   if (user)
     603             :     {
     604           0 :       argv[argc++] = "--user";
     605           0 :       argv[argc++] = user;
     606             :     }
     607             : 
     608             :   /* All entries in argv from this index on are malloc'ed.  */
     609           0 :   argc_malloced = argc;
     610             : 
     611           0 :   for (; patterns; patterns = patterns->next)
     612             :     {
     613             :       strlist_t sl;
     614             :       char *url;
     615             : 
     616           0 :       if (argc >= DIM (argv) - 1)
     617             :         {
     618             :           /* Too many patterns.  It does not make sense to allow an
     619             :              arbitrary number of patters because the length of the
     620             :              command line is limited anyway.  */
     621             :           /* fixme: cleanup. */
     622           0 :           return gpg_error (GPG_ERR_RESOURCE_LIMIT);
     623             :         }
     624           0 :       sl = parse_one_pattern (patterns->d);
     625           0 :       if (!sl)
     626             :         {
     627           0 :           log_error (_("start_cert_fetch: invalid pattern '%s'\n"),
     628           0 :                      patterns->d);
     629           0 :           err = gpg_error (GPG_ERR_INV_USER_ID);
     630           0 :           goto leave;
     631             :         }
     632           0 :       if ((sl->flags & 1))
     633           0 :         err = make_url (&url, sl->d, "objectClass=*");
     634             :       else
     635           0 :         err = make_url (&url, base, sl->d);
     636           0 :       free_strlist (sl);
     637           0 :       if (err)
     638           0 :         goto leave;
     639           0 :       argv[argc++] = url;
     640             :     }
     641           0 :   argv[argc] = NULL;
     642             : 
     643           0 :   *context = xtrycalloc (1, sizeof **context);
     644           0 :   if (!*context)
     645             :     {
     646           0 :       err = gpg_error_from_errno (errno);
     647           0 :       goto leave;
     648             :     }
     649             : 
     650           0 :   err = ldap_wrapper (ctrl, &(*context)->reader, (const char**)argv);
     651             : 
     652           0 :   if (err)
     653             :     {
     654           0 :       xfree (*context);
     655           0 :       *context = NULL;
     656             :     }
     657             : 
     658             :  leave:
     659           0 :   for (; argc_malloced < argc; argc_malloced++)
     660           0 :     xfree (argv[argc_malloced]);
     661           0 :   xfree (proxy);
     662           0 :   xfree (host);
     663           0 :   xfree (user);
     664           0 :   xfree (pass);
     665           0 :   return err;
     666             : }
     667             : 
     668             : 
     669             : /* Read a fixed amount of data from READER into BUFFER.  */
     670             : static gpg_error_t
     671           0 : read_buffer (ksba_reader_t reader, unsigned char *buffer, size_t count)
     672             : {
     673             :   gpg_error_t err;
     674             :   size_t nread;
     675             : 
     676           0 :   while (count)
     677             :     {
     678           0 :       err = ksba_reader_read (reader, buffer, count, &nread);
     679           0 :       if (err)
     680           0 :         return err;
     681           0 :       buffer += nread;
     682           0 :       count -= nread;
     683             :     }
     684           0 :   return 0;
     685             : }
     686             : 
     687             : 
     688             : /* Fetch the next certificate. Return 0 on success, GPG_ERR_EOF if no
     689             :    (more) certificates are available or any other error
     690             :    code. GPG_ERR_TRUNCATED may be returned to indicate that the result
     691             :    has been truncated. */
     692             : gpg_error_t
     693           0 : fetch_next_cert_ldap (cert_fetch_context_t context,
     694             :                       unsigned char **value, size_t *valuelen)
     695             : {
     696             :   gpg_error_t err;
     697             :   unsigned char hdr[5];
     698             :   char *p, *pend;
     699             :   unsigned long n;
     700           0 :   int okay = 0;
     701             :   /* int is_cms = 0; */
     702             : 
     703           0 :   *value = NULL;
     704           0 :   *valuelen = 0;
     705             : 
     706           0 :   err = 0;
     707           0 :   while (!err)
     708             :     {
     709           0 :       err = read_buffer (context->reader, hdr, 5);
     710           0 :       if (err)
     711           0 :         break;
     712           0 :       n = buf32_to_ulong (hdr+1);
     713           0 :       if (*hdr == 'V' && okay)
     714             :         {
     715             : #if 0  /* That code is not yet ready.  */
     716             : 
     717             :           if (is_cms)
     718             :             {
     719             :               /* The certificate needs to be parsed from CMS data. */
     720             :               ksba_cms_t cms;
     721             :               ksba_stop_reason_t stopreason;
     722             :               int i;
     723             : 
     724             :               err = ksba_cms_new (&cms);
     725             :               if (err)
     726             :                 goto leave;
     727             :               err = ksba_cms_set_reader_writer (cms, context->reader, NULL);
     728             :               if (err)
     729             :                 {
     730             :                   log_error ("ksba_cms_set_reader_writer failed: %s\n",
     731             :                              gpg_strerror (err));
     732             :                   goto leave;
     733             :                 }
     734             : 
     735             :               do
     736             :                 {
     737             :                   err = ksba_cms_parse (cms, &stopreason);
     738             :                   if (err)
     739             :                     {
     740             :                       log_error ("ksba_cms_parse failed: %s\n",
     741             :                                  gpg_strerror (err));
     742             :                       goto leave;
     743             :                     }
     744             : 
     745             :                   if (stopreason == KSBA_SR_BEGIN_DATA)
     746             :                     log_error ("userSMIMECertificate is not "
     747             :                                "a certs-only message\n");
     748             :                 }
     749             :               while (stopreason != KSBA_SR_READY);
     750             : 
     751             :               for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
     752             :                 {
     753             :                   check_and_store (ctrl, stats, cert, 0);
     754             :                   ksba_cert_release (cert);
     755             :                   cert = NULL;
     756             :                 }
     757             :               if (!i)
     758             :                 log_error ("no certificate found\n");
     759             :               else
     760             :                 any = 1;
     761             :             }
     762             :           else
     763             : #endif
     764             :             {
     765           0 :               *value = xtrymalloc (n);
     766           0 :               if (!*value)
     767           0 :                 return gpg_error_from_errno (errno);
     768           0 :               *valuelen = n;
     769           0 :               err = read_buffer (context->reader, *value, n);
     770           0 :               break; /* Ready or error.  */
     771             :             }
     772             :         }
     773           0 :       else if (!n && *hdr == 'A')
     774           0 :         okay = 0;
     775           0 :       else if (n)
     776             :         {
     777           0 :           if (n > context->tmpbufsize)
     778             :             {
     779           0 :               xfree (context->tmpbuf);
     780           0 :               context->tmpbufsize = 0;
     781           0 :               context->tmpbuf = xtrymalloc (n+1);
     782           0 :               if (!context->tmpbuf)
     783           0 :                 return gpg_error_from_errno (errno);
     784           0 :               context->tmpbufsize = n;
     785             :             }
     786           0 :           err = read_buffer (context->reader, context->tmpbuf, n);
     787           0 :           if (err)
     788           0 :             break;
     789           0 :           if (*hdr == 'A')
     790             :             {
     791           0 :               p = context->tmpbuf;
     792           0 :               p[n] = 0; /*(we allocated one extra byte for this.)*/
     793             :               /* fixme: is_cms = 0; */
     794           0 :               if ( (pend = strchr (p, ';')) )
     795           0 :                 *pend = 0; /* Strip off the extension. */
     796           0 :               if (!ascii_strcasecmp (p, USERCERTIFICATE))
     797             :                 {
     798           0 :                   if (DBG_LOOKUP)
     799           0 :                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
     800             :                                USERCERTIFICATE);
     801           0 :                   okay = 1;
     802             :                 }
     803           0 :               else if (!ascii_strcasecmp (p, CACERTIFICATE))
     804             :                 {
     805           0 :                   if (DBG_LOOKUP)
     806           0 :                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
     807             :                                CACERTIFICATE);
     808           0 :                   okay = 1;
     809             :                 }
     810           0 :               else if (!ascii_strcasecmp (p, X509CACERT))
     811             :                 {
     812           0 :                   if (DBG_LOOKUP)
     813           0 :                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
     814             :                                CACERTIFICATE);
     815           0 :                   okay = 1;
     816             :                 }
     817             : /*               else if (!ascii_strcasecmp (p, USERSMIMECERTIFICATE)) */
     818             : /*                 { */
     819             : /*                   if (DBG_LOOKUP) */
     820             : /*                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n", */
     821             : /*                                USERSMIMECERTIFICATE); */
     822             : /*                   okay = 1; */
     823             : /*                   is_cms = 1; */
     824             : /*                 } */
     825             :               else
     826             :                 {
     827           0 :                   if (DBG_LOOKUP)
     828           0 :                     log_debug ("fetch_next_cert_ldap: got attribute '%s'"
     829             :                                " -  ignored\n", p);
     830           0 :                   okay = 0;
     831             :                 }
     832             :             }
     833           0 :           else if (*hdr == 'E')
     834             :             {
     835           0 :               p = context->tmpbuf;
     836           0 :               p[n] = 0; /*(we allocated one extra byte for this.)*/
     837           0 :               if (!strcmp (p, "truncated"))
     838             :                 {
     839           0 :                   context->truncated = 1;
     840           0 :                   log_info (_("ldap_search hit the size limit of"
     841             :                               " the server\n"));
     842             :                 }
     843             :             }
     844             :         }
     845             :     }
     846             : 
     847           0 :   if (err)
     848             :     {
     849           0 :       xfree (*value);
     850           0 :       *value = NULL;
     851           0 :       *valuelen = 0;
     852           0 :       if (gpg_err_code (err) == GPG_ERR_EOF && context->truncated)
     853             :         {
     854           0 :           context->truncated = 0; /* So that the next call would return EOF. */
     855           0 :           err = gpg_error (GPG_ERR_TRUNCATED);
     856             :         }
     857             :     }
     858             : 
     859           0 :   return err;
     860             : }
     861             : 
     862             : 
     863             : void
     864           0 : end_cert_fetch_ldap (cert_fetch_context_t context)
     865             : {
     866           0 :   if (context)
     867             :     {
     868           0 :       ksba_reader_t reader = context->reader;
     869             : 
     870           0 :       xfree (context->tmpbuf);
     871           0 :       xfree (context);
     872           0 :       ldap_wrapper_release_context (reader);
     873           0 :       ksba_reader_release (reader);
     874             :     }
     875           0 : }

Generated by: LCOV version 1.11