Fix "allow trusted domain" so it disables trusted domains.
[samba.git] / source / winbindd / winbindd_util.c
index 5ac1eb64da63dde17395a21f37ef234766ac467c..624d68e04bf1f639ead7f6e8cc91ba2e23b579bb 100644 (file)
@@ -27,7 +27,9 @@
 #define DBGC_CLASS DBGC_WINBIND
 
 extern struct winbindd_methods cache_methods;
-extern struct winbindd_methods passdb_methods;
+extern struct winbindd_methods builtin_passdb_methods;
+extern struct winbindd_methods sam_passdb_methods;
+
 
 /**
  * @file winbindd_util.c
@@ -41,7 +43,7 @@ extern struct winbindd_methods passdb_methods;
    individual winbindd_domain structures cannot be made.  Keep a copy of
    the domain name instead. */
 
-static struct winbindd_domain *_domain_list;
+static struct winbindd_domain *_domain_list = NULL;
 
 /**
    When was the last scan of trusted domains done?
@@ -107,13 +109,22 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
 {
        struct winbindd_domain *domain;
        const char *alternative_name = NULL;
-       
+        const char **ignored_domains, **dom;
+
+        ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
+        for (dom=ignored_domains; dom && *dom; dom++) {
+                if (gen_fnmatch(*dom, domain_name) == 0) {
+                        DEBUG(2,("Ignoring domain '%s'\n", domain_name));
+                        return NULL;
+                }
+        }
+
        /* ignore alt_name if we are not in an AD domain */
-       
+
        if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
                alternative_name = alt_name;
        }
-        
+
        /* We can't call domain_list() as this function is called from
           init_domain_list() and we'll get stuck in a loop. */
        for (domain = _domain_list; domain; domain = domain->next) {
@@ -163,15 +174,9 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
         
        ZERO_STRUCTP(domain);
 
-       /* prioritise the short name */
-       if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
-               fstrcpy(domain->name, alternative_name);
-               fstrcpy(domain->alt_name, domain_name);
-       } else {
-               fstrcpy(domain->name, domain_name);
-               if (alternative_name) {
-                       fstrcpy(domain->alt_name, alternative_name);
-               }
+       fstrcpy(domain->name, domain_name);
+       if (alternative_name) {
+               fstrcpy(domain->alt_name, alternative_name);
        }
 
        domain->methods = methods;
@@ -218,7 +223,7 @@ 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);    
+       uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
 
        struct trustdom_state *state;
 
@@ -345,7 +350,7 @@ static void trustdom_recv(void *private_data, bool success)
        */
 
        if ( state->primary ) {
-               /* If this is our primary domain and we are not the in the
+               /* If this is our primary domain and we are not in the
                   forest root, we have to scan the root trusts first */
 
                if ( !state->forest_root )
@@ -355,7 +360,7 @@ static void trustdom_recv(void *private_data, bool success)
 
        } else if ( state->forest_root ) {
                /* Once we have done root forest trust search, we can
-                  go on to search thing trusted forests */
+                  go on to search the trusted forests */
 
                rescan_forest_trusts();
        }
@@ -391,8 +396,8 @@ static void rescan_forest_root_trusts( void )
                   the domain_list() as our primary domain may not 
                   have been initialized. */
 
-               if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
-                       continue;                       
+               if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
+                       continue;
                }
        
                /* Here's the forest root */
@@ -406,6 +411,10 @@ static void rescan_forest_root_trusts( void )
                                                &dom_list[i].sid );
                }
 
+               if (d == NULL) {
+                       continue;
+               }
+
                        DEBUG(10,("rescan_forest_root_trusts: Following trust path "
                          "for domain tree root %s (%s)\n",
                          d->name, d->alt_name ));
@@ -425,7 +434,7 @@ static void rescan_forest_root_trusts( void )
 }
 
 /********************************************************************
- scan the transitive forest trists (not our own)
+ scan the transitive forest trusts (not our own)
 ********************************************************************/
 
 
@@ -456,10 +465,10 @@ static void rescan_forest_trusts( void )
 
                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) )
+
+               if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
+                    (type == NETR_TRUST_TYPE_UPLEVEL) &&
+                    (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
                {
                        /* add the trusted domain if we don't know
                           about it */
@@ -470,6 +479,10 @@ static void rescan_forest_trusts( void )
                                                        &cache_methods,
                                                        &dom_list[i].sid );
                        }
+
+                       if (d == NULL) {
+                               continue;
+                       }
                        
                        DEBUG(10,("Following trust path for domain %s (%s)\n",
                                  d->name, d->alt_name ));
@@ -493,16 +506,24 @@ static void rescan_forest_trusts( void )
 void rescan_trusted_domains( void )
 {
        time_t now = time(NULL);
-       
+
+       /* Check that we allow trusted domains at all */
+       if (!lp_allow_trusted_domains())
+               return;
+
        /* see if the time has come... */
        
        if ((now >= last_trustdom_scan) &&
            ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
                return;
                
-       /* clear the TRUSTDOM cache first */
-
-       wcache_tdc_clear();
+       /* I use to clear the cache here and start over but that
+          caused problems in child processes that needed the
+          trust dom list early on.  Removing it means we
+          could have some trusted domains listed that have been
+          removed from our primary domain's DC until a full
+          restart.  This should be ok since I think this is what
+          Windows does as well. */
 
        /* this will only add new domains we didn't already know about
           in the domain_list()*/
@@ -567,7 +588,7 @@ enum winbindd_result init_child_connection(struct winbindd_domain *domain,
                /* 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 = domain->internal ? False : True;
+               request->data.init_conn.is_primary = domain->primary ? true : false;
                fstrcpy(request->data.init_conn.dcname, "");
                async_request(mem_ctx, &domain->child, request, response,
                              init_child_recv, state);
@@ -668,7 +689,7 @@ enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domai
 
        fstrcpy(state->response.data.domain_info.name, domain->name);
        fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
-       sid_to_string(state->response.data.domain_info.sid, &domain->sid);
+       sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
        
        state->response.data.domain_info.native_mode
                = domain->native_mode;
@@ -691,7 +712,7 @@ bool init_domain_list(void)
 
        /* BUILTIN domain */
 
-       domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
+       domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
                                    &global_sid_Builtin);
        if (domain) {
                setup_domain_child(domain,
@@ -701,7 +722,7 @@ bool init_domain_list(void)
        /* Local SAM */
 
        domain = add_trusted_domain(get_global_sam_name(), NULL,
-                                   &passdb_methods, get_global_sam_sid());
+                                   &sam_passdb_methods, get_global_sam_sid());
        if (domain) {
                if ( role != ROLE_DOMAIN_MEMBER ) {
                        domain->primary = True;
@@ -745,7 +766,12 @@ void check_domain_trusted( const char *name, const DOM_SID *user_sid )
        struct winbindd_domain *domain; 
        DOM_SID dom_sid;
        uint32 rid;
-       
+
+       /* Check if we even care */
+
+       if (!lp_allow_trusted_domains())
+               return;
+
        domain = find_domain_from_name_noinit( name );
        if ( domain )
                return; 
@@ -766,8 +792,8 @@ void check_domain_trusted( const char *name, const DOM_SID *user_sid )
           forest trust */
 
        domain->active_directory = True;
-       domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
-       domain->domain_type  = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
+       domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
+       domain->domain_type  = NETR_TRUST_TYPE_UPLEVEL;
        domain->internal = False;
        domain->online = True;  
 
@@ -1024,13 +1050,12 @@ void free_getent_state(struct getent_state *state)
        temp = state;
 
        while(temp != NULL) {
-               struct getent_state *next;
+               struct getent_state *next = temp->next;
 
                /* Free sam entries then list entry */
 
                SAFE_FREE(state->sam_entries);
                DLIST_REMOVE(state, state);
-               next = temp->next;
 
                SAFE_FREE(temp);
                temp = next;
@@ -1104,6 +1129,31 @@ bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
        return ((*domain != NULL) && (*user != NULL));
 }
 
+/* add a domain user name to a buffer */
+void parse_add_domuser(void *buf, char *domuser, int *len)
+{
+       fstring domain;
+       char *p, *user;
+
+       user = domuser;
+       p = strchr(domuser, *lp_winbind_separator());
+
+       if (p) {
+
+               fstrcpy(domain, domuser);
+               domain[PTR_DIFF(p, domuser)] = 0;
+               p++;
+
+               if (assume_domain(domain)) {
+
+                       user = p;
+                       *len -= (PTR_DIFF(p, domuser));
+               }
+       }
+
+       safe_strcpy((char *)buf, user, *len);
+}
+
 /* Ensure an incoming username from NSS is fully qualified. Replace the
    incoming fstring with DOMAIN <separator> user. Returns the same
    values as parse_domain_user() but also replaces the incoming username.
@@ -1154,6 +1204,33 @@ void fill_domain_username(fstring name, const char *domain, const char *user, bo
        }
 }
 
+/**
+ * talloc version of fill_domain_username()
+ * return NULL on talloc failure.
+ */
+char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
+                                 const char *domain,
+                                 const char *user,
+                                 bool can_assume)
+{
+       char *tmp_user, *name;
+
+       tmp_user = talloc_strdup(mem_ctx, user);
+       strlower_m(tmp_user);
+
+       if (can_assume && assume_domain(domain)) {
+               name = tmp_user;
+       } else {
+               name = talloc_asprintf(mem_ctx, "%s%c%s",
+                                      domain,
+                                      *lp_winbind_separator(),
+                                      tmp_user);
+               TALLOC_FREE(tmp_user);
+       }
+
+       return name;
+}
+
 /*
  * Winbindd socket accessor functions
  */
@@ -1274,16 +1351,13 @@ NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
                                  const DOM_SID *user_sid,
                                  uint32 *p_num_groups, DOM_SID **user_sids)
 {
-       NET_USER_INFO_3 *info3 = NULL;
+       struct netr_SamInfo3 *info3 = NULL;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
-       int i;
        size_t num_groups = 0;
-       DOM_SID group_sid, primary_group;
-       
+
        DEBUG(3,(": lookup_usergroups_cached\n"));
-       
+
        *user_sids = NULL;
-       num_groups = 0;
        *p_num_groups = 0;
 
        info3 = netsamlogon_cache_get(mem_ctx, user_sid);
@@ -1292,46 +1366,22 @@ NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       if (info3->num_groups == 0) {
+       if (info3->base.groups.count == 0) {
                TALLOC_FREE(info3);
                return NT_STATUS_UNSUCCESSFUL;
        }
-       
-       /* always add the primary group to the sid array */
-       sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
-       
-       if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
-               TALLOC_FREE(info3);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       for (i=0; i<info3->num_groups; i++) {
-               sid_copy(&group_sid, &info3->dom_sid.sid);
-               sid_append_rid(&group_sid, info3->gids[i].g_rid);
-
-               if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
-                                &num_groups)) {
-                       TALLOC_FREE(info3);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
-
-       /* Add any Universal groups in the other_sids list */
 
-       for (i=0; i<info3->num_other_sids; i++) {
-               /* Skip Domain local groups outside our domain.
-                  We'll get these from the getsidaliases() RPC call. */
-               if (info3->other_sids_attrib[i] & SE_GROUP_RESOURCE)
-                       continue;
+       /* Skip Domain local groups outside our domain.
+          We'll get these from the getsidaliases() RPC call. */
+       status = sid_array_from_info3(mem_ctx, info3,
+                                     user_sids,
+                                     &num_groups,
+                                     false, true);
 
-               if (!add_sid_to_array(mem_ctx, &info3->other_sids[i].sid,
-                                     user_sids, &num_groups))
-               {
-                       TALLOC_FREE(info3);
-                       return NT_STATUS_NO_MEMORY;                     
-               }
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(info3);
+               return status;
        }
-       
 
        TALLOC_FREE(info3);
        *p_num_groups = num_groups;
@@ -1379,31 +1429,56 @@ void ws_name_return( char *name, char replace )
 /*********************************************************************
  ********************************************************************/
 
-bool winbindd_can_contact_domain( struct winbindd_domain *domain )
+bool winbindd_can_contact_domain(struct winbindd_domain *domain)
 {
+       struct winbindd_tdc_domain *tdc = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
+       bool ret = false;
+
        /* We can contact the domain if it is our primary domain */
 
-       if ( domain->primary )
-               return True;
+       if (domain->primary) {
+               return true;
+       }
 
-       /* Can always contact a domain that is in out forest */
+       /* Trust the TDC cache and not the winbindd_domain flags */
 
-       if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
-               return True;    
+       if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
+               DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
+                         domain->name));
+               return false;
+       }
 
-       /* We cannot contact the domain if it is running AD and
-          we have no inbound trust */
+       /* Can always contact a domain that is in out forest */
 
-       if ( domain->active_directory && 
-            ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) ) 
-       {
-               return False;
+       if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
+               ret = true;
+               goto done;
        }
        
+       /*
+        * On a _member_ server, we cannot contact the domain if it
+        * is running AD and we have no inbound trust.
+        */
+
+       if (!IS_DC && 
+            domain->active_directory &&
+           ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
+       {
+               DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
+                          "and we have no inbound trust.\n", domain->name));
+               goto done;
+       }
+
        /* Assume everything else is ok (probably not true but what
           can you do?) */
+
+       ret = true;     
+
+done:  
+       talloc_destroy(frame);
        
-       return True;    
+       return ret;     
 }
 
 /*********************************************************************