You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
/* nmbd.c sets this to True. */
BOOL global_in_nmbd = False;
+/****************************
+ * SERVER AFFINITY ROUTINES *
+ ****************************/
+
+ /* Server affinity is the concept of preferring the last domain
+ controller with whom you had a successful conversation */
+
+/****************************************************************************
+****************************************************************************/
+#define SAFKEY_FMT "SAF/DOMAIN/%s"
+#define SAF_TTL 900
+
+static char *saf_key(const char *domain)
+{
+ char *keystr;
+
+ asprintf( &keystr, SAFKEY_FMT, strupper_static(domain) );
+
+ return keystr;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+BOOL saf_store( const char *domain, const char *servername )
+{
+ char *key;
+ time_t expire;
+ BOOL ret = False;
+
+ if ( !domain || !servername ) {
+ DEBUG(2,("saf_store: Refusing to store empty domain or servername!\n"));
+ return False;
+ }
+
+ if ( (strlen(domain) == 0) || (strlen(servername) == 0) ) {
+ DEBUG(0,("saf_store: refusing to store 0 length domain or servername!\n"));
+ return False;
+ }
+
+ if ( !gencache_init() )
+ return False;
+
+ key = saf_key( domain );
+ expire = time( NULL ) + SAF_TTL;
+
+
+ DEBUG(10,("saf_store: domain = [%s], server = [%s], expire = [%u]\n",
+ domain, servername, (unsigned int)expire ));
+
+ ret = gencache_set( key, servername, expire );
+
+ SAFE_FREE( key );
+
+ return ret;
+}
+
+BOOL saf_delete( const char *domain )
+{
+ char *key;
+ BOOL ret = False;
+
+ if ( !domain ) {
+ DEBUG(2,("saf_delete: Refusing to delete empty domain\n"));
+ return False;
+ }
+
+ if ( !gencache_init() )
+ return False;
+
+ key = saf_key(domain);
+ ret = gencache_del(key);
+
+ if (ret) {
+ DEBUG(10,("saf_delete: domain = [%s]\n", domain ));
+ }
+
+ SAFE_FREE( key );
+
+ return ret;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+char *saf_fetch( const char *domain )
+{
+ char *server = NULL;
+ time_t timeout;
+ BOOL ret = False;
+ char *key = NULL;
+
+ if ( !domain || strlen(domain) == 0) {
+ DEBUG(2,("saf_fetch: Empty domain name!\n"));
+ return NULL;
+ }
+
+ if ( !gencache_init() )
+ return False;
+
+ key = saf_key( domain );
+
+ ret = gencache_get( key, &server, &timeout );
+
+ SAFE_FREE( key );
+
+ if ( !ret ) {
+ DEBUG(5,("saf_fetch: failed to find server for \"%s\" domain\n", domain ));
+ } else {
+ DEBUG(5,("saf_fetch: Returning \"%s\" for \"%s\" domain\n",
+ server, domain ));
+ }
+
+ return server;
+}
+
/****************************************************************************
Generate a random trn_id.
****************************************************************************/
Parse a node status response into an array of structures.
****************************************************************************/
-static struct node_status *parse_node_status(char *p, int *num_names)
+static NODE_STATUS_STRUCT *parse_node_status(char *p, int *num_names, struct node_status_extra *extra)
{
- struct node_status *ret;
+ NODE_STATUS_STRUCT *ret;
int i;
*num_names = CVAL(p,0);
if (*num_names == 0)
return NULL;
- ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names));
- if (!ret) return NULL;
+ ret = SMB_MALLOC_ARRAY(NODE_STATUS_STRUCT,*num_names);
+ if (!ret)
+ return NULL;
p++;
for (i=0;i< *num_names;i++) {
DEBUG(10, ("%s#%02x: flags = 0x%02x\n", ret[i].name,
ret[i].type, ret[i].flags));
}
+ /*
+ * Also, pick up the MAC address ...
+ */
+ if (extra) {
+ memcpy(&extra->mac_addr, p, 6); /* Fill in the mac addr */
+ }
return ret;
}
structures holding the returned names or NULL if the query failed.
**************************************************************************/
-struct node_status *node_status_query(int fd,struct nmb_name *name,
- struct in_addr to_ip, int *num_names)
+NODE_STATUS_STRUCT *node_status_query(int fd,struct nmb_name *name,
+ struct in_addr to_ip, int *num_names,
+ struct node_status_extra *extra)
{
BOOL found=False;
int retries = 2;
struct packet_struct p;
struct packet_struct *p2;
struct nmb_packet *nmb = &p.packet.nmb;
- struct node_status *ret;
+ NODE_STATUS_STRUCT *ret;
ZERO_STRUCT(p);
continue;
}
- ret = parse_node_status(&nmb2->answers->rdata[0], num_names);
+ ret = parse_node_status(&nmb2->answers->rdata[0], num_names, extra);
free_packet(p2);
return ret;
}
a servers name given its IP. Return the matched name in *name.
**************************************************************************/
-BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr to_ip, char *name)
+BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr to_ip, fstring name)
{
- struct node_status *status = NULL;
+ NODE_STATUS_STRUCT *status = NULL;
struct nmb_name nname;
int count, i;
int sock;
/* W2K PDC's seem not to respond to '*'#0. JRA */
make_nmb_name(&nname, q_name, q_type);
- status = node_status_query(sock, &nname, to_ip, &count);
+ status = node_status_query(sock, &nname, to_ip, &count, NULL);
close(sock);
if (!status)
goto done;
if (i == count)
goto done;
- pull_ascii(name, status[i].name, 16, 15, STR_TERMINATE);
+ pull_ascii_nstring(name, sizeof(fstring), status[i].name);
/* Store the result in the cache. */
/* but don't store an entry for 0x1c names here. Here we have
compare 2 ldap IPs by nearness to our interfaces - used in qsort
*******************************************************************/
-static int ip_service_compare(struct ip_service *ip1, struct ip_service *ip2)
+int ip_service_compare(struct ip_service *ip1, struct ip_service *ip2)
{
int result;
while (1) {
struct timeval tval2;
- struct in_addr *tmp_ip_list;
GetTimeOfDay(&tval2);
if (TvalDiff(&tval,&tval2) > retry_time) {
continue;
}
- tmp_ip_list = (struct in_addr *)Realloc( ip_list, sizeof( ip_list[0] )
- * ( (*count) + nmb2->answers->rdlength/6 ) );
+ ip_list = SMB_REALLOC_ARRAY( ip_list, struct in_addr,
+ (*count) + nmb2->answers->rdlength/6 );
- if (!tmp_ip_list) {
+ if (!ip_list) {
DEBUG(0,("name_query: Realloc failed.\n"));
- SAFE_FREE(ip_list);
+ free_packet(p2);
+ return( NULL );
}
- ip_list = tmp_ip_list;
-
- if (ip_list) {
- DEBUG(2,("Got a positive name query response from %s ( ", inet_ntoa(p2->ip)));
- for (i=0;i<nmb2->answers->rdlength/6;i++) {
- putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
- DEBUGADD(2,("%s ",inet_ntoa(ip_list[(*count)])));
- (*count)++;
- }
- DEBUGADD(2,(")\n"));
+ DEBUG(2,("Got a positive name query response from %s ( ", inet_ntoa(p2->ip)));
+ for (i=0;i<nmb2->answers->rdlength/6;i++) {
+ putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
+ DEBUGADD(2,("%s ",inet_ntoa(ip_list[(*count)])));
+ (*count)++;
}
+ DEBUGADD(2,(")\n"));
found=True;
retries=0;
BOOL getlmhostsent( XFILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
{
- pstring line;
-
- while(!x_feof(fp) && !x_ferror(fp)) {
- pstring ip,flags,extra;
- const char *ptr;
- char *ptr1;
- int count = 0;
+ pstring line;
- *name_type = -1;
+ while(!x_feof(fp) && !x_ferror(fp)) {
+ pstring ip,flags,extra;
+ const char *ptr;
+ char *ptr1;
+ int count = 0;
- if (!fgets_slash(line,sizeof(pstring),fp))
- continue;
+ *name_type = -1;
- if (*line == '#')
- continue;
+ if (!fgets_slash(line,sizeof(pstring),fp)) {
+ continue;
+ }
- pstrcpy(ip,"");
- pstrcpy(name,"");
- pstrcpy(flags,"");
+ if (*line == '#') {
+ continue;
+ }
- ptr = line;
+ pstrcpy(ip,"");
+ pstrcpy(name,"");
+ pstrcpy(flags,"");
- if (next_token(&ptr,ip ,NULL,sizeof(ip)))
- ++count;
- if (next_token(&ptr,name ,NULL, sizeof(pstring)))
- ++count;
- if (next_token(&ptr,flags,NULL, sizeof(flags)))
- ++count;
- if (next_token(&ptr,extra,NULL, sizeof(extra)))
- ++count;
+ ptr = line;
- if (count <= 0)
- continue;
+ if (next_token(&ptr,ip ,NULL,sizeof(ip)))
+ ++count;
+ if (next_token(&ptr,name ,NULL, sizeof(pstring)))
+ ++count;
+ if (next_token(&ptr,flags,NULL, sizeof(flags)))
+ ++count;
+ if (next_token(&ptr,extra,NULL, sizeof(extra)))
+ ++count;
- if (count > 0 && count < 2)
- {
- DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
- continue;
- }
+ if (count <= 0)
+ continue;
- if (count >= 4)
- {
- DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
- continue;
- }
+ if (count > 0 && count < 2) {
+ DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
+ continue;
+ }
- DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
+ if (count >= 4) {
+ DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
+ continue;
+ }
- if (strchr_m(flags,'G') || strchr_m(flags,'S'))
- {
- DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
- continue;
- }
+ DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
- *ipaddr = *interpret_addr2(ip);
+ if (strchr_m(flags,'G') || strchr_m(flags,'S')) {
+ DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
+ continue;
+ }
- /* Extra feature. If the name ends in '#XX', where XX is a hex number,
- then only add that name type. */
- if((ptr1 = strchr_m(name, '#')) != NULL)
- {
- char *endptr;
+ *ipaddr = *interpret_addr2(ip);
- ptr1++;
- *name_type = (int)strtol(ptr1, &endptr, 16);
+ /* Extra feature. If the name ends in '#XX', where XX is a hex number,
+ then only add that name type. */
+ if((ptr1 = strchr_m(name, '#')) != NULL) {
+ char *endptr;
+ ptr1++;
- if(!*ptr1 || (endptr == ptr1))
- {
- DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
- continue;
- }
+ *name_type = (int)strtol(ptr1, &endptr, 16);
+ if(!*ptr1 || (endptr == ptr1)) {
+ DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
+ continue;
+ }
- *(--ptr1) = '\0'; /* Truncate at the '#' */
- }
+ *(--ptr1) = '\0'; /* Truncate at the '#' */
+ }
- return True;
- }
+ return True;
+ }
- return False;
+ return False;
}
/********************************************************
return False;
/* copy the ip address; port will be PORT_NONE */
- if ( (*return_iplist = (struct ip_service*)malloc(count*sizeof(struct ip_service))) == NULL ) {
+ if ( (*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, count)) == NULL ) {
DEBUG(0,("convert_ip2service: malloc failed for %d enetries!\n", count ));
return False;
}
pstring lmhost_name;
int name_type2;
struct in_addr return_ip;
+ BOOL result = False;
*return_iplist = NULL;
*return_count = 0;
DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
fp = startlmhosts(dyn_LMHOSTSFILE);
- if(fp) {
- while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip)) {
- if (strequal(name, lmhost_name) &&
- ((name_type2 == -1) || (name_type == name_type2))
- ) {
- endlmhosts(fp);
- if ( (*return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service))) == NULL ) {
- DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
- return False;
- }
- (*return_iplist)[0].ip = return_ip;
- (*return_iplist)[0].port = PORT_NONE;
- *return_count = 1;
- return True;
- }
+
+ if ( fp == NULL )
+ return False;
+
+ while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip))
+ {
+
+ if (!strequal(name, lmhost_name))
+ continue;
+
+ if ((name_type2 != -1) && (name_type != name_type2))
+ continue;
+
+ *return_iplist = SMB_REALLOC_ARRAY((*return_iplist), struct ip_service,
+ (*return_count)+1);
+
+ if ((*return_iplist) == NULL) {
+ endlmhosts(fp);
+ DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
+ return False;
}
- endlmhosts(fp);
+
+ (*return_iplist)[*return_count].ip = return_ip;
+ (*return_iplist)[*return_count].port = PORT_NONE;
+ *return_count += 1;
+
+ /* we found something */
+ result = True;
+
+ /* Multiple names only for DC lookup */
+ if (name_type != 0x1c)
+ break;
}
- return False;
+
+ endlmhosts(fp);
+
+ return result;
}
if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
struct in_addr return_ip;
putip((char *)&return_ip,(char *)hp->h_addr);
- *return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service));
+ *return_iplist = SMB_MALLOC_P(struct ip_service);
if(*return_iplist == NULL) {
DEBUG(3,("resolve_hosts: malloc fail !\n"));
return False;
*********************************************************/
static BOOL resolve_ads(const char *name, int name_type,
+ const char *sitename,
struct ip_service **return_iplist, int *return_count)
{
+ int i, j;
+ NTSTATUS status;
+ TALLOC_CTX *ctx;
+ struct dns_rr_srv *dcs = NULL;
+ int numdcs = 0;
+ int numaddrs = 0;
+
+ if ((name_type != 0x1c) && (name_type != KDC_NAME_TYPE))
+ return False;
+
+ DEBUG(5,("resolve_ads: Attempting to resolve DC's for %s using DNS\n",
+ name));
+
+ if ( (ctx = talloc_init("resolve_ads")) == NULL ) {
+ DEBUG(0,("resolve_ads: talloc_init() failed!\n"));
+ return False;
+ }
+
+ if (name_type == KDC_NAME_TYPE) {
+ status = ads_dns_query_kdcs(ctx, name, sitename, &dcs, &numdcs);
+ } else {
+ status = ads_dns_query_dcs(ctx, name, sitename, &dcs, &numdcs);
+ }
+ if ( !NT_STATUS_IS_OK( status ) ) {
+ talloc_destroy(ctx);
+ return False;
+ }
+
+ for (i=0;i<numdcs;i++) {
+ numaddrs += MAX(dcs[i].num_ips,1);
+ }
+
+ if ( (*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, numaddrs)) == NULL ) {
+ DEBUG(0,("resolve_ads: malloc failed for %d entries\n", numaddrs ));
+ talloc_destroy(ctx);
+ return False;
+ }
-#ifdef HAVE_ADS
- if ( name_type == 0x1c ) {
- int count, i = 0;
- char *list = NULL;
- const char *ptr;
- pstring tok;
+ /* now unroll the list of IP addresses */
+
+ *return_count = 0;
+ i = 0;
+ j = 0;
+ while ( i < numdcs && (*return_count<numaddrs) ) {
+ struct ip_service *r = &(*return_iplist)[*return_count];
+
+ r->port = dcs[i].port;
- /* try to lookup the _ldap._tcp.<domain> if we are using ADS */
- if ( lp_security() != SEC_ADS )
- return False;
+ /* If we don't have an IP list for a name, lookup it up */
+
+ if ( !dcs[i].ips ) {
+ r->ip = *interpret_addr2(dcs[i].hostname);
+ i++;
+ j = 0;
+ } else {
+ /* use the IP addresses from the SRV sresponse */
- DEBUG(5,("resolve_hosts: Attempting to resolve DC's for %s using DNS\n",
- name));
+ if ( j >= dcs[i].num_ips ) {
+ i++;
+ j = 0;
+ continue;
+ }
- if (ldap_domain2hostlist(name, &list) != LDAP_SUCCESS)
- return False;
-
- count = count_chars(list, ' ') + 1;
- if ( (*return_iplist = malloc(count * sizeof(struct ip_service))) == NULL ) {
- DEBUG(0,("resolve_hosts: malloc failed for %d entries\n", count ));
- return False;
+ r->ip = dcs[i].ips[j];
+ j++;
}
-
- ptr = list;
- while (next_token(&ptr, tok, " ", sizeof(tok))) {
- unsigned port = LDAP_PORT;
- char *p = strchr(tok, ':');
- if (p) {
- *p = 0;
- port = atoi(p+1);
- }
- (*return_iplist)[i].ip = *interpret_addr2(tok);
- (*return_iplist)[i].port = port;
- /* make sure it is a valid IP. I considered checking the negative
- connection cache, but this is the wrong place for it. Maybe only
- as a hac. After think about it, if all of the IP addresses retuend
- from DNS are dead, what hope does a netbios name lookup have?
- The standard reason for falling back to netbios lookups is that
- our DNS server doesn't know anything about the DC's -- jerry */
+ /* make sure it is a valid IP. I considered checking the negative
+ connection cache, but this is the wrong place for it. Maybe only
+ as a hac. After think about it, if all of the IP addresses retuend
+ from DNS are dead, what hope does a netbios name lookup have?
+ The standard reason for falling back to netbios lookups is that
+ our DNS server doesn't know anything about the DC's -- jerry */
- if ( is_zero_ip((*return_iplist)[i].ip) )
- continue;
-
- i++;
- }
- SAFE_FREE(list);
-
- *return_count = i;
-
- return True;
- } else
-#endif /* HAVE_ADS */
- {
- return False;
+ if ( ! is_zero_ip(r->ip) )
+ (*return_count)++;
}
+
+ talloc_destroy(ctx);
+ return True;
}
/*******************************************************************
resolve_hosts() when looking up DC's via SRV RR entries in DNS
**********************************************************************/
-static BOOL internal_resolve_name(const char *name, int name_type,
- struct ip_service **return_iplist,
- int *return_count, const char *resolve_order)
+BOOL internal_resolve_name(const char *name, int name_type,
+ const char *sitename,
+ struct ip_service **return_iplist,
+ int *return_count, const char *resolve_order)
{
- pstring name_resolve_list;
- fstring tok;
- const char *ptr;
- BOOL allones = (strcmp(name,"255.255.255.255") == 0);
- BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
- BOOL is_address = is_ipaddress(name);
- BOOL result = False;
- int i;
+ pstring name_resolve_list;
+ fstring tok;
+ const char *ptr;
+ BOOL allones = (strcmp(name,"255.255.255.255") == 0);
+ BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
+ BOOL is_address = is_ipaddress(name);
+ BOOL result = False;
+ int i;
- *return_iplist = NULL;
- *return_count = 0;
+ *return_iplist = NULL;
+ *return_count = 0;
- DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type));
+ DEBUG(10, ("internal_resolve_name: looking up %s#%x (sitename %s)\n",
+ name, name_type, sitename ? sitename : NULL));
- if (allzeros || allones || is_address) {
+ if (allzeros || allones || is_address) {
- if ( (*return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service))) == NULL ) {
- DEBUG(0,("internal_resolve_name: malloc fail !\n"));
- return False;
- }
+ if ( (*return_iplist = SMB_MALLOC_P(struct ip_service)) == NULL ) {
+ DEBUG(0,("internal_resolve_name: malloc fail !\n"));
+ return False;
+ }
- if(is_address) {
- /* ignore the port here */
- (*return_iplist)->port = PORT_NONE;
+ if(is_address) {
+ /* ignore the port here */
+ (*return_iplist)->port = PORT_NONE;
- /* if it's in the form of an IP address then get the lib to interpret it */
- if (((*return_iplist)->ip.s_addr = inet_addr(name)) == 0xFFFFFFFF ){
- DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name));
- return False;
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (((*return_iplist)->ip.s_addr = inet_addr(name)) == 0xFFFFFFFF ){
+ DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name));
+ SAFE_FREE(*return_iplist);
+ return False;
+ }
+ } else {
+ (*return_iplist)->ip.s_addr = allones ? 0xFFFFFFFF : 0;
}
- } else {
- (*return_iplist)->ip.s_addr = allones ? 0xFFFFFFFF : 0;
+ *return_count = 1;
+ return True;
}
- *return_count = 1;
- return True;
- }
- /* Check name cache */
+ /* Check name cache */
- if (namecache_fetch(name, name_type, return_iplist, return_count)) {
- /* This could be a negative response */
- return (*return_count > 0);
- }
+ if (namecache_fetch(name, name_type, return_iplist, return_count)) {
+ /* This could be a negative response */
+ return (*return_count > 0);
+ }
- /* set the name resolution order */
+ /* set the name resolution order */
- if ( strcmp( resolve_order, "NULL") == 0 ) {
- DEBUG(8,("internal_resolve_name: all lookups disabled\n"));
- return False;
- }
-
- if ( !resolve_order )
- pstrcpy(name_resolve_list, lp_name_resolve_order());
- else
- pstrcpy(name_resolve_list, resolve_order);
+ if ( strcmp( resolve_order, "NULL") == 0 ) {
+ DEBUG(8,("internal_resolve_name: all lookups disabled\n"));
+ return False;
+ }
- if ( !name_resolve_list[0] )
- ptr = "host";
- else
- ptr = name_resolve_list;
+ if ( !resolve_order ) {
+ pstrcpy(name_resolve_list, lp_name_resolve_order());
+ } else {
+ pstrcpy(name_resolve_list, resolve_order);
+ }
- /* iterate through the name resolution backends */
+ if ( !name_resolve_list[0] ) {
+ ptr = "host";
+ } else {
+ ptr = name_resolve_list;
+ }
+
+ /* iterate through the name resolution backends */
- while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
- if((strequal(tok, "host") || strequal(tok, "hosts"))) {
- if (resolve_hosts(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else if(strequal( tok, "ads")) {
- /* deal with 0x1c names here. This will result in a
- SRV record lookup for _ldap._tcp.<domain> if we
- are using 'security = ads' */
- if (resolve_ads(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else if(strequal( tok, "lmhosts")) {
- if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else if(strequal( tok, "wins")) {
- /* don't resolve 1D via WINS */
- if (name_type != 0x1D &&
- resolve_wins(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else if(strequal( tok, "bcast")) {
- if (name_resolve_bcast(name, name_type, return_iplist, return_count)) {
- result = True;
- goto done;
- }
- } else {
- DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
- }
- }
-
- /* All of the resolve_* functions above have returned false. */
-
- SAFE_FREE(*return_iplist);
- *return_count = 0;
-
- return False;
+ while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
+ if((strequal(tok, "host") || strequal(tok, "hosts"))) {
+ if (resolve_hosts(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "kdc")) {
+ /* deal with KDC_NAME_TYPE names here. This will result in a
+ SRV record lookup */
+ if (resolve_ads(name, KDC_NAME_TYPE, sitename, return_iplist, return_count)) {
+ result = True;
+ /* Ensure we don't namecache this with the KDC port. */
+ name_type = KDC_NAME_TYPE;
+ goto done;
+ }
+ } else if(strequal( tok, "ads")) {
+ /* deal with 0x1c names here. This will result in a
+ SRV record lookup */
+ if (resolve_ads(name, name_type, sitename, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "lmhosts")) {
+ if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "wins")) {
+ /* don't resolve 1D via WINS */
+ if (name_type != 0x1D && resolve_wins(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "bcast")) {
+ if (name_resolve_bcast(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else {
+ DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
+ }
+ }
- done:
+ /* All of the resolve_* functions above have returned false. */
+
+ SAFE_FREE(*return_iplist);
+ *return_count = 0;
+
+ return False;
+
+ done:
- /* Remove duplicate entries. Some queries, notably #1c (domain
- controllers) return the PDC in iplist[0] and then all domain
- controllers including the PDC in iplist[1..n]. Iterating over
- the iplist when the PDC is down will cause two sets of timeouts. */
+ /* Remove duplicate entries. Some queries, notably #1c (domain
+ controllers) return the PDC in iplist[0] and then all domain
+ controllers including the PDC in iplist[1..n]. Iterating over
+ the iplist when the PDC is down will cause two sets of timeouts. */
- if ( *return_count ) {
- *return_count = remove_duplicate_addrs2( *return_iplist, *return_count );
- }
+ if ( *return_count ) {
+ *return_count = remove_duplicate_addrs2( *return_iplist, *return_count );
+ }
- /* Save in name cache */
- if ( DEBUGLEVEL >= 100 ) {
- for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++)
- DEBUG(100, ("Storing name %s of type %d (%s:%d)\n", name,
- name_type, inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
- }
+ /* Save in name cache */
+ if ( DEBUGLEVEL >= 100 ) {
+ for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++)
+ DEBUG(100, ("Storing name %s of type %d (%s:%d)\n", name,
+ name_type, inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
+ }
- namecache_store(name, name_type, *return_count, *return_iplist);
+ namecache_store(name, name_type, *return_count, *return_iplist);
- /* Display some debugging info */
+ /* Display some debugging info */
- if ( DEBUGLEVEL >= 10 ) {
- DEBUG(10, ("internal_resolve_name: returning %d addresses: ",
- *return_count));
+ if ( DEBUGLEVEL >= 10 ) {
+ DEBUG(10, ("internal_resolve_name: returning %d addresses: ", *return_count));
- for (i = 0; i < *return_count; i++)
- DEBUGADD(10, ("%s:%d ", inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
-
- DEBUG(10, ("\n"));
- }
+ for (i = 0; i < *return_count; i++) {
+ DEBUGADD(10, ("%s:%d ", inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
+ }
+ DEBUG(10, ("\n"));
+ }
- return result;
+ return result;
}
/********************************************************
BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
{
struct ip_service *ip_list = NULL;
+ char *sitename = sitename_fetch();
int count = 0;
if (is_ipaddress(name)) {
*return_ip = *interpret_addr2(name);
+ SAFE_FREE(sitename);
return True;
}
- if (internal_resolve_name(name, name_type, &ip_list, &count, lp_name_resolve_order())) {
+ if (internal_resolve_name(name, name_type, sitename, &ip_list, &count, lp_name_resolve_order())) {
int i;
/* only return valid addresses for TCP connections */
{
*return_ip = ip_list[i].ip;
SAFE_FREE(ip_list);
+ SAFE_FREE(sitename);
return True;
}
}
}
SAFE_FREE(ip_list);
+ SAFE_FREE(sitename);
return False;
}
return False;
}
- if (internal_resolve_name(group, 0x1D, &ip_list, &count, lp_name_resolve_order())) {
+ if (internal_resolve_name(group, 0x1D, NULL, &ip_list, &count, lp_name_resolve_order())) {
*master_ip = ip_list[0].ip;
SAFE_FREE(ip_list);
return True;
}
- if(internal_resolve_name(group, 0x1B, &ip_list, &count, lp_name_resolve_order())) {
+ if(internal_resolve_name(group, 0x1B, NULL, &ip_list, &count, lp_name_resolve_order())) {
*master_ip = ip_list[0].ip;
SAFE_FREE(ip_list);
return True;
BOOL get_pdc_ip(const char *domain, struct in_addr *ip)
{
- struct ip_service *ip_list;
- int count;
+ char *sitename = sitename_fetch();
+ struct ip_service *ip_list = NULL;
+ int count = 0;
/* Look up #1B name */
- if (!internal_resolve_name(domain, 0x1b, &ip_list, &count, lp_name_resolve_order()))
+ if (!internal_resolve_name(domain, 0x1b, sitename, &ip_list, &count, lp_name_resolve_order())) {
+ SAFE_FREE(sitename);
return False;
+ }
+
+ SAFE_FREE(sitename);
/* if we get more than 1 IP back we have to assume it is a
multi-homed PDC and not a mess up */
return True;
}
+/* Private enum type for lookups. */
+
+enum dc_lookup_type { DC_NORMAL_LOOKUP, DC_ADS_ONLY, DC_KDC_ONLY };
+
/********************************************************
Get the IP address list of the domain controllers for
a domain.
*********************************************************/
-static BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
- int *count, BOOL ads_only, int *ordered)
+static NTSTATUS get_dc_list(const char *domain, const char *sitename, struct ip_service **ip_list,
+ int *count, enum dc_lookup_type lookup_type, int *ordered)
{
fstring resolve_order;
+ char *saf_servername;
+ pstring pserver;
+ const char *p;
+ char *port_str;
+ int port;
+ fstring name;
+ int num_addresses = 0;
+ int local_count, i, j;
+ struct ip_service *return_iplist = NULL;
+ struct ip_service *auto_ip_list = NULL;
+ BOOL done_auto_lookup = False;
+ int auto_count = 0;
+
+ *ordered = False;
/* if we are restricted to solely using DNS for looking
up a domain controller, make sure that host lookups
fstrcpy( resolve_order, lp_name_resolve_order() );
strlower_m( resolve_order );
- if ( ads_only ) {
- if ( strstr( resolve_order, "host" ) )
+ if ( lookup_type == DC_ADS_ONLY) {
+ if ( strstr( resolve_order, "host" ) ) {
fstrcpy( resolve_order, "ads" );
- else
- fstrcpy( resolve_order, "NULL" );
+
+ /* DNS SRV lookups used by the ads resolver
+ are already sorted by priority and weight */
+ *ordered = True;
+ } else {
+ fstrcpy( resolve_order, "NULL" );
+ }
+ } else if (lookup_type == DC_KDC_ONLY) {
+ /* DNS SRV lookups used by the ads/kdc resolver
+ are already sorted by priority and weight */
+ *ordered = True;
+ fstrcpy( resolve_order, "kdc" );
}
+ /* fetch the server we have affinity for. Add the
+ 'password server' list to a search for our domain controllers */
+
+ saf_servername = saf_fetch( domain);
- *ordered = False;
-
- /* If it's our domain then use the 'password server' parameter. */
-
if ( strequal(domain, lp_workgroup()) || strequal(domain, lp_realm()) ) {
- const char *p;
- char *pserver = lp_passwordserver(); /* UNIX charset. */
- char *port_str;
- int port;
- fstring name;
- int num_addresses = 0;
- int local_count, i, j;
- struct ip_service *return_iplist = NULL;
- struct ip_service *auto_ip_list = NULL;
- BOOL done_auto_lookup = False;
- int auto_count = 0;
-
+ pstr_sprintf( pserver, "%s, %s",
+ saf_servername ? saf_servername : "",
+ lp_passwordserver() );
+ } else {
+ pstr_sprintf( pserver, "%s, *",
+ saf_servername ? saf_servername : "" );
+ }
- if (!*pserver)
- return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order);
-
- 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, "*")) {
- if ( internal_resolve_name(domain, 0x1C, &auto_ip_list, &auto_count, resolve_order) )
- num_addresses += auto_count;
- done_auto_lookup = True;
- DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count));
- }
- else
- num_addresses++;
+ SAFE_FREE( saf_servername );
+
+ /* if we are starting from scratch, just lookup DOMAIN<0x1c> */
+
+ if ( !*pserver ) {
+ DEBUG(10,("get_dc_list: no preferred domain controllers.\n"));
+ /* TODO: change return type of internal_resolve_name to
+ * NTSTATUS */
+ if (internal_resolve_name(domain, 0x1C, sitename, ip_list, count,
+ resolve_order)) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_NO_LOGON_SERVERS;
}
+ }
- /* 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, resolve_order);
+ DEBUG(3,("get_dc_list: preferred server list: \"%s\"\n", 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
+ */
- /* maybe we just failed? */
-
- if ( num_addresses == 0 ) {
- DEBUG(4,("get_dc_list: no servers found\n"));
- return False;
+ p = pserver;
+ while (next_token(&p,name,LIST_SEP,sizeof(name))) {
+ if (strequal(name, "*")) {
+ if (internal_resolve_name(domain, 0x1C, sitename, &auto_ip_list,
+ &auto_count, resolve_order))
+ num_addresses += auto_count;
+ done_auto_lookup = True;
+ DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count));
+ } else {
+ num_addresses++;
}
-
- if ( (return_iplist = (struct ip_service *)
- malloc(num_addresses * sizeof(struct ip_service))) == NULL )
- {
- DEBUG(3,("get_dc_list: malloc fail !\n"));
- return False;
+ }
+
+ /* if we have no addresses and haven't done the auto lookup, then
+ just return the list of DC's. Or maybe we just failed. */
+
+ if ( (num_addresses == 0) ) {
+ if ( done_auto_lookup ) {
+ DEBUG(4,("get_dc_list: no servers found\n"));
+ SAFE_FREE(auto_ip_list);
+ return NT_STATUS_NO_LOGON_SERVERS;
+ }
+ if (internal_resolve_name(domain, 0x1C, sitename, ip_list, count,
+ resolve_order)) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_NO_LOGON_SERVERS;
}
+ }
- p = pserver;
- local_count = 0;
+ if ( (return_iplist = SMB_MALLOC_ARRAY(struct ip_service, num_addresses)) == NULL ) {
+ DEBUG(3,("get_dc_list: malloc fail !\n"));
+ SAFE_FREE(auto_ip_list);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ p = pserver;
+ local_count = 0;
- /* fill in the return list now with real IP's */
+ /* 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;
+ while ( (local_count<num_addresses) && next_token(&p,name,LIST_SEP,sizeof(name)) ) {
+ struct in_addr name_ip;
- /* copy any addersses from the auto lookup */
+ /* copy any addersses from the auto lookup */
- if ( strequal(name, "*") ) {
- for ( j=0; j<auto_count; j++ ) {
- return_iplist[local_count].ip = auto_ip_list[j].ip;
- return_iplist[local_count].port = auto_ip_list[j].port;
- local_count++;
+ if ( strequal(name, "*") ) {
+ for ( j=0; j<auto_count; j++ ) {
+ /* Check for and don't copy any known bad DC IP's. */
+ if(!NT_STATUS_IS_OK(check_negative_conn_cache(domain,
+ inet_ntoa(auto_ip_list[j].ip)))) {
+ DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n",
+ inet_ntoa(auto_ip_list[j].ip) ));
+ continue;
}
- continue;
+ return_iplist[local_count].ip = auto_ip_list[j].ip;
+ return_iplist[local_count].port = auto_ip_list[j].port;
+ local_count++;
}
+ continue;
+ }
- /* added support for address:port syntax for ads (not that I think
- anyone will ever run the LDAP server in an AD domain on something
- other than port 389 */
+ /* added support for address:port syntax for ads (not that I think
+ anyone will ever run the LDAP server in an AD domain on something
+ other than port 389 */
- port = (lp_security() == SEC_ADS) ? LDAP_PORT : PORT_NONE;
- if ( (port_str=strchr(name, ':')) != NULL ) {
- *port_str = '\0';
- port_str++;
- port = atoi( port_str );
- }
+ port = (lp_security() == SEC_ADS) ? LDAP_PORT : PORT_NONE;
+ if ( (port_str=strchr(name, ':')) != NULL ) {
+ *port_str = '\0';
+ port_str++;
+ port = atoi( port_str );
+ }
- /* explicit lookup; resolve_name() will handle names & IP addresses */
- if ( resolve_name( name, &name_ip, 0x20 ) ) {
- return_iplist[local_count].ip = name_ip;
- return_iplist[local_count].port = port;
- local_count++;
- *ordered = True;
+ /* explicit lookup; resolve_name() will handle names & IP addresses */
+ if ( resolve_name( name, &name_ip, 0x20 ) ) {
+
+ /* Check for and don't copy any known bad DC IP's. */
+ if( !NT_STATUS_IS_OK(check_negative_conn_cache(domain, inet_ntoa(name_ip))) ) {
+ DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n",name ));
+ continue;
}
+
+ return_iplist[local_count].ip = name_ip;
+ return_iplist[local_count].port = port;
+ local_count++;
+ *ordered = True;
}
+ }
- SAFE_FREE(auto_ip_list);
+ SAFE_FREE(auto_ip_list);
- /* need to remove duplicates in the list if we have any
- explicit password servers */
-
- if ( local_count )
- local_count = remove_duplicate_addrs2( return_iplist, local_count );
+ /* need to remove duplicates in the list if we have any
+ explicit password servers */
+
+ if ( local_count ) {
+ local_count = remove_duplicate_addrs2( return_iplist, local_count );
+ }
- if ( DEBUGLEVEL >= 4 ) {
- DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count,
- *ordered ? "":"un"));
- DEBUG(4,("get_dc_list: "));
- for ( i=0; i<local_count; i++ )
- DEBUGADD(4,("%s:%d ", inet_ntoa(return_iplist[i].ip), return_iplist[i].port ));
- DEBUGADD(4,("\n"));
- }
+ if ( DEBUGLEVEL >= 4 ) {
+ DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count,
+ *ordered ? "":"un"));
+ DEBUG(4,("get_dc_list: "));
+ for ( i=0; i<local_count; i++ )
+ DEBUGADD(4,("%s:%d ", inet_ntoa(return_iplist[i].ip), return_iplist[i].port ));
+ DEBUGADD(4,("\n"));
+ }
- *ip_list = return_iplist;
- *count = local_count;
+ *ip_list = return_iplist;
+ *count = local_count;
- return (*count != 0);
- }
-
- DEBUG(10,("get_dc_list: defaulting to internal auto lookup for domain %s\n", domain));
-
- return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order);
+ return ( *count != 0 ? NT_STATUS_OK : NT_STATUS_NO_LOGON_SERVERS );
}
/*********************************************************************
- small wrapper function to get the DC list and sort it if neccessary
+ Small wrapper function to get the DC list and sort it if neccessary.
*********************************************************************/
-BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *count, BOOL ads_only )
+
+NTSTATUS get_sorted_dc_list( const char *domain, const char *sitename, struct ip_service **ip_list, int *count, BOOL ads_only )
{
BOOL ordered;
-
- DEBUG(8,("get_sorted_dc_list: attempting lookup using [%s]\n",
+ NTSTATUS status;
+ enum dc_lookup_type lookup_type = DC_NORMAL_LOOKUP;
+
+ DEBUG(8,("get_sorted_dc_list: attempting lookup for name %s (sitename %s) "
+ "using [%s]\n",
+ domain,
+ sitename ? sitename : "NULL",
(ads_only ? "ads" : lp_name_resolve_order())));
- if ( !get_dc_list(domain, ip_list, count, ads_only, &ordered) )
- return False;
+ if (ads_only) {
+ lookup_type = DC_ADS_ONLY;
+ }
+
+ status = get_dc_list(domain, sitename, ip_list, count, lookup_type, &ordered);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
/* only sort if we don't already have an ordered list */
- if ( !ordered )
+ if ( !ordered ) {
sort_ip_list2( *ip_list, *count );
+ }
- return True;
+ return NT_STATUS_OK;
}
+/*********************************************************************
+ Get the KDC list - re-use all the logic in get_dc_list.
+*********************************************************************/
+
+NTSTATUS get_kdc_list( const char *realm, const char *sitename, struct ip_service **ip_list, int *count)
+{
+ BOOL ordered;
+ NTSTATUS status;
+
+ *count = 0;
+ *ip_list = NULL;
+
+ status = get_dc_list(realm, sitename, ip_list, count, DC_KDC_ONLY, &ordered);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* only sort if we don't already have an ordered list */
+ if ( !ordered ) {
+ sort_ip_list2( *ip_list, *count );
+ }
+
+ return NT_STATUS_OK;
+}