summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/auth/auth_domain.c5
-rw-r--r--source3/libads/ldap.c3
-rw-r--r--source3/libsmb/namequery.c126
-rw-r--r--source3/nsswitch/winbindd_cm.c7
-rw-r--r--source3/utils/net_lookup.c3
5 files changed, 115 insertions, 29 deletions
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c
index 2a6614e28e..eebe647ec0 100644
--- a/source3/auth/auth_domain.c
+++ b/source3/auth/auth_domain.c
@@ -275,6 +275,7 @@ static NTSTATUS find_connect_pdc(struct cli_state **cli,
NTSTATUS nt_status = NT_STATUS_NO_LOGON_SERVERS;
time_t time_now = time(NULL);
BOOL use_pdc_only = False;
+ BOOL list_ordered;
/*
* If the time the machine password has changed
@@ -301,7 +302,7 @@ static NTSTATUS find_connect_pdc(struct cli_state **cli,
count = 1;
} else {
- if (!get_dc_list(domain, &ip_list, &count))
+ if (!get_dc_list(domain, &ip_list, &count, &list_ordered))
return NT_STATUS_NO_LOGON_SERVERS;
}
@@ -310,7 +311,7 @@ static NTSTATUS find_connect_pdc(struct cli_state **cli,
* network address as any of our interfaces.
*/
for(i = 0; i < count; i++) {
- if(!is_local_net(ip_list[i]))
+ if( !list_ordered && !is_local_net(ip_list[i]) )
continue;
if(NT_STATUS_IS_OK(nt_status =
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 60427323b0..fcb96dd174 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -186,6 +186,7 @@ static BOOL ads_try_netbios(ADS_STRUCT *ads)
int count;
int i;
const char *workgroup = ads->server.workgroup;
+ BOOL list_ordered;
if (!workgroup) {
workgroup = lp_workgroup();
@@ -202,7 +203,7 @@ static BOOL ads_try_netbios(ADS_STRUCT *ads)
}
/* now any DC, including backups */
- if (get_dc_list(workgroup, &ip_list, &count)) {
+ if (get_dc_list(workgroup, &ip_list, &count, &list_ordered)) {
for (i=0;i<count;i++) {
DEBUG(6,("ads_try_netbios: trying server '%s'\n",
inet_ntoa(ip_list[i])));
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 5c3d942b90..6190c872ee 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -1235,19 +1235,24 @@ BOOL get_pdc_ip(const char *domain, struct in_addr *ip)
a domain.
*********************************************************/
-BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count)
+BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count, int *ordered)
{
- /*
- * If it's our domain then
- * use the 'password server' parameter.
- */
+
+ *ordered = False;
+
+ /* If it's our domain then use the 'password server' parameter. */
if (strequal(domain, lp_workgroup())) {
- const char *p;
- char *pserver = lp_passwordserver();
+ char *p;
+ char *pserver = lp_passwordserver(); /* UNIX charset. */
fstring name;
- int num_adresses = 0;
+ int num_addresses = 0;
+ int local_count, i, j;
struct in_addr *return_iplist = NULL;
+ struct in_addr *auto_ip_list = NULL;
+ BOOL done_auto_lookup = False;
+ int auto_count = 0;
+
if (!*pserver)
return internal_resolve_name(
@@ -1255,19 +1260,31 @@ BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count)
p = pserver;
+ /*
+ * if '*' appears in the "password server" list then add
+ * an auto lookup to the list of manually configured
+ * DC's. If any DC is listed by name, then the list should be
+ * considered to be ordered
+ */
+
while (next_token(&p,name,LIST_SEP,sizeof(name))) {
- if (strequal(name, "*"))
- return internal_resolve_name(
- domain, 0x1C, ip_list, count);
- num_adresses++;
+ if (strequal(name, "*")) {
+ if ( internal_resolve_name(domain, 0x1C, &auto_ip_list, &auto_count) )
+ num_addresses += auto_count;
+ done_auto_lookup = True;
+ DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count));
+ }
+ else
+ num_addresses++;
}
- if (num_adresses == 0)
- return internal_resolve_name(
- domain, 0x1C, ip_list, count);
+ /* if we have no addresses and haven't done the auto lookup, then
+ just return the list of DC's */
+
+ if ( (num_addresses == 0) && !done_auto_lookup )
+ return internal_resolve_name(domain, 0x1C, ip_list, count);
- return_iplist = (struct in_addr *)malloc(
- num_adresses * sizeof(struct in_addr));
+ return_iplist = (struct in_addr *)malloc(num_addresses * sizeof(struct in_addr));
if (return_iplist == NULL) {
DEBUG(3,("get_dc_list: malloc fail !\n"));
@@ -1275,19 +1292,84 @@ BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count)
}
p = pserver;
- *count = 0;
+ local_count = 0;
- while (next_token(&p,name,LIST_SEP,sizeof(name))) {
+ /* fill in the return list now with real IP's */
+
+ while ( (local_count<num_addresses) && next_token(&p,name,LIST_SEP,sizeof(name)) )
+ {
struct in_addr name_ip;
- if (resolve_name( name, &name_ip, 0x20) == False)
+
+ /* copy any addersses from the auto lookup */
+
+ if ( strequal(name, "*") ) {
+ for ( j=0; j<auto_count; j++ )
+ return_iplist[local_count++] = auto_ip_list[j];
continue;
- return_iplist[(*count)++] = name_ip;
+ }
+
+ /* explicit lookup */
+
+ if ( resolve_name( name, &name_ip, 0x20) ) {
+ return_iplist[local_count++] = name_ip;
+ *ordered = True;
+ }
+
}
-
+
+ /* need to remove duplicates in the list if we have
+ any explicit password servers */
+
+ if ( *ordered )
+ {
+ int hole_index = -1;
+
+ /* one loop to remove duplicates */
+ for ( i=0; i<local_count; i++ )
+ {
+ if ( is_zero_ip(return_iplist[i]) )
+ continue;
+
+ for ( j=i+1; j<local_count; j++ ) {
+ if ( ip_equal( return_iplist[i], return_iplist[j]) )
+ zero_ip(&return_iplist[j]);
+ }
+ }
+
+ /* one loop to clean up any holes we left */
+ /* first ip can never be a zero_ip() */
+ i = 0;
+ while ( i<local_count )
+ {
+ if ( !is_zero_ip(return_iplist[i]) ) {
+ i++;
+ continue;
+ }
+
+ hole_index = i;
+ i++;
+
+ while ( i<local_count ) {
+ if ( !is_zero_ip(return_iplist[i]) )
+ return_iplist[hole_index++] = return_iplist[i];
+ i++;
+ }
+
+ /* we should exit the loop implicitly here, but ... */
+ break;
+ }
+
+ local_count = hole_index;
+ }
+
*ip_list = return_iplist;
+ *count = local_count;
+
+ DEBUG(8,("get_dc_list: return %d ip addresses\n", *count));
return (*count != 0);
}
return internal_resolve_name(domain, 0x1C, ip_list, count);
}
+
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c
index d44219d172..403bc38052 100644
--- a/source3/nsswitch/winbindd_cm.c
+++ b/source3/nsswitch/winbindd_cm.c
@@ -142,8 +142,9 @@ static BOOL cm_rpc_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr
{
struct in_addr *ip_list = NULL;
int count, i;
+ BOOL list_ordered;
- if (!get_dc_list(domain, &ip_list, &count)) {
+ if (!get_dc_list(domain, &ip_list, &count, &list_ordered)) {
struct in_addr pdc_ip;
if (!get_pdc_ip(domain, &pdc_ip)) {
@@ -161,8 +162,8 @@ static BOOL cm_rpc_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr
count = 1;
}
- /* Pick a nice close server */
- if (count > 1) {
+ /* Pick a nice close server, but only if the list was not ordered */
+ if (!list_ordered && (count > 1) ) {
qsort(ip_list, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
}
diff --git a/source3/utils/net_lookup.c b/source3/utils/net_lookup.c
index 32921de620..271094480c 100644
--- a/source3/utils/net_lookup.c
+++ b/source3/utils/net_lookup.c
@@ -128,6 +128,7 @@ static int net_lookup_dc(int argc, const char **argv)
char *pdc_str = NULL;
const char *domain=opt_target_workgroup;
int count, i;
+ BOOL list_ordered;
if (argc > 0)
domain=argv[0];
@@ -139,7 +140,7 @@ static int net_lookup_dc(int argc, const char **argv)
asprintf(&pdc_str, "%s", inet_ntoa(addr));
d_printf("%s\n", pdc_str);
- if (!get_dc_list(domain, &ip_list, &count)) {
+ if (!get_dc_list(domain, &ip_list, &count, &list_ordered)) {
SAFE_FREE(pdc_str);
return 0;
}