dirmngr: New command AD_QUERY.

* dirmngr/dirmngr.h: Include name-value.h
(struct server_control_s): Add rootdse and rootdse_tried.
* dirmngr/dirmngr.c (dirmngr_deinit_default_ctrl): Release them.
* dirmngr/ks-engine.h (KS_GET_FLAG_ROOTDSE): Add two new flags.
* dirmngr/ks-engine-ldap.c: Include ks-action.h
(SERVERINFO_GENERIC): New.
(struct ks_engine_ldap_local_s): Add scope.
(ks_ldap_new_state): Set a default scope.
(ks_ldap_clear_state): Ditto.
(my_ldap_connect): Add flag generic.
(return_all_attributes): New.
(fetch_rootdse): New.
(basedn_from_rootdse): New.
(ks_ldap_get): Move some code out to ...
(ks_ldap_prepare_my_state): New.
(ks_ldap_query): New.
* dirmngr/ks-action.c (ks_action_parse_uri): Factored out from server.c
(ks_action_query): New.
* dirmngr/server.c (make_keyserver_item): Factored most code out to
ks_action_parse_uri.
(cmd_ad_query): New.
--

This command allows to query the Windows Active directory.
This commit is contained in:
Werner Koch 2023-03-20 19:24:49 +01:00
parent f5347fbc25
commit 625aeb65b0
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
8 changed files with 758 additions and 138 deletions

View File

@ -1705,6 +1705,8 @@ dirmngr_deinit_default_ctrl (ctrl_t ctrl)
xfree (ctrl->http_proxy); xfree (ctrl->http_proxy);
ctrl->http_proxy = NULL; ctrl->http_proxy = NULL;
nvc_release (ctrl->rootdse);
ctrl->rootdse = NULL;
} }

View File

@ -36,6 +36,7 @@
#include "../common/sysutils.h" /* (gnupg_fd_t) */ #include "../common/sysutils.h" /* (gnupg_fd_t) */
#include "../common/asshelp.h" /* (assuan_context_t) */ #include "../common/asshelp.h" /* (assuan_context_t) */
#include "../common/i18n.h" #include "../common/i18n.h"
#include "../common/name-value.h"
#include "dirmngr-status.h" #include "dirmngr-status.h"
#include "http.h" /* (parsed_uri_t) */ #include "http.h" /* (parsed_uri_t) */
@ -220,9 +221,12 @@ struct server_control_s
int audit_events; /* Send audit events to client. */ int audit_events; /* Send audit events to client. */
char *http_proxy; /* The used http_proxy or NULL. */ char *http_proxy; /* The used http_proxy or NULL. */
nvc_t rootdse; /* Container wit the rootDSE properties. */
unsigned int timeout; /* Timeout for connect calls in ms. */ unsigned int timeout; /* Timeout for connect calls in ms. */
unsigned int http_no_crl:1; /* Do not check CRLs for https. */ unsigned int http_no_crl:1; /* Do not check CRLs for https. */
unsigned int rootdse_tried:1;/* Already tried to get the rootDSE. */
}; };
@ -241,6 +245,8 @@ void ks_hkp_reload (void);
void ks_hkp_init (void); void ks_hkp_init (void);
/*-- server.c --*/ /*-- server.c --*/
void release_uri_item_list (uri_item_t list);
ldap_server_t get_ldapservers_from_ctrl (ctrl_t ctrl); ldap_server_t get_ldapservers_from_ctrl (ctrl_t ctrl);
ksba_cert_t get_cert_local (ctrl_t ctrl, const char *issuer); ksba_cert_t get_cert_local (ctrl_t ctrl, const char *issuer);
ksba_cert_t get_issuing_cert_local (ctrl_t ctrl, const char *issuer); ksba_cert_t get_issuing_cert_local (ctrl_t ctrl, const char *issuer);

View File

@ -823,7 +823,7 @@ fetch_ldap (LDAP *ld, const char *base, int scope, const char *filter)
/* Main processing. Take the filter and run the LDAP query. The /* Main processing. Take the filter and run the LDAP query. The
* result is printed to stdout, errors are logged to the log stream. * result is printed to stdout, errors are logged to the log stream.
* To allow searching with a different base it is possible to extend * To allow searching with a different base it is possible to extend
* the filer. For example: * the filter. For example:
* *
* ^CN=foo, OU=My Users&(objectClasses=*) * ^CN=foo, OU=My Users&(objectClasses=*)
* *

View File

@ -34,6 +34,100 @@
# include "ldap-parse-uri.h" # include "ldap-parse-uri.h"
#endif #endif
/* Parse an URI and store it in a new parsed URI item object which is
* returned at R_PARSEDURI (with its next set to NULL). On error an
* error code is returned an NULL stored at R_PARSEDITEM. */
gpg_error_t
ks_action_parse_uri (const char *uri, uri_item_t *r_parseduri)
{
gpg_error_t err;
uri_item_t item;
char *tmpstr = NULL;
#if USE_LDAP
const char *s;
#endif
*r_parseduri = NULL;
if (!uri)
return gpg_error (GPG_ERR_INV_URI);
item = xtrymalloc (sizeof *item + strlen (uri));
if (!item)
return gpg_error_from_syserror ();
item->next = NULL;
item->parsed_uri = NULL;
strcpy (item->uri, uri);
#if USE_LDAP
if (!strncmp (uri, "ldap:", 5) && !(uri[5] == '/' && uri[6] == '/'))
{
/* Special ldap scheme given. This differs from a valid ldap
* scheme in that no double slash follows. We use
* http_parse_uri to put it as opaque value into parsed_uri. */
tmpstr = strconcat ("opaque:", uri+5, NULL);
if (!tmpstr)
err = gpg_error_from_syserror ();
else
err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
}
else if ((s=strchr (uri, ':')) && !(s[1] == '/' && s[2] == '/'))
{
/* No valid scheme given. We use http_parse_uri to put the
* string as opaque value into parsed_uri. */
tmpstr = strconcat ("opaque:", uri, NULL);
if (!tmpstr)
err = gpg_error_from_syserror ();
else
err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
}
else if (ldap_uri_p (uri))
{
int fixup = 0;
/* Fixme: We should get rid of that parser and replace it with
* our generic (http) URI parser. */
/* If no port has been specified and the scheme ist ldaps we use
* our idea of the default port because the standard LDAP URL
* parser would use 636 here. This is because we redefined
* ldaps to mean starttls. */
#ifdef HAVE_W32_SYSTEM
if (!strcmp (uri, "ldap:///"))
fixup = 1;
else
#endif
if (!http_parse_uri (&item->parsed_uri,uri,HTTP_PARSE_NO_SCHEME_CHECK))
{
if (!item->parsed_uri->port
&& !strcmp (item->parsed_uri->scheme, "ldaps"))
fixup = 2;
http_release_parsed_uri (item->parsed_uri);
item->parsed_uri = NULL;
}
err = ldap_parse_uri (&item->parsed_uri, uri);
if (!err && fixup == 1)
item->parsed_uri->ad_current = 1;
else if (!err && fixup == 2)
item->parsed_uri->port = 389;
}
else
#endif /* USE_LDAP */
{
err = http_parse_uri (&item->parsed_uri, uri, HTTP_PARSE_NO_SCHEME_CHECK);
}
xfree (tmpstr);
if (err)
xfree (item);
else
*r_parseduri = item;
return err;
}
/* Called by the engine's help functions to print the actual help. */ /* Called by the engine's help functions to print the actual help. */
gpg_error_t gpg_error_t
ks_print_help (ctrl_t ctrl, const char *text) ks_print_help (ctrl_t ctrl, const char *text)
@ -270,7 +364,7 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|| strcmp (uri->parsed_uri->scheme, "https") == 0); || strcmp (uri->parsed_uri->scheme, "https") == 0);
int is_ldap = 0; int is_ldap = 0;
if ((ks_get_flags & KS_GET_FLAG_ONLY_LDAP)) if ((ks_get_flags & (KS_GET_FLAG_ONLY_LDAP|KS_GET_FLAG_ONLY_AD)))
is_hkp_s = is_http_s = 0; is_hkp_s = is_http_s = 0;
#if USE_LDAP #if USE_LDAP
@ -448,3 +542,52 @@ ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
err = first_err; err = first_err;
return err; return err;
} }
/* Query the default LDAP server or the one given by URL using
* the filter expression FILTER. Write the result to OUTFP. */
gpg_error_t
ks_action_query (ctrl_t ctrl, const char *url, unsigned int ks_get_flags,
const char *filter, char **attrs, estream_t outfp)
{
#if USE_LDAP
gpg_error_t err;
estream_t infp = NULL;
uri_item_t puri; /* The broken down URI (only one item used). */
if (!url && (ks_get_flags & KS_GET_FLAG_ROOTDSE))
url = "ldap://";
err = ks_action_parse_uri (url, &puri);
if (err)
return err;
if ((ks_get_flags & KS_GET_FLAG_ROOTDSE))
{
/* Reset authentication for a serverless connection. */
puri->parsed_uri->ad_current = 0;
puri->parsed_uri->auth = NULL;
}
if (!strcmp (puri->parsed_uri->scheme, "ldap")
|| !strcmp (puri->parsed_uri->scheme, "ldaps")
|| !strcmp (puri->parsed_uri->scheme, "ldapi")
|| puri->parsed_uri->opaque)
{
err = ks_ldap_query (ctrl, puri->parsed_uri, ks_get_flags, filter,
attrs, &infp);
if (!err)
err = copy_stream (infp, outfp);
}
else
err = gpg_error (GPG_ERR_CONFIGURATION); /* No LDAP server known. */
es_fclose (infp);
release_uri_item_list (puri);
return err;
#else /* !USE_LDAP */
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
#endif
}

View File

@ -21,6 +21,7 @@
#ifndef DIRMNGR_KS_ACTION_H #ifndef DIRMNGR_KS_ACTION_H
#define DIRMNGR_KS_ACTION_H 1 #define DIRMNGR_KS_ACTION_H 1
gpg_error_t ks_action_parse_uri (const char *uri, uri_item_t *r_parseduri);
gpg_error_t ks_action_help (ctrl_t ctrl, const char *url); gpg_error_t ks_action_help (ctrl_t ctrl, const char *url);
gpg_error_t ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers); gpg_error_t ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers);
gpg_error_t ks_action_search (ctrl_t ctrl, uri_item_t keyservers, gpg_error_t ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
@ -32,6 +33,9 @@ gpg_error_t ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp);
gpg_error_t ks_action_put (ctrl_t ctrl, uri_item_t keyservers, gpg_error_t ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
void *data, size_t datalen, void *data, size_t datalen,
void *info, size_t infolen); void *info, size_t infolen);
gpg_error_t ks_action_query (ctrl_t ctrl, const char *ldapserver,
unsigned int ks_get_flags,
const char *filter, char **attr, estream_t outfp);
#endif /*DIRMNGR_KS_ACTION_H*/ #endif /*DIRMNGR_KS_ACTION_H*/

View File

@ -1,7 +1,7 @@
/* ks-engine-ldap.c - talk to a LDAP keyserver /* ks-engine-ldap.c - talk to a LDAP keyserver
* Copyright (C) 2001, 2002, 2004, 2005, 2006 * Copyright (C) 2001, 2002, 2004, 2005, 2006
* 2007 Free Software Foundation, Inc. * 2007 Free Software Foundation, Inc.
* Copyright (C) 2015, 2020 g10 Code GmbH * Copyright (C) 2015, 2020, 2023 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -32,6 +32,7 @@
#include "misc.h" #include "misc.h"
#include "../common/userids.h" #include "../common/userids.h"
#include "../common/mbox-util.h" #include "../common/mbox-util.h"
#include "ks-action.h"
#include "ks-engine.h" #include "ks-engine.h"
#include "ldap-misc.h" #include "ldap-misc.h"
#include "ldap-parse-uri.h" #include "ldap-parse-uri.h"
@ -43,6 +44,7 @@
#define SERVERINFO_PGPKEYV2 2 /* Needs "pgpKeyV2" instead of "pgpKey"*/ #define SERVERINFO_PGPKEYV2 2 /* Needs "pgpKeyV2" instead of "pgpKey"*/
#define SERVERINFO_SCHEMAV2 4 /* Version 2 of the Schema. */ #define SERVERINFO_SCHEMAV2 4 /* Version 2 of the Schema. */
#define SERVERINFO_NTDS 8 /* Server is an Active Directory. */ #define SERVERINFO_NTDS 8 /* Server is an Active Directory. */
#define SERVERINFO_GENERIC 16 /* Connected in genric mode. */
/* The page size requested from the server. */ /* The page size requested from the server. */
@ -61,6 +63,7 @@ struct ks_engine_ldap_local_s
LDAPMessage *message; LDAPMessage *message;
LDAPMessage *msg_iter; /* Iterator for message. */ LDAPMessage *msg_iter; /* Iterator for message. */
unsigned int serverinfo; unsigned int serverinfo;
int scope;
char *basedn; char *basedn;
char *keyspec; char *keyspec;
char *filter; char *filter;
@ -192,7 +195,12 @@ ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri)
static struct ks_engine_ldap_local_s * static struct ks_engine_ldap_local_s *
ks_ldap_new_state (void) ks_ldap_new_state (void)
{ {
return xtrycalloc (1, sizeof(struct ks_engine_ldap_local_s)); struct ks_engine_ldap_local_s *state;
state = xtrycalloc (1, sizeof(struct ks_engine_ldap_local_s));
if (state)
state->scope = LDAP_SCOPE_SUBTREE;
return state;
} }
@ -217,6 +225,7 @@ ks_ldap_clear_state (struct ks_engine_ldap_local_s *state)
} }
state->serverinfo = 0; state->serverinfo = 0;
xfree (state->basedn); xfree (state->basedn);
state->scope = LDAP_SCOPE_SUBTREE;
state->basedn = NULL; state->basedn = NULL;
xfree (state->keyspec); xfree (state->keyspec);
state->keyspec = NULL; state->keyspec = NULL;
@ -240,6 +249,45 @@ ks_ldap_free_state (struct ks_engine_ldap_local_s *state)
} }
/* Helper for ks_ldap_get and ks_ldap_query. On return first_mode and
* next_mode are set accordingly. */
static gpg_error_t
ks_ldap_prepare_my_state (ctrl_t ctrl, unsigned int ks_get_flags,
int *first_mode, int *next_mode)
{
*first_mode = *next_mode = 0;
if ((ks_get_flags & KS_GET_FLAG_FIRST))
{
if (ctrl->ks_get_state)
ks_ldap_clear_state (ctrl->ks_get_state);
else if (!(ctrl->ks_get_state = ks_ldap_new_state ()))
return gpg_error_from_syserror ();
*first_mode = 1;
}
if ((ks_get_flags & KS_GET_FLAG_NEXT))
{
if (!ctrl->ks_get_state || !ctrl->ks_get_state->ldap_conn
|| !ctrl->ks_get_state->message)
{
log_error ("ks-ldap: --next requested but no state\n");
return gpg_error (GPG_ERR_INV_STATE);
}
*next_mode = 1;
}
/* Do not keep an old state around if not needed. */
if (!(*first_mode || *next_mode))
{
ks_ldap_free_state (ctrl->ks_get_state);
ctrl->ks_get_state = NULL;
}
return 0;
}
/* Convert a keyspec to a filter. Return an error if the keyspec is /* Convert a keyspec to a filter. Return an error if the keyspec is
bad or is not supported. The filter is escaped and returned in bad or is not supported. The filter is escaped and returned in
@ -437,7 +485,9 @@ interrogate_ldap_dn (LDAP *ldap_conn, const char *basedn_search,
* *
* URI describes the server to connect to and various options * URI describes the server to connect to and various options
* including whether to use TLS and the username and password (see * including whether to use TLS and the username and password (see
* ldap_parse_uri for a description of the various fields). * ldap_parse_uri for a description of the various fields). Be
* default a PGP keyserver is assumed; if GENERIC is true a generic
* ldap conenction is instead established.
* *
* Returns: The ldap connection handle in *LDAP_CONNP, R_BASEDN is set * Returns: The ldap connection handle in *LDAP_CONNP, R_BASEDN is set
* to the base DN for the PGP key space, several flags will be stored * to the base DN for the PGP key space, several flags will be stored
@ -450,7 +500,7 @@ interrogate_ldap_dn (LDAP *ldap_conn, const char *basedn_search,
* If it is NULL, then the server does not appear to be an OpenPGP * If it is NULL, then the server does not appear to be an OpenPGP
* keyserver. */ * keyserver. */
static gpg_error_t static gpg_error_t
my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp, my_ldap_connect (parsed_uri_t uri, unsigned int generic, LDAP **ldap_connp,
char **r_basedn, char **r_host, int *r_use_tls, char **r_basedn, char **r_host, int *r_use_tls,
unsigned int *r_serverinfo) unsigned int *r_serverinfo)
{ {
@ -519,15 +569,15 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
} }
if (opt.verbose) if (opt.verbose)
log_info ("ldap connect to '%s:%d:%s:%s:%s:%s%s%s'\n", log_info ("ldap connect to '%s:%d:%s:%s:%s:%s%s%s'%s\n",
host, port, host, port,
basedn_arg ? basedn_arg : "", basedn_arg ? basedn_arg : "",
bindname ? bindname : "", bindname ? bindname : "",
password ? "*****" : "", password ? "*****" : "",
use_tls == 1? "starttls" : use_tls == 2? "ldaptls" : "plain", use_tls == 1? "starttls" : use_tls == 2? "ldaptls" : "plain",
use_ntds ? ",ntds":"", use_ntds ? ",ntds":"",
use_areconly? ",areconly":""); use_areconly? ",areconly":"",
generic? " (generic)":"");
/* If the uri specifies a secure connection and we don't support /* If the uri specifies a secure connection and we don't support
TLS, then fail; don't silently revert to an insecure TLS, then fail; don't silently revert to an insecure
@ -535,7 +585,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
if (use_tls) if (use_tls)
{ {
#ifndef HAVE_LDAP_START_TLS_S #ifndef HAVE_LDAP_START_TLS_S
log_error ("ldap: can't connect to the server: no TLS support."); log_error ("ks-ldap: can't connect to the server: no TLS support.");
err = GPG_ERR_LDAP_NOT_SUPPORTED; err = GPG_ERR_LDAP_NOT_SUPPORTED;
goto out; goto out;
#endif #endif
@ -607,6 +657,8 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
{ {
int ver = opt.ldaptimeout; int ver = opt.ldaptimeout;
/* fixme: also use LDAP_OPT_SEND_TIMEOUT? */
lerr = ldap_set_option (ldap_conn, LDAP_OPT_TIMELIMIT, &ver); lerr = ldap_set_option (ldap_conn, LDAP_OPT_TIMELIMIT, &ver);
if (lerr != LDAP_SUCCESS) if (lerr != LDAP_SUCCESS)
{ {
@ -699,7 +751,21 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
/* By default we don't bind as there is usually no need to. */ /* By default we don't bind as there is usually no need to. */
} }
if (basedn_arg && *basedn_arg) if (generic)
{
/* Generic use of this function for arbitrary LDAP servers. */
*r_serverinfo |= SERVERINFO_GENERIC;
if (basedn_arg && *basedn_arg)
{
basedn = xtrystrdup (basedn_arg);
if (!basedn)
{
err = gpg_error_from_syserror ();
goto out;
}
}
}
else if (basedn_arg && *basedn_arg)
{ {
/* User specified base DN. In this case we know the server is a /* User specified base DN. In this case we know the server is a
* real LDAP server. */ * real LDAP server. */
@ -819,11 +885,15 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
if (!err && opt.debug) if (!err && opt.debug)
{ {
log_debug ("ldap_conn: %p\n", ldap_conn); log_debug ("ldap_conn: %p\n", ldap_conn);
log_debug ("server_type: %s\n", ((*r_serverinfo & SERVERINFO_REALLDAP) log_debug ("server_type: %s\n",
? "LDAP" : "PGP.com keyserver") ); ((*r_serverinfo & SERVERINFO_GENERIC)
? "Generic" :
(*r_serverinfo & SERVERINFO_REALLDAP)
? "LDAP" : "PGP.com keyserver") );
log_debug ("basedn: %s\n", basedn); log_debug ("basedn: %s\n", basedn);
log_debug ("pgpkeyattr: %s\n", if (!(*r_serverinfo & SERVERINFO_GENERIC))
(*r_serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2":"pgpKey"); log_debug ("pgpkeyattr: %s\n",
(*r_serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2":"pgpKey");
} }
ldapserver_list_free (server); ldapserver_list_free (server);
@ -1028,11 +1098,132 @@ return_one_keyblock (LDAP *ldap_conn, LDAPMessage *msg, unsigned int serverinfo,
} }
/* Helper for ks_ldap_get. Note that KEYSPEC is only used for /* Helper for ks_ldap_query. Returns 0 if an attr was fetched and
* diagnostics. */ * printed to FP. The error code GPG_ERR_NO_DATA is returned if no
* data was printed. Note that FP is updated by this function. */
static gpg_error_t
return_all_attributes (LDAP *ld, LDAPMessage *msg, estream_t *fp)
{
gpg_error_t err = 0;
BerElement *berctx = NULL;
char *attr = NULL;
const char *attrprefix;
struct berval **values = NULL;
int idx;
int any = 0;
const char *s;
const char *val;
size_t len;
char *mydn;
mydn = ldap_get_dn (ld, msg);
if (!*fp)
{
*fp = es_fopenmem(0, "rw");
if (!*fp)
{
err = gpg_error_from_syserror ();
goto leave;
}
}
/* Always print the DN - note that by using only unbkown attributes
* it is pissible to list just the DNs with out addiional
* linefeeds. */
es_fprintf (*fp, "Dn: %s\n", mydn? mydn : "[oops DN missing]");
for (npth_unprotect (), attr = ldap_first_attribute (ld, msg, &berctx),
npth_protect ();
attr;
npth_unprotect (), attr = ldap_next_attribute (ld, msg, berctx),
npth_protect ())
{
npth_unprotect ();
values = ldap_get_values_len (ld, msg, attr);
npth_protect ();
if (!values)
{
if (opt.verbose)
log_info ("attribute '%s' not found\n", attr);
ldap_memfree (attr);
attr = NULL;
continue;
}
any = 1;
if (opt.verbose > 1)
{
log_info ("found attribute '%s'\n", attr);
for (idx=0; values[idx]; idx++)
log_info (" length[%d]=%d\n",
idx, (int)values[0]->bv_len);
}
if (!ascii_strcasecmp (attr, "Dn"))
attrprefix = "X-";
else if (*attr == '#')
attrprefix = "X-hash-";
else if (*attr == ' ')
attrprefix = "X-blank-";
else
attrprefix = "";
/* FIXME: We should remap all invalid chars in ATTR. */
for (idx=0; values[idx]; idx++)
{
es_fprintf (*fp, "%s%s: ", attrprefix, attr);
val = values[idx]->bv_val;
len = values[idx]->bv_len;
while (len && (s = memchr (val, '\n', len)))
{
s++; /* We als want to print the LF. */
if (es_fwrite (val, s - val, 1, *fp) != 1)
goto fwrite_failed;
len -= (s-val);
val = s;
if (len && es_fwrite (" ", 1, 1, *fp) != 1)
goto fwrite_failed;
}
if (len && es_fwrite (val, len, 1, *fp) != 1)
goto fwrite_failed;
if (es_fwrite ("\n", 1, 1, *fp) != 1) /* Final LF. */
goto fwrite_failed;
}
ldap_value_free_len (values);
values = NULL;
ldap_memfree (attr);
attr = NULL;
}
/* One final linefeed to prettify the output. */
if (any && es_fwrite ("\n", 1, 1, *fp) != 1)
goto fwrite_failed;
leave:
if (values)
ldap_value_free_len (values);
ldap_memfree (attr);
if (mydn)
ldap_memfree (mydn);
ber_free (berctx, 0);
return err;
fwrite_failed:
err = gpg_error_from_syserror ();
log_error ("error writing to stdout: %s\n", gpg_strerror (err));
goto leave;
}
/* Helper for ks_ldap_get and ks_ldap_query. Note that KEYSPEC is
* only used for diagnostics. */
static gpg_error_t static gpg_error_t
search_and_parse (ctrl_t ctrl, const char *keyspec, search_and_parse (ctrl_t ctrl, const char *keyspec,
LDAP *ldap_conn, char *basedn, char *filter, LDAP *ldap_conn, char *basedn, int scope, char *filter,
char **attrs, LDAPMessage **r_message) char **attrs, LDAPMessage **r_message)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
@ -1065,7 +1256,7 @@ search_and_parse (ctrl_t ctrl, const char *keyspec,
} }
npth_unprotect (); npth_unprotect ();
l_err = ldap_search_ext_s (ldap_conn, basedn, LDAP_SCOPE_SUBTREE, l_err = ldap_search_ext_s (ldap_conn, basedn, scope,
filter, attrs, 0, filter, attrs, 0,
srvctrls[0]? srvctrls : NULL, NULL, NULL, 0, srvctrls[0]? srvctrls : NULL, NULL, NULL, 0,
r_message); r_message);
@ -1130,7 +1321,7 @@ search_and_parse (ctrl_t ctrl, const char *keyspec,
if (count < 1) if (count < 1)
{ {
if (!ctrl->ks_get_state || ctrl->ks_get_state->pageno == 1) if (!ctrl->ks_get_state || ctrl->ks_get_state->pageno == 1)
log_info ("ks-ldap: key %s not found on keyserver\n", keyspec); log_info ("ks-ldap: '%s' not found on LDAP server\n", keyspec);
if (count == -1) if (count == -1)
err = ldap_to_gpg_err (ldap_conn); err = ldap_to_gpg_err (ldap_conn);
@ -1150,6 +1341,77 @@ search_and_parse (ctrl_t ctrl, const char *keyspec,
} }
/* Fetch all entries from the RootDSE and return them as a name value
* object. */
static nvc_t
fetch_rootdse (ctrl_t ctrl, parsed_uri_t uri)
{
gpg_error_t err;
estream_t infp = NULL;
uri_item_t puri; /* The broken down URI (only one item used). */
nvc_t nvc = NULL;
/* FIXME: We need the unparsed URI here - use uri_item_t instead
* of fix the parser to fill in original */
err = ks_action_parse_uri (uri && uri->original? uri->original : "ldap://",
&puri);
if (err)
return NULL;
/* Reset authentication for a serverless. */
puri->parsed_uri->ad_current = 0;
puri->parsed_uri->auth = NULL;
if (!strcmp (puri->parsed_uri->scheme, "ldap")
|| !strcmp (puri->parsed_uri->scheme, "ldaps")
|| !strcmp (puri->parsed_uri->scheme, "ldapi")
|| puri->parsed_uri->opaque)
{
err = ks_ldap_query (ctrl, puri->parsed_uri, KS_GET_FLAG_ROOTDSE,
"^&base&(objectclass=*)", NULL, &infp);
if (err)
log_error ("ldap: reading the rootDES failed: %s\n",
gpg_strerror (err));
else if ((err = nvc_parse (&nvc, NULL, infp)))
log_error ("parsing the rootDES failed: %s\n", gpg_strerror (err));
}
es_fclose (infp);
release_uri_item_list (puri);
if (err)
{
nvc_release (nvc);
nvc = NULL;
}
return nvc;
}
/* Return the baseDN for URI which might have already been cached for
* this session. */
static char *
basedn_from_rootdse (ctrl_t ctrl, parsed_uri_t uri)
{
const char *s;
if (!ctrl->rootdse && !ctrl->rootdse_tried)
{
ctrl->rootdse = fetch_rootdse (ctrl, uri);
ctrl->rootdse_tried = 1;
if (ctrl->rootdse)
{
log_debug ("Dump of all rootDSE attributes:\n");
nvc_write (ctrl->rootdse, log_get_stream ());
log_debug ("End of dump\n");
}
}
s = nvc_get_string (ctrl->rootdse, "defaultNamingContext:");
return s? xtrystrdup (s): NULL;
}
/* Get the key described key the KEYSPEC string from the keyserver /* Get the key described key the KEYSPEC string from the keyserver
* identified by URI. On success R_FP has an open stream to read the * identified by URI. On success R_FP has an open stream to read the
* data. KS_GET_FLAGS conveys flags from the client. */ * data. KS_GET_FLAGS conveys flags from the client. */
@ -1157,13 +1419,14 @@ gpg_error_t
ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
unsigned int ks_get_flags, estream_t *r_fp) unsigned int ks_get_flags, estream_t *r_fp)
{ {
gpg_error_t err = 0; gpg_error_t err;
unsigned int serverinfo; unsigned int serverinfo;
char *host = NULL; char *host = NULL;
int use_tls; int use_tls;
char *filter = NULL; char *filter = NULL;
LDAP *ldap_conn = NULL; LDAP *ldap_conn = NULL;
char *basedn = NULL; char *basedn = NULL;
int scope = LDAP_SCOPE_SUBTREE;
estream_t fp = NULL; estream_t fp = NULL;
LDAPMessage *message = NULL; LDAPMessage *message = NULL;
LDAPMessage *msg; LDAPMessage *msg;
@ -1184,41 +1447,14 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
NULL NULL
}; };
(void) ctrl;
if (dirmngr_use_tor ()) if (dirmngr_use_tor ())
{ {
return no_ldap_due_to_tor (ctrl); return no_ldap_due_to_tor (ctrl);
} }
/* Make sure we got a state. */ err = ks_ldap_prepare_my_state (ctrl, ks_get_flags, &first_mode, &next_mode);
if ((ks_get_flags & KS_GET_FLAG_FIRST)) if (err)
{ return err;
if (ctrl->ks_get_state)
ks_ldap_clear_state (ctrl->ks_get_state);
else if (!(ctrl->ks_get_state = ks_ldap_new_state ()))
return gpg_error_from_syserror ();
first_mode = 1;
}
if ((ks_get_flags & KS_GET_FLAG_NEXT))
{
if (!ctrl->ks_get_state || !ctrl->ks_get_state->ldap_conn
|| !ctrl->ks_get_state->message)
{
log_error ("ks_ldap: --next requested but no state\n");
return gpg_error (GPG_ERR_INV_STATE);
}
next_mode = 1;
}
/* Do not keep an old state around if not needed. */
if (!(first_mode || next_mode))
{
ks_ldap_free_state (ctrl->ks_get_state);
ctrl->ks_get_state = NULL;
}
if (next_mode) if (next_mode)
{ {
@ -1236,6 +1472,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
err = search_and_parse (ctrl, ctrl->ks_get_state->keyspec, err = search_and_parse (ctrl, ctrl->ks_get_state->keyspec,
ctrl->ks_get_state->ldap_conn, ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->basedn, ctrl->ks_get_state->basedn,
ctrl->ks_get_state->scope,
ctrl->ks_get_state->filter, ctrl->ks_get_state->filter,
attrs, attrs,
&ctrl->ks_get_state->message); &ctrl->ks_get_state->message);
@ -1284,7 +1521,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
else /* Not in --next mode. */ else /* Not in --next mode. */
{ {
/* Make sure we are talking to an OpenPGP LDAP server. */ /* Make sure we are talking to an OpenPGP LDAP server. */
err = my_ldap_connect (uri, &ldap_conn, err = my_ldap_connect (uri, 0, &ldap_conn,
&basedn, &host, &use_tls, &serverinfo); &basedn, &host, &use_tls, &serverinfo);
if (err || !basedn) if (err || !basedn)
{ {
@ -1311,8 +1548,8 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
/* Replace "dummy". */ /* Replace "dummy". */
attrs[0] = (serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2" : "pgpKey"; attrs[0] = (serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2" : "pgpKey";
err = search_and_parse (ctrl, keyspec, ldap_conn, basedn, filter, attrs, err = search_and_parse (ctrl, keyspec, ldap_conn, basedn, scope,
&message); filter, attrs, &message);
if (err) if (err)
goto leave; goto leave;
@ -1363,6 +1600,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
ctrl->ks_get_state->message = message; ctrl->ks_get_state->message = message;
message = NULL; message = NULL;
ctrl->ks_get_state->serverinfo = serverinfo; ctrl->ks_get_state->serverinfo = serverinfo;
ctrl->ks_get_state->scope = scope;
ctrl->ks_get_state->basedn = basedn; ctrl->ks_get_state->basedn = basedn;
basedn = NULL; basedn = NULL;
ctrl->ks_get_state->keyspec = keyspec? xtrystrdup (keyspec) : NULL; ctrl->ks_get_state->keyspec = keyspec? xtrystrdup (keyspec) : NULL;
@ -1423,7 +1661,7 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
} }
/* Make sure we are talking to an OpenPGP LDAP server. */ /* Make sure we are talking to an OpenPGP LDAP server. */
err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL, &serverinfo); err = my_ldap_connect (uri, 0, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
if (err || !basedn) if (err || !basedn)
{ {
if (!err) if (!err)
@ -2312,7 +2550,7 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
return no_ldap_due_to_tor (ctrl); return no_ldap_due_to_tor (ctrl);
} }
err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL, &serverinfo); err = my_ldap_connect (uri, 0, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
if (err || !basedn) if (err || !basedn)
{ {
if (!err) if (!err)
@ -2538,3 +2776,224 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
return err; return err;
} }
/* Get the data described by FILTER_ARG from URI. On success R_FP has
* an open stream to read the data. KS_GET_FLAGS conveys flags from
* the client. ATTRS is a NULL terminated list of attributes to
* return or NULL for all. */
gpg_error_t
ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri, unsigned int ks_get_flags,
const char *filter_arg, char **attrs, estream_t *r_fp)
{
gpg_error_t err;
unsigned int serverinfo;
char *host = NULL;
int use_tls;
LDAP *ldap_conn = NULL;
char *basedn = NULL;
estream_t fp = NULL;
char *filter = NULL;
int scope = LDAP_SCOPE_SUBTREE;
LDAPMessage *message = NULL;
LDAPMessage *msg;
int anydata = 0;
int first_mode = 0;
int next_mode = 0;
int get_first;
if (dirmngr_use_tor ())
return no_ldap_due_to_tor (ctrl);
if ((!filter_arg || !*filter_arg) && (ks_get_flags & KS_GET_FLAG_ROOTDSE))
filter_arg = "^&base&(objectclass=*)";
err = ks_ldap_prepare_my_state (ctrl, ks_get_flags, &first_mode, &next_mode);
if (err)
goto leave;
if (!next_mode) /* (In --next mode the filter is ignored.) */
{
if (!filter_arg || !*filter_arg)
{
err = gpg_error (GPG_ERR_LDAP_FILTER);
goto leave;
}
err = ldap_parse_extfilter (filter_arg, 0, &basedn, &scope, &filter);
if (err)
goto leave;
}
if (next_mode)
{
next_again:
if (!ctrl->ks_get_state->msg_iter && ctrl->ks_get_state->more_pages)
{
/* Get the next page of results. */
if (ctrl->ks_get_state->message)
{
ldap_msgfree (ctrl->ks_get_state->message);
ctrl->ks_get_state->message = NULL;
}
err = search_and_parse (ctrl, ctrl->ks_get_state->keyspec,
ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->basedn,
ctrl->ks_get_state->scope,
ctrl->ks_get_state->filter,
attrs,
&ctrl->ks_get_state->message);
if (err)
goto leave;
ctrl->ks_get_state->msg_iter = ctrl->ks_get_state->message;
get_first = 1;
}
else
get_first = 0;
while (ctrl->ks_get_state->msg_iter)
{
npth_unprotect ();
ctrl->ks_get_state->msg_iter
= get_first? ldap_first_entry (ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->msg_iter)
/* */ : ldap_next_entry (ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->msg_iter);
npth_protect ();
get_first = 0;
if (ctrl->ks_get_state->msg_iter)
{
err = return_all_attributes (ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->msg_iter,
&fp);
if (!err)
break; /* Found. */
else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
err = 0; /* Skip empty attributes. */
else
goto leave;
}
}
if (!ctrl->ks_get_state->msg_iter || !fp)
{
ctrl->ks_get_state->msg_iter = NULL;
if (ctrl->ks_get_state->more_pages)
goto next_again;
err = gpg_error (GPG_ERR_NO_DATA);
}
}
else /* Not in --next mode. */
{
/* Connect to the LDAP server in generic mode. */
char *tmpbasedn;
err = my_ldap_connect (uri, 1 /*generic*/, &ldap_conn,
&tmpbasedn, &host, &use_tls, &serverinfo);
if (err)
goto leave;
if (basedn)
xfree (tmpbasedn); /* Extended syntax overrides. */
else if (tmpbasedn)
basedn = tmpbasedn;
else if (!(ks_get_flags & KS_GET_FLAG_ROOTDSE))
{
/* No BaseDN known - get one. */
basedn = basedn_from_rootdse (ctrl, uri);
}
if (opt.debug)
{
log_debug ("ks-ldap: using basedn: %s\n", basedn);
log_debug ("ks-ldap: using filter: %s\n", filter);
}
err = search_and_parse (ctrl, filter, ldap_conn, basedn, scope, filter,
attrs, &message);
if (err)
goto leave;
for (npth_unprotect (),
msg = ldap_first_entry (ldap_conn, message),
npth_protect ();
msg;
npth_unprotect (),
msg = ldap_next_entry (ldap_conn, msg),
npth_protect ())
{
err = return_all_attributes (ldap_conn, msg, &fp);
if (!err)
{
anydata = 1;
if (first_mode)
break;
}
else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
err = 0; /* Skip empty/duplicate attributes. */
else
goto leave;
}
if (ctrl->ks_get_state) /* Save the iterator. */
ctrl->ks_get_state->msg_iter = msg;
if (!fp) /* Nothing was found. */
err = gpg_error (GPG_ERR_NO_DATA);
if (!err && anydata)
err = dirmngr_status_printf (ctrl, "SOURCE", "%s://%s",
use_tls? "ldaps" : "ldap",
host? host:"");
}
leave:
/* Store our state if needed. */
if (!err && (ks_get_flags & KS_GET_FLAG_FIRST))
{
log_assert (!ctrl->ks_get_state->ldap_conn);
ctrl->ks_get_state->ldap_conn = ldap_conn;
ldap_conn = NULL;
log_assert (!ctrl->ks_get_state->message);
ctrl->ks_get_state->message = message;
message = NULL;
ctrl->ks_get_state->serverinfo = serverinfo;
ctrl->ks_get_state->scope = scope;
ctrl->ks_get_state->basedn = basedn;
basedn = NULL;
ctrl->ks_get_state->keyspec = filter? xtrystrdup (filter) : NULL;
ctrl->ks_get_state->filter = filter;
filter = NULL;
}
if ((ks_get_flags & KS_GET_FLAG_NEXT))
{
/* Keep the state in --next mode even with errors. */
ldap_conn = NULL;
message = NULL;
}
if (message)
ldap_msgfree (message);
if (err)
es_fclose (fp);
else
{
if (fp)
es_fseek (fp, 0, SEEK_SET);
*r_fp = fp;
}
xfree (basedn);
xfree (host);
if (ldap_conn)
ldap_unbind (ldap_conn);
xfree (filter);
return err;
}

View File

@ -27,6 +27,8 @@
#define KS_GET_FLAG_ONLY_LDAP 1 #define KS_GET_FLAG_ONLY_LDAP 1
#define KS_GET_FLAG_FIRST 2 #define KS_GET_FLAG_FIRST 2
#define KS_GET_FLAG_NEXT 4 #define KS_GET_FLAG_NEXT 4
#define KS_GET_FLAG_ONLY_AD 8 /* Do this only if we have an AD. */
#define KS_GET_FLAG_ROOTDSE 16 /* Get the rootDSE. */
/*-- ks-action.c --*/ /*-- ks-action.c --*/
@ -78,6 +80,9 @@ gpg_error_t ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri,
gpg_error_t ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri, gpg_error_t ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
void *data, size_t datalen, void *data, size_t datalen,
void *info, size_t infolen); void *info, size_t infolen);
gpg_error_t ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri,
unsigned int ks_get_flags,
const char *filter, char **attrs, estream_t *r_fp);
#endif /*DIRMNGR_KS_ENGINE_H*/ #endif /*DIRMNGR_KS_ENGINE_H*/

View File

@ -146,7 +146,7 @@ get_ldapservers_from_ctrl (ctrl_t ctrl)
} }
/* Release an uri_item_t list. */ /* Release an uri_item_t list. */
static void void
release_uri_item_list (uri_item_t list) release_uri_item_list (uri_item_t list)
{ {
while (list) while (list)
@ -2147,15 +2147,6 @@ cmd_validate (assuan_context_t ctx, char *line)
static gpg_error_t static gpg_error_t
make_keyserver_item (const char *uri, uri_item_t *r_item) make_keyserver_item (const char *uri, uri_item_t *r_item)
{ {
gpg_error_t err;
uri_item_t item;
char *tmpstr = NULL;
#if USE_LDAP
const char *s;
#endif
*r_item = NULL;
/* We used to have DNS CNAME redirection from the URLs below to /* We used to have DNS CNAME redirection from the URLs below to
* sks-keyserver. pools. The idea was to allow for a quick way to * sks-keyserver. pools. The idea was to allow for a quick way to
* switch to a different set of pools. The problem with that * switch to a different set of pools. The problem with that
@ -2187,78 +2178,7 @@ make_keyserver_item (const char *uri, uri_item_t *r_item)
else if (!strcmp (uri, "http://http-keys.gnupg.net")) else if (!strcmp (uri, "http://http-keys.gnupg.net"))
uri = "hkp://keyserver.ubuntu.com:80"; uri = "hkp://keyserver.ubuntu.com:80";
item = xtrymalloc (sizeof *item + strlen (uri)); return ks_action_parse_uri (uri, r_item);
if (!item)
return gpg_error_from_syserror ();
item->next = NULL;
item->parsed_uri = NULL;
strcpy (item->uri, uri);
#if USE_LDAP
if (!strncmp (uri, "ldap:", 5) && !(uri[5] == '/' && uri[6] == '/'))
{
/* Special ldap scheme given. This differs from a valid ldap
* scheme in that no double slash follows.. Use http_parse_uri
* to put it as opaque value into parsed_uri. */
tmpstr = strconcat ("opaque:", uri+5, NULL);
if (!tmpstr)
err = gpg_error_from_syserror ();
else
err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
}
else if ((s=strchr (uri, ':')) && !(s[1] == '/' && s[2] == '/'))
{
/* No valid scheme given. Use http_parse_uri to put the string
* as opaque value into parsed_uri. */
tmpstr = strconcat ("opaque:", uri, NULL);
if (!tmpstr)
err = gpg_error_from_syserror ();
else
err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
}
else if (ldap_uri_p (uri))
{
int fixup = 0;
/* Fixme: We should get rid of that parser and replace it with
* our generic (http) URI parser. */
/* If no port has been specified and the scheme ist ldaps we use
* our idea of the default port because the standard LDAP URL
* parser would use 636 here. This is because we redefined
* ldaps to mean starttls. */
#ifdef HAVE_W32_SYSTEM
if (!strcmp (uri, "ldap:///"))
fixup = 1;
else
#endif
if (!http_parse_uri (&item->parsed_uri,uri,HTTP_PARSE_NO_SCHEME_CHECK))
{
if (!item->parsed_uri->port
&& !strcmp (item->parsed_uri->scheme, "ldaps"))
fixup = 2;
http_release_parsed_uri (item->parsed_uri);
item->parsed_uri = NULL;
}
err = ldap_parse_uri (&item->parsed_uri, uri);
if (!err && fixup == 1)
item->parsed_uri->ad_current = 1;
else if (!err && fixup == 2)
item->parsed_uri->port = 389;
}
else
#endif /* USE_LDAP */
{
err = http_parse_uri (&item->parsed_uri, uri, HTTP_PARSE_NO_SCHEME_CHECK);
}
xfree (tmpstr);
if (err)
xfree (item);
else
*r_item = item;
return err;
} }
@ -2768,6 +2688,86 @@ cmd_ks_put (assuan_context_t ctx, char *line)
} }
static const char hlp_ad_query[] =
"AD_QUERY [--first|--next] [--] <filter_expression> \n"
"\n"
"Query properties from a Windows Active Directory.\n"
"Our extended filter syntax may be used for the filter\n"
"expression; see gnupg/dirmngr/ldap-misc.c. There are\n"
"a couple of other options available:\n\n"
" --rootdse - Query the root using serverless binding,\n"
" --attr=<attribs> - Comma delimited list of attributes\n"
" to return.\n"
;
static gpg_error_t
cmd_ad_query (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
unsigned int flags = 0;
const char *filter;
estream_t outfp = NULL;
char *p;
char **opt_attr = NULL;
/* No options for now. */
if (has_option (line, "--first"))
flags |= KS_GET_FLAG_FIRST;
if (has_option (line, "--next"))
flags |= KS_GET_FLAG_NEXT;
if (has_option (line, "--rootdse"))
flags |= KS_GET_FLAG_ROOTDSE;
err = get_option_value (line, "--attr", &p);
if (err)
goto leave;
if (p)
{
opt_attr = strtokenize (p, ",");
if (!opt_attr)
{
err = gpg_error_from_syserror ();
xfree (p);
goto leave;
}
xfree (p);
}
line = skip_options (line);
filter = line;
if ((flags & KS_GET_FLAG_NEXT))
{
if (*filter || (flags & ~KS_GET_FLAG_NEXT))
{
err = PARM_ERROR ("No filter or other options allowed with --next");
goto leave;
}
}
/* Setup an output stream and perform the get. */
outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
if (!outfp)
{
err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
goto leave;
}
ctrl->server_local->inhibit_data_logging = 1;
ctrl->server_local->inhibit_data_logging_now = 0;
ctrl->server_local->inhibit_data_logging_count = 0;
err = ks_action_query (ctrl,
(flags & KS_GET_FLAG_ROOTDSE)? NULL : "ldap:///",
flags, filter, opt_attr, outfp);
leave:
es_fclose (outfp);
xfree (opt_attr);
ctrl->server_local->inhibit_data_logging = 0;
return leave_cmd (ctx, err);
}
static const char hlp_loadswdb[] = static const char hlp_loadswdb[] =
"LOADSWDB [--force]\n" "LOADSWDB [--force]\n"
@ -2973,6 +2973,7 @@ register_commands (assuan_context_t ctx)
{ "KS_GET", cmd_ks_get, hlp_ks_get }, { "KS_GET", cmd_ks_get, hlp_ks_get },
{ "KS_FETCH", cmd_ks_fetch, hlp_ks_fetch }, { "KS_FETCH", cmd_ks_fetch, hlp_ks_fetch },
{ "KS_PUT", cmd_ks_put, hlp_ks_put }, { "KS_PUT", cmd_ks_put, hlp_ks_put },
{ "AD_QUERY", cmd_ad_query, hlp_ad_query },
{ "GETINFO", cmd_getinfo, hlp_getinfo }, { "GETINFO", cmd_getinfo, hlp_getinfo },
{ "LOADSWDB", cmd_loadswdb, hlp_loadswdb }, { "LOADSWDB", cmd_loadswdb, hlp_loadswdb },
{ "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr }, { "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },