* Winbind daemon for NT domain authentication nss module.
**/
-
-/**
- * Used to clobber name fields that have an undefined value.
- *
- * Correct code should never look at a field that has this value.
- **/
-
-static const fstring name_deadbeef = "<deadbeef>";
-
/* The list of trusted domains. Note that the list can be deleted and
recreated using the init_domain_list() function so pointers to
individual winbindd_domain structures cannot be made. Keep a copy of
/* Initialise list */
if ((!_domain_list) && (!init_domain_list())) {
- smb_panic("Init_domain_list failed\n");
+ smb_panic("Init_domain_list failed");
}
return _domain_list;
if (sid == NULL)
return False;
+ if ( IS_DC )
+ return sid_check_is_builtin(sid);
+
return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
}
if (sid == NULL)
return False;
+ if ( IS_DC )
+ return sid_check_is_in_builtin(sid);
+
return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
}
init_domain_list() and we'll get stuck in a loop. */
for (domain = _domain_list; domain; domain = domain->next) {
if (strequal(domain_name, domain->name) ||
- strequal(domain_name, domain->alt_name)) {
- return domain;
+ strequal(domain_name, domain->alt_name))
+ {
+ break;
}
- if (alternative_name && *alternative_name) {
+
+ if (alternative_name && *alternative_name)
+ {
if (strequal(alternative_name, domain->name) ||
- strequal(alternative_name, domain->alt_name)) {
- return domain;
+ strequal(alternative_name, domain->alt_name))
+ {
+ break;
}
}
- if (sid) {
+
+ if (sid)
+ {
if (is_null_sid(sid)) {
+ continue;
+ }
- } else if (sid_equal(sid, &domain->sid)) {
- return domain;
+ if (sid_equal(sid, &domain->sid)) {
+ break;
}
}
}
+ /* See if we found a match. Check if we need to update the
+ SID. */
+
+ if ( domain ) {
+ if ( sid_equal( &domain->sid, &global_sid_NULL ) )
+ sid_copy( &domain->sid, sid );
+
+ return domain;
+ }
+
/* Create new domain entry */
if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
/* Link to domain list */
DLIST_ADD(_domain_list, domain);
+ wcache_tdc_add_domain( domain );
+
DEBUG(2,("Added domain %s %s %s\n",
domain->name, domain->alt_name,
&domain->sid?sid_string_static(&domain->sid):""));
struct trustdom_state {
TALLOC_CTX *mem_ctx;
+ BOOL primary;
+ BOOL forest_root;
struct winbindd_response *response;
};
static void trustdom_recv(void *private_data, BOOL success);
+static void rescan_forest_root_trusts( void );
+static void rescan_forest_trusts( void );
static void add_trusted_domains( struct winbindd_domain *domain )
{
TALLOC_CTX *mem_ctx;
struct winbindd_request *request;
struct winbindd_response *response;
+ uint32 fr_flags = (DS_DOMAIN_TREE_ROOT|DS_DOMAIN_IN_FOREST);
struct trustdom_state *state;
state->mem_ctx = mem_ctx;
state->response = response;
+ /* Flags used to know how to continue the forest trust search */
+
+ state->primary = domain->primary;
+ state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
+
request->length = sizeof(*request);
request->cmd = WINBINDD_LIST_TRUSTDOM;
while ((p != NULL) && (*p != '\0')) {
char *q, *sidstr, *alt_name;
DOM_SID sid;
+ struct winbindd_domain *domain;
+ char *alternate_name = NULL;
alt_name = strchr(p, '\\');
if (alt_name == NULL) {
}
}
- if (find_domain_from_name_noinit(p) == NULL) {
- struct winbindd_domain *domain;
- char *alternate_name = NULL;
-
/* use the real alt_name if we have one, else pass in NULL */
if ( !strequal( alt_name, "(null)" ) )
alternate_name = alt_name;
+ /* If we have an existing domain structure, calling
+ add_trusted_domain() will update the SID if
+ necessary. This is important because we need the
+ SID for sibling domains */
+
+ if ( find_domain_from_name_noinit(p) != NULL ) {
+ domain = add_trusted_domain(p, alternate_name,
+ &cache_methods,
+ &sid);
+ } else {
domain = add_trusted_domain(p, alternate_name,
&cache_methods,
&sid);
}
SAFE_FREE(response->extra_data.data);
+
+ /*
+ Cases to consider when scanning trusts:
+ (a) we are calling from a child domain (primary && !forest_root)
+ (b) we are calling from the root of the forest (primary && forest_root)
+ (c) we are calling from a trusted forest domain (!primary
+ && !forest_root)
+ */
+
+ if ( state->primary ) {
+ /* If this is our primary domain and we are not the in the
+ forest root, we have to scan the root trusts first */
+
+ if ( !state->forest_root )
+ rescan_forest_root_trusts();
+ else
+ rescan_forest_trusts();
+
+ } else if ( state->forest_root ) {
+ /* Once we have done root forest trust search, we can
+ go on to search thing trusted forests */
+
+ rescan_forest_trusts();
+ }
+
talloc_destroy(state->mem_ctx);
+
+ return;
}
/********************************************************************
- Periodically we need to refresh the trusted domain cache for smbd
+ Scan the trusts of our forest root
********************************************************************/
+static void rescan_forest_root_trusts( void )
+{
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_trusts = 0;
+ int i;
+
+ /* The only transitive trusts supported by Windows 2003 AD are
+ (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
+ first two are handled in forest and listed by
+ DsEnumerateDomainTrusts(). Forest trusts are not so we
+ have to do that ourselves. */
+
+ if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
+ return;
+
+ for ( i=0; i<num_trusts; i++ ) {
+ struct winbindd_domain *d = NULL;
+
+ /* Find the forest root. Don't necessarily trust
+ the domain_list() as our primary domain may not
+ have been initialized. */
+
+ if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
+ continue;
+ }
+
+ /* Here's the forest root */
+
+ d = find_domain_from_name_noinit( dom_list[i].domain_name );
+
+ if ( !d ) {
+ d = add_trusted_domain( dom_list[i].domain_name,
+ dom_list[i].dns_name,
+ &cache_methods,
+ &dom_list[i].sid );
+ }
+
+ DEBUG(10,("rescan_forest_root_trusts: Following trust path "
+ "for domain tree root %s (%s)\n",
+ d->name, d->alt_name ));
+
+ d->domain_flags = dom_list[i].trust_flags;
+ d->domain_type = dom_list[i].trust_type;
+ d->domain_trust_attribs = dom_list[i].trust_attribs;
+
+ add_trusted_domains( d );
+
+ break;
+ }
+
+ TALLOC_FREE( dom_list );
+
+ return;
+}
+
+/********************************************************************
+ scan the transitive forest trists (not our own)
+********************************************************************/
+
+
+static void rescan_forest_trusts( void )
+{
+ struct winbindd_domain *d = NULL;
+ struct winbindd_tdc_domain *dom_list = NULL;
+ size_t num_trusts = 0;
+ int i;
+
+ /* The only transitive trusts supported by Windows 2003 AD are
+ (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
+ first two are handled in forest and listed by
+ DsEnumerateDomainTrusts(). Forest trusts are not so we
+ have to do that ourselves. */
+
+ if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
+ return;
+
+ for ( i=0; i<num_trusts; i++ ) {
+ uint32 flags = dom_list[i].trust_flags;
+ uint32 type = dom_list[i].trust_type;
+ uint32 attribs = dom_list[i].trust_attribs;
+
+ d = find_domain_from_name_noinit( dom_list[i].domain_name );
+
+ /* ignore our primary and internal domains */
+
+ if ( d && (d->internal || d->primary ) )
+ continue;
+
+ if ( (flags & DS_DOMAIN_DIRECT_INBOUND) &&
+ (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) &&
+ (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) )
+ {
+ /* add the trusted domain if we don't know
+ about it */
+
+ if ( !d ) {
+ d = add_trusted_domain( dom_list[i].domain_name,
+ dom_list[i].dns_name,
+ &cache_methods,
+ &dom_list[i].sid );
+ }
+
+ DEBUG(10,("Following trust path for domain %s (%s)\n",
+ d->name, d->alt_name ));
+ add_trusted_domains( d );
+ }
+ }
+
+ TALLOC_FREE( dom_list );
+
+ return;
+}
+
+/*********************************************************************
+ The process of updating the trusted domain list is a three step
+ async process:
+ (a) ask our domain
+ (b) ask the root domain in our forest
+ (c) ask the a DC in any Win2003 trusted forests
+*********************************************************************/
+
void rescan_trusted_domains( void )
{
time_t now = time(NULL);
((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
return;
- /* this will only add new domains we didn't already know about */
+ /* clear the TRUSTDOM cache first */
+
+ wcache_tdc_clear();
+
+ /* this will only add new domains we didn't already know about
+ in the domain_list()*/
add_trusted_domains( find_our_domain() );
state->continuation = continuation;
state->private_data = private_data;
- if (IS_DC || domain->primary) {
+ if (IS_DC || domain->primary || domain->internal ) {
/* The primary domain has to find the DC name itself */
request->cmd = WINBINDD_INIT_CONNECTION;
fstrcpy(request->domain_name, domain->name);
- request->data.init_conn.is_primary = True;
+ request->data.init_conn.is_primary = domain->internal ? False : True;
fstrcpy(request->data.init_conn.dcname, "");
async_request(mem_ctx, &domain->child, request, response,
init_child_recv, state);
fstrcpy(request->domain_name, domain->name);
request_domain = find_our_domain();
-
async_domain_request(mem_ctx, request_domain, request, response,
init_child_getdc_recv, state);
return WINBINDD_PENDING;
return True;
}
+void check_domain_trusted( const char *name, const DOM_SID *user_sid )
+{
+ struct winbindd_domain *domain;
+ DOM_SID dom_sid;
+ uint32 rid;
+
+ domain = find_domain_from_name_noinit( name );
+ if ( domain )
+ return;
+
+ sid_copy( &dom_sid, user_sid );
+ if ( !sid_split_rid( &dom_sid, &rid ) )
+ return;
+
+ /* add the newly discovered trusted domain */
+
+ domain = add_trusted_domain( name, NULL, &cache_methods,
+ &dom_sid);
+
+ if ( !domain )
+ return;
+
+ /* assume this is a trust from a one-way transitive
+ forest trust */
+
+ domain->active_directory = True;
+ domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
+ domain->domain_type = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
+ domain->internal = False;
+ domain->online = True;
+
+ setup_domain_child(domain, &domain->child, NULL);
+
+ wcache_tdc_add_domain( domain );
+
+ return;
+}
+
/**
* Given a domain name, return the struct winbindd domain info for it
*
return domain;
}
- smb_panic("Could not find our domain\n");
+ smb_panic("Could not find our domain");
return NULL;
}
string_to_sid(&sid, "S-1-5-32");
domain = find_domain_from_sid(&sid);
- if (domain == NULL)
- smb_panic("Could not find BUILTIN domain\n");
+ if (domain == NULL) {
+ smb_panic("Could not find BUILTIN domain");
+ }
return domain;
}
struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
{
+ /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
+
+ if ( sid_check_is_in_unix_groups(sid) ||
+ sid_check_is_unix_groups(sid) ||
+ sid_check_is_in_unix_users(sid) ||
+ sid_check_is_unix_users(sid) )
+ {
+ return find_domain_from_sid(get_global_sam_sid());
+ }
+
/* A DC can't ask the local smbd for remote SIDs, here winbindd is the
* one to contact the external DC's. On member servers the internal
* domains are different: These are part of the local SAM. */
if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
DEBUG(10, ("calling find_domain_from_sid\n"));
return find_domain_from_sid(sid);
- }
+ }
/* On a member server a query for SID or name can always go to our
* primary DC. */
struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
{
+ if ( strequal(domain_name, unix_users_domain_name() ) ||
+ strequal(domain_name, unix_groups_domain_name() ) )
+ {
+ return find_domain_from_name_noinit( get_global_sam_name() );
+ }
+
if (IS_DC || strequal(domain_name, "BUILTIN") ||
strequal(domain_name, get_global_sam_name()))
return find_domain_from_name_noinit(domain_name);
+ /* The "Unix User" and "Unix Group" domain our handled by passdb */
+
return find_our_domain();
}
/* Lookup a sid in a domain from a name */
BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
+ enum winbindd_cmd orig_cmd,
struct winbindd_domain *domain,
const char *domain_name,
const char *name, DOM_SID *sid,
NTSTATUS result;
/* Lookup name */
- result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
+ result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
+ domain_name, name, sid, type);
/* Return sid and type if lookup successful */
if (!NT_STATUS_IS_OK(result)) {
* are set, otherwise False.
**/
BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
+ struct winbindd_domain *domain,
DOM_SID *sid,
char **dom_name,
char **name,
enum lsa_SidType *type)
{
NTSTATUS result;
- struct winbindd_domain *domain;
*dom_name = NULL;
*name = NULL;
- domain = find_lookup_domain_from_sid(sid);
-
- if (!domain) {
- DEBUG(1,("Can't find domain from sid\n"));
- return False;
- }
-
/* Lookup name */
result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
}
-/* Open the winbindd socket */
-
-static int _winbindd_socket = -1;
-static int _winbindd_priv_socket = -1;
-
-int open_winbindd_socket(void)
-{
- if (_winbindd_socket == -1) {
- _winbindd_socket = create_pipe_sock(
- WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
- DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
- _winbindd_socket));
- }
-
- return _winbindd_socket;
-}
-
-int open_winbindd_priv_socket(void)
-{
- if (_winbindd_priv_socket == -1) {
- _winbindd_priv_socket = create_pipe_sock(
- get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
- DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
- _winbindd_priv_socket));
- }
-
- return _winbindd_priv_socket;
-}
-
-/* Close the winbindd socket */
-
-void close_winbindd_socket(void)
-{
- if (_winbindd_socket != -1) {
- DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
- _winbindd_socket));
- close(_winbindd_socket);
- _winbindd_socket = -1;
- }
- if (_winbindd_priv_socket != -1) {
- DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
- _winbindd_priv_socket));
- close(_winbindd_priv_socket);
- _winbindd_priv_socket = -1;
- }
-}
-
/*
* Client list accessor functions
*/
}
if (info3->num_groups == 0) {
- SAFE_FREE(info3);
+ TALLOC_FREE(info3);
return NT_STATUS_UNSUCCESSFUL;
}
sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
- SAFE_FREE(info3);
+ TALLOC_FREE(info3);
return NT_STATUS_NO_MEMORY;
}
if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
&num_groups)) {
- SAFE_FREE(info3);
+ TALLOC_FREE(info3);
return NT_STATUS_NO_MEMORY;
}
}
- SAFE_FREE(info3);
+ TALLOC_FREE(info3);
*p_num_groups = num_groups;
status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
return;
}
+
+/*********************************************************************
+ ********************************************************************/
+
+BOOL winbindd_can_contact_domain( struct winbindd_domain *domain )
+{
+ /* We can contact the domain if it is our primary domain */
+
+ if ( domain->primary )
+ return True;
+
+ /* Can always contact a domain that is in out forest */
+
+ if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
+ return True;
+
+ /* We cannot contact the domain if it is running AD and
+ we have no inbound trust */
+
+ if ( domain->active_directory &&
+ ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) )
+ {
+ return False;
+ }
+
+ /* Assume everything else is ok (probably not true but what
+ can you do?) */
+
+ return True;
+}