summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/nsswitch/winbindd_cm.c168
1 files changed, 110 insertions, 58 deletions
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c
index 02162bbd23..3175860a79 100644
--- a/source3/nsswitch/winbindd_cm.c
+++ b/source3/nsswitch/winbindd_cm.c
@@ -90,12 +90,113 @@ struct get_dc_name_cache {
struct get_dc_name_cache *prev, *next;
};
+
+/*
+ find the DC for a domain using methods appropriate for a ADS domain
+*/
+static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name)
+{
+ ADS_STRUCT *ads;
+ ads = ads_init_simple();
+ if (!ads) {
+ return False;
+ }
+
+ DEBUG(4,("cm_ads_find_dc: realm=%s\n", ads->realm));
+
+#ifdef HAVE_ADS
+ /* a full ads_connect() is actually overkill, as we don't srictly need
+ to do the SASL auth in order to get the info we need, but libads
+ doesn't offer a better way right now */
+ ads_connect(ads);
+#endif
+
+ fstrcpy(srv_name, ads->ldap_server_name);
+ strupper(srv_name);
+ *dc_ip = ads->ldap_ip;
+ ads_destroy(&ads);
+
+ if (!*srv_name || is_zero_ip(*dc_ip)) {
+ return False;
+ }
+
+ DEBUG(4,("cm_ads_find_dc: using server='%s' IP=%s\n",
+ srv_name, inet_ntoa(*dc_ip)));
+
+ return True;
+}
+
+/*
+ find the DC for a domain using methods appropriate for a RPC domain
+*/
+static BOOL cm_rpc_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name)
+{
+ struct in_addr *ip_list = NULL;
+ int count, i;
+
+ /* Lookup domain controller name. Try the real PDC first to avoid
+ SAM sync delays */
+ if (!get_dc_list(True, domain, &ip_list, &count)) {
+ if (!get_dc_list(False, domain, &ip_list, &count)) {
+ DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
+ return False;
+ }
+ }
+
+ /* Pick a nice close server */
+ /* Look for DC on local net */
+ for (i = 0; i < count; i++) {
+ if (!is_local_net(ip_list[i]))
+ continue;
+
+ if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
+ *dc_ip = ip_list[i];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ zero_ip(&ip_list[i]);
+ }
+
+ /*
+ * Secondly try and contact a random PDC/BDC.
+ */
+
+ i = (sys_random() % count);
+
+ if (!is_zero_ip(ip_list[i]) &&
+ name_status_find(domain, 0x1c, 0x20,
+ ip_list[i], srv_name)) {
+ *dc_ip = ip_list[i];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ zero_ip(&ip_list[i]); /* Tried and failed. */
+
+ /* Finally return first DC that we can contact using a node
+ status */
+ for (i = 0; i < count; i++) {
+ if (is_zero_ip(ip_list[i]))
+ continue;
+
+ if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
+ *dc_ip = ip_list[i];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ }
+
+ SAFE_FREE(ip_list);
+
+ return False;
+}
+
+
static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
{
static struct get_dc_name_cache *get_dc_name_cache;
struct get_dc_name_cache *dcc;
- struct in_addr *ip_list, dc_ip;
- int count, i;
+ struct in_addr dc_ip;
+ BOOL ret;
/* Check the cache for previous lookups */
@@ -144,66 +245,19 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr
DLIST_ADD(get_dc_name_cache, dcc);
- /* Lookup domain controller name. Try the real PDC first to avoid
- SAM sync delays */
- if (!get_dc_list(True, domain, &ip_list, &count)) {
- if (!get_dc_list(False, domain, &ip_list, &count)) {
- DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
- return False;
- }
- }
-
- /* Pick a nice close server */
- /* Look for DC on local net */
-
- for (i = 0; i < count; i++) {
- if (!is_local_net(ip_list[i]))
- continue;
-
- if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
- dc_ip = ip_list[i];
- goto done;
- }
- zero_ip(&ip_list[i]);
- }
-
- /*
- * Secondly try and contact a random PDC/BDC.
- */
-
- i = (sys_random() % count);
+ zero_ip(&dc_ip);
- if (!is_zero_ip(ip_list[i]) &&
- name_status_find(domain, 0x1c, 0x20,
- ip_list[i], srv_name)) {
- dc_ip = ip_list[i];
- goto done;
+ if (lp_security() == SEC_ADS) {
+ ret = cm_ads_find_dc(domain, &dc_ip, srv_name);
+ } else {
+ ret = cm_rpc_find_dc(domain, &dc_ip, srv_name);
}
- 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 (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
- dc_ip = ip_list[i];
- goto done;
- }
+ if (!ret) {
+ return False;
}
- /* No-one to talk to )-: */
- return False; /* Boo-hoo */
-
- done:
- /* We have the netbios name and IP address of a domain controller.
- Ideally we should sent a SAMLOGON request to determine whether
- the DC is alive and kicking. If we can catch a dead DC before
- performing a cli_connect() we can avoid a 30-second timeout. */
-
/* We have a name so make the cache entry positive now */
-
fstrcpy(dcc->srv_name, srv_name);
DEBUG(3, ("cm_get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
@@ -211,8 +265,6 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr
*ip_out = dc_ip;
- SAFE_FREE(ip_list);
-
return True;
}