mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
dirmngr: Extend the AD_QUERY command.
* dirmngr/server.c (cmd_ad_query): Add options --help and --subst. (cmd_getinfo): Add sub-command "sid". * dirmngr/ks-engine.h (KS_GET_FLAG_SUBST): New. * dirmngr/ks-engine-ldap.c (ks_ldap_help_variables): New. (getval_for_filter): New. (map_rid_to_dn): New. (ks_ldap_query): Support variables. -- The new variables features makes it easier to write AD queries without requiring domain specific expressions.
This commit is contained in:
parent
7b7fdf45e5
commit
207c99567c
@ -616,7 +616,7 @@ nve_next_value (nve_t entry, const char *name)
|
|||||||
|
|
||||||
/* Return the string for the first entry in NVC with NAME. If an
|
/* Return the string for the first entry in NVC with NAME. If an
|
||||||
* entry with NAME is missing in NVC or its value is the empty string
|
* entry with NAME is missing in NVC or its value is the empty string
|
||||||
* NULL is returned. Note that the The returned string is a pointer
|
* NULL is returned. Note that the the returned string is a pointer
|
||||||
* into NVC. */
|
* into NVC. */
|
||||||
const char *
|
const char *
|
||||||
nvc_get_string (nvc_t nvc, const char *name)
|
nvc_get_string (nvc_t nvc, const char *name)
|
||||||
|
@ -26,6 +26,13 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <npth.h>
|
#include <npth.h>
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
# ifndef WINVER
|
||||||
|
# define WINVER 0x0500 /* Same as in common/sysutils.c */
|
||||||
|
# endif
|
||||||
|
# include <winsock2.h>
|
||||||
|
# include <sddl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include "dirmngr.h"
|
#include "dirmngr.h"
|
||||||
@ -73,6 +80,9 @@ struct ks_engine_ldap_local_s
|
|||||||
int more_pages; /* More pages announced by server. */
|
int more_pages; /* More pages announced by server. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*-- prototypes --*/
|
||||||
|
static char *map_rid_to_dn (ctrl_t ctrl, const char *rid);
|
||||||
|
static char *basedn_from_rootdse (ctrl_t ctrl, parsed_uri_t uri);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -150,6 +160,114 @@ my_ldap_value_free (char **vals)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Print a description of supported variables. */
|
||||||
|
void
|
||||||
|
ks_ldap_help_variables (ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
const char data[] =
|
||||||
|
"Supported variables in LDAP filter expressions:\n"
|
||||||
|
"\n"
|
||||||
|
"domain - The defaultNamingContext.\n"
|
||||||
|
"domain_admins - Group of domain admins.\n"
|
||||||
|
"domain_users - Group with all user accounts.\n"
|
||||||
|
"domain_guests - Group with the builtin gues account.\n"
|
||||||
|
"domain_computers - Group with all clients and servers.\n"
|
||||||
|
"cert_publishers - Group with all cert issuing computers.\n"
|
||||||
|
"protected_users - Group of users with extra protection.\n"
|
||||||
|
"key_admins - Group for delegated access to msdsKeyCredentialLink.\n"
|
||||||
|
"enterprise_key_admins - Similar to key_admins.\n"
|
||||||
|
"domain_domain_controllers - Group with all domain controllers.\n"
|
||||||
|
"sid_domain - SubAuthority numbers.\n";
|
||||||
|
|
||||||
|
ks_print_help (ctrl, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper function for substitute_vars. */
|
||||||
|
static const char *
|
||||||
|
getval_for_filter (void *cookie, const char *name)
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = cookie;
|
||||||
|
const char *result = NULL;
|
||||||
|
|
||||||
|
if (!strcmp (name, "sid_domain"))
|
||||||
|
{
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
PSID mysid;
|
||||||
|
static char *sidstr;
|
||||||
|
char *s, *s0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!sidstr)
|
||||||
|
{
|
||||||
|
mysid = w32_get_user_sid ();
|
||||||
|
if (!mysid)
|
||||||
|
{
|
||||||
|
gpg_err_set_errno (ENOENT);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ConvertSidToStringSid (mysid, &sidstr))
|
||||||
|
{
|
||||||
|
gpg_err_set_errno (EINVAL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
/* Example for SIDSTR:
|
||||||
|
* S-1-5-21-3636969917-2569447256-918939550-1127 */
|
||||||
|
for (s0=NULL,s=sidstr,i=0; (s=strchr (s, '-')); i++)
|
||||||
|
{
|
||||||
|
s++;
|
||||||
|
if (i == 3)
|
||||||
|
s0 = s;
|
||||||
|
else if (i==6)
|
||||||
|
{
|
||||||
|
s[-1] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!s0)
|
||||||
|
{
|
||||||
|
log_error ("oops: invalid SID received from OS");
|
||||||
|
gpg_err_set_errno (EINVAL);
|
||||||
|
LocalFree (sidstr);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
sidstr = s0; /* (We never release SIDSTR thus no memmove.) */
|
||||||
|
}
|
||||||
|
result = sidstr;
|
||||||
|
#else
|
||||||
|
gpg_err_set_errno (ENOSYS);
|
||||||
|
goto leave;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, "domain"))
|
||||||
|
result = basedn_from_rootdse (ctrl, NULL);
|
||||||
|
else if (!strcmp (name, "domain_admins"))
|
||||||
|
result = map_rid_to_dn (ctrl, "512");
|
||||||
|
else if (!strcmp (name, "domain_users"))
|
||||||
|
result = map_rid_to_dn (ctrl, "513");
|
||||||
|
else if (!strcmp (name, "domain_guests"))
|
||||||
|
result = map_rid_to_dn (ctrl, "514");
|
||||||
|
else if (!strcmp (name, "domain_computers"))
|
||||||
|
result = map_rid_to_dn (ctrl, "515");
|
||||||
|
else if (!strcmp (name, "domain_domain_controllers"))
|
||||||
|
result = map_rid_to_dn (ctrl, "516");
|
||||||
|
else if (!strcmp (name, "cert_publishers"))
|
||||||
|
result = map_rid_to_dn (ctrl, "517");
|
||||||
|
else if (!strcmp (name, "protected_users"))
|
||||||
|
result = map_rid_to_dn (ctrl, "525");
|
||||||
|
else if (!strcmp (name, "key_admins"))
|
||||||
|
result = map_rid_to_dn (ctrl, "526");
|
||||||
|
else if (!strcmp (name, "enterprise_key_admins"))
|
||||||
|
result = map_rid_to_dn (ctrl, "527");
|
||||||
|
else
|
||||||
|
result = ""; /* Unknown variables are empty. */
|
||||||
|
|
||||||
|
leave:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Print a help output for the schemata supported by this module. */
|
/* Print a help output for the schemata supported by this module. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
@ -1396,6 +1514,63 @@ fetch_rootdse (ctrl_t ctrl, parsed_uri_t uri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the DN for the given RID. This is used with the Active
|
||||||
|
* Directory. */
|
||||||
|
static char *
|
||||||
|
map_rid_to_dn (ctrl_t ctrl, const char *rid)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char *result = NULL;
|
||||||
|
estream_t infp = NULL;
|
||||||
|
uri_item_t puri; /* The broken down URI. */
|
||||||
|
nvc_t nvc = NULL;
|
||||||
|
char *filter = NULL;
|
||||||
|
const char *s;
|
||||||
|
char *attr[2] = {"dn", NULL};
|
||||||
|
|
||||||
|
err = ks_action_parse_uri ("ldap:///", &puri);
|
||||||
|
if (err)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
filter = strconcat ("(objectSid=S-1-5-21-$sid_domain-", rid, ")", NULL);
|
||||||
|
if (!filter)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = ks_ldap_query (ctrl, puri->parsed_uri, KS_GET_FLAG_SUBST,
|
||||||
|
filter, attr, NULL, &infp);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("ldap: AD query '%s' failed: %s\n", filter,gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
if ((err = nvc_parse (&nvc, NULL, infp)))
|
||||||
|
{
|
||||||
|
log_error ("ldap: parsing the result failed: %s\n",gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
if (!(s = nvc_get_string (nvc, "Dn:")))
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||||
|
log_error ("ldap: mapping rid '%s'failed: %s\n", rid, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
result = xtrystrdup (s);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("ldap: strdup failed: %s\n", gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
es_fclose (infp);
|
||||||
|
release_uri_item_list (puri);
|
||||||
|
xfree (filter);
|
||||||
|
nvc_release (nvc);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the baseDN for URI which might have already been cached for
|
/* Return the baseDN for URI which might have already been cached for
|
||||||
* this session. */
|
* this session. */
|
||||||
static char *
|
static char *
|
||||||
@ -2824,6 +2999,7 @@ ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri, unsigned int ks_get_flags,
|
|||||||
LDAP *ldap_conn = NULL;
|
LDAP *ldap_conn = NULL;
|
||||||
char *basedn = NULL;
|
char *basedn = NULL;
|
||||||
estream_t fp = NULL;
|
estream_t fp = NULL;
|
||||||
|
char *filter_arg_buffer = NULL;
|
||||||
char *filter = NULL;
|
char *filter = NULL;
|
||||||
int scope = LDAP_SCOPE_SUBTREE;
|
int scope = LDAP_SCOPE_SUBTREE;
|
||||||
LDAPMessage *message = NULL;
|
LDAPMessage *message = NULL;
|
||||||
@ -2839,6 +3015,20 @@ ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri, unsigned int ks_get_flags,
|
|||||||
if ((!filter_arg || !*filter_arg) && (ks_get_flags & KS_GET_FLAG_ROOTDSE))
|
if ((!filter_arg || !*filter_arg) && (ks_get_flags & KS_GET_FLAG_ROOTDSE))
|
||||||
filter_arg = "^&base&(objectclass=*)";
|
filter_arg = "^&base&(objectclass=*)";
|
||||||
|
|
||||||
|
if ((ks_get_flags & KS_GET_FLAG_SUBST)
|
||||||
|
&& filter_arg && strchr (filter_arg, '$'))
|
||||||
|
{
|
||||||
|
filter_arg_buffer = substitute_vars (filter_arg, getval_for_filter, ctrl);
|
||||||
|
if (!filter_arg_buffer)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("substituting filter variables failed: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
filter_arg = filter_arg_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
err = ks_ldap_prepare_my_state (ctrl, ks_get_flags, &first_mode, &next_mode);
|
err = ks_ldap_prepare_my_state (ctrl, ks_get_flags, &first_mode, &next_mode);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -3048,6 +3238,7 @@ ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri, unsigned int ks_get_flags,
|
|||||||
ldap_unbind (ldap_conn);
|
ldap_unbind (ldap_conn);
|
||||||
|
|
||||||
xfree (filter);
|
xfree (filter);
|
||||||
|
xfree (filter_arg_buffer);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#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_ONLY_AD 8 /* Do this only if we have an AD. */
|
||||||
#define KS_GET_FLAG_ROOTDSE 16 /* Get the rootDSE. */
|
#define KS_GET_FLAG_ROOTDSE 16 /* Get the rootDSE. */
|
||||||
|
#define KS_GET_FLAG_SUBST 32 /* Substiture variables. */
|
||||||
|
|
||||||
|
|
||||||
/*-- ks-action.c --*/
|
/*-- ks-action.c --*/
|
||||||
@ -70,6 +71,7 @@ gpg_error_t ks_kdns_help (ctrl_t ctrl, parsed_uri_t uri);
|
|||||||
gpg_error_t ks_kdns_fetch (ctrl_t ctrl, parsed_uri_t uri, estream_t *r_fp);
|
gpg_error_t ks_kdns_fetch (ctrl_t ctrl, parsed_uri_t uri, estream_t *r_fp);
|
||||||
|
|
||||||
/*-- ks-engine-ldap.c --*/
|
/*-- ks-engine-ldap.c --*/
|
||||||
|
void ks_ldap_help_variables (ctrl_t ctrl);
|
||||||
gpg_error_t ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri);
|
gpg_error_t ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri);
|
||||||
void ks_ldap_free_state (struct ks_engine_ldap_local_s *state);
|
void ks_ldap_free_state (struct ks_engine_ldap_local_s *state);
|
||||||
gpg_error_t ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
|
gpg_error_t ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
|
||||||
|
@ -32,6 +32,13 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
# ifndef WINVER
|
||||||
|
# define WINVER 0x0500 /* Same as in common/sysutils.c */
|
||||||
|
# endif
|
||||||
|
# include <winsock2.h>
|
||||||
|
# include <sddl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "dirmngr.h"
|
#include "dirmngr.h"
|
||||||
#include <assuan.h>
|
#include <assuan.h>
|
||||||
@ -2701,15 +2708,21 @@ cmd_ks_put (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
|
|
||||||
static const char hlp_ad_query[] =
|
static const char hlp_ad_query[] =
|
||||||
"AD_QUERY [--first|--next] [--] <filter_expression> \n"
|
"AD_QUERY [--first|--next] [--] <filter> \n"
|
||||||
"\n"
|
"\n"
|
||||||
"Query properties from a Windows Active Directory.\n"
|
"Query properties from a Windows Active Directory.\n"
|
||||||
"Our extended filter syntax may be used for the filter\n"
|
"Options:\n"
|
||||||
"expression; see gnupg/dirmngr/ldap-misc.c. There are\n"
|
"\n"
|
||||||
"a couple of other options available:\n\n"
|
|
||||||
" --rootdse - Query the root using serverless binding,\n"
|
" --rootdse - Query the root using serverless binding,\n"
|
||||||
|
" --subst - Substitute variables in the filter\n"
|
||||||
" --attr=<attribs> - Comma delimited list of attributes\n"
|
" --attr=<attribs> - Comma delimited list of attributes\n"
|
||||||
" to return.\n"
|
" to return.\n"
|
||||||
|
" --help - List supported variables\n"
|
||||||
|
"\n"
|
||||||
|
"Extended filter syntax is allowed:\n"
|
||||||
|
" ^[<base>][&<scope>]&[<filter>]\n"
|
||||||
|
"Usual escaping rules apply. An ampersand in <base> must\n"
|
||||||
|
"doubled. <scope> may be \"base\", \"one\", or \"sub\"."
|
||||||
;
|
;
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_ad_query (assuan_context_t ctx, char *line)
|
cmd_ad_query (assuan_context_t ctx, char *line)
|
||||||
@ -2723,6 +2736,7 @@ cmd_ad_query (assuan_context_t ctx, char *line)
|
|||||||
char **opt_attr = NULL;
|
char **opt_attr = NULL;
|
||||||
const char *s;
|
const char *s;
|
||||||
gnupg_isotime_t opt_newer;
|
gnupg_isotime_t opt_newer;
|
||||||
|
int opt_help = 0;
|
||||||
|
|
||||||
*opt_newer = 0;
|
*opt_newer = 0;
|
||||||
|
|
||||||
@ -2733,6 +2747,10 @@ cmd_ad_query (assuan_context_t ctx, char *line)
|
|||||||
flags |= KS_GET_FLAG_NEXT;
|
flags |= KS_GET_FLAG_NEXT;
|
||||||
if (has_option (line, "--rootdse"))
|
if (has_option (line, "--rootdse"))
|
||||||
flags |= KS_GET_FLAG_ROOTDSE;
|
flags |= KS_GET_FLAG_ROOTDSE;
|
||||||
|
if (has_option (line, "--subst"))
|
||||||
|
flags |= KS_GET_FLAG_SUBST;
|
||||||
|
if (has_option (line, "--help"))
|
||||||
|
opt_help = 1;
|
||||||
if ((s = option_value (line, "--newer"))
|
if ((s = option_value (line, "--newer"))
|
||||||
&& !string2isotime (opt_newer, s))
|
&& !string2isotime (opt_newer, s))
|
||||||
{
|
{
|
||||||
@ -2756,6 +2774,13 @@ cmd_ad_query (assuan_context_t ctx, char *line)
|
|||||||
line = skip_options (line);
|
line = skip_options (line);
|
||||||
filter = line;
|
filter = line;
|
||||||
|
|
||||||
|
if (opt_help)
|
||||||
|
{
|
||||||
|
ks_ldap_help_variables (ctrl);
|
||||||
|
err = 0;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
if ((flags & KS_GET_FLAG_NEXT))
|
if ((flags & KS_GET_FLAG_NEXT))
|
||||||
{
|
{
|
||||||
if (*filter || (flags & ~KS_GET_FLAG_NEXT))
|
if (*filter || (flags & ~KS_GET_FLAG_NEXT))
|
||||||
@ -2907,14 +2932,39 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
|||||||
{
|
{
|
||||||
const char *s = getenv (line);
|
const char *s = getenv (line);
|
||||||
if (!s)
|
if (!s)
|
||||||
|
{
|
||||||
err = set_error (GPG_ERR_NOT_FOUND, "No such envvar");
|
err = set_error (GPG_ERR_NOT_FOUND, "No such envvar");
|
||||||
else
|
goto leave;
|
||||||
|
}
|
||||||
err = assuan_send_data (ctx, s, strlen (s));
|
err = assuan_send_data (ctx, s, strlen (s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
else if (!strcmp (line, "sid"))
|
||||||
|
{
|
||||||
|
PSID mysid;
|
||||||
|
char *sidstr;
|
||||||
|
|
||||||
|
mysid = w32_get_user_sid ();
|
||||||
|
if (!mysid)
|
||||||
|
{
|
||||||
|
err = set_error (GPG_ERR_NOT_FOUND, "Error getting my SID");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ConvertSidToStringSid (mysid, &sidstr))
|
||||||
|
{
|
||||||
|
err = set_error (GPG_ERR_BUG, "Error converting SID to a string");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
err = assuan_send_data (ctx, sidstr, strlen (sidstr));
|
||||||
|
LocalFree (sidstr);
|
||||||
|
}
|
||||||
|
#endif /*HAVE_W32_SYSTEM*/
|
||||||
else
|
else
|
||||||
err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
|
err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
|
||||||
|
|
||||||
|
leave:
|
||||||
return leave_cmd (ctx, err);
|
return leave_cmd (ctx, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user