diff options
Diffstat (limited to 'source3/winbindd/idmap_rfc2307.c')
-rw-r--r-- | source3/winbindd/idmap_rfc2307.c | 848 |
1 files changed, 848 insertions, 0 deletions
diff --git a/source3/winbindd/idmap_rfc2307.c b/source3/winbindd/idmap_rfc2307.c new file mode 100644 index 0000000..d84cf93 --- /dev/null +++ b/source3/winbindd/idmap_rfc2307.c @@ -0,0 +1,848 @@ +/* + * Unix SMB/CIFS implementation. + * + * Id mapping using LDAP records as defined in RFC 2307 + * + * The SID<->uid/gid mapping is performed in two steps: 1) Query the + * AD server for the name<->sid mapping. 2) Query an LDAP server + * according to RFC 2307 for the name<->uid/gid mapping. + * + * Copyright (C) Christof Schmitt 2012,2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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/>. + */ + +#include "includes.h" +#include "winbindd.h" +#include "winbindd_ads.h" +#include "idmap.h" +#include "smbldap.h" +#include "nsswitch/winbind_client.h" +#include "lib/winbind_util.h" +#include "libcli/security/dom_sid.h" +#include "lib/global_contexts.h" + +/* + * Config and connection info per domain. + */ +struct idmap_rfc2307_context { + const char *bind_path_user; + const char *bind_path_group; + const char *ldap_domain; + bool user_cn; + const char *realm; + + /* + * Pointer to ldap struct in ads or smbldap_state, has to be + * updated after connecting to server + */ + LDAP *ldap; + + /* Optional function to check connection to server */ + NTSTATUS (*check_connection)(struct idmap_domain *dom); + + /* Issue ldap query */ + NTSTATUS (*search)(struct idmap_rfc2307_context *ctx, + const char *bind_path, const char *expr, + const char **attrs, LDAPMessage **res); + + /* Access to LDAP in AD server */ + ADS_STRUCT *ads; + + /* Access to stand-alone LDAP server */ + struct smbldap_state *smbldap_state; +}; + +/* + * backend functions for LDAP queries through ADS + */ + +static NTSTATUS idmap_rfc2307_ads_check_connection(struct idmap_domain *dom) +{ + struct idmap_rfc2307_context *ctx; + const char *dom_name = dom->name; + ADS_STATUS status; + + DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n", + dom->name)); + + ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context); + dom_name = ctx->ldap_domain ? ctx->ldap_domain : dom->name; + + status = ads_idmap_cached_connection(dom_name, ctx, &ctx->ads); + if (ADS_ERR_OK(status)) { + ctx->ldap = ctx->ads->ldap.ld; + } else { + DEBUG(1, ("Could not connect to domain %s: %s\n", dom->name, + ads_errstr(status))); + } + + return ads_ntstatus(status); +} + +static NTSTATUS idmap_rfc2307_ads_search(struct idmap_rfc2307_context *ctx, + const char *bind_path, + const char *expr, + const char **attrs, + LDAPMessage **result) +{ + ADS_STATUS status; + + status = ads_do_search_retry(ctx->ads, bind_path, + LDAP_SCOPE_SUBTREE, expr, attrs, result); + + if (!ADS_ERR_OK(status)) { + return ads_ntstatus(status); + } + + ctx->ldap = ctx->ads->ldap.ld; + return ads_ntstatus(status); +} + +static NTSTATUS idmap_rfc2307_init_ads(struct idmap_rfc2307_context *ctx, + const char *domain_name) +{ + const char *ldap_domain; + + ctx->search = idmap_rfc2307_ads_search; + ctx->check_connection = idmap_rfc2307_ads_check_connection; + + ldap_domain = idmap_config_const_string(domain_name, "ldap_domain", + NULL); + if (ldap_domain) { + ctx->ldap_domain = talloc_strdup(ctx, ldap_domain); + if (ctx->ldap_domain == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + + return NT_STATUS_OK; +} + +/* + * backend function for LDAP queries through stand-alone LDAP server + */ + +static NTSTATUS idmap_rfc2307_ldap_search(struct idmap_rfc2307_context *ctx, + const char *bind_path, + const char *expr, + const char **attrs, + LDAPMessage **result) +{ + int ret; + + ret = smbldap_search(ctx->smbldap_state, bind_path, LDAP_SCOPE_SUBTREE, + expr, attrs, 0, result); + ctx->ldap = smbldap_get_ldap(ctx->smbldap_state); + + if (ret == LDAP_SUCCESS) { + return NT_STATUS_OK; + } + + return NT_STATUS_LDAP(ret); +} + +static bool idmap_rfc2307_get_uint32(LDAP *ldap, LDAPMessage *entry, + const char *field, uint32_t *value) +{ + bool b; + char str[20]; + + b = smbldap_get_single_attribute(ldap, entry, field, str, sizeof(str)); + + if (b) { + *value = atoi(str); + } + + return b; +} + +static NTSTATUS idmap_rfc2307_init_ldap(struct idmap_rfc2307_context *ctx, + const char *domain_name) +{ + NTSTATUS ret; + char *url; + char *secret = NULL; + const char *ldap_url, *user_dn; + TALLOC_CTX *mem_ctx = ctx; + + ldap_url = idmap_config_const_string(domain_name, "ldap_url", NULL); + if (!ldap_url) { + DEBUG(1, ("ERROR: missing idmap ldap url\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + url = talloc_strdup(talloc_tos(), ldap_url); + + user_dn = idmap_config_const_string(domain_name, "ldap_user_dn", NULL); + if (user_dn) { + secret = idmap_fetch_secret("ldap", domain_name, user_dn); + if (!secret) { + ret = NT_STATUS_ACCESS_DENIED; + goto done; + } + } + + /* assume anonymous if we don't have a specified user */ + ret = smbldap_init(mem_ctx, global_event_context(), url, + (user_dn == NULL), user_dn, secret, + &ctx->smbldap_state); + SAFE_FREE(secret); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", url)); + goto done; + } + + ctx->search = idmap_rfc2307_ldap_search; + +done: + talloc_free(url); + return ret; +} + +/* + * common code for stand-alone LDAP and ADS + */ + +static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context *ctx, + TALLOC_CTX *mem_ctx, + struct id_map **ids, + LDAPMessage *result, + const char *dom_name, + const char **attrs, int type) +{ + int count, i; + LDAPMessage *entry; + + count = ldap_count_entries(ctx->ldap, result); + + for (i = 0; i < count; i++) { + char *name; + struct dom_sid sid; + enum lsa_SidType lsa_type; + struct id_map *map; + uint32_t id; + bool b; + + if (i == 0) { + entry = ldap_first_entry(ctx->ldap, result); + } else { + entry = ldap_next_entry(ctx->ldap, entry); + } + if (!entry) { + DEBUG(2, ("Unable to fetch entry.\n")); + break; + } + + name = smbldap_talloc_single_attribute(ctx->ldap, entry, + attrs[0], mem_ctx); + if (!name) { + DEBUG(1, ("Could not get user name\n")); + continue; + } + + b = idmap_rfc2307_get_uint32(ctx->ldap, entry, attrs[1], &id); + if (!b) { + DEBUG(1, ("Could not pull id for record %s\n", name)); + continue; + } + + map = idmap_find_map_by_id(ids, type, id); + if (!map) { + DEBUG(1, ("Could not find id %d, name %s\n", id, name)); + continue; + } + + if (ctx->realm != NULL) { + /* Strip @realm from user or group name */ + char *delim; + + delim = strchr(name, '@'); + if (delim) { + *delim = '\0'; + } + } + + /* by default calls to winbindd are disabled + the following call will not recurse so this is safe */ + (void)winbind_on(); + /* Lookup name from PDC using lsa_lookup_names() */ + b = winbind_lookup_name(dom_name, name, &sid, &lsa_type); + (void)winbind_off(); + + if (!b) { + DEBUG(1, ("SID lookup failed for id %d, %s\n", + id, name)); + continue; + } + + if (type == ID_TYPE_UID && lsa_type != SID_NAME_USER) { + DEBUG(1, ("Wrong type %d for user name %s\n", + type, name)); + continue; + } + + if (type == ID_TYPE_GID && lsa_type != SID_NAME_DOM_GRP && + lsa_type != SID_NAME_ALIAS && + lsa_type != SID_NAME_WKN_GRP) { + DEBUG(1, ("Wrong type %d for group name %s\n", + type, name)); + continue; + } + + map->status = ID_MAPPED; + sid_copy(map->sid, &sid); + } +} + +/* + * Map unixids to names and then to sids. + */ +static NTSTATUS idmap_rfc2307_unixids_to_sids(struct idmap_domain *dom, + struct id_map **ids) +{ + struct idmap_rfc2307_context *ctx; + char *fltr_usr = NULL, *fltr_grp = NULL; + TALLOC_CTX *mem_ctx; + int cnt_usr = 0, cnt_grp = 0, idx = 0, bidx = 0; + LDAPMessage *result = NULL; + NTSTATUS ret; + + ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context); + mem_ctx = talloc_new(ctx); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + + if (ctx->check_connection) { + ret = ctx->check_connection(dom); + if (!NT_STATUS_IS_OK(ret)) { + goto out; + } + } + +again: + bidx = idx; + + if (!fltr_usr) { + /* prepare new user query, see getpwuid() in RFC2307 */ + fltr_usr = talloc_asprintf(mem_ctx, + "(&(objectClass=posixAccount)(|"); + } + + if (!fltr_grp) { + /* prepare new group query, see getgrgid() in RFC2307 */ + fltr_grp = talloc_asprintf(mem_ctx, + "(&(objectClass=posixGroup)(|"); + } + + if (!fltr_usr || !fltr_grp) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + + while (cnt_usr < IDMAP_LDAP_MAX_IDS && + cnt_grp < IDMAP_LDAP_MAX_IDS && ids[idx]) { + + switch (ids[idx]->xid.type) { + case ID_TYPE_UID: + fltr_usr = talloc_asprintf_append_buffer(fltr_usr, + "(uidNumber=%d)", ids[idx]->xid.id); + cnt_usr++; + break; + case ID_TYPE_GID: + fltr_grp = talloc_asprintf_append_buffer(fltr_grp, + "(gidNumber=%d)", ids[idx]->xid.id); + cnt_grp++; + break; + default: + DEBUG(3, ("Error: unknown ID type %d\n", + ids[idx]->xid.type)); + ret = NT_STATUS_UNSUCCESSFUL; + goto out; + } + + if (!fltr_usr || !fltr_grp) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + + idx++; + } + + if (cnt_usr == IDMAP_LDAP_MAX_IDS || (cnt_usr != 0 && !ids[idx])) { + const char *attrs[] = { NULL, /* uid or cn */ + "uidNumber", + NULL }; + + fltr_usr = talloc_strdup_append(fltr_usr, "))"); + if (!fltr_usr) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + + attrs[0] = ctx->user_cn ? "cn" : "uid"; + ret = ctx->search(ctx, ctx->bind_path_user, fltr_usr, attrs, + &result); + if (!NT_STATUS_IS_OK(ret)) { + goto out; + } + + idmap_rfc2307_map_sid_results(ctx, mem_ctx, &ids[bidx], result, + dom->name, attrs, ID_TYPE_UID); + cnt_usr = 0; + TALLOC_FREE(fltr_usr); + } + + if (cnt_grp == IDMAP_LDAP_MAX_IDS || (cnt_grp != 0 && !ids[idx])) { + const char *attrs[] = { "cn", "gidNumber", NULL }; + + fltr_grp = talloc_strdup_append(fltr_grp, "))"); + if (!fltr_grp) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + ret = ctx->search(ctx, ctx->bind_path_group, fltr_grp, attrs, + &result); + if (!NT_STATUS_IS_OK(ret)) { + goto out; + } + + idmap_rfc2307_map_sid_results(ctx, mem_ctx, &ids[bidx], result, + dom->name, attrs, ID_TYPE_GID); + cnt_grp = 0; + TALLOC_FREE(fltr_grp); + } + + if (ids[idx]) { + goto again; + } + + ret = NT_STATUS_OK; + +out: + talloc_free(mem_ctx); + return ret; +} + +struct idmap_rfc2307_map { + struct id_map *map; + const char *name; + enum id_type type; +}; + +/* + * Lookup names for SIDS and store the data in the local mapping + * array. + */ +static NTSTATUS idmap_rfc_2307_sids_to_names(TALLOC_CTX *mem_ctx, + struct id_map **ids, + struct idmap_rfc2307_map *maps, + struct idmap_rfc2307_context *ctx) +{ + int i; + + for (i = 0; ids[i]; i++) { + const char *domain, *name; + enum lsa_SidType lsa_type; + struct id_map *id = ids[i]; + struct idmap_rfc2307_map *map = &maps[i]; + struct dom_sid_buf buf; + bool b; + + /* by default calls to winbindd are disabled + the following call will not recurse so this is safe */ + (void)winbind_on(); + b = winbind_lookup_sid(mem_ctx, ids[i]->sid, &domain, &name, + &lsa_type); + (void)winbind_off(); + + if (!b) { + DEBUG(1, ("Lookup sid %s failed.\n", + dom_sid_str_buf(ids[i]->sid, &buf))); + continue; + } + + switch(lsa_type) { + case SID_NAME_USER: + id->xid.type = map->type = ID_TYPE_UID; + if (ctx->user_cn && ctx->realm != NULL) { + name = talloc_asprintf(mem_ctx, "%s@%s", + name, ctx->realm); + } + id->xid.type = map->type = ID_TYPE_UID; + break; + + case SID_NAME_DOM_GRP: + case SID_NAME_ALIAS: + case SID_NAME_WKN_GRP: + if (ctx->realm != NULL) { + name = talloc_asprintf(mem_ctx, "%s@%s", + name, ctx->realm); + } + id->xid.type = map->type = ID_TYPE_GID; + break; + + default: + DEBUG(1, ("Unknown lsa type %d for sid %s\n", + lsa_type, + dom_sid_str_buf(id->sid, &buf))); + id->status = ID_UNMAPPED; + continue; + } + + map->map = id; + id->status = ID_UNKNOWN; + map->name = strupper_talloc(mem_ctx, name); + + if (!map->name) { + return NT_STATUS_NO_MEMORY; + } + } + + return NT_STATUS_OK; +} + +/* + * Find id_map entry by looking up the name in the internal + * mapping array. + */ +static struct id_map* idmap_rfc2307_find_map(struct idmap_rfc2307_map *maps, + enum id_type type, + const char *name) +{ + int i; + + DEBUG(10, ("Looking for name %s, type %d\n", name, type)); + + for (i = 0; maps[i].map != NULL; i++) { + DEBUG(10, ("Entry %d: name %s, type %d\n", + i, maps[i].name, maps[i].type)); + if (type == maps[i].type && strcmp(name, maps[i].name) == 0) { + return maps[i].map; + } + } + + return NULL; +} + +static void idmap_rfc2307_map_xid_results(struct idmap_rfc2307_context *ctx, + TALLOC_CTX *mem_ctx, + struct idmap_rfc2307_map *maps, + LDAPMessage *result, + struct idmap_domain *dom, + const char **attrs, enum id_type type) +{ + int count, i; + LDAPMessage *entry; + + count = ldap_count_entries(ctx->ldap, result); + + for (i = 0; i < count; i++) { + uint32_t id; + char *name; + bool b; + struct id_map *id_map; + + if (i == 0) { + entry = ldap_first_entry(ctx->ldap, result); + } else { + entry = ldap_next_entry(ctx->ldap, entry); + } + if (!entry) { + DEBUG(2, ("Unable to fetch entry.\n")); + break; + } + + name = smbldap_talloc_single_attribute(ctx->ldap, entry, + attrs[0], mem_ctx); + if (!name) { + DEBUG(1, ("Could not get user name\n")); + continue; + } + + b = idmap_rfc2307_get_uint32(ctx->ldap, entry, attrs[1], &id); + if (!b) { + DEBUG(5, ("Could not pull id for record %s\n", name)); + continue; + } + + if (!idmap_unix_id_is_in_range(id, dom)) { + DEBUG(5, ("Requested id (%u) out of range (%u - %u).\n", + id, dom->low_id, dom->high_id)); + continue; + } + + if (!strupper_m(name)) { + DEBUG(5, ("Could not convert %s to uppercase\n", name)); + continue; + } + id_map = idmap_rfc2307_find_map(maps, type, name); + if (!id_map) { + DEBUG(0, ("Could not find mapping entry for name %s\n", + name)); + continue; + } + + id_map->xid.id = id; + id_map->status = ID_MAPPED; + } +} + +/* + * Map sids to names and then to unixids. + */ +static NTSTATUS idmap_rfc2307_sids_to_unixids(struct idmap_domain *dom, + struct id_map **ids) +{ + struct idmap_rfc2307_context *ctx; + TALLOC_CTX *mem_ctx; + struct idmap_rfc2307_map *int_maps; + int cnt_usr = 0, cnt_grp = 0, idx = 0; + char *fltr_usr = NULL, *fltr_grp = NULL; + NTSTATUS ret; + int i; + + ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context); + mem_ctx = talloc_new(talloc_tos()); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + + if (ctx->check_connection) { + ret = ctx->check_connection(dom); + if (!NT_STATUS_IS_OK(ret)) { + goto out; + } + } + + for (i = 0; ids[i]; i++); + int_maps = talloc_zero_array(mem_ctx, struct idmap_rfc2307_map, i); + if (!int_maps) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + + ret = idmap_rfc_2307_sids_to_names(mem_ctx, ids, int_maps, ctx); + if (!NT_STATUS_IS_OK(ret)) { + goto out; + } + +again: + if (!fltr_usr) { + /* prepare new user query, see getpwuid() in RFC2307 */ + fltr_usr = talloc_asprintf(mem_ctx, + "(&(objectClass=posixAccount)(|"); + } + + if (!fltr_grp) { + /* prepare new group query, see getgrgid() in RFC2307 */ + fltr_grp = talloc_asprintf(mem_ctx, + "(&(objectClass=posixGroup)(|"); + } + + if (!fltr_usr || !fltr_grp) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + + while (cnt_usr < IDMAP_LDAP_MAX_IDS && + cnt_grp < IDMAP_LDAP_MAX_IDS && ids[idx]) { + struct id_map *id = ids[idx]; + struct idmap_rfc2307_map *map = &int_maps[idx]; + + switch(id->xid.type) { + case ID_TYPE_UID: + fltr_usr = talloc_asprintf_append_buffer(fltr_usr, + "(%s=%s)", (ctx->user_cn ? "cn" : "uid"), + map->name); + cnt_usr++; + break; + + case ID_TYPE_GID: + fltr_grp = talloc_asprintf_append_buffer(fltr_grp, + "(cn=%s)", map->name); + cnt_grp++; + break; + + default: + break; + } + + if (!fltr_usr || !fltr_grp) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + + idx++; + } + + if (cnt_usr == IDMAP_LDAP_MAX_IDS || (cnt_usr != 0 && !ids[idx])) { + const char *attrs[] = { NULL, /* uid or cn */ + "uidNumber", + NULL }; + LDAPMessage *result; + + fltr_usr = talloc_strdup_append(fltr_usr, "))"); + if (!fltr_usr) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + + attrs[0] = ctx->user_cn ? "cn" : "uid"; + ret = ctx->search(ctx, ctx->bind_path_user, fltr_usr, attrs, + &result); + if (!NT_STATUS_IS_OK(ret)) { + goto out; + } + + idmap_rfc2307_map_xid_results(ctx, mem_ctx, int_maps, + result, dom, attrs, ID_TYPE_UID); + + cnt_usr = 0; + TALLOC_FREE(fltr_usr); + } + + if (cnt_grp == IDMAP_LDAP_MAX_IDS || (cnt_grp != 0 && !ids[idx])) { + const char *attrs[] = {"cn", "gidNumber", NULL }; + LDAPMessage *result; + + fltr_grp = talloc_strdup_append(fltr_grp, "))"); + if (!fltr_grp) { + ret = NT_STATUS_NO_MEMORY; + goto out; + } + + ret = ctx->search(ctx, ctx->bind_path_group, fltr_grp, attrs, + &result); + if (!NT_STATUS_IS_OK(ret)) { + goto out; + } + + idmap_rfc2307_map_xid_results(ctx, mem_ctx, int_maps, result, + dom, attrs, ID_TYPE_GID); + cnt_grp = 0; + TALLOC_FREE(fltr_grp); + } + + if (ids[idx]) { + goto again; + } + + ret = NT_STATUS_OK; + +out: + talloc_free(mem_ctx); + return ret; +} + +static int idmap_rfc2307_context_destructor(struct idmap_rfc2307_context *ctx) +{ + TALLOC_FREE(ctx->ads); + + if (ctx->smbldap_state != NULL) { + smbldap_free_struct(&ctx->smbldap_state); + } + + return 0; +} + +static NTSTATUS idmap_rfc2307_initialize(struct idmap_domain *domain) +{ + struct idmap_rfc2307_context *ctx; + const char *bind_path_user, *bind_path_group, *ldap_server, *realm; + NTSTATUS status; + + ctx = talloc_zero(domain, struct idmap_rfc2307_context); + if (ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + talloc_set_destructor(ctx, idmap_rfc2307_context_destructor); + + bind_path_user = idmap_config_const_string( + domain->name, "bind_path_user", NULL); + if (bind_path_user == NULL) { + status = NT_STATUS_INVALID_PARAMETER; + goto err; + } + ctx->bind_path_user = talloc_strdup(ctx, bind_path_user); + if (ctx->bind_path_user == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err; + } + + bind_path_group = idmap_config_const_string( + domain->name, "bind_path_group", NULL); + if (bind_path_group == NULL) { + status = NT_STATUS_INVALID_PARAMETER; + goto err; + } + ctx->bind_path_group = talloc_strdup(ctx, bind_path_group); + if (ctx->bind_path_group == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err; + } + + ldap_server = idmap_config_const_string( + domain->name, "ldap_server", NULL); + if (!ldap_server) { + status = NT_STATUS_INVALID_PARAMETER; + goto err; + } + + if (strcmp(ldap_server, "stand-alone") == 0) { + status = idmap_rfc2307_init_ldap(ctx, domain->name); + + } else if (strcmp(ldap_server, "ad") == 0) { + status = idmap_rfc2307_init_ads(ctx, domain->name); + + } else { + status = NT_STATUS_INVALID_PARAMETER; + } + + if (!NT_STATUS_IS_OK(status)) { + goto err; + } + + realm = idmap_config_const_string(domain->name, "realm", NULL); + if (realm) { + ctx->realm = talloc_strdup(ctx, realm); + if (ctx->realm == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err; + } + } + + ctx->user_cn = idmap_config_bool(domain->name, "user_cn", false); + + domain->private_data = ctx; + return NT_STATUS_OK; + +err: + talloc_free(ctx); + return status; +} + +static const struct idmap_methods rfc2307_methods = { + .init = idmap_rfc2307_initialize, + .unixids_to_sids = idmap_rfc2307_unixids_to_sids, + .sids_to_unixids = idmap_rfc2307_sids_to_unixids, +}; + +static_decl_idmap; +NTSTATUS idmap_rfc2307_init(TALLOC_CTX *ctx) +{ + return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rfc2307", + &rfc2307_methods); +} |