tests: Move environment creation and teardown into each test.
[gnupg.git] / dirmngr / ks-engine-ldap.c
index bf56d35..ee55bf2 100644 (file)
@@ -16,7 +16,7 @@
  * 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, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -306,7 +306,9 @@ ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri)
     "Supported methods: search, get, put\n";
   gpg_error_t err;
 
-  if (strcmp (uri->scheme, "ldap") == 0
+  if(!uri)
+    err = ks_print_help (ctrl, "  ldap");
+  else if (strcmp (uri->scheme, "ldap") == 0
       || strcmp (uri->scheme, "ldaps") == 0
       || strcmp (uri->scheme, "ldapi") == 0)
     err = ks_print_help (ctrl, data);
@@ -431,16 +433,16 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact)
 
    If this function successfully interrogated the server, it returns
    0.  If there was an LDAP error, it returns the LDAP error code.  If
-   an error occured, *basednp, etc., are undefined (and don't need to
+   an error occurred, *basednp, etc., are undefined (and don't need to
    be freed.)
 
-   If no LDAP error occured, you still need to check that *basednp is
+   If no LDAP error occurred, you still need to check that *basednp is
    valid.  If it is NULL, then the server does not appear to be an
    OpenPGP Keyserver.  In this case, you also do not need to xfree
    *pgpkeyattrp.  */
 static int
-ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
-             char **basednp, char **pgpkeyattrp, int *real_ldapp)
+my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
+                 char **basednp, char **pgpkeyattrp, int *real_ldapp)
 {
   int err = 0;
 
@@ -455,7 +457,7 @@ ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
   char *pgpkeyattr = "pgpKey";
   int real_ldap = 0;
 
-  log_debug ("ldap_connect(%s:%d/%s????%s%s%s%s%s)\n",
+  log_debug ("my_ldap_connect(%s:%d/%s????%s%s%s%s%s)\n",
             uri->host, uri->port,
             uri->path ?: "",
             uri->auth ? "bindname=" : "", uri->auth ?: "",
@@ -511,12 +513,13 @@ ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
 #endif /* LDAP_OPT_X_TLS_CACERTFILE && HAVE_LDAP_SET_OPTION */
 #endif
 
-#ifndef HAVE_LDAP_START_TLS_S
+#ifdef HAVE_LDAP_START_TLS_S
   if (uri->use_tls)
     {
       /* XXX: We need an option to determine whether to abort if the
         certificate is bad or not.  Right now we conservatively
         default to checking the certificate and aborting.  */
+#ifndef HAVE_W32_SYSTEM
       int check_cert = LDAP_OPT_X_TLS_HARD; /* LDAP_OPT_X_TLS_NEVER */
 
       err = ldap_set_option (ldap_conn,
@@ -526,8 +529,21 @@ ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
          log_error ("Failed to set TLS option on LDAP connection.\n");
          goto out;
        }
+#else
+      /* On Windows, the certificates are checked by default.  If the
+        option to disable checking mentioned above is ever
+        implemented, the way to do that on Windows is to install a
+        callback routine using ldap_set_option (..,
+        LDAP_OPT_SERVER_CERTIFICATE, ..); */
+#endif
 
-      err = ldap_start_tls_s (ldap_conn, NULL, NULL);
+      err = ldap_start_tls_s (ldap_conn,
+#ifdef HAVE_W32_SYSTEM
+                             /* ServerReturnValue, result */
+                             NULL, NULL,
+#endif
+                             /* ServerControls, ClientControls */
+                             NULL, NULL);
       if (err)
        {
          log_error ("Failed to connect to LDAP server with TLS.\n");
@@ -834,6 +850,13 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
 
   (void) ctrl;
 
+  if (opt.use_tor)
+    {
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("LDAP access not possible due to Tor mode\n"));
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
+
   /* Before connecting to the server, make sure we have a sane
      keyspec.  If not, there is no need to establish a network
      connection.  */
@@ -842,7 +865,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
     return (err);
 
   /* Make sure we are talking to an OpenPGP LDAP server.  */
-  ldap_err = ldap_connect (uri, &ldap_conn, &basedn, &pgpkeyattr, NULL);
+  ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &pgpkeyattr, NULL);
   if (ldap_err || !basedn)
     {
       if (ldap_err)
@@ -1010,6 +1033,13 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
 
   (void) ctrl;
 
+  if (opt.use_tor)
+    {
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("LDAP access not possible due to Tor mode\n"));
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
+
   /* Before connecting to the server, make sure we have a sane
      keyspec.  If not, there is no need to establish a network
      connection.  */
@@ -1021,7 +1051,7 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
     }
 
   /* Make sure we are talking to an OpenPGP LDAP server.  */
-  ldap_err = ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL);
+  ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL);
   if (ldap_err || !basedn)
     {
       if (ldap_err)
@@ -1123,118 +1153,117 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
 
                es_fprintf (fp, "pub:%s:",certid[0]);
 
-                 vals = ldap_get_values (ldap_conn, each, "pgpkeytype");
-                 if (vals)
-                   {
-                     /* The LDAP server doesn't exactly handle this
-                        well. */
-                     if (strcasecmp (vals[0], "RSA") == 0)
-                       es_fputs ("1", fp);
-                     else if (strcasecmp (vals[0], "DSS/DH") == 0)
-                       es_fputs ("17", fp);
-                     ldap_value_free (vals);
-                   }
-
-                 es_fputc (':', fp);
-
-                 vals = ldap_get_values (ldap_conn, each, "pgpkeysize");
-                 if (vals)
-                   {
-                     /* Not sure why, but some keys are listed with a
-                        key size of 0.  Treat that like an
-                        unknown. */
-                     if (atoi (vals[0]) > 0)
-                       es_fprintf (fp, "%d", atoi (vals[0]));
-                     ldap_value_free (vals);
-                   }
-
-                 es_fputc (':', fp);
-
-                 /* YYYYMMDDHHmmssZ */
-
-                 vals = ldap_get_values (ldap_conn, each, "pgpkeycreatetime");
-                 if(vals && strlen (vals[0]) == 15)
-                   {
-                     es_fprintf (fp, "%u",
-                                 (unsigned int) ldap2epochtime(vals[0]));
-                     ldap_value_free (vals);
-                   }
-
-                 es_fputc (':', fp);
-
-                 vals = ldap_get_values (ldap_conn, each, "pgpkeyexpiretime");
-                 if (vals && strlen (vals[0]) == 15)
-                   {
-                     es_fprintf (fp, "%u",
-                                 (unsigned int) ldap2epochtime (vals[0]));
-                     ldap_value_free (vals);
-                   }
-
-                 es_fputc (':', fp);
-
-                 vals = ldap_get_values (ldap_conn, each, "pgprevoked");
-                 if (vals)
-                   {
-                     if (atoi (vals[0]) == 1)
-                       es_fprintf (fp, "r");
-                     ldap_value_free (vals);
-                   }
-
-                 vals = ldap_get_values (ldap_conn, each, "pgpdisabled");
-                 if (vals)
-                   {
-                     if (atoi (vals[0]) ==1)
-                       es_fprintf (fp, "d");
-                     ldap_value_free (vals);
-                   }
+               vals = ldap_get_values (ldap_conn, each, "pgpkeytype");
+               if (vals)
+                 {
+                   /* The LDAP server doesn't exactly handle this
+                      well. */
+                   if (strcasecmp (vals[0], "RSA") == 0)
+                     es_fputs ("1", fp);
+                   else if (strcasecmp (vals[0], "DSS/DH") == 0)
+                     es_fputs ("17", fp);
+                   ldap_value_free (vals);
+                 }
+
+               es_fputc (':', fp);
+
+               vals = ldap_get_values (ldap_conn, each, "pgpkeysize");
+               if (vals)
+                 {
+                   /* Not sure why, but some keys are listed with a
+                      key size of 0.  Treat that like an unknown. */
+                   if (atoi (vals[0]) > 0)
+                     es_fprintf (fp, "%d", atoi (vals[0]));
+                   ldap_value_free (vals);
+                 }
+
+               es_fputc (':', fp);
+
+               /* YYYYMMDDHHmmssZ */
+
+               vals = ldap_get_values (ldap_conn, each, "pgpkeycreatetime");
+               if(vals && strlen (vals[0]) == 15)
+                 {
+                   es_fprintf (fp, "%u",
+                               (unsigned int) ldap2epochtime(vals[0]));
+                   ldap_value_free (vals);
+                 }
+
+               es_fputc (':', fp);
+
+               vals = ldap_get_values (ldap_conn, each, "pgpkeyexpiretime");
+               if (vals && strlen (vals[0]) == 15)
+                 {
+                   es_fprintf (fp, "%u",
+                               (unsigned int) ldap2epochtime (vals[0]));
+                   ldap_value_free (vals);
+                 }
+
+               es_fputc (':', fp);
+
+               vals = ldap_get_values (ldap_conn, each, "pgprevoked");
+               if (vals)
+                 {
+                   if (atoi (vals[0]) == 1)
+                     es_fprintf (fp, "r");
+                   ldap_value_free (vals);
+                 }
+
+               vals = ldap_get_values (ldap_conn, each, "pgpdisabled");
+               if (vals)
+                 {
+                   if (atoi (vals[0]) ==1)
+                     es_fprintf (fp, "d");
+                   ldap_value_free (vals);
+                 }
 
 #if 0
-                 /* This is not yet specified in the keyserver
-                    protocol, but may be someday. */
-                 es_fputc (':', fp);
-
-                 vals = ldap_get_values (ldap_conn, each, "modifytimestamp");
-                 if(vals && strlen (vals[0]) == 15)
-                   {
-                     es_fprintf (fp, "%u",
-                                 (unsigned int) ldap2epochtime (vals[0]));
-                     ldap_value_free (vals);
-                   }
+               /* This is not yet specified in the keyserver
+                  protocol, but may be someday. */
+               es_fputc (':', fp);
+
+               vals = ldap_get_values (ldap_conn, each, "modifytimestamp");
+               if(vals && strlen (vals[0]) == 15)
+                 {
+                   es_fprintf (fp, "%u",
+                               (unsigned int) ldap2epochtime (vals[0]));
+                   ldap_value_free (vals);
+                 }
 #endif
 
-                 es_fprintf (fp, "\n");
-
-                 /* Now print all the uids that have this certid */
-                 for (uids = ldap_first_entry (ldap_conn, res);
-                      uids;
-                      uids = ldap_next_entry (ldap_conn, uids))
-                   {
-                     vals = ldap_get_values (ldap_conn, uids, "pgpcertid");
-                     if (! vals)
-                       continue;
-
-                     if (strcasecmp (certid[0], vals[0]) == 0)
-                       {
-                         char **uidvals;
-
-                         es_fprintf (fp, "uid:");
-
-                         uidvals = ldap_get_values (ldap_conn,
-                                                    uids, "pgpuserid");
-                         if (uidvals)
-                           {
-                             /* Need to escape any colons */
-                             char *quoted = percent_escape (uidvals[0], NULL);
-                             es_fputs (quoted, fp);
-                             xfree (quoted);
-                             ldap_value_free (uidvals);
-                           }
-
-                         es_fprintf (fp, "\n");
-                       }
-
-                     ldap_value_free(vals);
-                   }
+               es_fprintf (fp, "\n");
+
+               /* Now print all the uids that have this certid */
+               for (uids = ldap_first_entry (ldap_conn, res);
+                    uids;
+                    uids = ldap_next_entry (ldap_conn, uids))
+                 {
+                   vals = ldap_get_values (ldap_conn, uids, "pgpcertid");
+                   if (! vals)
+                     continue;
+
+                   if (strcasecmp (certid[0], vals[0]) == 0)
+                     {
+                       char **uidvals;
+
+                       es_fprintf (fp, "uid:");
+
+                       uidvals = ldap_get_values (ldap_conn,
+                                                  uids, "pgpuserid");
+                       if (uidvals)
+                         {
+                           /* Need to escape any colons */
+                           char *quoted = percent_escape (uidvals[0], NULL);
+                           es_fputs (quoted, fp);
+                           xfree (quoted);
+                           ldap_value_free (uidvals);
+                         }
+
+                       es_fprintf (fp, "\n");
+                     }
+
+                   ldap_value_free(vals);
+                 }
              }
 
              ldap_value_free (certid);
@@ -1403,7 +1432,7 @@ modlist_lookup (LDAPMod **modlist, const char *attr)
 
 /* Dump a modlist to a file.  This is useful for debugging.  */
 static estream_t modlist_dump (LDAPMod **modlist, estream_t output)
-  GNUPG_GCC_A_USED;
+  GPGRT_ATTR_USED;
 
 static estream_t
 modlist_dump (LDAPMod **modlist, estream_t output)
@@ -1441,29 +1470,22 @@ modlist_dump (LDAPMod **modlist, estream_t output)
 
          for ((ptr = (*m)->mod_values), (i = 1); ptr && *ptr; ptr++, i ++)
            {
-             /* At most about 10 lines.  */
+             /* Assuming terminals are about 80 characters wide,
+                display at most most about 10 lines of debugging
+                output.  If we do trim the buffer, append '...' to
+                the end.  */
              const int max_len = 10 * 70;
              size_t value_len = strlen (*ptr);
-             char buffer[max_len + 4];
-             char *temp;
-             int elided = 0;
-             if (value_len > max_len)
-               {
-                 temp = buffer;
-                 memcpy (temp, *ptr, max_len);
-                 temp[max_len] = temp[max_len + 1] = temp[max_len + 2] = '.';
-                 temp[max_len + 3] = 0;
-                 elided = 1;
-               }
-             else
-               temp = *ptr;
+             int elide = value_len > max_len;
 
              if (multi)
                es_fprintf (output, "    %d. ", i);
-             es_fprintf (output, "`%s'", temp);
-             if (elided)
-               es_fprintf (output, " (%zd bytes elided)",
+             es_fprintf (output, "`%.*s", max_len, *ptr);
+             if (elide)
+               es_fprintf (output, "...' (%zd bytes elided)",
                            value_len - max_len);
+             else
+               es_fprintf (output, "'");
              es_fprintf (output, "\n");
            }
        }
@@ -1608,7 +1630,7 @@ extract_attributes (LDAPMod ***modlist, char *line)
 
   fields = strsplit (line, ':', '\0', &field_count);
   if (field_count == 1)
-    /* We only have a single field.  There is definately nothing to
+    /* We only have a single field.  There is definitely nothing to
        do.  */
     goto out;
 
@@ -1756,12 +1778,13 @@ extract_attributes (LDAPMod ***modlist, char *line)
             Check that first and then if it fails, then try
             parse_timestamp.  */
 
-         if (strptime (create_time, "%Y-%m-%d", &tm))
+         if (!isodate_human_to_tm (create_time, &tm))
            create_time = tm2ldaptime (&tm);
          else if ((t = parse_timestamp (create_time, &end)) != (time_t) -1
                   && *end == '\0')
            {
-             if (! gmtime_r (&t, &tm))
+
+             if (!gnupg_gmtime (&t, &tm))
                create_time = NULL;
              else
                create_time = tm2ldaptime (&tm);
@@ -1803,12 +1826,12 @@ extract_attributes (LDAPMod ***modlist, char *line)
             Check that first and then if it fails, then try
             parse_timestamp.  */
 
-         if (strptime (expire_time, "%Y-%m-%d", &tm))
+         if (!isodate_human_to_tm (expire_time, &tm))
            expire_time = tm2ldaptime (&tm);
          else if ((t = parse_timestamp (expire_time, &end)) != (time_t) -1
                   && *end == '\0')
            {
-             if (! gmtime_r (&t, &tm))
+             if (!gnupg_gmtime (&t, &tm))
                expire_time = NULL;
              else
                expire_time = tm2ldaptime (&tm);
@@ -1886,7 +1909,15 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
   /* Elide a warning.  */
   (void) ctrl;
 
-  ldap_err = ldap_connect (uri, &ldap_conn, &basedn, &pgpkeyattr, &real_ldap);
+  if (opt.use_tor)
+    {
+      /* For now we do not support LDAP over Tor.  */
+      log_error (_("LDAP access not possible due to Tor mode\n"));
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
+
+  ldap_err = my_ldap_connect (uri,
+                              &ldap_conn, &basedn, &pgpkeyattr, &real_ldap);
   if (ldap_err || !basedn)
     {
       if (ldap_err)
@@ -1969,7 +2000,7 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
        /* The last line is not \n terminated!  Make a copy so we can
           add a NUL terminator.  */
        {
-         temp = alloca (infolen + 1);
+         temp = xmalloc (infolen + 1);
          memcpy (temp, info, infolen);
          info = temp;
          newline = (char *) info + infolen;
@@ -1986,7 +2017,10 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
       if (! temp)
        assert ((char *) info + infolen - 1 == infoend);
       else
-       assert (infolen == -1);
+       {
+         assert (infolen == -1);
+         xfree (temp);
+       }
     }
 
   modlist_add (&addlist, "objectClass", "pgpKeyInfo");