summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2003-06-23 05:10:07 +0000
committerGerald Carter <jerry@samba.org>2003-06-23 05:10:07 +0000
commit81d8eefc0d7620d5835b991d28bafe3d4f30eee2 (patch)
tree4502a265a52f3916a302ff23ddca31d70b6b18f1
parent5f1ff72f7d314d4bb9762ac11398188719507bc4 (diff)
downloadsamba-81d8eefc0d7620d5835b991d28bafe3d4f30eee2.tar.gz
samba-81d8eefc0d7620d5835b991d28bafe3d4f30eee2.tar.bz2
samba-81d8eefc0d7620d5835b991d28bafe3d4f30eee2.zip
* set domain->last_status = NT_STATUS_SERVER_DISABLED on an ads_connect() failure
* 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)
-rw-r--r--source3/lib/username.c13
-rw-r--r--source3/nsswitch/winbindd_ads.c77
-rw-r--r--source3/nsswitch/winbindd_cache.c20
-rw-r--r--source3/nsswitch/winbindd_group.c24
-rw-r--r--source3/nsswitch/winbindd_rpc.c178
5 files changed, 276 insertions, 36 deletions
diff --git a/source3/lib/username.c b/source3/lib/username.c
index 8130b93c3f..0005372a8f 100644
--- a/source3/lib/username.c
+++ b/source3/lib/username.c
@@ -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);
diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c
index 04eb65637c..b54392a92e 100644
--- a/source3/nsswitch/winbindd_ads.c
+++ b/source3/nsswitch/winbindd_ads.c
@@ -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;
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c
index 5464e765d1..9f7d3686a5 100644
--- a/source3/nsswitch/winbindd_cache.c
+++ b/source3/nsswitch/winbindd_cache.c
@@ -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
diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c
index 41f594fe61..6749f55bff 100644
--- a/source3/nsswitch/winbindd_group.c
+++ b/source3/nsswitch/winbindd_group.c
@@ -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,
diff --git a/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c
index 5710a323e8..7d6055006d 100644
--- a/source3/nsswitch/winbindd_rpc.c
+++ b/source3/nsswitch/winbindd_rpc.c
@@ -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;