* set domain->last_status = NT_STATUS_SERVER_DISABLED on an ads_connect() failure
authorGerald Carter <jerry@samba.org>
Mon, 23 Jun 2003 05:10:07 +0000 (05:10 +0000)
committerGerald Carter <jerry@samba.org>
Mon, 23 Jun 2003 05:10:07 +0000 (05:10 +0000)
* Fix code to use winbind_rpc methods for trusted mixed mode or NT4 domains
  ( does no one ever test this? )
* add in LDAP code to get the sequence number for rpc based seqnum update.
  ( this is needed if the DC is upgraded and samba is not reconfigured
    to use security = ads; it's not pretty but it works (from app_head) )
* fix bug that caused us to enumerate domain local groups in domains
  other than our own
(This used to be commit 14f2cd139a22454571cea8475d3b7c5c2787d378)

source3/lib/username.c
source3/nsswitch/winbindd_ads.c
source3/nsswitch/winbindd_cache.c
source3/nsswitch/winbindd_group.c
source3/nsswitch/winbindd_rpc.c

index 8130b93c3f07a07abef9f7d4df4b0a100098e270..0005372a8f8875ae485d1d494ffe51e2479a1977 100644 (file)
@@ -589,13 +589,14 @@ BOOL user_in_list(const char *user,const char **list, gid_t *groups, size_t n_gr
                                fstrcpy(domain, *list);
                                domain[PTR_DIFF(p, *list)] = 0;
 
-                       /* Check to see if name is a Windows group;  Win2k native mode DCs
-                          will return domain local groups; while NT4 or mixed mode 2k DCs
-                          will not */
+                               /* Check to see if name is a Windows group;  Win2k native mode DCs
+                                  will return domain local groups; while NT4 or mixed mode 2k DCs
+                                  will not */
                        
-                       if ( winbind_lookup_name(NULL, *list, &g_sid, &name_type) 
-                               && ( name_type==SID_NAME_DOM_GRP || name_type==SID_NAME_ALIAS ) )
-                       {
+                               if ( winbind_lookup_name(NULL, *list, &g_sid, &name_type) 
+                                       && ( name_type==SID_NAME_DOM_GRP || 
+                                          (strequal(lp_workgroup(), domain) && name_type==SID_NAME_ALIAS) ) )
+                               {
                                        
                                        /* Check if user name is in the Windows group */
                                        ret = user_in_winbind_group_list(user, *list, &winbind_answered);
index 04eb65637c3f14e079a942a2cd5a36786253b8c5..b54392a92ef8a90b49c5bcb53000832e8453418b 100644 (file)
@@ -116,7 +116,11 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
        DEBUG(3,("ads: query_user_list\n"));
 
        ads = ads_cached_connection(domain);
-       if (!ads) goto done;
+       
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               goto done;
+       }
 
        rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
        if (!ADS_ERR_OK(rc)) {
@@ -213,7 +217,11 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
        DEBUG(3,("ads: enum_dom_groups\n"));
 
        ads = ads_cached_connection(domain);
-       if (!ads) goto done;
+
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               goto done;
+       }
 
        rc = ads_search_retry(ads, &res, "(objectCategory=group)", attrs);
        if (!ADS_ERR_OK(rc)) {
@@ -236,7 +244,9 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
        i = 0;
        
        group_flags = ATYPE_GLOBAL_GROUP;
-       if ( domain->native_mode )
+
+       /* only grab domain local groups for our domain */
+       if ( domain->native_mode && strequal(lp_realm(), domain->alt_name)  )
                group_flags |= ATYPE_LOCAL_GROUP;
 
        for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
@@ -286,7 +296,7 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
 {
        /*
         * This is a stub function only as we returned the domain 
-        * ocal groups in enum_dom_groups() if the domain->native field
+        * local groups in enum_dom_groups() if the domain->native field
         * was true.  This is a simple performance optimization when
         * using LDAP.
         *
@@ -311,8 +321,11 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
        DEBUG(3,("ads: name_to_sid\n"));
 
        ads = ads_cached_connection(domain);
-       if (!ads) 
+       
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
                return NT_STATUS_UNSUCCESSFUL;
+       }
 
        return ads_name_to_sid(ads, name, sid, type);
 }
@@ -326,9 +339,13 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain,
 {
        ADS_STRUCT *ads = NULL;
        DEBUG(3,("ads: sid_to_name\n"));
+
        ads = ads_cached_connection(domain);
-       if (!ads) 
+       
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
                return NT_STATUS_UNSUCCESSFUL;
+       }
 
        return ads_sid_to_name(ads, mem_ctx, sid, name, type);
 }
@@ -408,7 +425,11 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
        DEBUG(3,("ads: query_user\n"));
 
        ads = ads_cached_connection(domain);
-       if (!ads) goto done;
+       
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               goto done;
+       }
 
        sidstr = sid_binstring(sid);
        asprintf(&exp, "(objectSid=%s)", sidstr);
@@ -474,7 +495,11 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain,
        DEBUG(3,("ads: lookup_usergroups_alt\n"));
 
        ads = ads_cached_connection(domain);
-       if (!ads) goto done;
+
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               goto done;
+       }
 
        /* buggy server, no tokenGroups.  Instead lookup what groups this user
           is a member of by DN search on member*/
@@ -562,7 +587,11 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
        *num_groups = 0;
 
        ads = ads_cached_connection(domain);
-       if (!ads) goto done;
+       
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               goto done;
+       }
 
        if (!(sidstr = sid_binstring(sid))) {
                DEBUG(1,("lookup_usergroups(sid=%s) sid_binstring returned NULL\n", sid_to_string(sid_string, sid)));
@@ -669,7 +698,11 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
        *num_names = 0;
 
        ads = ads_cached_connection(domain);
-       if (!ads) goto done;
+       
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               goto done;
+       }
 
        sidstr = sid_binstring(group_sid);
 
@@ -745,7 +778,11 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
        *seq = DOM_SEQUENCE_NONE;
 
        ads = ads_cached_connection(domain);
-       if (!ads) return NT_STATUS_UNSUCCESSFUL;
+       
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
        rc = ads_USN(ads, seq);
        if (!ADS_ERR_OK(rc)) {
@@ -773,7 +810,11 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
        *names = NULL;
 
        ads = ads_cached_connection(domain);
-       if (!ads) return NT_STATUS_UNSUCCESSFUL;
+
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
        rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, alt_names, dom_sids);
 
@@ -789,7 +830,11 @@ static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
        DEBUG(3,("ads: domain_sid\n"));
 
        ads = ads_cached_connection(domain);
-       if (!ads) return NT_STATUS_UNSUCCESSFUL;
+
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
        rc = ads_domain_sid(ads, sid);
 
@@ -815,7 +860,11 @@ static NTSTATUS alternate_name(struct winbindd_domain *domain)
        DEBUG(3,("ads: alternate_name\n"));
 
        ads = ads_cached_connection(domain);
-       if (!ads) return NT_STATUS_UNSUCCESSFUL;
+       
+       if (!ads) {
+               domain->last_status = NT_STATUS_SERVER_DISABLED;
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
        if (!(ctx = talloc_init("alternate_name"))) {
                return NT_STATUS_NO_MEMORY;
index 5464e765d18d7c159ea4bb0d32f86cbb7812b0cd..9f7d3686a5b514a68bfb57385c74605f50a17cba 100644 (file)
@@ -105,9 +105,19 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
 #ifdef HAVE_ADS
                case SEC_ADS: {
                        extern struct winbindd_methods ads_methods;
-                       domain->backend = &ads_methods;
-                       break;
-               }
+                       /* always obey the lp_security parameter for our domain */
+                       if ( strequal(lp_realm(), domain->alt_name) ) {
+                               domain->backend = &ads_methods;
+                               break;
+                       }
+
+                       if ( domain->native_mode ) {
+                               domain->backend = &ads_methods;
+                               break;
+                       }
+
+                       /* fall through */
+               }       
 #endif
                default:
                        domain->backend = &msrpc_methods;
@@ -990,10 +1000,6 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain,
 do_query:
        *name = NULL;
 
-       if (wcache_server_down(domain)) {
-               return NT_STATUS_SERVER_DISABLED;
-       }
-
        /* If the seq number check indicated that there is a problem
         * with this DC, then return that status... except for
         * access_denied.  This is special because the dc may be in
index 41f594fe611b8dd1936c97a4c4ce4a15106d800c..6749f55bff35c9846842a2f94b7e4dde3c7de410 100644 (file)
@@ -75,7 +75,9 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
 
        *num_gr_mem = 0;
        
-       if ((group_name_type!=SID_NAME_DOM_GRP) && (group_name_type!=SID_NAME_ALIAS)) {
+       if ( !((group_name_type==SID_NAME_DOM_GRP) ||
+               ((group_name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
+       {
                DEBUG(1, ("SID %s in domain %s isn't a domain group (%d)\n", 
                          sid_to_string(sid_string, group_sid), domain->name, 
                          group_name_type));
@@ -228,7 +230,9 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
                return WINBINDD_ERROR;
        }
 
-       if ((name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_DOM_GRP)) {
+       if ( !((name_type==SID_NAME_DOM_GRP) ||
+               ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
+       {
                DEBUG(1, ("name '%s' is not a local or domain group: %d\n", 
                          name_group, name_type));
                return WINBINDD_ERROR;
@@ -292,8 +296,9 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
                return WINBINDD_ERROR;
        }
 
-       if (!((name_type == SID_NAME_ALIAS) || 
-             (name_type == SID_NAME_DOM_GRP))) {
+       if ( !((name_type==SID_NAME_DOM_GRP) ||
+               ((name_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
+       {
                DEBUG(1, ("name '%s' is not a local or domain group: %d\n", 
                          group_name, name_type));
                return WINBINDD_ERROR;
@@ -451,10 +456,10 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
        
        ent->num_sam_entries = num_entries;
        
-       /* get the domain local groups if we are a member of a native win2k domain */
+       /* get the domain local groups if we are a member of a native win2k domain
+          and are not using LDAP to get the groups */
           
-       if ( domain->native_mode 
-               && domain->methods->enum_local_groups 
+       if ( lp_security != SEC_ADS && domain->native_mode 
                && strequal(lp_workgroup(), domain->name) )
        {
                DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
@@ -891,8 +896,9 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
                        /* Check it is a domain group or an alias (domain local group) 
                           in a win2k native mode domain. */
                        
-                       if ( !(sid_type == SID_NAME_DOM_GRP || sid_type == SID_NAME_ALIAS) ) {
-
+                       if ( !((sid_type==SID_NAME_DOM_GRP) ||
+                               ((sid_type==SID_NAME_ALIAS) && strequal(lp_workgroup(), domain->name))) )
+                       {
                                DEBUG(10, ("winbindd_getgroups: sid type %d "
                                           "for %s is not a domain group\n",
                                           sid_type,
index 5710a323e8f74608d62d194eba0050b2136fa40f..7d6055006d7795b49c5857b5922b5a4cbfba7ed9 100644 (file)
@@ -681,6 +681,168 @@ done:
         return result;
 }
 
+#ifdef HAVE_LDAP
+
+#include <ldap.h>
+
+static SIG_ATOMIC_T gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+       gotalarm = 1;
+}
+
+static LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to)
+{
+       LDAP *ldp = NULL;
+
+       /* Setup timeout */
+       gotalarm = 0;
+       CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+       alarm(to);
+       /* End setup timeout. */
+
+       ldp = ldap_open(server, port);
+
+       /* Teardown timeout. */
+       CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+       alarm(0);
+
+       return ldp;
+}
+
+static int get_ldap_seq(const char *server, uint32 *seq)
+{
+       int ret = -1;
+       struct timeval to;
+       char *attrs[] = {"highestCommittedUSN", NULL};
+       LDAPMessage *res = NULL;
+       char **values = NULL;
+       LDAP *ldp = NULL;
+
+       *seq = DOM_SEQUENCE_NONE;
+
+       /*
+        * 10 second timeout on open. This is needed as the search timeout
+        * doesn't seem to apply to doing an open as well. JRA.
+        */
+
+       if ((ldp = ldap_open_with_timeout(server, LDAP_PORT, 10)) == NULL)
+               return -1;
+
+#if 0
+       /* As per tridge comment this doesn't seem to be needed. JRA */
+       if ((err = ldap_simple_bind_s(ldp, NULL, NULL)) != 0)
+               goto done;
+#endif
+
+       /* Timeout if no response within 20 seconds. */
+       to.tv_sec = 10;
+       to.tv_usec = 0;
+
+       if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)", &attrs[0], 0, &to, &res))
+               goto done;
+
+       if (ldap_count_entries(ldp, res) != 1)
+               goto done;
+
+       values = ldap_get_values(ldp, res, "highestCommittedUSN");
+       if (!values || !values[0])
+               goto done;
+
+       *seq = atoi(values[0]);
+       ret = 0;
+
+  done:
+
+       if (values)
+               ldap_value_free(values);
+       if (res)
+               ldap_msgfree(res);
+       if (ldp)
+               ldap_unbind(ldp);
+       return ret;
+}
+
+/**********************************************************************
+ Get the sequence number for a Windows AD native mode domain using
+ LDAP queries
+**********************************************************************/
+
+int get_ldap_sequence_number( const char* domain, uint32 *seq)
+{
+       int ret = -1;
+       int i;
+       struct in_addr *ip_list = NULL;
+       int count;
+       BOOL list_ordered;
+       
+       if ( !get_dc_list( domain, &ip_list, &count, &list_ordered ) ) {
+               DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
+               return False;
+       }
+
+       if ( !list_ordered )
+       {
+               /* 
+                * Pick a nice close server. Look for DC on local net 
+                * (assuming we don't have a list of preferred DC's)
+                */
+
+               for (i = 0; i < count; i++) {
+                       if (is_zero_ip(ip_list[i]))
+                               continue;
+
+                       if ( !is_local_net(ip_list[i]) )
+                               continue;
+               
+                       if ( (ret = get_ldap_seq( inet_ntoa(ip_list[i]), seq)) == 0 )
+                               goto done;
+               
+                       zero_ip(&ip_list[i]);
+               }
+       
+
+               /*
+                * Secondly try and contact a random PDC/BDC.
+                */
+
+               i = (sys_random() % count);
+
+               if ( !is_zero_ip(ip_list[i]) ) {
+                       if ( (ret = get_ldap_seq( inet_ntoa(ip_list[i]), seq)) == 0 )
+                               goto done;
+               }
+               zero_ip(&ip_list[i]); /* Tried and failed. */
+       }
+
+       /* Finally return first DC that we can contact */
+
+       for (i = 0; i < count; i++) {
+               if (is_zero_ip(ip_list[i]))
+                       continue;
+
+               if ( (ret = get_ldap_seq( inet_ntoa(ip_list[i]), seq)) == 0 )
+                       goto done;
+       }
+
+done:
+       if ( ret == 0 ) {
+               DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence number for Domain (%s) from DC (%s)\n", 
+                       domain, inet_ntoa(ip_list[i])));
+       }
+
+       SAFE_FREE(ip_list);
+
+       return ret;
+}
+
+#endif /* HAVE_LDAP */
+
 /* find the sequence number for a domain */
 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
 {
@@ -704,6 +866,22 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
 
        retry = 0;
        do {
+#ifdef HAVE_LDAP
+               if ( domain->native_mode ) 
+               {
+                       DEBUG(8,("using get_ldap_seq() to retrieve the sequence number\n"));
+
+                       if ( get_ldap_sequence_number( domain->name, seq ) == 0 ) {                     
+                               result = NT_STATUS_OK;
+                               DEBUG(10,("domain_sequence_number: LDAP for domain %s is %u\n",
+                                       domain->name, *seq));
+                               goto done;
+                       }
+
+                       DEBUG(10,("domain_sequence_number: failed to get LDAP sequence number for domain %s\n",
+                       domain->name ));
+               }
+#endif /* HAVE_LDAP */
                /* Get sam handle */
                if (!NT_STATUS_IS_OK(result = cm_get_sam_handle(domain->name, &hnd)))
                        goto done;