mirror of
https://github.com/samba-team/samba.git
synced 2025-01-28 17:47:29 +03:00
Merge branch 'master' of ssh://git.samba.org/data/git/samba into abartlet-devel
This commit is contained in:
commit
c5265ea3bf
@ -985,6 +985,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 \
|
||||
@ -2218,6 +2226,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
|
||||
|
@ -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)
|
||||
@ -6271,8 +6272,10 @@ fi
|
||||
SMBD_LIBS="$samba_dmapi_libs"
|
||||
AC_SUBST(SMBD_LIBS)
|
||||
|
||||
CFLAGS="${CFLAGS} \$(FLAGS)"
|
||||
|
||||
if test x$MERGED_BUILD != x1; then
|
||||
CFLAGS="${CFLAGS} \$(FLAGS) -D_SAMBA_BUILD_=3"
|
||||
CFLAGS="${CFLAGS} -D_SAMBA_BUILD_=3"
|
||||
fi
|
||||
|
||||
AC_OUTPUT(Makefile
|
||||
|
292
source3/winbindd/idmap_adex/cell_util.c
Normal file
292
source3/winbindd/idmap_adex/cell_util.c
Normal file
@ -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;
|
||||
}
|
278
source3/winbindd/idmap_adex/domain_util.c
Normal file
278
source3/winbindd/idmap_adex/domain_util.c
Normal file
@ -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;
|
||||
}
|
848
source3/winbindd/idmap_adex/gc_util.c
Normal file
848
source3/winbindd/idmap_adex/gc_util.c
Normal file
@ -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;
|
||||
}
|
460
source3/winbindd/idmap_adex/idmap_adex.c
Normal file
460
source3/winbindd/idmap_adex/idmap_adex.c
Normal file
@ -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();
|
||||
}
|
257
source3/winbindd/idmap_adex/idmap_adex.h
Normal file
257
source3/winbindd/idmap_adex/idmap_adex.h
Normal file
@ -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 */
|
425
source3/winbindd/idmap_adex/likewise_cell.c
Normal file
425
source3/winbindd/idmap_adex/likewise_cell.c
Normal file
@ -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);
|
||||
}
|
1180
source3/winbindd/idmap_adex/provider_unified.c
Normal file
1180
source3/winbindd/idmap_adex/provider_unified.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user