diff --git a/common/name-value.c b/common/name-value.c index 6f3df5a8d..0dffc63b4 100644 --- a/common/name-value.c +++ b/common/name-value.c @@ -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 * 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. */ const char * nvc_get_string (nvc_t nvc, const char *name) diff --git a/dirmngr/ks-engine-ldap.c b/dirmngr/ks-engine-ldap.c index 1ffd30ecb..c2a210542 100644 --- a/dirmngr/ks-engine-ldap.c +++ b/dirmngr/ks-engine-ldap.c @@ -26,6 +26,13 @@ #include #include #include +#ifdef HAVE_W32_SYSTEM +# ifndef WINVER +# define WINVER 0x0500 /* Same as in common/sysutils.c */ +# endif +# include +# include +#endif #include "dirmngr.h" @@ -73,6 +80,9 @@ struct ks_engine_ldap_local_s 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. */ 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 * this session. */ 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; char *basedn = NULL; estream_t fp = NULL; + char *filter_arg_buffer = NULL; char *filter = NULL; int scope = LDAP_SCOPE_SUBTREE; 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)) 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); if (err) 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); xfree (filter); + xfree (filter_arg_buffer); return err; } diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index 03588a4d3..6de77ccb2 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -29,6 +29,7 @@ #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. */ +#define KS_GET_FLAG_SUBST 32 /* Substiture variables. */ /*-- 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); /*-- 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); 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, diff --git a/dirmngr/server.c b/dirmngr/server.c index 2c5a41b07..51a149cb2 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -32,6 +32,13 @@ #include #include #include +#ifdef HAVE_W32_SYSTEM +# ifndef WINVER +# define WINVER 0x0500 /* Same as in common/sysutils.c */ +# endif +# include +# include +#endif #include "dirmngr.h" #include @@ -2701,15 +2708,21 @@ cmd_ks_put (assuan_context_t ctx, char *line) static const char hlp_ad_query[] = - "AD_QUERY [--first|--next] [--] \n" + "AD_QUERY [--first|--next] [--] \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" + "Options:\n" + "\n" + " --rootdse - Query the root using serverless binding,\n" + " --subst - Substitute variables in the filter\n" " --attr= - Comma delimited list of attributes\n" " to return.\n" + " --help - List supported variables\n" + "\n" + "Extended filter syntax is allowed:\n" + " ^[][&]&[]\n" + "Usual escaping rules apply. An ampersand in must\n" + "doubled. may be \"base\", \"one\", or \"sub\"." ; static gpg_error_t 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; const char *s; gnupg_isotime_t opt_newer; + int opt_help = 0; *opt_newer = 0; @@ -2733,6 +2747,10 @@ cmd_ad_query (assuan_context_t ctx, char *line) flags |= KS_GET_FLAG_NEXT; if (has_option (line, "--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")) && !string2isotime (opt_newer, s)) { @@ -2756,6 +2774,13 @@ cmd_ad_query (assuan_context_t ctx, char *line) line = skip_options (line); filter = line; + if (opt_help) + { + ks_ldap_help_variables (ctrl); + err = 0; + goto leave; + } + if ((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); if (!s) - err = set_error (GPG_ERR_NOT_FOUND, "No such envvar"); - else - err = assuan_send_data (ctx, s, strlen (s)); + { + err = set_error (GPG_ERR_NOT_FOUND, "No such envvar"); + goto leave; + } + 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 err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); + leave: return leave_cmd (ctx, err); }