#include "includes.h"
BOOL global_in_nmbd = False;
static int generate_trn_id(void)
{
static int trn_id;
if (trn_id == 0) {
sys_srandom(sys_getpid());
}
trn_id = sys_random();
return trn_id % (unsigned)0x7FFF;
}
static struct node_status *parse_node_status(char *p, int *num_names, struct node_status_extra *extra)
{
struct node_status *ret;
int i;
*num_names = CVAL(p,0);
if (*num_names == 0)
return NULL;
ret = SMB_MALLOC_ARRAY(struct node_status,*num_names);
if (!ret)
return NULL;
p++;
for (i=0;i< *num_names;i++) {
StrnCpy(ret[i].name,p,15);
trim_char(ret[i].name,'\0',' ');
ret[i].type = CVAL(p,15);
ret[i].flags = p[16];
p += 18;
DEBUG(10, ("%s#%02x: flags = 0x%02x\n", ret[i].name,
ret[i].type, ret[i].flags));
}
if (extra) {
memcpy(&extra->mac_addr, p, 6);
}
return ret;
}
struct node_status *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;
int retry_time = 2000;
struct timeval tval;
struct packet_struct p;
struct packet_struct *p2;
struct nmb_packet *nmb = &p.packet.nmb;
struct node_status *ret;
ZERO_STRUCT(p);
nmb->header.name_trn_id = generate_trn_id();
nmb->header.opcode = 0;
nmb->header.response = False;
nmb->header.nm_flags.bcast = False;
nmb->header.nm_flags.recursion_available = False;
nmb->header.nm_flags.recursion_desired = False;
nmb->header.nm_flags.trunc = False;
nmb->header.nm_flags.authoritative = False;
nmb->header.rcode = 0;
nmb->header.qdcount = 1;
nmb->header.ancount = 0;
nmb->header.nscount = 0;
nmb->header.arcount = 0;
nmb->question.question_name = *name;
nmb->question.question_type = 0x21;
nmb->question.question_class = 0x1;
p.ip = to_ip;
p.port = NMB_PORT;
p.fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
GetTimeOfDay(&tval);
if (!send_packet(&p))
return NULL;
retries--;
while (1) {
struct timeval tval2;
GetTimeOfDay(&tval2);
if (TvalDiff(&tval,&tval2) > retry_time) {
if (!retries)
break;
if (!found && !send_packet(&p))
return NULL;
GetTimeOfDay(&tval);
retries--;
}
if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
struct nmb_packet *nmb2 = &p2->packet.nmb;
debug_nmb_packet(p2);
if (nmb2->header.opcode != 0 ||
nmb2->header.nm_flags.bcast ||
nmb2->header.rcode ||
!nmb2->header.ancount ||
nmb2->answers->rr_type != 0x21) {
free_packet(p2);
continue;
}
ret = parse_node_status(&nmb2->answers->rdata[0], num_names, extra);
free_packet(p2);
return ret;
}
}
return NULL;
}
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;
struct nmb_name nname;
int count, i;
int sock;
BOOL result = False;
if (lp_disable_netbios()) {
DEBUG(5,("name_status_find(%s#%02x): netbios is disabled\n", q_name, q_type));
return False;
}
DEBUG(10, ("name_status_find: looking up %s#%02x at %s\n", q_name,
q_type, inet_ntoa(to_ip)));
if (namecache_status_fetch(q_name, q_type, type, to_ip, name))
return True;
sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True);
if (sock == -1)
goto done;
make_nmb_name(&nname, q_name, q_type);
status = node_status_query(sock, &nname, to_ip, &count, NULL);
close(sock);
if (!status)
goto done;
for (i=0;i<count;i++) {
if (status[i].type == type)
break;
}
if (i == count)
goto done;
pull_ascii_nstring(name, sizeof(fstring), status[i].name);
if ( q_type != 0x1c )
namecache_status_store(q_name, q_type, type, to_ip, name);
result = True;
done:
SAFE_FREE(status);
DEBUG(10, ("name_status_find: name %sfound", result ? "" : "not "));
if (result)
DEBUGADD(10, (", name %s ip address is %s", name, inet_ntoa(to_ip)));
DEBUG(10, ("\n"));
return result;
}
static int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
{
int max_bits1=0, max_bits2=0;
int num_interfaces = iface_count();
int i;
for (i=0;i<num_interfaces;i++) {
struct in_addr ip;
int bits1, bits2;
ip = *iface_n_bcast(i);
bits1 = matching_quad_bits((uchar *)&ip1->s_addr, (uchar *)&ip.s_addr);
bits2 = matching_quad_bits((uchar *)&ip2->s_addr, (uchar *)&ip.s_addr);
max_bits1 = MAX(bits1, max_bits1);
max_bits2 = MAX(bits2, max_bits2);
}
if (iface_local(*ip1)) {
max_bits1 += 32;
}
if (iface_local(*ip2)) {
max_bits2 += 32;
}
return max_bits2 - max_bits1;
}
static int ip_service_compare(struct ip_service *ip1, struct ip_service *ip2)
{
int result;
if ( (result = ip_compare(&ip1->ip, &ip2->ip)) != 0 )
return result;
if ( ip1->port > ip2->port )
return 1;
if ( ip1->port < ip2->port )
return -1;
return 0;
}
static void sort_ip_list(struct in_addr *iplist, int count)
{
if (count <= 1) {
return;
}
qsort(iplist, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
}
static void sort_ip_list2(struct ip_service *iplist, int count)
{
if (count <= 1) {
return;
}
qsort(iplist, count, sizeof(struct ip_service), QSORT_CAST ip_service_compare);
}
static int remove_duplicate_addrs2( struct ip_service *iplist, int count )
{
int i, j;
DEBUG(10,("remove_duplicate_addrs2: looking for duplicate address/port pairs\n"));
for ( i=0; i<count; i++ ) {
if ( is_zero_ip(iplist[i].ip) )
continue;
for ( j=i+1; j<count; j++ ) {
if ( ip_service_equal(iplist[i], iplist[j]) )
zero_ip(&iplist[j].ip);
}
}
for (i = 0; i<count; ) {
if ( is_zero_ip(iplist[i].ip) ) {
if (i != count-1 )
memmove(&iplist[i], &iplist[i+1], (count - i - 1)*sizeof(iplist[i]));
count--;
continue;
}
i++;
}
return count;
}
struct in_addr *name_query(int fd,const char *name,int name_type,
BOOL bcast,BOOL recurse,
struct in_addr to_ip, int *count, int *flags,
BOOL *timed_out)
{
BOOL found=False;
int i, retries = 3;
int retry_time = bcast?250:2000;
struct timeval tval;
struct packet_struct p;
struct packet_struct *p2;
struct nmb_packet *nmb = &p.packet.nmb;
struct in_addr *ip_list = NULL;
if (lp_disable_netbios()) {
DEBUG(5,("name_query(%s#%02x): netbios is disabled\n", name, name_type));
return NULL;
}
if (timed_out) {
*timed_out = False;
}
memset((char *)&p,'\0',sizeof(p));
(*count) = 0;
(*flags) = 0;
nmb->header.name_trn_id = generate_trn_id();
nmb->header.opcode = 0;
nmb->header.response = False;
nmb->header.nm_flags.bcast = bcast;
nmb->header.nm_flags.recursion_available = False;
nmb->header.nm_flags.recursion_desired = recurse;
nmb->header.nm_flags.trunc = False;
nmb->header.nm_flags.authoritative = False;
nmb->header.rcode = 0;
nmb->header.qdcount = 1;
nmb->header.ancount = 0;
nmb->header.nscount = 0;
nmb->header.arcount = 0;
make_nmb_name(&nmb->question.question_name,name,name_type);
nmb->question.question_type = 0x20;
nmb->question.question_class = 0x1;
p.ip = to_ip;
p.port = NMB_PORT;
p.fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
GetTimeOfDay(&tval);
if (!send_packet(&p))
return NULL;
retries--;
while (1) {
struct timeval tval2;
struct in_addr *tmp_ip_list;
GetTimeOfDay(&tval2);
if (TvalDiff(&tval,&tval2) > retry_time) {
if (!retries)
break;
if (!found && !send_packet(&p))
return NULL;
GetTimeOfDay(&tval);
retries--;
}
if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
struct nmb_packet *nmb2 = &p2->packet.nmb;
debug_nmb_packet(p2);
if( 0 == nmb2->header.opcode
&& !(bcast)
&& nmb2->header.rcode
) {
if( DEBUGLVL( 3 ) ) {
dbgtext( "Negative name query response, rcode 0x%02x: ", nmb2->header.rcode );
switch( nmb2->header.rcode ) {
case 0x01:
dbgtext( "Request was invalidly formatted.\n" );
break;
case 0x02:
dbgtext( "Problem with NBNS, cannot process name.\n");
break;
case 0x03:
dbgtext( "The name requested does not exist.\n" );
break;
case 0x04:
dbgtext( "Unsupported request error.\n" );
break;
case 0x05:
dbgtext( "Query refused error.\n" );
break;
default:
dbgtext( "Unrecognized error code.\n" );
break;
}
}
free_packet(p2);
return( NULL );
}
if (nmb2->header.opcode != 0 ||
nmb2->header.nm_flags.bcast ||
nmb2->header.rcode ||
!nmb2->header.ancount) {
free_packet(p2);
continue;
}
tmp_ip_list = SMB_REALLOC_ARRAY( ip_list, struct in_addr,
(*count) + nmb2->answers->rdlength/6 );
if (!tmp_ip_list) {
DEBUG(0,("name_query: Realloc failed.\n"));
SAFE_FREE(ip_list);
}
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"));
}
found=True;
retries=0;
if (nmb2->header.response)
(*flags) |= NM_FLAGS_RS;
if (nmb2->header.nm_flags.authoritative)
(*flags) |= NM_FLAGS_AA;
if (nmb2->header.nm_flags.trunc)
(*flags) |= NM_FLAGS_TC;
if (nmb2->header.nm_flags.recursion_desired)
(*flags) |= NM_FLAGS_RD;
if (nmb2->header.nm_flags.recursion_available)
(*flags) |= NM_FLAGS_RA;
if (nmb2->header.nm_flags.bcast)
(*flags) |= NM_FLAGS_B;
free_packet(p2);
if(!bcast && found)
break;
}
}
if ( !found && timed_out ) {
*timed_out = True;
}
sort_ip_list(ip_list, *count);
return ip_list;
}
XFILE *startlmhosts(char *fname)
{
XFILE *fp = x_fopen(fname,O_RDONLY, 0);
if (!fp) {
DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
fname, strerror(errno)));
return NULL;
}
return fp;
}
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;
*name_type = -1;
if (!fgets_slash(line,sizeof(pstring),fp)) {
continue;
}
if (*line == '#') {
continue;
}
pstrcpy(ip,"");
pstrcpy(name,"");
pstrcpy(flags,"");
ptr = line;
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)
continue;
if (count > 0 && count < 2) {
DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
continue;
}
if (count >= 4) {
DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
continue;
}
DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
if (strchr_m(flags,'G') || strchr_m(flags,'S')) {
DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
continue;
}
*ipaddr = *interpret_addr2(ip);
if((ptr1 = strchr_m(name, '#')) != NULL) {
char *endptr;
ptr1++;
*name_type = (int)strtol(ptr1, &endptr, 16);
if(!*ptr1 || (endptr == ptr1)) {
DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
continue;
}
*(--ptr1) = '\0';
}
return True;
}
return False;
}
void endlmhosts(XFILE *fp)
{
x_fclose(fp);
}
static BOOL convert_ip2service( struct ip_service **return_iplist, struct in_addr *ip_list, int count )
{
int i;
if ( count==0 || !ip_list )
return False;
if ( (*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, count)) == NULL ) {
DEBUG(0,("convert_ip2service: malloc failed for %d enetries!\n", count ));
return False;
}
for ( i=0; i<count; i++ ) {
(*return_iplist)[i].ip = ip_list[i];
(*return_iplist)[i].port = PORT_NONE;
}
return True;
}
BOOL name_resolve_bcast(const char *name, int name_type,
struct ip_service **return_iplist, int *return_count)
{
int sock, i;
int num_interfaces = iface_count();
struct in_addr *ip_list;
BOOL ret;
if (lp_disable_netbios()) {
DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n", name, name_type));
return False;
}
*return_iplist = NULL;
*return_count = 0;
DEBUG(3,("name_resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
sock = open_socket_in( SOCK_DGRAM, 0, 3,
interpret_addr(lp_socket_address()), True );
if (sock == -1) return False;
set_socket_options(sock,"SO_BROADCAST");
for( i = num_interfaces-1; i >= 0; i--) {
struct in_addr sendto_ip;
int flags;
sendto_ip = *iface_n_bcast(i);
ip_list = name_query(sock, name, name_type, True,
True, sendto_ip, return_count, &flags, NULL);
if( ip_list )
goto success;
}
close(sock);
return False;
success:
ret = True;
if ( !convert_ip2service(return_iplist, ip_list, *return_count) )
ret = False;
SAFE_FREE( ip_list );
close(sock);
return ret;
}
BOOL resolve_wins(const char *name, int name_type,
struct ip_service **return_iplist, int *return_count)
{
int sock, t, i;
char **wins_tags;
struct in_addr src_ip, *ip_list = NULL;
BOOL ret;
if (lp_disable_netbios()) {
DEBUG(5,("resolve_wins(%s#%02x): netbios is disabled\n", name, name_type));
return False;
}
*return_iplist = NULL;
*return_count = 0;
DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
if (wins_srv_count() < 1) {
DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
return False;
}
wins_tags = wins_srv_tags();
if (!wins_tags) {
return False;
}
src_ip = *interpret_addr2(lp_socket_address());
for (t=0; wins_tags && wins_tags[t]; t++) {
int srv_count = wins_srv_count_tag(wins_tags[t]);
for (i=0; i<srv_count; i++) {
struct in_addr wins_ip;
int flags;
BOOL timed_out;
wins_ip = wins_srv_ip_tag(wins_tags[t], src_ip);
if (global_in_nmbd && ismyip(wins_ip)) {
continue;
}
if (wins_srv_is_dead(wins_ip, src_ip)) {
continue;
}
DEBUG(3,("resolve_wins: using WINS server %s and tag '%s'\n", inet_ntoa(wins_ip), wins_tags[t]));
sock = open_socket_in(SOCK_DGRAM, 0, 3, src_ip.s_addr, True);
if (sock == -1) {
continue;
}
ip_list = name_query(sock,name,name_type, False,
True, wins_ip, return_count, &flags,
&timed_out);
if ( ip_list )
goto success;
close(sock);
if (timed_out) {
wins_srv_died(wins_ip, src_ip);
} else {
break;
}
}
}
wins_srv_tags_free(wins_tags);
return False;
success:
ret = True;
if ( !convert_ip2service( return_iplist, ip_list, *return_count ) )
ret = False;
SAFE_FREE( ip_list );
wins_srv_tags_free(wins_tags);
close(sock);
return ret;
}
static BOOL resolve_lmhosts(const char *name, int name_type,
struct ip_service **return_iplist, int *return_count)
{
XFILE *fp;
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 == 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) {
DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
return False;
}
(*return_iplist)[*return_count].ip = return_ip;
(*return_iplist)[*return_count].port = PORT_NONE;
*return_count += 1;
result = True;
if (name_type != 0x1c)
break;
}
endlmhosts(fp);
return result;
}
static BOOL resolve_hosts(const char *name, int name_type,
struct ip_service **return_iplist, int *return_count)
{
struct hostent *hp;
if ( name_type != 0x20 && name_type != 0x0) {
DEBUG(5, ("resolve_hosts: not appropriate for name type <0x%x>\n", name_type));
return False;
}
*return_iplist = NULL;
*return_count = 0;
DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x%x>\n", name, name_type));
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 = SMB_MALLOC_P(struct ip_service);
if(*return_iplist == NULL) {
DEBUG(3,("resolve_hosts: malloc fail !\n"));
return False;
}
(*return_iplist)->ip = return_ip;
(*return_iplist)->port = PORT_NONE;
*return_count = 1;
return True;
}
return False;
}
static BOOL resolve_ads(const char *name, int name_type,
struct ip_service **return_iplist, int *return_count)
{
#ifdef HAVE_ADS
if ( name_type == 0x1c ) {
int count, i = 0;
char *list = NULL;
const char *ptr;
pstring tok;
if ( lp_security() != SEC_ADS )
return False;
DEBUG(5,("resolve_hosts: Attempting to resolve DC's for %s using DNS\n",
name));
if (ldap_domain2hostlist(name, &list) != LDAP_SUCCESS)
return False;
count = count_chars(list, ' ') + 1;
if ( (*return_iplist = SMB_MALLOC_ARRAY(struct ip_service, count)) == NULL ) {
DEBUG(0,("resolve_hosts: malloc failed for %d entries\n", count ));
return False;
}
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;
if ( is_zero_ip((*return_iplist)[i].ip) )
continue;
i++;
}
SAFE_FREE(list);
*return_count = i;
return True;
} else
#endif
{
return False;
}
}
static BOOL internal_resolve_name(const char *name, int name_type,
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;
*return_iplist = NULL;
*return_count = 0;
DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type));
if (allzeros || allones || is_address) {
if ( (*return_iplist = SMB_MALLOC_P(struct ip_service)) == NULL ) {
DEBUG(0,("internal_resolve_name: malloc fail !\n"));
return False;
}
if(is_address) {
(*return_iplist)->port = PORT_NONE;
if (((*return_iplist)->ip.s_addr = inet_addr(name)) == 0xFFFFFFFF ){
DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name));
return False;
}
} else {
(*return_iplist)->ip.s_addr = allones ? 0xFFFFFFFF : 0;
}
*return_count = 1;
return True;
}
if (namecache_fetch(name, name_type, return_iplist, return_count)) {
return (*return_count > 0);
}
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 ( !name_resolve_list[0] ) {
ptr = "host";
} else {
ptr = name_resolve_list;
}
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")) {
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")) {
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));
}
}
SAFE_FREE(*return_iplist);
*return_count = 0;
return False;
done:
if ( *return_count ) {
*return_count = remove_duplicate_addrs2( *return_iplist, *return_count );
}
if ( SAMBA_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);
if ( SAMBA_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"));
}
}
return result;
}
BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
{
struct ip_service *ip_list = NULL;
int count = 0;
if (is_ipaddress(name)) {
*return_ip = *interpret_addr2(name);
return True;
}
if (internal_resolve_name(name, name_type, &ip_list, &count, lp_name_resolve_order())) {
int i;
for (i=0; i<count; i++) {
char *ip_str = inet_ntoa(ip_list[i].ip);
if (ip_str &&
strcmp(ip_str, "255.255.255.255") != 0 &&
strcmp(ip_str, "0.0.0.0") != 0)
{
*return_ip = ip_list[i].ip;
SAFE_FREE(ip_list);
return True;
}
}
}
SAFE_FREE(ip_list);
return False;
}
BOOL find_master_ip(const char *group, struct in_addr *master_ip)
{
struct ip_service *ip_list = NULL;
int count = 0;
if (lp_disable_netbios()) {
DEBUG(5,("find_master_ip(%s): netbios is disabled\n", group));
return False;
}
if (internal_resolve_name(group, 0x1D, &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())) {
*master_ip = ip_list[0].ip;
SAFE_FREE(ip_list);
return True;
}
SAFE_FREE(ip_list);
return False;
}
BOOL get_pdc_ip(const char *domain, struct in_addr *ip)
{
struct ip_service *ip_list;
int count;
if (!internal_resolve_name(domain, 0x1b, &ip_list, &count, lp_name_resolve_order())) {
return False;
}
if ( count > 1 ) {
DEBUG(6,("get_pdc_ip: PDC has %d IP addresses!\n", count));
sort_ip_list2( ip_list, count );
}
*ip = ip_list[0].ip;
SAFE_FREE(ip_list);
return True;
}
static BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
int *count, BOOL ads_only, int *ordered)
{
fstring resolve_order;
fstrcpy( resolve_order, lp_name_resolve_order() );
strlower_m( resolve_order );
if ( ads_only ) {
if ( strstr( resolve_order, "host" ) )
fstrcpy( resolve_order, "ads" );
else
fstrcpy( resolve_order, "NULL" );
}
*ordered = False;
if ( strequal(domain, lp_workgroup()) || strequal(domain, lp_realm()) ) {
const char *p;
char *pserver = lp_passwordserver();
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;
if (!*pserver)
return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order);
p = pserver;
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++;
}
}
if ( (num_addresses == 0) && !done_auto_lookup ) {
return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order);
}
if ( num_addresses == 0 ) {
DEBUG(4,("get_dc_list: no servers found\n"));
return False;
}
if ( (return_iplist = SMB_MALLOC_ARRAY(struct ip_service, num_addresses)) == NULL ) {
DEBUG(3,("get_dc_list: malloc fail !\n"));
return False;
}
p = pserver;
local_count = 0;
while ( (local_count<num_addresses) && next_token(&p,name,LIST_SEP,sizeof(name)) ) {
struct in_addr name_ip;
if ( strequal(name, "*") ) {
for ( j=0; j<auto_count; j++ ) {
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;
}
return_iplist[local_count].ip = auto_ip_list[j].ip;
return_iplist[local_count].port = auto_ip_list[j].port;
local_count++;
}
continue;
}
port = (lp_security() == SEC_ADS) ? LDAP_PORT : PORT_NONE;
if ( (port_str=strchr(name, ':')) != NULL ) {
*port_str = '\0';
port_str++;
port = atoi( port_str );
}
if ( resolve_name( name, &name_ip, 0x20 ) ) {
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);
if ( local_count ) {
local_count = remove_duplicate_addrs2( return_iplist, local_count );
}
if ( SAMBA_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;
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);
}
BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *count, BOOL ads_only )
{
BOOL ordered;
DEBUG(8,("get_sorted_dc_list: attempting lookup using [%s]\n",
(ads_only ? "ads" : lp_name_resolve_order())));
if ( !get_dc_list(domain, ip_list, count, ads_only, &ordered) ) {
return False;
}
if ( !ordered ) {
sort_ip_list2( *ip_list, *count );
}
return True;
}