The Samba-Bugzilla – Attachment 3603 Details for
Bug 3661
idmap_ad doesn't find users in trusted domains
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
New AdEx idmap/nss_info plugin for the trunk
0001-idmap_adex-Add-new-idmap-plugin-for-support-RFC2307.patch (text/plain), 102.01 KB, created by
Gerald (Jerry) Carter (dead mail address)
on 2008-09-19 12:39:25 UTC
(
hide
)
Description:
New AdEx idmap/nss_info plugin for the trunk
Filename:
MIME Type:
Creator:
Gerald (Jerry) Carter (dead mail address)
Created:
2008-09-19 12:39:25 UTC
Size:
102.01 KB
patch
obsolete
>From 22e7f9d9be4a818e60db86464987d8e0c83a1abe Mon Sep 17 00:00:00 2001 >From: Gerald (Jerry) Carter <jerry@samba.org> >Date: Fri, 19 Sep 2008 12:27:15 -0500 >Subject: [PATCH] idmap_adex: Add new idmap plugin for support RFC2307 enabled AD forests. > >The adex idmap/nss_info plugin is an adapation of the Likewise >Enterprise plugin with support for OU based cells removed >(since the Windows pieces to manage the cells are not available). > >This plugin supports > > * The RFC2307 schema for users and groups. > * Connections to trusted domains > * Global catalog searches > * Cross forest trusts > * User and group aliases > >Prerequiste: Add the following attributes to the Partial Attribute >Set in global catalog: > > * uidNumber > * uid > * gidNumber > >A basic config using the current trunk code would look like > > [global] > idmap backend = adex > idmap uid = 10000 - 19999 > idmap gid = 20000 - 29999 > idmap config US:backend = adex > idmap config US:range = 20000 - 29999 > winbind nss info = adex > > winbind normalize names = yes > winbind refresh tickets = yes > template homedir = /home/%D/%U > template shell = /bin/bash >--- > source3/Makefile.in | 12 + > source3/configure.in | 1 + > source3/winbindd/idmap_adex/cell_util.c | 292 ++++++ > source3/winbindd/idmap_adex/domain_util.c | 278 ++++++ > source3/winbindd/idmap_adex/gc_util.c | 848 +++++++++++++++++ > source3/winbindd/idmap_adex/idmap_adex.c | 460 +++++++++ > source3/winbindd/idmap_adex/idmap_adex.h | 257 +++++ > source3/winbindd/idmap_adex/likewise_cell.c | 425 +++++++++ > source3/winbindd/idmap_adex/provider_unified.c | 1180 ++++++++++++++++++++++++ > 9 files changed, 3753 insertions(+), 0 deletions(-) > create mode 100644 source3/winbindd/idmap_adex/cell_util.c > create mode 100644 source3/winbindd/idmap_adex/domain_util.c > create mode 100644 source3/winbindd/idmap_adex/gc_util.c > create mode 100644 source3/winbindd/idmap_adex/idmap_adex.c > create mode 100644 source3/winbindd/idmap_adex/idmap_adex.h > create mode 100644 source3/winbindd/idmap_adex/likewise_cell.c > create mode 100644 source3/winbindd/idmap_adex/provider_unified.c > >diff --git a/source3/Makefile.in b/source3/Makefile.in >index 2300e4a..5a7d87a 100644 >--- a/source3/Makefile.in >+++ b/source3/Makefile.in >@@ -984,6 +984,14 @@ IDMAP_HASH_OBJ = \ > winbindd/idmap_hash/idmap_hash.o \ > winbindd/idmap_hash/mapfile.o > >+IDMAP_ADEX_OBJ = \ >+ winbindd/idmap_adex/idmap_adex.o \ >+ winbindd/idmap_adex/cell_util.o \ >+ winbindd/idmap_adex/likewise_cell.o \ >+ winbindd/idmap_adex/provider_unified.o \ >+ winbindd/idmap_adex/gc_util.o \ >+ winbindd/idmap_adex/domain_util.o >+ > WINBINDD_OBJ1 = \ > winbindd/winbindd.o \ > winbindd/winbindd_user.o \ >@@ -2217,6 +2225,10 @@ bin/hash.@SHLIBEXT@: $(BINARY_PREREQS) $(IDMAP_HASH_OBJ) > @echo "Building plugin $@" > @$(SHLD_MODULE) $(IDMAP_HASH_OBJ) > >+bin/adex.@SHLIBEXT@: $(BINARY_PREREQS) $(IDMAP_ADEX_OBJ) >+ @echo "Building plugin $@" >+ @$(SHLD_MODULE) $(IDMAP_ADEX_OBJ) >+ > bin/tdb2.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_tdb2.o > @echo "Building plugin $@" > @$(SHLD_MODULE) winbindd/idmap_tdb2.o >diff --git a/source3/configure.in b/source3/configure.in >index 640afc4..d1000d9 100644 >--- a/source3/configure.in >+++ b/source3/configure.in >@@ -6058,6 +6058,7 @@ SMB_MODULE(idmap_nss, winbindd/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP) > SMB_MODULE(idmap_rid, winbindd/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP) > SMB_MODULE(idmap_ad, winbindd/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP) > SMB_MODULE(idmap_hash, \$(IDMAP_HASH_OBJ), "bin/hash.$SHLIBEXT", IDMAP) >+SMB_MODULE(idmap_adex, \$(IDMAP_ADEX_OBJ), "bin/adex.$SHLIBEXT", IDMAP) > SMB_SUBSYSTEM(IDMAP, winbindd/idmap.o) > > SMB_MODULE(nss_info_template, winbindd/nss_info_template.o, "bin/template.$SHLIBEXT", NSS_INFO) >diff --git a/source3/winbindd/idmap_adex/cell_util.c b/source3/winbindd/idmap_adex/cell_util.c >new file mode 100644 >index 0000000..f5c08a0 >--- /dev/null >+++ b/source3/winbindd/idmap_adex/cell_util.c >@@ -0,0 +1,292 @@ >+/* >+ * idmap_adex: Support for AD Forests >+ * >+ * Copyright (C) Gerald (Jerry) Carter 2006-2008 >+ * >+ * 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 2 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, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include "includes.h" >+#include "idmap_adex.h" >+ >+#undef DBGC_CLASS >+#define DBGC_CLASS DBGC_IDMAP >+ >+/********************************************************************** >+**********************************************************************/ >+ >+ char *find_attr_string(char **list, size_t num_lines, const char *substr) >+{ >+ int i; >+ int cmplen = strlen(substr); >+ >+ for (i = 0; i < num_lines; i++) { >+ /* make sure to avoid substring matches like uid >+ and uidNumber */ >+ if ((StrnCaseCmp(list[i], substr, cmplen) == 0) && >+ (list[i][cmplen] == '=')) { >+ /* Don't return an empty string */ >+ if (list[i][cmplen + 1] != '\0') >+ return &(list[i][cmplen + 1]); >+ >+ return NULL; >+ } >+ } >+ >+ return NULL; >+} >+ >+/********************************************************************** >+**********************************************************************/ >+ >+ bool is_object_class(char **list, size_t num_lines, const char *substr) >+{ >+ int i; >+ >+ for (i = 0; i < num_lines; i++) { >+ if (strequal(list[i], substr)) { >+ return true; >+ } >+ } >+ >+ return false; >+} >+ >+/********************************************************************** >+ Find out about the cell (e.g. use2307Attrs, etc...) >+**********************************************************************/ >+ >+ NTSTATUS cell_lookup_settings(struct likewise_cell * cell) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ >+ /* Parameter check */ >+ >+ if (!cell) { >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Only supporting Forest-wide, schema based searches */ >+ >+ cell_set_flags(cell, LWCELL_FLAG_USE_RFC2307_ATTRS); >+ cell_set_flags(cell, LWCELL_FLAG_SEARCH_FOREST); >+ >+ cell->provider = &ccp_unified; >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ DEBUG(1,("LWI: Failed to obtain cell settings (%s)\n", >+ nt_errstr(nt_status))); >+ } >+ >+ return nt_status; >+} >+ >+ >+static NTSTATUS cell_lookup_forest(struct likewise_cell *c) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct gc_info *gc = NULL; >+ >+ if (!c) { >+ return NT_STATUS_INVALID_PARAMETER; >+ } >+ >+ if ((gc = TALLOC_ZERO_P(NULL, struct gc_info)) == NULL) { >+ nt_status = NT_STATUS_NO_MEMORY; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Query the rootDSE for the forest root naming conect first. >+ Check that the a GC server for the forest has not already >+ been added */ >+ >+ nt_status = gc_find_forest_root(gc, cell_dns_domain(c)); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ c->forest_name = talloc_strdup(c, gc->forest_name); >+ BAIL_ON_PTR_ERROR(c->forest_name, nt_status); >+ >+done: >+ if (gc) { >+ talloc_free(gc); >+ } >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+**********************************************************************/ >+ >+ NTSTATUS cell_locate_membership(ADS_STRUCT * ads) >+{ >+ ADS_STATUS status; >+ char *domain_dn = ads_build_dn(lp_realm()); >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ DOM_SID sid; >+ struct likewise_cell *cell = NULL; >+ >+ /* In the Likewise plugin, I had to support the concept of cells >+ based on the machine's membership in an OU. However, now I'll >+ just assume our membership in the forest cell */ >+ >+ DEBUG(2, ("locate_cell_membership: Located membership " >+ "in cell \"%s\"\n", domain_dn)); >+ >+ if ((cell = cell_new()) == NULL) { >+ nt_status = NT_STATUS_NO_MEMORY; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ status = ads_domain_sid(ads, &sid); >+ if (!ADS_ERR_OK(status)) { >+ DEBUG(3,("locate_cell_membership: Failed to find " >+ "domain SID for %s\n", domain_dn)); >+ } >+ >+ /* save the SID and search base for our domain */ >+ >+ cell_set_dns_domain(cell, lp_realm()); >+ cell_set_connection(cell, ads); >+ cell_set_dn(cell, domain_dn); >+ cell_set_domain_sid(cell, &sid); >+ >+ /* Now save our forest root */ >+ >+ cell_lookup_forest(cell); >+ >+ /* Add the cell to the list */ >+ >+ if (!cell_list_add(cell)) { >+ nt_status = NT_STATUS_INSUFFICIENT_RESOURCES; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Done! */ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ DEBUG(0,("LWI: Failed to locate cell membership (%s)\n", >+ nt_errstr(nt_status))); >+ } >+ >+ SAFE_FREE(domain_dn); >+ >+ return nt_status; >+} >+ >+/********************************************************************* >+ ********************************************************************/ >+ >+ int min_id_value(void) >+{ >+ int id_val; >+ >+ id_val = lp_parm_int(-1, "lwidentity", "min_id_value", MIN_ID_VALUE); >+ >+ /* Still don't let it go below 50 */ >+ >+ return MAX(50, id_val); >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+ char *cell_dn_to_dns(const char *dn) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ char *domain = NULL; >+ char *dns_name = NULL; >+ const char *tmp_dn; >+ char *buffer = NULL; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ >+ if (!dn || !*dn) { >+ goto done; >+ } >+ >+ tmp_dn = talloc_strdup(frame, dn); >+ BAIL_ON_PTR_ERROR(tmp_dn, nt_status); >+ >+ while (next_token_talloc(frame, &tmp_dn, &buffer, ",")) { >+ >+ /* skip everything up the where DC=... begins */ >+ if (StrnCaseCmp(buffer, "DC=", 3) != 0) >+ continue; >+ >+ if (!domain) { >+ domain = talloc_strdup(frame, &buffer[3]); >+ } else { >+ domain = talloc_asprintf_append(domain, ".%s", >+ &buffer[3]); >+ } >+ BAIL_ON_PTR_ERROR(domain, nt_status); >+ } >+ >+ dns_name = SMB_STRDUP(domain); >+ BAIL_ON_PTR_ERROR(dns_name, nt_status); >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ PRINT_NTSTATUS_ERROR(nt_status, "cell_dn_to_dns", 1); >+ >+ talloc_destroy(frame); >+ >+ return dns_name; >+} >+ >+/********************************************************************* >+ ********************************************************************/ >+ >+ NTSTATUS get_sid_type(ADS_STRUCT *ads, >+ LDAPMessage *msg, >+ enum lsa_SidType *type) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ uint32_t atype; >+ >+ if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) { >+ nt_status = NT_STATUS_INVALID_USER_BUFFER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ switch (atype &0xF0000000) { >+ case ATYPE_SECURITY_GLOBAL_GROUP: >+ *type = SID_NAME_DOM_GRP; >+ break; >+ case ATYPE_SECURITY_LOCAL_GROUP: >+ *type = SID_NAME_ALIAS; >+ break; >+ case ATYPE_NORMAL_ACCOUNT: >+ case ATYPE_WORKSTATION_TRUST: >+ case ATYPE_INTERDOMAIN_TRUST: >+ *type = SID_NAME_USER; >+ break; >+ default: >+ *type = SID_NAME_USE_NONE; >+ nt_status = NT_STATUS_INVALID_ACCOUNT_NAME; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ return nt_status; >+} >diff --git a/source3/winbindd/idmap_adex/domain_util.c b/source3/winbindd/idmap_adex/domain_util.c >new file mode 100644 >index 0000000..ab31cce >--- /dev/null >+++ b/source3/winbindd/idmap_adex/domain_util.c >@@ -0,0 +1,278 @@ >+/* >+ * idmap_adex: Domain search interface >+ * >+ * Copyright (C) Gerald (Jerry) Carter 2007-2008 >+ * >+ * 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 2 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, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include "includes.h" >+#include "idmap_adex.h" >+ >+#undef DBGC_CLASS >+#define DBGC_CLASS DBGC_IDMAP >+ >+struct dc_info { >+ struct dc_info *prev, *next; >+ char *dns_name; >+ struct likewise_cell *domain_cell; >+}; >+ >+static struct dc_info *_dc_server_list = NULL; >+ >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static struct dc_info *dc_list_head(void) >+{ >+ return _dc_server_list; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS dc_add_domain(const char *domain) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct dc_info *dc = NULL; >+ >+ /* Check for duplicates */ >+ >+ dc = dc_list_head(); >+ while (dc) { >+ if (strequal (dc->dns_name, domain)) >+ break; >+ dc = dc->next; >+ } >+ >+ if (dc) { >+ DEBUG(10,("dc_add_domain: %s already in list\n", domain)); >+ return NT_STATUS_OK; >+ } >+ >+ dc = TALLOC_ZERO_P(NULL, struct dc_info); >+ BAIL_ON_PTR_ERROR(dc, nt_status); >+ >+ dc->dns_name = talloc_strdup(dc, domain); >+ BAIL_ON_PTR_ERROR(dc->dns_name, nt_status); >+ >+ DLIST_ADD_END(_dc_server_list, dc, struct dc_info*); >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ talloc_destroy(dc); >+ DEBUG(0,("LWI: Failed to add new DC connection for %s (%s)\n", >+ domain, nt_errstr(nt_status))); >+ } >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static void dc_server_list_destroy(void) >+{ >+ struct dc_info *dc = dc_list_head(); >+ >+ while (dc) { >+ struct dc_info *p = dc->next; >+ >+ cell_destroy(dc->domain_cell); >+ talloc_destroy(dc); >+ >+ dc = p; >+ } >+ >+ return; >+} >+ >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ NTSTATUS domain_init_list(void) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct winbindd_tdc_domain *domains = NULL; >+ size_t num_domains = 0; >+ int i; >+ >+ if (_dc_server_list != NULL) { >+ dc_server_list_destroy(); >+ } >+ >+ /* Add our domain */ >+ >+ nt_status = dc_add_domain(lp_realm()); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ if (!wcache_tdc_fetch_list(&domains, &num_domains)) { >+ nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Add all domains with an incoming trust path */ >+ >+ for (i=0; i<num_domains; i++) { >+ uint32_t flags = (NETR_TRUST_FLAG_INBOUND|NETR_TRUST_FLAG_IN_FOREST); >+ >+ /* We just require one of the flags to be set here */ >+ >+ if (domains[i].trust_flags & flags) { >+ nt_status = dc_add_domain(domains[i].dns_name); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ DEBUG(2,("LWI: Failed to initialize DC list (%s)\n", >+ nt_errstr(nt_status))); >+ } >+ >+ TALLOC_FREE(domains); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS dc_do_search(struct dc_info *dc, >+ const char *search_base, >+ int scope, >+ const char *expr, >+ const char **attrs, >+ LDAPMessage ** msg) >+{ >+ ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ >+ status = cell_do_search(dc->domain_cell, search_base, >+ scope, expr, attrs, msg); >+ nt_status = ads_ntstatus(status); >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static struct dc_info *dc_find_domain(const char *dns_domain) >+{ >+ struct dc_info *dc = dc_list_head(); >+ >+ if (!dc) >+ return NULL; >+ >+ while (dc) { >+ if (strequal(dc->dns_name, dns_domain)) { >+ return dc; >+ } >+ >+ dc = dc->next; >+ } >+ >+ return NULL; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ NTSTATUS dc_search_domains(struct likewise_cell **cell, >+ LDAPMessage **msg, >+ const char *dn, >+ const DOM_SID *sid) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ char *dns_domain; >+ const char *attrs[] = { "*", NULL }; >+ struct dc_info *dc = NULL; >+ const char *base = NULL; >+ >+ if (!dn || !*dn) { >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ dns_domain = cell_dn_to_dns(dn); >+ BAIL_ON_PTR_ERROR(dns_domain, nt_status); >+ >+ if ((dc = dc_find_domain(dns_domain)) == NULL) { >+ nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Reparse the cell settings for the domain if necessary */ >+ >+ if (!dc->domain_cell) { >+ char *base_dn; >+ >+ base_dn = ads_build_dn(dc->dns_name); >+ BAIL_ON_PTR_ERROR(base_dn, nt_status); >+ >+ nt_status = cell_connect_dn(&dc->domain_cell, base_dn); >+ SAFE_FREE(base_dn); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = cell_lookup_settings(dc->domain_cell); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* By definition this is already part of a larger >+ forest-wide search scope */ >+ >+ cell_set_flags(dc->domain_cell, LWCELL_FLAG_SEARCH_FOREST); >+ } >+ >+ /* Check whether we are operating in non-schema or RFC2307 >+ mode */ >+ >+ if (cell_flags(dc->domain_cell) & LWCELL_FLAG_USE_RFC2307_ATTRS) { >+ nt_status = dc_do_search(dc, dn, LDAP_SCOPE_BASE, >+ "(objectclass=*)", attrs, msg); >+ } else { >+ const char *sid_str = NULL; >+ char *filter = NULL; >+ >+ sid_str = sid_string_talloc(frame, sid); >+ BAIL_ON_PTR_ERROR(sid_str, nt_status); >+ >+ filter = talloc_asprintf(frame, "(keywords=backLink=%s)", >+ sid_str); >+ BAIL_ON_PTR_ERROR(filter, nt_status); >+ >+ base = cell_search_base(dc->domain_cell); >+ BAIL_ON_PTR_ERROR(base, nt_status); >+ >+ nt_status = dc_do_search(dc, base, LDAP_SCOPE_SUBTREE, >+ filter, attrs, msg); >+ } >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ *cell = dc->domain_cell; >+ >+done: >+ talloc_destroy(CONST_DISCARD(char*, base)); >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >diff --git a/source3/winbindd/idmap_adex/gc_util.c b/source3/winbindd/idmap_adex/gc_util.c >new file mode 100644 >index 0000000..87dd3c0 >--- /dev/null >+++ b/source3/winbindd/idmap_adex/gc_util.c >@@ -0,0 +1,848 @@ >+/* >+ * idmap_adex: Global Catalog search interface >+ * >+ * Copyright (C) Gerald (Jerry) Carter 2007-2008 >+ * >+ * 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 2 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, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include "includes.h" >+#include "idmap_adex.h" >+ >+#undef DBGC_CLASS >+#define DBGC_CLASS DBGC_IDMAP >+ >+static struct gc_info *_gc_server_list = NULL; >+ >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static struct gc_info *gc_list_head(void) >+{ >+ return _gc_server_list; >+} >+ >+/********************************************************************** >+ Checks if either of the domains is a subdomain of the other >+ *********************************************************************/ >+ >+static bool is_subdomain(const char* a, const char *b) >+{ >+ char *s; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ char *x, *y; >+ bool ret = false; >+ >+ /* Trivial cases */ >+ >+ if (!a && !b) >+ return true; >+ >+ if (!a || !b) >+ return false; >+ >+ /* Normalize the case */ >+ >+ x = talloc_strdup(frame, a); >+ y = talloc_strdup(frame, b); >+ if (!x || !y) { >+ ret = false; >+ goto done; >+ } >+ >+ strupper_m(x); >+ strupper_m(y); >+ >+ /* Exact match */ >+ >+ if (strcmp(x, y) == 0) { >+ ret = true; >+ goto done; >+ } >+ >+ /* Check for trailing substrings */ >+ >+ s = strstr_m(x, y); >+ if (s && (strlen(s) == strlen(y))) { >+ ret = true; >+ goto done; >+ } >+ >+ s = strstr_m(y, x); >+ if (s && (strlen(s) == strlen(x))) { >+ ret = true; >+ goto done; >+ } >+ >+done: >+ talloc_destroy(frame); >+ >+ return ret; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ NTSTATUS gc_find_forest_root(struct gc_info *gc, const char *domain) >+{ >+ ADS_STRUCT *ads = NULL; >+ ADS_STATUS ads_status; >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct nbt_cldap_netlogon_5 cldap_reply; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ >+ if (!gc || !domain) { >+ return NT_STATUS_INVALID_PARAMETER; >+ } >+ >+ ZERO_STRUCT(cldap_reply); >+ >+ ads = ads_init(domain, NULL, NULL); >+ BAIL_ON_PTR_ERROR(ads, nt_status); >+ >+ ads->auth.flags = ADS_AUTH_NO_BIND; >+ ads_status = ads_connect(ads); >+ if (!ADS_ERR_OK(ads_status)) { >+ DEBUG(4, ("find_forest_root: ads_connect(%s) failed! (%s)\n", >+ domain, ads_errstr(ads_status))); >+ } >+ nt_status = ads_ntstatus(ads_status); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ if (!ads_cldap_netlogon_5(frame, >+ ads->config.ldap_server_name, >+ ads->config.realm, >+ &cldap_reply)) >+ { >+ DEBUG(4,("find_forest_root: Failed to get a CLDAP reply from %s!\n", >+ ads->server.ldap_server)); >+ nt_status = NT_STATUS_IO_TIMEOUT; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ gc->forest_name = talloc_strdup(gc, cldap_reply.forest); >+ BAIL_ON_PTR_ERROR(gc->forest_name, nt_status); >+ >+done: >+ if (ads) { >+ ads_destroy(&ads); >+ } >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS gc_add_forest(const char *domain) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct gc_info *gc = NULL; >+ struct gc_info *find_gc = NULL; >+ char *dn; >+ ADS_STRUCT *ads = NULL; >+ struct likewise_cell *primary_cell = NULL; >+ >+ primary_cell = cell_list_head(); >+ if (!primary_cell) { >+ nt_status = NT_STATUS_INVALID_SERVER_STATE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Check for duplicates based on domain name first as this >+ requires no connection */ >+ >+ find_gc = gc_list_head(); >+ while (find_gc) { >+ if (strequal (find_gc->forest_name, domain)) >+ break; >+ find_gc = find_gc->next; >+ } >+ >+ if (find_gc) { >+ DEBUG(10,("gc_add_forest: %s already in list\n", find_gc->forest_name)); >+ return NT_STATUS_OK; >+ } >+ >+ if ((gc = TALLOC_ZERO_P(NULL, struct gc_info)) == NULL) { >+ nt_status = NT_STATUS_NO_MEMORY; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Query the rootDSE for the forest root naming conect first. >+ Check that the a GC server for the forest has not already >+ been added */ >+ >+ nt_status = gc_find_forest_root(gc, domain); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ find_gc = gc_list_head(); >+ while (find_gc) { >+ if (strequal (find_gc->forest_name, gc->forest_name)) >+ break; >+ find_gc = find_gc->next; >+ } >+ >+ if (find_gc) { >+ DEBUG(10,("gc_add_forest: Forest %s already in list\n", >+ find_gc->forest_name)); >+ return NT_STATUS_OK; >+ } >+ >+ /* Not found, so add it here. Make sure we connect to >+ a DC in _this_ domain and not the forest root. */ >+ >+ dn = ads_build_dn(gc->forest_name); >+ BAIL_ON_PTR_ERROR(dn, nt_status); >+ >+ gc->search_base = talloc_strdup(gc, dn); >+ SAFE_FREE(dn); >+ BAIL_ON_PTR_ERROR(gc->search_base, nt_status); >+ >+#if 0 >+ /* Can't use cell_connect_dn() here as there is no way to >+ specifiy the LWCELL_FLAG_GC_CELL flag setting for cell_connect() */ >+ >+ nt_status = cell_connect_dn(&gc->forest_cell, gc->search_base); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+#else >+ >+ gc->forest_cell = cell_new(); >+ BAIL_ON_PTR_ERROR(gc->forest_cell, nt_status); >+ >+ /* Set the DNS domain, dn, etc ... and add it to the list */ >+ >+ cell_set_dns_domain(gc->forest_cell, gc->forest_name); >+ cell_set_dn(gc->forest_cell, gc->search_base); >+ cell_set_flags(gc->forest_cell, LWCELL_FLAG_GC_CELL); >+#endif >+ >+ /* It is possible to belong to a non-forest cell and a >+ non-provisioned forest (at our domain levele). In that >+ case, we should just inherit the flags from our primary >+ cell since the GC searches will match our own schema >+ model. */ >+ >+ if (strequal(primary_cell->forest_name, gc->forest_name) >+ || is_subdomain(primary_cell->dns_domain, gc->forest_name)) >+ { >+ cell_set_flags(gc->forest_cell, cell_flags(primary_cell)); >+ } else { >+ /* outside of our domain */ >+ >+ nt_status = cell_connect(gc->forest_cell); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = cell_lookup_settings(gc->forest_cell); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* Drop the connection now that we have the settings */ >+ >+ ads = cell_connection(gc->forest_cell); >+ ads_destroy(&ads); >+ cell_set_connection(gc->forest_cell, NULL); >+ } >+ >+ DLIST_ADD_END(_gc_server_list, gc, struct gc_info*); >+ >+ DEBUG(10,("gc_add_forest: Added %s to Global Catalog list of servers\n", >+ gc->forest_name)); >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ talloc_destroy(gc); >+ DEBUG(3,("LWI: Failed to add new GC connection for %s (%s)\n", >+ domain, nt_errstr(nt_status))); >+ } >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static void gc_server_list_destroy(void) >+{ >+ struct gc_info *gc = gc_list_head(); >+ >+ while (gc) { >+ struct gc_info *p = gc->next; >+ >+ cell_destroy(gc->forest_cell); >+ talloc_destroy(gc); >+ >+ gc = p; >+ } >+ >+ _gc_server_list = NULL; >+ >+ return; >+} >+ >+/********************************************************************** >+ Setup the initial list of forests and initial the forest cell >+ settings for each. FIXME!!! >+ *********************************************************************/ >+ >+ NTSTATUS gc_init_list(void) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct winbindd_tdc_domain *domains = NULL; >+ size_t num_domains = 0; >+ int i; >+ >+ if (_gc_server_list != NULL) { >+ gc_server_list_destroy(); >+ } >+ >+ if (!wcache_tdc_fetch_list(&domains, &num_domains)) { >+ nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Find our forest first. Have to try all domains here starting >+ with our own. gc_add_forest() filters duplicates */ >+ >+ nt_status = gc_add_forest(lp_realm()); >+ WARN_ON_NTSTATUS_ERROR(nt_status); >+ >+ for (i=0; i<num_domains; i++) { >+ uint32_t flags = (NETR_TRUST_FLAG_IN_FOREST); >+ >+ /* I think we should be able to break out of loop once >+ we add a GC for our forest and not have to test every one. >+ In fact, this entire loop is probably irrelevant since >+ the GC location code should always find a GC given lp_realm(). >+ Will have to spend time testing before making the change. >+ --jerry */ >+ >+ if ((domains[i].trust_flags & flags) == flags) { >+ nt_status = gc_add_forest(domains[i].dns_name); >+ WARN_ON_NTSTATUS_ERROR(nt_status); >+ /* Don't BAIL here since not every domain may >+ have a GC server */ >+ } >+ } >+ >+ /* Now add trusted forests. gc_add_forest() will filter out >+ duplicates. Check everything with an incoming trust path >+ that is not in our own forest. */ >+ >+ for (i=0; i<num_domains; i++) { >+ uint32_t flags = domains[i].trust_flags; >+ uint32_t attribs = domains[i].trust_attribs; >+ >+ /* Skip non_AD domains */ >+ >+ if (strlen(domains[i].dns_name) == 0) { >+ continue; >+ } >+ >+ /* Only add a GC for a forest outside of our own. >+ Ignore QUARANTINED/EXTERNAL trusts */ >+ >+ if ((flags & NETR_TRUST_FLAG_INBOUND) >+ && !(flags & NETR_TRUST_FLAG_IN_FOREST) >+ && (attribs & NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) >+ { >+ nt_status = gc_add_forest(domains[i].dns_name); >+ WARN_ON_NTSTATUS_ERROR(nt_status); >+ } >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ DEBUG(2,("LWI: Failed to initialized GC list (%s)\n", >+ nt_errstr(nt_status))); >+ } >+ >+ TALLOC_FREE(domains); >+ >+ return nt_status; >+} >+ >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ struct gc_info *gc_search_start(void) >+{ >+ NTSTATUS nt_status = NT_STATUS_OK; >+ struct gc_info *gc = gc_list_head(); >+ >+ if (!gc) { >+ nt_status = gc_init_list(); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ gc = gc_list_head(); >+ } >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ DEBUG(2,("LWI: Failed to initialize GC list (%s)\n", >+ nt_errstr(nt_status))); >+ } >+ >+ return gc; >+} >+ >+/********************************************************************** >+ Search Global Catalog. Always search our own forest. The flags set >+ controls whether or not we search cross forest. Assume that the >+ resulting set is always returned from one GC so that we don't have to >+ both combining the LDAPMessage * results >+ *********************************************************************/ >+ >+ NTSTATUS gc_search_forest(struct gc_info *gc, >+ LDAPMessage **msg, >+ const char *filter) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); >+ const char *attrs[] = {"*", NULL}; >+ LDAPMessage *m = NULL; >+ >+ if (!gc || !msg || !filter) { >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* When you have multiple domain trees in a forest, the >+ GC will search all naming contexts when you send it >+ and empty ("") base search suffix. Tested against >+ Windows 2003. */ >+ >+ ads_status = cell_do_search(gc->forest_cell, "", >+ LDAP_SCOPE_SUBTREE, filter, attrs, &m); >+ nt_status = ads_ntstatus(ads_status); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ *msg = m; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ DEBUG(2,("LWI: Forest wide search %s failed (%s)\n", >+ filter, nt_errstr(nt_status))); >+ } >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ Search all forests via GC and return the results in an array of >+ ADS_STRUCT/LDAPMessage pairs. >+ *********************************************************************/ >+ >+ NTSTATUS gc_search_all_forests(const char *filter, >+ ADS_STRUCT ***ads_list, >+ LDAPMessage ***msg_list, >+ int *num_resp, uint32_t flags) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct gc_info *gc = NULL; >+ uint32_t test_flags = ADEX_GC_SEARCH_CHECK_UNIQUE; >+ >+ *ads_list = NULL; >+ *msg_list = NULL; >+ *num_resp = 0; >+ >+ if ((gc = gc_search_start()) == NULL) { >+ nt_status = NT_STATUS_INVALID_DOMAIN_STATE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ while (gc) { >+ LDAPMessage *m = NULL; >+ >+ nt_status = gc_search_forest(gc, &m, filter); >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ gc = gc->next; >+ continue; >+ } >+ >+ nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell), >+ m, ads_list, msg_list, >+ num_resp); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* If there can only be one match, then we are done */ >+ >+ if ((*num_resp > 0) && ((flags & test_flags) == test_flags)) { >+ break; >+ } >+ >+ gc = gc->next; >+ } >+ >+ if (*num_resp == 0) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ return nt_status; >+} >+ >+/********************************************************************** >+ Search all forests via GC and return the results in an array of >+ ADS_STRUCT/LDAPMessage pairs. >+ *********************************************************************/ >+ >+ NTSTATUS gc_search_all_forests_unique(const char *filter, >+ ADS_STRUCT **ads, >+ LDAPMessage **msg) >+{ >+ ADS_STRUCT **ads_list = NULL; >+ LDAPMessage **msg_list = NULL; >+ int num_resp; >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ >+ nt_status = gc_search_all_forests(filter, &ads_list, >+ &msg_list, &num_resp, >+ ADEX_GC_SEARCH_CHECK_UNIQUE); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = check_result_unique(ads_list[0], msg_list[0]); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ *ads = ads_list[0]; >+ *msg = msg_list[0]; >+ >+done: >+ /* Be care that we don't free the msg result being returned */ >+ >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ free_result_array(ads_list, msg_list, num_resp); >+ } else { >+ talloc_destroy(ads_list); >+ talloc_destroy(msg_list); >+ } >+ >+ return nt_status; >+} >+ >+/********************************************************************* >+ ********************************************************************/ >+ >+ NTSTATUS gc_name_to_sid(const char *domain, >+ const char *name, >+ DOM_SID *sid, >+ enum lsa_SidType *sid_type) >+{ >+ TALLOC_CTX *frame = talloc_stackframe(); >+ char *p, *name_user; >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ char *name_filter; >+ ADS_STRUCT *ads = NULL; >+ LDAPMessage *msg = NULL; >+ LDAPMessage *e = NULL; >+ char *dn = NULL; >+ char *dns_domain = NULL; >+ ADS_STRUCT **ads_list = NULL; >+ LDAPMessage **msg_list = NULL; >+ int num_resp = 0; >+ int i; >+ >+ /* Strip the "DOMAIN\" prefix if necessary and search for >+ a matching sAMAccountName in the forest */ >+ >+ if ((p = strchr_m( name, '\\' )) == NULL) >+ name_user = talloc_strdup( frame, name ); >+ else >+ name_user = talloc_strdup( frame, p+1 ); >+ BAIL_ON_PTR_ERROR(name_user, nt_status); >+ >+ name_filter = talloc_asprintf(frame, "(sAMAccountName=%s)", name_user); >+ BAIL_ON_PTR_ERROR(name_filter, nt_status); >+ >+ nt_status = gc_search_all_forests(name_filter, &ads_list, >+ &msg_list, &num_resp, 0); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* Assume failure until we know otherwise*/ >+ >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ >+ /* Match the domain name from the DN */ >+ >+ for (i=0; i<num_resp; i++) { >+ ads = ads_list[i]; >+ msg = msg_list[i]; >+ >+ e = ads_first_entry(ads, msg); >+ while (e) { >+ struct winbindd_tdc_domain *domain_rec; >+ >+ dn = ads_get_dn(ads, e); >+ BAIL_ON_PTR_ERROR(dn, nt_status); >+ >+ dns_domain = cell_dn_to_dns(dn); >+ SAFE_FREE(dn); >+ BAIL_ON_PTR_ERROR(dns_domain, nt_status); >+ >+ domain_rec = wcache_tdc_fetch_domain(frame, dns_domain); >+ SAFE_FREE(dns_domain); >+ >+ /* Ignore failures and continue the search */ >+ >+ if (!domain_rec) { >+ e = ads_next_entry(ads, e); >+ continue; >+ } >+ >+ /* Check for a match on the domain name */ >+ >+ if (strequal(domain, domain_rec->domain_name)) { >+ if (!ads_pull_sid(ads, e, "objectSid", sid)) { >+ nt_status = NT_STATUS_INVALID_SID; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ talloc_destroy(domain_rec); >+ >+ nt_status = get_sid_type(ads, msg, sid_type); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* We're done! */ >+ nt_status = NT_STATUS_OK; >+ break; >+ } >+ >+ /* once more around thew merry-go-round */ >+ >+ talloc_destroy(domain_rec); >+ e = ads_next_entry(ads, e); >+ } >+ } >+ >+done: >+ free_result_array(ads_list, msg_list, num_resp); >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ Pull an attribute string value >+ *******************************************************************/ >+ >+static NTSTATUS get_object_account_name(ADS_STRUCT *ads, >+ LDAPMessage *msg, >+ char **name) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ char *sam_name = NULL; >+ struct winbindd_tdc_domain *domain_rec = NULL; >+ char *dns_domain = NULL; >+ char *dn = NULL; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ int len; >+ >+ /* Check parameters */ >+ >+ if (!ads || !msg || !name) { >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* get the name and domain */ >+ >+ dn = ads_get_dn(ads, msg); >+ BAIL_ON_PTR_ERROR(dn, nt_status); >+ >+ DEBUG(10,("get_object_account_name: dn = \"%s\"\n", dn)); >+ >+ dns_domain = cell_dn_to_dns(dn); >+ SAFE_FREE(dn); >+ BAIL_ON_PTR_ERROR(dns_domain, nt_status); >+ >+ domain_rec = wcache_tdc_fetch_domain(frame, dns_domain); >+ SAFE_FREE(dns_domain); >+ >+ if (!domain_rec) { >+ nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ sam_name = ads_pull_string(ads, frame, msg, "sAMAccountName"); >+ BAIL_ON_PTR_ERROR(sam_name, nt_status); >+ >+ len = asprintf(name, "%s\\%s", domain_rec->domain_name, sam_name); >+ if (len == -1) { >+ *name = NULL; >+ BAIL_ON_PTR_ERROR((*name), nt_status); >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/********************************************************************* >+ ********************************************************************/ >+ >+ NTSTATUS gc_sid_to_name(const DOM_SID *sid, >+ char **name, >+ enum lsa_SidType *sid_type) >+{ >+ TALLOC_CTX *frame = talloc_stackframe(); >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ char *filter; >+ ADS_STRUCT *ads = NULL; >+ LDAPMessage *msg = NULL; >+ char *sid_string; >+ >+ *name = NULL; >+ >+ sid_string = sid_binstring(sid); >+ BAIL_ON_PTR_ERROR(sid_string, nt_status); >+ >+ filter = talloc_asprintf(frame, "(objectSid=%s)", sid_string); >+ SAFE_FREE(sid_string); >+ BAIL_ON_PTR_ERROR(filter, nt_status); >+ >+ nt_status = gc_search_all_forests_unique(filter, &ads, &msg); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = get_object_account_name(ads, msg, name); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = get_sid_type(ads, msg, sid_type); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+done: >+ ads_msgfree(ads, msg); >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ NTSTATUS add_ads_result_to_array(ADS_STRUCT *ads, >+ LDAPMessage *msg, >+ ADS_STRUCT ***ads_list, >+ LDAPMessage ***msg_list, >+ int *size) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ ADS_STRUCT **ads_tmp = NULL; >+ LDAPMessage **msg_tmp = NULL; >+ int count = *size; >+ >+ if (!ads || !msg) { >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+#if 0 >+ /* Don't add a response with no entries */ >+ >+ if (ads_count_replies(ads, msg) == 0) { >+ return NT_STATUS_OK; >+ } >+#endif >+ >+ if (count == 0) { >+ ads_tmp = TALLOC_ARRAY(NULL, ADS_STRUCT*, 1); >+ BAIL_ON_PTR_ERROR(ads_tmp, nt_status); >+ >+ msg_tmp = TALLOC_ARRAY(NULL, LDAPMessage*, 1); >+ BAIL_ON_PTR_ERROR(msg_tmp, nt_status); >+ } else { >+ ads_tmp = TALLOC_REALLOC_ARRAY(*ads_list, *ads_list, ADS_STRUCT*, >+ count+1); >+ BAIL_ON_PTR_ERROR(ads_tmp, nt_status); >+ >+ msg_tmp = TALLOC_REALLOC_ARRAY(*msg_list, *msg_list, LDAPMessage*, >+ count+1); >+ BAIL_ON_PTR_ERROR(msg_tmp, nt_status); >+ } >+ >+ ads_tmp[count] = ads; >+ msg_tmp[count] = msg; >+ count++; >+ >+ *ads_list = ads_tmp; >+ *msg_list = msg_tmp; >+ *size = count; >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ talloc_destroy(ads_tmp); >+ talloc_destroy(msg_tmp); >+ } >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ Frees search results. Do not free the ads_list as these are >+ references back to the GC search structures. >+ *********************************************************************/ >+ >+ void free_result_array(ADS_STRUCT **ads_list, >+ LDAPMessage **msg_list, >+ int num_resp) >+{ >+ int i; >+ >+ for (i=0; i<num_resp; i++) { >+ ads_msgfree(ads_list[i], msg_list[i]); >+ } >+ >+ talloc_destroy(ads_list); >+ talloc_destroy(msg_list); >+} >+ >+/********************************************************************** >+ Check that we have exactly one entry from the search >+ *********************************************************************/ >+ >+ NTSTATUS check_result_unique(ADS_STRUCT *ads, LDAPMessage *msg) >+{ >+ NTSTATUS nt_status; >+ int count; >+ >+ count = ads_count_replies(ads, msg); >+ >+ if (count <= 0) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ if (count > 1) { >+ nt_status = NT_STATUS_DUPLICATE_NAME; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ return nt_status; >+} >diff --git a/source3/winbindd/idmap_adex/idmap_adex.c b/source3/winbindd/idmap_adex/idmap_adex.c >new file mode 100644 >index 0000000..23ab843 >--- /dev/null >+++ b/source3/winbindd/idmap_adex/idmap_adex.c >@@ -0,0 +1,460 @@ >+/* >+ * idmap_adex: Support for D Forests >+ * >+ * Copyright (C) Gerald (Jerry) Carter 2006-2008 >+ * >+ * 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 2 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, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include "includes.h" >+#include "idmap_adex.h" >+ >+#undef DBGC_CLASS >+#define DBGC_CLASS DBGC_IDMAP >+ >+#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache" >+ >+NTSTATUS init_module(void); >+ >+/* >+ * IdMap backend >+ */ >+ >+/******************************************************************** >+ Basic init function responsible for determining our current mode >+ (standalone or using Centeris Cells). This must return success or >+ it will be dropped from the idmap backend list. >+ *******************************************************************/ >+ >+static NTSTATUS _idmap_adex_init(struct idmap_domain *dom, >+ const char *params) >+{ >+ ADS_STRUCT *ads = NULL; >+ ADS_STATUS status; >+ static NTSTATUS init_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; >+ DOM_SID domain_sid; >+ fstring dcname; >+ struct sockaddr_storage ip; >+ struct likewise_cell *lwcell; >+ >+ if (NT_STATUS_IS_OK(init_status)) >+ return NT_STATUS_OK; >+ >+ /* Silently fail if we are not a member server in security = ads */ >+ >+ if ((lp_server_role() != ROLE_DOMAIN_MEMBER) || >+ (lp_security() != SEC_ADS)) { >+ init_status = NT_STATUS_INVALID_SERVER_STATE; >+ BAIL_ON_NTSTATUS_ERROR(init_status); >+ } >+ >+ /* fetch our domain SID first */ >+ >+ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { >+ init_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; >+ BAIL_ON_NTSTATUS_ERROR(init_status); >+ } >+ >+ /* reuse the same ticket cache as winbindd */ >+ >+ setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); >+ >+ /* Establish a connection to a DC */ >+ >+ if ((ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL) { >+ init_status = NT_STATUS_NO_MEMORY; >+ BAIL_ON_NTSTATUS_ERROR(init_status); >+ } >+ >+ ads->auth.password = >+ secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); >+ ads->auth.realm = SMB_STRDUP(lp_realm()); >+ >+ /* get the DC name here to setup the server affinity cache and >+ local krb5.conf */ >+ >+ get_dc_name(lp_workgroup(), lp_realm(), dcname, &ip); >+ >+ status = ads_connect(ads); >+ if (!ADS_ERR_OK(status)) { >+ DEBUG(0, ("_idmap_adex_init: ads_connect() failed! (%s)\n", >+ ads_errstr(status))); >+ } >+ init_status = ads_ntstatus(status); >+ BAIL_ON_NTSTATUS_ERROR(init_status); >+ >+ >+ /* Find out cell membership */ >+ >+ init_status = cell_locate_membership(ads); >+ if (!NT_STATUS_IS_OK(init_status)) { >+ DEBUG(0,("LWI: Fail to locate cell membership (%s).", >+ nt_errstr(init_status))); >+ goto done; >+ } >+ >+ /* Fill in the cell information */ >+ >+ lwcell = cell_list_head(); >+ >+ init_status = cell_lookup_settings(lwcell); >+ BAIL_ON_NTSTATUS_ERROR(init_status); >+ >+ /* Miscellaneous setup. E.g. set up the list of GC >+ servers and domain list for our forest (does not actually >+ connect). */ >+ >+ init_status = gc_init_list(); >+ BAIL_ON_NTSTATUS_ERROR(init_status); >+ >+ init_status = domain_init_list(); >+ BAIL_ON_NTSTATUS_ERROR(init_status); >+ >+done: >+ if (!NT_STATUS_IS_OK(init_status)) { >+ DEBUG(1,("Likewise initialization failed (%s)\n", >+ nt_errstr(init_status))); >+ } >+ >+ /* cleanup */ >+ >+ if (!NT_STATUS_IS_OK(init_status)) { >+ cell_list_destroy(); >+ >+ /* init_status stores the failure reason but we need to >+ return success or else idmap_init() will drop us from the >+ backend list */ >+ return NT_STATUS_OK; >+ } >+ >+ init_status = NT_STATUS_OK; >+ >+ return init_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _idmap_adex_get_sid_from_id(struct >+ idmap_domain >+ *dom, struct >+ id_map >+ **ids) >+{ >+ int i; >+ bool one_mapped = false; >+ bool all_mapped = true; >+ NTSTATUS nt_status; >+ struct likewise_cell *cell; >+ >+ nt_status = _idmap_adex_init(dom, NULL); >+ if (!NT_STATUS_IS_OK(nt_status)) >+ return nt_status; >+ >+ if ((cell = cell_list_head()) == NULL) { >+ return NT_STATUS_INVALID_SERVER_STATE; >+ } >+ >+ /* have to work through these one by one */ >+ for (i = 0; ids[i]; i++) { >+ NTSTATUS status; >+ status = cell->provider->get_sid_from_id(ids[i]->sid, >+ ids[i]->xid.id, >+ ids[i]->xid.type); >+ /* Fail if we cannot find any DC */ >+ if (NT_STATUS_EQUAL >+ (status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) { >+ return status; >+ } >+ >+ if (!NT_STATUS_IS_OK(status)) { >+ ids[i]->status = ID_UNMAPPED; >+ all_mapped = false; >+ continue; >+ } >+ >+ ids[i]->status = ID_MAPPED; >+ one_mapped = true; >+ } >+ >+ return NT_STATUS_OK; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _idmap_adex_get_id_from_sid(struct >+ idmap_domain >+ *dom, struct >+ id_map >+ **ids) >+{ >+ int i; >+ bool one_mapped = false; >+ bool all_mapped = true; >+ NTSTATUS nt_status; >+ struct likewise_cell *cell; >+ >+ nt_status = _idmap_adex_init(dom, NULL); >+ if (!NT_STATUS_IS_OK(nt_status)) >+ return nt_status; >+ >+ if ((cell = cell_list_head()) == NULL) { >+ return NT_STATUS_INVALID_SERVER_STATE; >+ } >+ >+ /* have to work through these one by one */ >+ for (i = 0; ids[i]; i++) { >+ NTSTATUS status; >+ status = cell->provider->get_id_from_sid(&ids[i]->xid.id, >+ &ids[i]->xid. >+ type, ids[i]->sid); >+ /* Fail if we cannot find any DC */ >+ if (NT_STATUS_EQUAL >+ (status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) { >+ return status; >+ } >+ >+ if (!NT_STATUS_IS_OK(status)) { >+ ids[i]->status = ID_UNMAPPED; >+ all_mapped = false; >+ continue; >+ } >+ >+ ids[i]->status = ID_MAPPED; >+ one_mapped = true; >+ } >+ >+ return NT_STATUS_OK; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _idmap_adex_set_mapping(struct >+ idmap_domain >+ *dom, const struct >+ id_map *map) >+{ >+ DEBUG(0, ("_idmap_adex_set_mapping: not implemented\n")); >+ return NT_STATUS_NOT_IMPLEMENTED; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _idmap_adex_remove_mapping(struct >+ idmap_domain >+ *dom, const >+ struct >+ id_map >+ *map) >+{ >+ DEBUG(0, ("_idmap_adex_remove_mapping: not implemented\n")); >+ return NT_STATUS_NOT_IMPLEMENTED; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _idmap_adex_dump(struct idmap_domain >+ *dom, struct id_map **maps, int *num_map) >+{ >+ return NT_STATUS_NOT_IMPLEMENTED; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _idmap_adex_close(struct idmap_domain >+ *dom) >+{ >+ /* FIXME! need to do cleanup here */ >+ >+ return NT_STATUS_OK; >+} >+ >+/* >+ * IdMap NSS plugin >+ */ >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _nss_adex_init(struct nss_domain_entry >+ *e) >+{ >+ return _idmap_adex_init(NULL, NULL); >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _nss_adex_get_info(struct >+ nss_domain_entry *e, >+ const DOM_SID * sid, >+ TALLOC_CTX * ctx, >+ ADS_STRUCT * ads, >+ LDAPMessage * msg, >+ char **homedir, >+ char **shell, char **gecos, gid_t * p_gid) >+{ >+ NTSTATUS nt_status; >+ struct likewise_cell *cell; >+ >+ nt_status = _idmap_adex_init(NULL, NULL); >+ if (!NT_STATUS_IS_OK(nt_status)) >+ return nt_status; >+ >+ if ((cell = cell_list_head()) == NULL) { >+ return NT_STATUS_INVALID_SERVER_STATE; >+ } >+ >+ return cell->provider->get_nss_info(sid, ctx, homedir, >+ shell, gecos, p_gid); >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _nss_adex_map_to_alias(TALLOC_CTX * mem_ctx, const char >+ *domain, const char >+ *name, char **alias) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct likewise_cell *cell = NULL; >+ >+ nt_status = _idmap_adex_init(NULL, NULL); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ if ((cell = cell_list_head()) == NULL) { >+ nt_status = NT_STATUS_INVALID_SERVER_STATE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ nt_status = cell->provider->map_to_alias(mem_ctx, domain, >+ name, alias); >+ >+ /* go ahead and allow the cache mgr to mark this in >+ negative cache */ >+ >+ if (!NT_STATUS_IS_OK(nt_status)) >+ nt_status = NT_STATUS_NONE_MAPPED; >+ >+done: >+ return nt_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _nss_adex_map_from_alias(TALLOC_CTX * mem_ctx, const char >+ *domain, const char >+ *alias, char **name) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct likewise_cell *cell = NULL; >+ >+ nt_status = _idmap_adex_init(NULL, NULL); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ if ((cell = cell_list_head()) == NULL) { >+ nt_status = NT_STATUS_INVALID_SERVER_STATE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ >+ nt_status = cell->provider->map_from_alias(mem_ctx, domain, >+ alias, name); >+ >+ /* go ahead and allow the cache mgr to mark this in >+ negative cache */ >+ >+ if (!NT_STATUS_IS_OK(nt_status)) >+ nt_status = NT_STATUS_NONE_MAPPED; >+ >+done: >+ return nt_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _nss_adex_close(void) >+{ >+ return NT_STATUS_NOT_IMPLEMENTED; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static struct idmap_methods adex_idmap_methods = { >+ >+ .init = _idmap_adex_init, >+ .unixids_to_sids = _idmap_adex_get_sid_from_id, >+ .sids_to_unixids = _idmap_adex_get_id_from_sid, >+ .set_mapping = _idmap_adex_set_mapping, >+ .remove_mapping = _idmap_adex_remove_mapping, >+ .dump_data = _idmap_adex_dump, >+ .close_fn = _idmap_adex_close >+}; >+static struct nss_info_methods adex_nss_methods = { >+ .init = _nss_adex_init, >+ .get_nss_info = _nss_adex_get_info, >+ .map_to_alias = _nss_adex_map_to_alias, >+ .map_from_alias = _nss_adex_map_from_alias, >+ .close_fn = _nss_adex_close >+}; >+ >+/********************************************************************** >+ Register with the idmap and idmap_nss subsystems. We have to protect >+ against the idmap and nss_info interfaces being in a half-registered >+ state. >+ **********************************************************************/ >+NTSTATUS idmap_adex_init(void) >+{ >+ static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL; >+ static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL; >+ if (!NT_STATUS_IS_OK(idmap_status)) { >+ idmap_status = >+ smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, >+ "adex", &adex_idmap_methods); >+ if (!NT_STATUS_IS_OK(idmap_status)) { >+ DEBUG(0, >+ ("idmap_centeris_init: Failed to register the adex" >+ "idmap plugin.\n")); >+ return idmap_status; >+ } >+ } >+ >+ if (!NT_STATUS_IS_OK(nss_status)) { >+ nss_status = >+ smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, >+ "adex", &adex_nss_methods); >+ if (!NT_STATUS_IS_OK(nss_status)) { >+ DEBUG(0, >+ ("idmap_adex_init: Failed to register the adex" >+ "nss plugin.\n")); >+ return nss_status; >+ } >+ } >+ >+ return NT_STATUS_OK; >+} >+ >+NTSTATUS nss_info_adex_init(void) >+{ >+ return idmap_adex_init(); >+} >diff --git a/source3/winbindd/idmap_adex/idmap_adex.h b/source3/winbindd/idmap_adex/idmap_adex.h >new file mode 100644 >index 0000000..f91bba8 >--- /dev/null >+++ b/source3/winbindd/idmap_adex/idmap_adex.h >@@ -0,0 +1,257 @@ >+/* >+ * idmap_centeris: Support for Local IDs and Centeris Cell Structure >+ * >+ * Copyright (C) Gerald (Jerry) Carter 2006-2008 >+ * >+ * 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 2 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, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#ifndef _IDMAP_ADEX_H >+#define _IDMAP_ADEX_H >+ >+#include "winbindd/winbindd.h" >+ >+#define ADEX_CELL_RDN "$LikewiseIdentityCell" >+ >+#define ADEX_OC_USER "centerisLikewiseUser" >+#define ADEX_OC_GROUP "centerisLikewiseGroup" >+ >+#define AD_USER "User" >+#define AD_GROUP "Group" >+ >+#define ADEX_OC_POSIX_USER "posixAccount" >+#define ADEX_OC_POSIX_GROUP "posixGroup" >+ >+#define ADEX_ATTR_UIDNUM "uidNumber" >+#define ADEX_ATTR_GIDNUM "gidNUmber" >+#define ADEX_ATTR_HOMEDIR "unixHomeDirectory" >+#define ADEX_ATTR_USERPW "unixUserPassword" >+#define ADEX_ATTR_GROUPALIAS "groupAlias" /* Not part of RFC2307 */ >+#define ADEX_ATTR_SHELL "loginShell" >+#define ADEX_ATTR_GECOS "gecos" >+#define ADEX_ATTR_UID "uid" >+#define ADEX_ATTR_DISPLAYNAME "displayName" >+ >+#define MIN_ID_VALUE 100 >+ >+#define BAIL_ON_NTSTATUS_ERROR(x) \ >+ do { \ >+ if (!NT_STATUS_IS_OK(x)) { \ >+ DEBUG(10,("Failed! (%s)\n", nt_errstr(x))); \ >+ goto done; \ >+ } \ >+ } \ >+ while (0); \ >+ >+#define WARN_ON_NTSTATUS_ERROR(x) \ >+ do { \ >+ if (!NT_STATUS_IS_OK(x)) { \ >+ DEBUG(10,("Failure ignored! (%s)\n", nt_errstr(x))); \ >+ } \ >+ } \ >+ while (0); \ >+ >+#define BAIL_ON_ADS_ERROR(x) \ >+ do { \ >+ if (!ADS_ERR_OK(x)) { \ >+ goto done; \ >+ } \ >+ } \ >+ while (0); >+ >+#define BAIL_ON_PTR_ERROR(p, x) \ >+ do { \ >+ if ((p) == NULL ) { \ >+ DEBUG(10,("NULL pointer!\n")); \ >+ x = NT_STATUS_NO_MEMORY; \ >+ goto done; \ >+ } \ >+ } while (0); >+ >+#define PRINT_NTSTATUS_ERROR(x, hdr, level) \ >+ do { \ >+ if (!NT_STATUS_IS_OK(x)) { \ >+ DEBUG(level,("LWI ("hdr"): %s\n", nt_errstr(x))); \ >+ } \ >+ } while(0); >+/* >+ * Cell Provider API >+ */ >+ >+struct cell_provider_api { >+ NTSTATUS(*get_sid_from_id) (DOM_SID * sid, >+ uint32_t id, enum id_type type); >+ NTSTATUS(*get_id_from_sid) (uint32_t * id, >+ enum id_type * type, const DOM_SID * sid); >+ NTSTATUS(*get_nss_info) (const DOM_SID * sid, >+ TALLOC_CTX * ctx, >+ char **homedir, >+ char **shell, char **gecos, gid_t * p_gid); >+ NTSTATUS(*map_to_alias) (TALLOC_CTX * mem_ctx, >+ const char *domain, >+ const char *name, char **alias); >+ NTSTATUS(*map_from_alias) (TALLOC_CTX * mem_ctx, >+ const char *domain, >+ const char *alias, char **name); >+}; >+ >+/* registered providers */ >+ >+extern struct cell_provider_api ccp_unified; >+extern struct cell_provider_api ccp_local; >+ >+#define LWCELL_FLAG_USE_RFC2307_ATTRS 0x00000001 >+#define LWCELL_FLAG_SEARCH_FOREST 0x00000002 >+#define LWCELL_FLAG_GC_CELL 0x00000004 >+#define LWCELL_FLAG_LOCAL_MODE 0x00000008 >+ >+struct likewise_cell { >+ struct likewise_cell *prev, *next; >+ ADS_STRUCT *conn; >+ struct likewise_cell *gc_search_cell; >+ DOM_SID domain_sid; >+ char *dns_domain; >+ char *forest_name; >+ char *dn; >+ struct GUID *links; /* only held by owning cell */ >+ size_t num_links; >+ uint32_t flags; >+ struct cell_provider_api *provider; >+}; >+ >+/* Search flags used for Global Catalog API */ >+ >+#define ADEX_GC_SEARCH_CHECK_UNIQUE 0x00000001 >+ >+struct gc_info { >+ struct gc_info *prev, *next; >+ char *forest_name; >+ char *search_base; >+ struct likewise_cell *forest_cell; >+}; >+ >+/* Available functions outside of idmap_lwidentity.c */ >+ >+/* cell_util.c */ >+ >+char *find_attr_string(char **list, size_t num_lines, const char *substr); >+bool is_object_class(char **list, size_t num_lines, const char *substr); >+int min_id_value(void); >+char *cell_dn_to_dns(const char *dn); >+NTSTATUS get_sid_type(ADS_STRUCT *ads, >+ LDAPMessage *msg, >+ enum lsa_SidType *type); >+ >+NTSTATUS cell_locate_membership(ADS_STRUCT * ads); >+NTSTATUS cell_lookup_settings(struct likewise_cell * cell); >+NTSTATUS cell_follow_links(struct likewise_cell *cell); >+NTSTATUS cell_set_local_provider(void); >+ >+/* likewise_cell.c */ >+ >+struct likewise_cell *cell_new(void); >+struct likewise_cell *cell_list_head(void); >+ >+bool cell_list_add(struct likewise_cell *cell); >+bool cell_list_remove(struct likewise_cell * cell); >+ >+void cell_list_destroy(); >+void cell_destroy(struct likewise_cell *c); >+void cell_set_forest_searches(struct likewise_cell *c, >+ bool search); >+void cell_set_dns_domain(struct likewise_cell *c, >+ const char *dns_domain); >+void cell_set_connection(struct likewise_cell *c, >+ ADS_STRUCT *ads); >+void cell_set_dn(struct likewise_cell *c, >+ const char *dn); >+void cell_set_domain_sid(struct likewise_cell *c, >+ DOM_SID *sid); >+void cell_set_flags(struct likewise_cell *c, uint32_t flags); >+void cell_clear_flags(struct likewise_cell *c, uint32_t flags); >+ >+const char* cell_search_base(struct likewise_cell *c); >+const char *cell_dns_domain(struct likewise_cell *c); >+ADS_STRUCT *cell_connection(struct likewise_cell *c); >+bool cell_search_forest(struct likewise_cell *c); >+ADS_STATUS cell_do_search(struct likewise_cell *c, >+ const char *search_base, >+ int scope, >+ const char *expr, >+ const char **attrs, >+ LDAPMessage ** msg); >+uint32_t cell_flags(struct likewise_cell *c); >+ >+NTSTATUS cell_connect_dn(struct likewise_cell **c, >+ const char *dn); >+NTSTATUS cell_connect(struct likewise_cell *c); >+ >+ >+/* gc_util.c */ >+ >+NTSTATUS gc_init_list(void); >+ >+NTSTATUS gc_find_forest_root(struct gc_info *gc, >+ const char *domain); >+ >+struct gc_info *gc_search_start(void); >+ >+NTSTATUS gc_search_forest(struct gc_info *gc, >+ LDAPMessage **msg, >+ const char *filter); >+ >+NTSTATUS gc_search_all_forests(const char *filter, >+ ADS_STRUCT ***ads_list, >+ LDAPMessage ***msg_list, >+ int *num_resp, uint32_t flags); >+ >+NTSTATUS gc_search_all_forests_unique(const char *filter, >+ ADS_STRUCT **ads, >+ LDAPMessage **msg); >+ >+NTSTATUS gc_name_to_sid(const char *domain, >+ const char *name, >+ DOM_SID *sid, >+ enum lsa_SidType *sid_type); >+ >+NTSTATUS gc_sid_to_name(const DOM_SID *sid, >+ char **name, >+ enum lsa_SidType *sid_type); >+ >+NTSTATUS add_ads_result_to_array(ADS_STRUCT *ads, >+ LDAPMessage *msg, >+ ADS_STRUCT ***ads_list, >+ LDAPMessage ***msg_list, >+ int *size); >+ >+void free_result_array(ADS_STRUCT **ads_list, >+ LDAPMessage **msg_list, >+ int num_resp); >+ >+NTSTATUS check_result_unique(ADS_STRUCT *ads, >+ LDAPMessage *msg); >+ >+ >+/* domain_util.c */ >+ >+NTSTATUS domain_init_list(void); >+ >+NTSTATUS dc_search_domains(struct likewise_cell **cell, >+ LDAPMessage **msg, >+ const char *dn, >+ const DOM_SID *user_sid); >+ >+ >+#endif /* _IDMAP_ADEX_H */ >diff --git a/source3/winbindd/idmap_adex/likewise_cell.c b/source3/winbindd/idmap_adex/likewise_cell.c >new file mode 100644 >index 0000000..77eeee4 >--- /dev/null >+++ b/source3/winbindd/idmap_adex/likewise_cell.c >@@ -0,0 +1,425 @@ >+/* >+ * idmap_adex: Support for AD Forests >+ * >+ * Copyright (C) Gerald (Jerry) Carter 2006-2008 >+ * >+ * 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 2 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, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include "includes.h" >+#include "idmap_adex.h" >+ >+#undef DBGC_CLASS >+#define DBGC_CLASS DBGC_IDMAP >+ >+static struct likewise_cell *_lw_cell_list = NULL; >+ >+/********************************************************************** >+ Return the current HEAD of the list >+ *********************************************************************/ >+ >+ struct likewise_cell *cell_list_head(void) >+{ >+ return _lw_cell_list; >+} >+ >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ void cell_destroy(struct likewise_cell *c) >+{ >+ if (!c) >+ return; >+ >+ if (c->conn) >+ ads_destroy(&c->conn); >+ >+ talloc_destroy(c); >+} >+ >+/********************************************************************** >+ Free all cell entries and reset the list head to NULL >+ *********************************************************************/ >+ >+ void cell_list_destroy(void) >+{ >+ struct likewise_cell *p = _lw_cell_list; >+ >+ while (p) { >+ struct likewise_cell *q = p->next; >+ >+ cell_destroy(p); >+ >+ p = q; >+ } >+ >+ _lw_cell_list = NULL; >+ >+ return; >+} >+ >+/********************************************************************** >+ Add a new cell structure to the list >+ *********************************************************************/ >+ >+ struct likewise_cell* cell_new(void) >+{ >+ struct likewise_cell *c; >+ >+ /* Each cell struct is a TALLOC_CTX* */ >+ >+ c = TALLOC_ZERO_P(NULL, struct likewise_cell); >+ if (!c) { >+ DEBUG(0,("cell_new: memory allocation failure!\n")); >+ return NULL; >+ } >+ >+ return c; >+} >+ >+/********************************************************************** >+ Add a new cell structure to the list >+ *********************************************************************/ >+ >+ bool cell_list_add(struct likewise_cell * cell) >+{ >+ if (!cell) { >+ return false; >+ } >+ >+ /* Always add to the end */ >+ >+ DLIST_ADD_END(_lw_cell_list, cell, struct likewise_cell *); >+ >+ return true; >+} >+ >+/********************************************************************** >+ Add a new cell structure to the list >+ *********************************************************************/ >+ >+ bool cell_list_remove(struct likewise_cell * cell) >+{ >+ if (!cell) { >+ return false; >+ } >+ >+ /* Remove and drop the cell structure */ >+ >+ DLIST_REMOVE(_lw_cell_list, cell); >+ talloc_destroy(cell); >+ >+ return true; >+} >+ >+/********************************************************************** >+ Set the containing DNS domain for a cell >+ *********************************************************************/ >+ >+ void cell_set_dns_domain(struct likewise_cell *c, const char *dns_domain) >+{ >+ c->dns_domain = talloc_strdup(c, dns_domain); >+} >+ >+/********************************************************************** >+ Set ADS connection for a cell >+ *********************************************************************/ >+ >+ void cell_set_connection(struct likewise_cell *c, ADS_STRUCT *ads) >+{ >+ c->conn = ads; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ void cell_set_flags(struct likewise_cell *c, uint32_t flags) >+{ >+ c->flags |= flags; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ void cell_clear_flags(struct likewise_cell *c, uint32_t flags) >+{ >+ c->flags &= ~flags; >+} >+ >+/********************************************************************** >+ Set the Cell's DN >+ *********************************************************************/ >+ >+ void cell_set_dn(struct likewise_cell *c, const char *dn) >+{ >+ if ( c->dn) { >+ talloc_free(c->dn); >+ c->dn = NULL; >+ } >+ >+ c->dn = talloc_strdup(c, dn); >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ void cell_set_domain_sid(struct likewise_cell *c, DOM_SID *sid) >+{ >+ sid_copy(&c->domain_sid, sid); >+} >+ >+/* >+ * Query Routines >+ */ >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ const char* cell_search_base(struct likewise_cell *c) >+{ >+ if (!c) >+ return NULL; >+ >+ return talloc_asprintf(c, "cn=%s,%s", ADEX_CELL_RDN, c->dn); >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ bool cell_search_forest(struct likewise_cell *c) >+{ >+ uint32_t test_flags = LWCELL_FLAG_SEARCH_FOREST; >+ >+ return ((c->flags & test_flags) == test_flags); >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ uint32_t cell_flags(struct likewise_cell *c) >+{ >+ if (!c) >+ return 0; >+ >+ return c->flags; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ const char *cell_dns_domain(struct likewise_cell *c) >+{ >+ if (!c) >+ return NULL; >+ >+ return c->dns_domain; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+ ADS_STRUCT *cell_connection(struct likewise_cell *c) >+{ >+ if (!c) >+ return NULL; >+ >+ return c->conn; >+} >+ >+/* >+ * Connection functions >+ */ >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+ NTSTATUS cell_connect(struct likewise_cell *c) >+{ >+ ADS_STRUCT *ads = NULL; >+ ADS_STATUS ads_status; >+ fstring dc_name; >+ struct sockaddr_storage dcip; >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ >+ /* have to at least have the AD domain name */ >+ >+ if (!c->dns_domain) { >+ nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* clear out any old information */ >+ >+ if (c->conn) { >+ ads_destroy(&c->conn); >+ c->conn = NULL; >+ } >+ >+ /* now setup the new connection */ >+ >+ ads = ads_init(c->dns_domain, NULL, NULL); >+ BAIL_ON_PTR_ERROR(ads, nt_status); >+ >+ ads->auth.password = >+ secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); >+ ads->auth.realm = SMB_STRDUP(lp_realm()); >+ >+ /* Make the connection. We should already have an initial >+ TGT using the machine creds */ >+ >+ if (cell_flags(c) & LWCELL_FLAG_GC_CELL) { >+ ads_status = ads_connect_gc(ads); >+ } else { >+ /* Set up server affinity for normal cells and the client >+ site name cache */ >+ >+ if (!get_dc_name("", c->dns_domain, dc_name, &dcip)) { >+ nt_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ ads_status = ads_connect(ads); >+ } >+ >+ >+ c->conn = ads; >+ >+ nt_status = ads_ntstatus(ads_status); >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ ads_destroy(&ads); >+ c->conn = NULL; >+ } >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+ NTSTATUS cell_connect_dn(struct likewise_cell **c, const char *dn) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct likewise_cell *new_cell = NULL; >+ char *dns_domain = NULL; >+ >+ if (*c || !dn) { >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ if ((new_cell = cell_new()) == NULL) { >+ nt_status = NT_STATUS_NO_MEMORY; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Set the DNS domain, dn, etc ... and add it to the list */ >+ >+ dns_domain = cell_dn_to_dns(dn); >+ cell_set_dns_domain(new_cell, dns_domain); >+ SAFE_FREE(dns_domain); >+ >+ cell_set_dn(new_cell, dn); >+ >+ nt_status = cell_connect(new_cell); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ *c = new_cell; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ DEBUG(1,("LWI: Failled to connect to cell \"%s\" (%s)\n", >+ dn ? dn : "NULL", nt_errstr(nt_status))); >+ talloc_destroy(new_cell); >+ } >+ >+ return nt_status; >+} >+ >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+#define MAX_SEARCH_COUNT 2 >+ >+ ADS_STATUS cell_do_search(struct likewise_cell *c, >+ const char *search_base, >+ int scope, >+ const char *expr, >+ const char **attrs, >+ LDAPMessage ** msg) >+{ >+ int search_count = 0; >+ ADS_STATUS status; >+ NTSTATUS nt_status; >+ >+ /* check for a NULL connection */ >+ >+ if (!c->conn) { >+ nt_status = cell_connect(c); >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ status = ADS_ERROR_NT(nt_status); >+ return status; >+ } >+ } >+ >+ DEBUG(10, ("cell_do_search: Base = %s, Filter = %s, Scope = %d, GC = %s\n", >+ search_base, expr, scope, >+ c->conn->server.gc ? "yes" : "no")); >+ >+ /* we try multiple times in case the ADS_STRUCT is bad >+ and we need to reconnect */ >+ >+ while (search_count < MAX_SEARCH_COUNT) { >+ *msg = NULL; >+ status = ads_do_search(c->conn, search_base, >+ scope, expr, attrs, msg); >+ if (ADS_ERR_OK(status)) { >+ return status; >+ } >+ >+ >+ DEBUG(5, ("cell_do_search: search[%d] failed (%s)\n", >+ search_count, ads_errstr(status))); >+ >+ search_count++; >+ >+ /* Houston, we have a problem */ >+ >+ if (status.error_type == ENUM_ADS_ERROR_LDAP) { >+ switch (status.err.rc) { >+ case LDAP_TIMELIMIT_EXCEEDED: >+ case LDAP_TIMEOUT: >+ case -1: /* we get this error if we cannot contact >+ the LDAP server */ >+ nt_status = cell_connect(c); >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ status = ADS_ERROR_NT(nt_status); >+ return status; >+ } >+ break; >+ default: >+ /* we're all done here */ >+ return status; >+ } >+ } >+ } >+ >+ DEBUG(5, ("cell_do_search: exceeded maximum search count!\n")); >+ >+ return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); >+} >diff --git a/source3/winbindd/idmap_adex/provider_unified.c b/source3/winbindd/idmap_adex/provider_unified.c >new file mode 100644 >index 0000000..f185347 >--- /dev/null >+++ b/source3/winbindd/idmap_adex/provider_unified.c >@@ -0,0 +1,1180 @@ >+/* >+ * idmap_adex >+ * >+ * Provider for RFC2307 and SFU AD Forests >+ * >+ * Copyright (C) Gerald (Jerry) Carter 2006-2008 >+ * >+ * 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 2 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, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include "includes.h" >+#include "idmap_adex.h" >+ >+#undef DBGC_CLASS >+#define DBGC_CLASS DBGC_IDMAP >+ >+/* Information needed by the LDAP search filters */ >+ >+enum filterType { SidFilter, IdFilter, AliasFilter }; >+ >+struct lwcell_filter >+{ >+ enum filterType ftype; >+ bool use2307; >+ union { >+ DOM_SID sid; >+ struct { >+ uint32_t id; >+ enum id_type type; >+ } id; >+ fstring alias; >+ } filter; >+}; >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static char* build_id_filter(uint32_t id, >+ enum id_type type, >+ uint32_t search_flags) >+{ >+ char *filter = NULL; >+ char *oc_filter, *attr_filter; >+ NTSTATUS nt_status; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS) >+ == LWCELL_FLAG_USE_RFC2307_ATTRS); >+ bool use_gc = ((search_flags & LWCELL_FLAG_SEARCH_FOREST) >+ == LWCELL_FLAG_SEARCH_FOREST); >+ const char *oc; >+ >+ /* Construct search filter for objectclass and attributes */ >+ >+ switch (type) { >+ case ID_TYPE_UID: >+ oc = ADEX_OC_USER; >+ if (use2307) { >+ oc = ADEX_OC_POSIX_USER; >+ if (use_gc) { >+ oc = AD_USER; >+ } >+ } >+ oc_filter = talloc_asprintf(frame, "objectclass=%s", oc); >+ attr_filter = talloc_asprintf(frame, "%s=%u", >+ ADEX_ATTR_UIDNUM, id); >+ break; >+ >+ case ID_TYPE_GID: >+ oc = ADEX_OC_GROUP; >+ if (use2307) { >+ oc = ADEX_OC_POSIX_GROUP; >+ if (use_gc) { >+ oc = AD_GROUP; >+ } >+ } >+ oc_filter = talloc_asprintf(frame, "objectclass=%s", oc); >+ attr_filter = talloc_asprintf(frame, "%s=%u", >+ ADEX_ATTR_GIDNUM, id); >+ break; >+ default: >+ return NULL; >+ } >+ >+ BAIL_ON_PTR_ERROR(oc_filter, nt_status); >+ BAIL_ON_PTR_ERROR(attr_filter, nt_status); >+ >+ /* Use "keywords=%s" for non-schema cells */ >+ >+ if (use2307) { >+ filter = talloc_asprintf(frame, "(&(%s)(%s))", >+ oc_filter, attr_filter); >+ } else { >+ filter = talloc_asprintf(frame, "(&(keywords=%s)(keywords=%s))", >+ oc_filter, attr_filter); >+ } >+ >+ talloc_destroy(oc_filter); >+ talloc_destroy(attr_filter); >+ >+done: >+ /* Don't destroy the stackframe CTX since we are returning >+ memory from it */ >+ >+ return filter; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static char* build_alias_filter(const char *alias, uint32_t search_flags) >+{ >+ char *filter = NULL; >+ char *user_attr_filter, *group_attr_filter; >+ NTSTATUS nt_status; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS) >+ == LWCELL_FLAG_USE_RFC2307_ATTRS); >+ bool search_forest = ((search_flags & LWCELL_FLAG_SEARCH_FOREST) >+ == LWCELL_FLAG_SEARCH_FOREST); >+ >+ /* Construct search filter for objectclass and attributes */ >+ >+ user_attr_filter = talloc_asprintf(frame, "%s=%s", >+ ADEX_ATTR_UID, alias); >+ group_attr_filter = talloc_asprintf(frame, "%s=%s", >+ ADEX_ATTR_DISPLAYNAME, alias); >+ BAIL_ON_PTR_ERROR(user_attr_filter, nt_status); >+ BAIL_ON_PTR_ERROR(group_attr_filter, nt_status); >+ >+ /* Use "keywords=%s" for non-schema cells */ >+ >+ if (use2307) { >+ filter = talloc_asprintf(frame, >+ "(|(&(%s)(objectclass=%s))(&(%s)(objectclass=%s)))", >+ user_attr_filter, >+ search_forest ? AD_USER : ADEX_OC_POSIX_USER, >+ group_attr_filter, >+ search_forest ? AD_GROUP : ADEX_OC_POSIX_GROUP); >+ } else { >+ filter = talloc_asprintf(frame, >+ "(|(keywords=%s)(keywords=%s))", >+ user_attr_filter, >+ group_attr_filter); >+ } >+ >+ talloc_destroy(user_attr_filter); >+ talloc_destroy(group_attr_filter); >+ >+done: >+ /* Don't destroy the stackframe CTX since we are returning >+ memory from it */ >+ >+ return filter; >+} >+ >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS search_cell(struct likewise_cell *c, >+ LDAPMessage **msg, >+ const struct lwcell_filter *fdata) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ TALLOC_CTX* frame = talloc_stackframe(); >+ char *filter = NULL; >+ const char *base = NULL; >+ ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); >+ const char *attrs[] = { "*", NULL }; >+ int count; >+ char *sid_str; >+ >+ /* get the filter and other search parameters */ >+ >+ switch (fdata->ftype) { >+ case SidFilter: >+ sid_str = sid_string_talloc(frame, &fdata->filter.sid); >+ BAIL_ON_PTR_ERROR(sid_str, nt_status); >+ >+ filter = talloc_asprintf(frame, "(keywords=backLink=%s)", >+ sid_str); >+ break; >+ case IdFilter: >+ filter = build_id_filter(fdata->filter.id.id, >+ fdata->filter.id.type, >+ cell_flags(c)); >+ break; >+ case AliasFilter: >+ filter = build_alias_filter(fdata->filter.alias, >+ cell_flags(c)); >+ break; >+ default: >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ break; >+ } >+ BAIL_ON_PTR_ERROR(filter, nt_status); >+ >+ base = cell_search_base(c); >+ BAIL_ON_PTR_ERROR(base, nt_status); >+ >+ ads_status = cell_do_search(c, base, LDAP_SCOPE_SUBTREE, >+ filter, attrs, msg); >+ >+ nt_status = ads_ntstatus(ads_status); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* Now check that we got only one reply */ >+ >+ count = ads_count_replies(c->conn, *msg); >+ if (count < 1) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ if ( count > 1) { >+ nt_status = NT_STATUS_DUPLICATE_NAME; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+done: >+ PRINT_NTSTATUS_ERROR(nt_status, "search_cell", 4); >+ >+ talloc_destroy(CONST_DISCARD(char*, base)); >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS search_domain(struct likewise_cell **cell, >+ LDAPMessage **msg, >+ const char *dn, >+ const DOM_SID *sid) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ TALLOC_CTX* frame = talloc_stackframe(); >+ int count; >+ >+ nt_status = dc_search_domains(cell, msg, dn, sid); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* Now check that we got only one reply */ >+ >+ count = ads_count_replies(cell_connection(*cell), *msg); >+ if (count < 1) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ if ( count > 1) { >+ nt_status = NT_STATUS_DUPLICATE_NAME; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+done: >+ PRINT_NTSTATUS_ERROR(nt_status, "search_domain", 4); >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+ >+/******************************************************************** >+ Check that a DN is within the forest scope. >+ *******************************************************************/ >+ >+static bool check_forest_scope(const char *dn) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ char *p = NULL; >+ char *q = NULL; >+ char *dns_domain = NULL; >+ struct winbindd_tdc_domain *domain; >+ >+ /* If the DN does *not* contain "$LikewiseIdentityCell", >+ assume this is a schema mode forest and it is in the >+ forest scope by definition. */ >+ >+ if ((p = strstr_m(dn, ADEX_CELL_RDN)) == NULL) { >+ nt_status = NT_STATUS_OK; >+ goto done; >+ } >+ >+ /* If this is a non-schema forest, then make sure that the DN >+ is in the form "...,cn=$LikewiseIdentityCell,DC=..." */ >+ >+ if ((q = strchr_m(p, ',')) == NULL) { >+ nt_status = NT_STATUS_OBJECT_NAME_INVALID; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ q++; >+ if (StrnCaseCmp(q, "dc=", 3) != 0) { >+ nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ >+ dns_domain = cell_dn_to_dns(q); >+ BAIL_ON_PTR_ERROR(dns_domain, nt_status); >+ >+ domain = wcache_tdc_fetch_domain(frame, dns_domain); >+ if (!domain) { >+ nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ talloc_destroy(frame); >+ SAFE_FREE(dns_domain); >+ >+ return NT_STATUS_IS_OK(nt_status); >+} >+ >+ >+ >+/******************************************************************** >+ Check that only one result was returned within the forest cell >+ scope. >+ *******************************************************************/ >+ >+static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list, >+ LDAPMessage **msg_list, >+ int num_resp, >+ char **dn, >+ DOM_SID *user_sid) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ int i; >+ ADS_STRUCT *ads = NULL; >+ LDAPMessage *msg = NULL; >+ int count = 0; >+ char *entry_dn = NULL; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ >+ if (!dn || !user_sid) { >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ *dn = NULL; >+ >+ if (!ads_list || !msg_list || (num_resp == 0)) { >+ nt_status = NT_STATUS_NO_SUCH_FILE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Loop over all msgs */ >+ >+ for (i=0; i<num_resp; i++) { >+ LDAPMessage *e = ads_first_entry(ads_list[i], msg_list[i]); >+ >+ while (e) { >+ entry_dn = ads_get_dn(ads_list[i], e); >+ BAIL_ON_PTR_ERROR(entry_dn, nt_status); >+ >+ if (check_forest_scope(entry_dn)) { >+ count++; >+ >+ /* If we've already broken the condition, no >+ need to continue */ >+ >+ if (count > 1) { >+ nt_status = NT_STATUS_DUPLICATE_NAME; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ ads = ads_list[i]; >+ msg = e; >+ *dn = SMB_STRDUP(entry_dn); >+ BAIL_ON_PTR_ERROR((*dn), nt_status); >+ } >+ >+ e = ads_next_entry(ads_list[i], e); >+ SAFE_FREE(entry_dn); >+ } >+ } >+ >+ if (!ads || !msg) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* If we made is through the loop, then grab the user_sid and >+ run home to base */ >+ >+ /* >+ Try and get the SID from either objectSid or keywords. >+ We cannot use pull_sid() here since we want to try >+ both methods and not only one or the other (and we >+ have no full likewise_cell struct. >+ >+ Fail if both are unavailable >+ */ >+ >+ if (!ads_pull_sid(ads, msg, "objectSid", user_sid)) { >+ char **keywords; >+ char *s; >+ size_t num_lines = 0; >+ >+ keywords = ads_pull_strings(ads, frame, msg, "keywords", >+ &num_lines); >+ BAIL_ON_PTR_ERROR(keywords, nt_status); >+ >+ s = find_attr_string(keywords, num_lines, "backLink"); >+ if (!s) { >+ nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ if (!string_to_sid(user_sid, s)) { >+ nt_status = NT_STATUS_INVALID_SID; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ SAFE_FREE(*dn); >+ } >+ >+ talloc_destroy(frame); >+ SAFE_FREE(entry_dn); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ Search all forests. Each forest can have it's own forest-cell >+ settings so we have to generate the filter for each search. >+ We don't use gc_search_all_forests() since we may have a different >+ schema model in each forest and need to construct the search >+ filter for each GC search. >+ *******************************************************************/ >+ >+static NTSTATUS search_forest(struct likewise_cell *forest_cell, >+ LDAPMessage **msg, >+ const struct lwcell_filter *fdata) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ char *filter = NULL; >+ char *dn = NULL; >+ struct gc_info *gc = NULL; >+ ADS_STRUCT **ads_list = NULL; >+ LDAPMessage **msg_list = NULL; >+ int num_resp = 0; >+ LDAPMessage *m; >+ DOM_SID user_sid; >+ struct likewise_cell *domain_cell = NULL; >+ >+ if ((gc = gc_search_start()) == NULL) { >+ nt_status = NT_STATUS_INVALID_DOMAIN_STATE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ while (gc) { >+ char *sid_binstr = NULL; >+ uint32_t flags = LWCELL_FLAG_SEARCH_FOREST; >+ >+ m = NULL; >+ >+ flags |= cell_flags(gc->forest_cell); >+ >+ switch (fdata->ftype) { >+ case SidFilter: >+ sid_binstr = sid_binstring(&fdata->filter.sid); >+ BAIL_ON_PTR_ERROR(sid_binstr, nt_status); >+ >+ filter = talloc_asprintf(frame, "(objectSid=%s)", sid_binstr); >+ SAFE_FREE(sid_binstr); >+ break; >+ case IdFilter: >+ filter = build_id_filter(fdata->filter.id.id, >+ fdata->filter.id.type, flags); >+ break; >+ case AliasFilter: >+ filter = build_alias_filter(fdata->filter.alias, flags); >+ break; >+ } >+ >+ /* First find the sparse object in GC */ >+ nt_status = gc_search_forest(gc, &m, filter); >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ gc = gc->next; >+ continue; >+ } >+ >+ nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell), >+ m, &ads_list, &msg_list, >+ &num_resp); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ gc = gc->next; >+ } >+ >+ /* Uniqueness check across forests */ >+ >+ nt_status = check_result_unique_scoped(ads_list, msg_list, num_resp, >+ &dn, &user_sid); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = search_domain(&domain_cell, &m, dn, &user_sid); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* Save the connection and results in the return parameters */ >+ >+ forest_cell->gc_search_cell = domain_cell; >+ *msg = m; >+ >+done: >+ PRINT_NTSTATUS_ERROR(nt_status, "search_forest", 4); >+ >+ SAFE_FREE(dn); >+ >+ free_result_array(ads_list, msg_list, num_resp); >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS search_cell_list(struct likewise_cell **c, >+ LDAPMessage **m, >+ const struct lwcell_filter *fdata) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ struct likewise_cell *cell = NULL; >+ LDAPMessage *msg = NULL; >+ struct likewise_cell *result_cell = NULL; >+ >+ if ((cell = cell_list_head()) == NULL) { >+ nt_status = NT_STATUS_INVALID_SERVER_STATE; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ while (cell) { >+ /* Clear any previous GC search results */ >+ >+ cell->gc_search_cell = NULL; >+ >+ if (cell_search_forest(cell)) { >+ nt_status = search_forest(cell, &msg, fdata); >+ } else { >+ nt_status = search_cell(cell, &msg, fdata); >+ } >+ >+ /* Always point to the search result cell. >+ In forests this might be for another domain >+ which means the schema model may be different */ >+ >+ result_cell = cell->gc_search_cell ? >+ cell->gc_search_cell : cell; >+ >+ /* Check if we are done */ >+ >+ if (NT_STATUS_IS_OK(nt_status)) { >+ break; >+ } >+ >+ /* No luck. Free memory and hit the next cell. >+ Forest searches always set the gc_search_cell >+ so give preference to that connection if possible. */ >+ >+ ads_msgfree(cell_connection(result_cell), msg); >+ msg = NULL; >+ >+ cell = cell->next; >+ } >+ >+ /* This might be assigning NULL but that is ok as long as we >+ give back the proper error code */ >+ >+ *c = result_cell; >+ *m = msg; >+ >+done: >+ PRINT_NTSTATUS_ERROR(nt_status, "search_cell_list", 3); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ Pull the SID from an object which is always stored in the keywords >+ attribute as "backLink=S-1-5-21-..." >+ *******************************************************************/ >+ >+static NTSTATUS pull_sid(struct likewise_cell *c, >+ LDAPMessage *msg, >+ DOM_SID *sid) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ ADS_STRUCT *ads = NULL; >+ >+ ads = cell_connection(c); >+ >+ /* >+ We have two ways of getting the sid: >+ (a) from the objectSID in case of a GC search, >+ (b) from backLink in the case of a cell search. >+ Pull the keywords attributes and grab the backLink. >+ */ >+ >+ if (!ads_pull_sid(ads, msg, "objectSid", sid)) { >+ char **keywords; >+ char *s; >+ size_t num_lines = 0; >+ >+ keywords = ads_pull_strings(ads, frame, msg, >+ "keywords", &num_lines); >+ BAIL_ON_PTR_ERROR(keywords, nt_status); >+ >+ s = find_attr_string(keywords, num_lines, "backLink"); >+ if (!s) { >+ nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ if (!string_to_sid(sid, s)) { >+ nt_status = NT_STATUS_INVALID_SID; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS get_object_type(struct likewise_cell *c, >+ LDAPMessage *msg, >+ enum id_type *type) >+{ >+ TALLOC_CTX *ctx = talloc_stackframe(); >+ char **oc_list = NULL; >+ NTSTATUS nt_status = NT_STATUS_OK; >+ size_t list_size = 0; >+ char *s = NULL; >+ ADS_STRUCT *ads = NULL; >+ >+ ads = cell_connection(c); >+ >+ /* Deal with RFC 2307 support first */ >+ >+ if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) { >+ oc_list = ads_pull_strings(ads, ctx, msg, >+ "objectClass", &list_size); >+ if (!oc_list) { >+ nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; >+ goto done; >+ } >+ >+ /* Check for posix classes and AD classes */ >+ >+ if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_USER) >+ || is_object_class(oc_list, list_size, AD_USER)) { >+ *type = ID_TYPE_UID; >+ } else if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_GROUP) >+ || is_object_class(oc_list, list_size, AD_GROUP)) { >+ *type = ID_TYPE_GID; >+ } else { >+ *type = ID_TYPE_NOT_SPECIFIED; >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ } >+ } else { >+ /* Default to non-schema mode */ >+ >+ oc_list = ads_pull_strings(ads, ctx, msg, >+ "keywords", &list_size); >+ if (!oc_list) { >+ nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; >+ goto done; >+ } >+ >+ s = find_attr_string(oc_list, list_size, "objectClass"); >+ if (!s) { >+ nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; >+ goto done; >+ } >+ >+ if (strequal(s, ADEX_OC_USER)) { >+ *type = ID_TYPE_UID; >+ } else if (strequal(s, ADEX_OC_GROUP)) { >+ *type = ID_TYPE_GID; >+ } else { >+ *type = ID_TYPE_NOT_SPECIFIED; >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ } >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ talloc_destroy(ctx); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ Pull an attribute uint32_t value >+ *******************************************************************/ >+ >+static NTSTATUS get_object_uint32(struct likewise_cell *c, >+ LDAPMessage *msg, >+ const char *attrib, >+ uint32_t *x) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ char **keywords = NULL; >+ size_t list_size = 0; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ ADS_STRUCT *ads = NULL; >+ >+ ads = cell_connection(c); >+ >+ /* Deal with RFC2307 schema */ >+ >+ if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) { >+ if (!ads_pull_uint32(ads, msg, attrib, x)) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ } else { >+ /* Non-schema mode */ >+ char *s = NULL; >+ uint32_t num; >+ >+ keywords = ads_pull_strings(ads, frame, msg, "keywords", >+ &list_size); >+ BAIL_ON_PTR_ERROR(keywords, nt_status); >+ >+ s = find_attr_string(keywords, list_size, attrib); >+ if (!s) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ num = strtoll(s, NULL, 10); >+ if (errno == ERANGE) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ *x = num; >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS get_object_id(struct likewise_cell *c, >+ LDAPMessage *msg, >+ enum id_type type, >+ uint32_t *id) >+{ >+ NTSTATUS nt_status = NT_STATUS_OK; >+ const char *id_attr; >+ >+ /* Figure out which attribute we need to pull */ >+ >+ switch (type) { >+ case ID_TYPE_UID: >+ id_attr = ADEX_ATTR_UIDNUM; >+ break; >+ case ID_TYPE_GID: >+ id_attr = ADEX_ATTR_GIDNUM; >+ break; >+ default: >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ break; >+ } >+ >+ nt_status = get_object_uint32(c, msg, id_attr, id); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+done: >+ return nt_status; >+} >+ >+/******************************************************************** >+ Pull the uid/gid and type from an object. This differs depending on >+ the cell flags. >+ *******************************************************************/ >+ >+static NTSTATUS pull_id(struct likewise_cell *c, >+ LDAPMessage *msg, >+ uint32_t *id, >+ enum id_type *type) >+{ >+ NTSTATUS nt_status; >+ >+ nt_status = get_object_type(c, msg, type); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = get_object_id(c, msg, *type, id); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+done: >+ return nt_status; >+} >+ >+/******************************************************************** >+ Pull an attribute string value >+ *******************************************************************/ >+ >+static NTSTATUS get_object_string(struct likewise_cell *c, >+ LDAPMessage *msg, >+ TALLOC_CTX *ctx, >+ const char *attrib, >+ char **string) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ char **keywords = NULL; >+ size_t list_size = 0; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ ADS_STRUCT *ads = NULL; >+ >+ *string = NULL; >+ >+ ads = cell_connection(c); >+ >+ /* Deal with RFC2307 schema */ >+ >+ if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) { >+ *string = ads_pull_string(ads, ctx, msg, attrib); >+ } else { >+ /* Non-schema mode */ >+ >+ char *s = NULL; >+ >+ keywords = ads_pull_strings(ads, frame, msg, >+ "keywords", &list_size); >+ if (!keywords) { >+ nt_status = NT_STATUS_NO_MEMORY; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ s = find_attr_string(keywords, list_size, attrib); >+ if (s) { >+ *string = talloc_strdup(ctx, s); >+ } >+ } >+ >+ if (!*string) { >+ nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ Pull the struct passwd fields for a user >+ *******************************************************************/ >+ >+static NTSTATUS pull_nss_info(struct likewise_cell *c, >+ LDAPMessage *msg, >+ TALLOC_CTX *ctx, >+ char **homedir, >+ char **shell, >+ char **gecos, >+ gid_t *p_gid) >+{ >+ NTSTATUS nt_status; >+ >+ nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_HOMEDIR, homedir); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_SHELL, shell); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_GECOS, gecos); >+ /* Gecos is often not set so ignore failures */ >+ >+ nt_status = get_object_uint32(c, msg, ADEX_ATTR_GIDNUM, p_gid); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+done: >+ return nt_status; >+} >+ >+/******************************************************************** >+ Pull the struct passwd fields for a user >+ *******************************************************************/ >+ >+static NTSTATUS pull_alias(struct likewise_cell *c, >+ LDAPMessage *msg, >+ TALLOC_CTX *ctx, >+ char **alias) >+{ >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ enum id_type type; >+ const char *attr = NULL; >+ >+ /* Figure out if this is a user or a group */ >+ >+ nt_status = get_object_type(c, msg, &type); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ switch (type) { >+ case ID_TYPE_UID: >+ attr = ADEX_ATTR_UID; >+ break; >+ case ID_TYPE_GID: >+ /* What is the group attr for RFC2307 Forests? */ >+ attr = ADEX_ATTR_DISPLAYNAME; >+ break; >+ default: >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ break; >+ } >+ >+ nt_status = get_object_string(c, msg, ctx, attr, alias); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+done: >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS _ccp_get_sid_from_id(DOM_SID * sid, >+ uint32_t id, enum id_type type) >+{ >+ struct likewise_cell *cell = NULL; >+ LDAPMessage *msg = NULL; >+ NTSTATUS nt_status; >+ struct lwcell_filter filter; >+ >+ filter.ftype = IdFilter; >+ filter.filter.id.id = id; >+ filter.filter.id.type = type; >+ >+ nt_status = search_cell_list(&cell, &msg, &filter); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = pull_sid(cell, msg, sid); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+done: >+ ads_msgfree(cell->conn, msg); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS _ccp_get_id_from_sid(uint32_t * id, >+ enum id_type *type, >+ const DOM_SID * sid) >+{ >+ struct likewise_cell *cell = NULL; >+ LDAPMessage *msg = NULL; >+ NTSTATUS nt_status; >+ struct lwcell_filter filter; >+ >+ filter.ftype = SidFilter; >+ sid_copy(&filter.filter.sid, sid); >+ >+ nt_status = search_cell_list(&cell, &msg, &filter); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = pull_id(cell, msg, id, type); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ if (*id < min_id_value()) { >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+done: >+ ads_msgfree(cell->conn, msg); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+static NTSTATUS _ccp_nss_get_info(const DOM_SID * sid, >+ TALLOC_CTX * ctx, >+ char **homedir, >+ char **shell, >+ char **gecos, gid_t * p_gid) >+{ >+ struct likewise_cell *cell = NULL; >+ LDAPMessage *msg = NULL; >+ NTSTATUS nt_status; >+ struct lwcell_filter filter; >+ enum id_type type; >+ >+ filter.ftype = SidFilter; >+ sid_copy(&filter.filter.sid, sid); >+ >+ nt_status = search_cell_list(&cell, &msg, &filter); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = get_object_type(cell, msg, &type); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ if (type != ID_TYPE_UID) { >+ nt_status = NT_STATUS_NO_SUCH_USER; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ nt_status = pull_nss_info(cell, msg, ctx, homedir, shell, gecos, >+ (uint32_t*) p_gid); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+done: >+ ads_msgfree(cell->conn, msg); >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ *********************************************************************/ >+ >+static NTSTATUS _ccp_map_to_alias(TALLOC_CTX *ctx, >+ const char *domain, >+ const char *name, char **alias) >+{ >+ TALLOC_CTX *frame = talloc_stackframe(); >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ DOM_SID sid; >+ struct likewise_cell *cell = NULL; >+ LDAPMessage *msg = NULL; >+ struct lwcell_filter filter; >+ enum lsa_SidType sid_type; >+ >+ /* Convert the name to a SID */ >+ >+ nt_status = gc_name_to_sid(domain, name, &sid, &sid_type); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* Find the user/group */ >+ >+ filter.ftype = SidFilter; >+ sid_copy(&filter.filter.sid, &sid); >+ >+ nt_status = search_cell_list(&cell, &msg, &filter); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* Pull the alias and return */ >+ >+ nt_status = pull_alias(cell, msg, ctx, alias); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+done: >+ PRINT_NTSTATUS_ERROR(nt_status, "map_to_alias", 3); >+ >+ talloc_destroy(frame); >+ ads_msgfree(cell_connection(cell), msg); >+ >+ return nt_status; >+} >+ >+/********************************************************************** >+ Map from an alias name to the canonical, qualified name. >+ Ensure that the alias is only pull from the closest in which >+ the user or gorup is enabled in >+ *********************************************************************/ >+ >+static NTSTATUS _ccp_map_from_alias(TALLOC_CTX *mem_ctx, >+ const char *domain, >+ const char *alias, char **name) >+{ >+ TALLOC_CTX *frame = talloc_stackframe(); >+ NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; >+ DOM_SID sid; >+ struct likewise_cell *cell_alias = NULL; >+ LDAPMessage *msg_alias = NULL; >+ struct likewise_cell *cell_sid = NULL; >+ LDAPMessage *msg_sid = NULL; >+ struct lwcell_filter filter; >+ char *canonical_name = NULL; >+ enum lsa_SidType type; >+ >+ /* Find the user/group */ >+ >+ filter.ftype = AliasFilter; >+ fstrcpy(filter.filter.alias, alias); >+ >+ nt_status = search_cell_list(&cell_alias, &msg_alias, &filter); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ nt_status = pull_sid(cell_alias, msg_alias, &sid); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ /* Now search again for the SID according to the cell list. >+ Verify that the cell of both search results is the same >+ so that we only match an alias from the closest cell >+ in which a user/group has been instantied. */ >+ >+ filter.ftype = SidFilter; >+ sid_copy(&filter.filter.sid, &sid); >+ >+ nt_status = search_cell_list(&cell_sid, &msg_sid, &filter); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ if (cell_alias != cell_sid) { >+ nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ } >+ >+ /* Finally do the GC sid/name conversion */ >+ >+ nt_status = gc_sid_to_name(&sid, &canonical_name, &type); >+ BAIL_ON_NTSTATUS_ERROR(nt_status); >+ >+ *name = talloc_strdup(mem_ctx, canonical_name); >+ BAIL_ON_PTR_ERROR((*name), nt_status); >+ >+ nt_status = NT_STATUS_OK; >+ >+done: >+ PRINT_NTSTATUS_ERROR(nt_status, "map_from_alias", 3); >+ >+ ads_msgfree(cell_connection(cell_alias), msg_alias); >+ ads_msgfree(cell_connection(cell_sid), msg_sid); >+ >+ SAFE_FREE(canonical_name); >+ >+ talloc_destroy(frame); >+ >+ return nt_status; >+} >+ >+/******************************************************************** >+ *******************************************************************/ >+ >+struct cell_provider_api ccp_unified = { >+ .get_sid_from_id = _ccp_get_sid_from_id, >+ .get_id_from_sid = _ccp_get_id_from_sid, >+ .get_nss_info = _ccp_nss_get_info, >+ .map_to_alias = _ccp_map_to_alias, >+ .map_from_alias = _ccp_map_from_alias >+}; >-- >1.5.4.3 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 3661
:
1846
|
2073
|
2089
|
3528
|
3529
| 3603 |
3613
|
3614
|
3630
|
3635