From 3db52feb1f3b2c07ce0b06ad4a7099fa6efe3fc7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 13 Dec 1999 13:27:58 +0000 Subject: first pass at updating head branch to be to be the same as the SAMBA_2_0 branch (This used to be commit 453a822a76780063dff23526c35408866d0c0154) --- source3/libsmb/namequery.c | 827 ++++++++++++++++++++++++++++++--------------- 1 file changed, 548 insertions(+), 279 deletions(-) (limited to 'source3/libsmb/namequery.c') diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 299145ceff..abb9b7d42f 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -23,17 +23,15 @@ #include "includes.h" extern pstring scope; -extern pstring global_myname; extern int DEBUGLEVEL; /* nmbd.c sets this to True. */ BOOL global_in_nmbd = False; - static int name_trn_id = 0; - /**************************************************************************** -interpret a node status response + Interpret a node status response. ****************************************************************************/ + static void _interpret_node_status(char *p, char *master,char *rname) { int numnames = CVAL(p,0); @@ -43,55 +41,54 @@ static void _interpret_node_status(char *p, char *master,char *rname) if (master) *master = 0; p += 1; - while (numnames--) - { - char qname[17]; - int type; - fstring flags; - int i; - *flags = 0; - StrnCpy(qname,p,15); - type = CVAL(p,15); - p += 16; - - fstrcat(flags, (p[0] & 0x80) ? " " : " "); - if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B "); - if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P "); - if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M "); - if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H "); - if (p[0] & 0x10) fstrcat(flags," "); - if (p[0] & 0x08) fstrcat(flags," "); - if (p[0] & 0x04) fstrcat(flags," "); - if (p[0] & 0x02) fstrcat(flags," "); - - if (master && !*master && type == 0x1d) { - StrnCpy(master,qname,15); - trim_string(master,NULL," "); - } + while (numnames--) { + char qname[17]; + int type; + fstring flags; + int i; + *flags = 0; + StrnCpy(qname,p,15); + type = CVAL(p,15); + p += 16; + + fstrcat(flags, (p[0] & 0x80) ? " " : " "); + if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B "); + if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P "); + if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M "); + if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H "); + if (p[0] & 0x10) fstrcat(flags," "); + if (p[0] & 0x08) fstrcat(flags," "); + if (p[0] & 0x04) fstrcat(flags," "); + if (p[0] & 0x02) fstrcat(flags," "); + + if (master && !*master && type == 0x1d) { + StrnCpy(master,qname,15); + trim_string(master,NULL," "); + } - if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) { - StrnCpy(rname,qname,15); - trim_string(rname,NULL," "); - } + if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) { + StrnCpy(rname,qname,15); + trim_string(rname,NULL," "); + } - for (i = strlen( qname) ; --i >= 0 ; ) { - if (!isprint((int)qname[i])) qname[i] = '.'; - } - DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags)); - p+=2; + for (i = strlen( qname) ; --i >= 0 ; ) { + if (!isprint((int)qname[i])) qname[i] = '.'; } + DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags)); + p+=2; + } + DEBUG(1,("num_good_sends=%d num_good_receives=%d\n", IVAL(p,20),IVAL(p,24))); } - /**************************************************************************** - do a netbios name status query on a host + Internal function handling a netbios name status query on a host. +**************************************************************************/ - the "master" parameter is a hack used for finding workgroups. - **************************************************************************/ -BOOL name_status(int fd,char *name,int name_type,BOOL recurse, - struct in_addr to_ip,char *master,char *rname, +static BOOL internal_name_status(int fd,char *name,int name_type,BOOL recurse, + struct in_addr to_ip,char *master,char *rname, BOOL verbose, + void (*fn_interpret_node_status)(char *, char *,char *), void (*fn)(struct packet_struct *)) { BOOL found=False; @@ -101,21 +98,9 @@ BOOL name_status(int fd,char *name,int name_type,BOOL recurse, struct packet_struct p; struct packet_struct *p2; struct nmb_packet *nmb = &p.packet.nmb; - int packet_type = NMB_PACKET; - BOOL first_time = True; + static int name_trn_id = 0; - if (fd == -1) - { - retries = 1; - packet_type = NMB_SOCK_PACKET; - fd = get_nmb_sock(); - - if (fd < 0) - { - return False; - } - } - bzero((char *)&p,sizeof(p)); + memset((char *)&p,'\0',sizeof(p)); if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)getpid()%(unsigned)100); @@ -144,39 +129,40 @@ BOOL name_status(int fd,char *name,int name_type,BOOL recurse, p.port = NMB_PORT; p.fd = fd; p.timestamp = time(NULL); - p.packet_type = packet_type; + p.packet_type = NMB_PACKET; GetTimeOfDay(&tval); - while (1) - { - struct timeval tval2; - GetTimeOfDay(&tval2); - if (first_time || TvalDiff(&tval,&tval2) > retry_time) - { - first_time = False; - if (!found && !send_packet(&p)) - { - if (packet_type == NMB_SOCK_PACKET) close(fd); - return False; - } - GetTimeOfDay(&tval); - } + if (!send_packet(&p)) + return(False); + + retries--; + + while (1) { + struct timeval tval2; + GetTimeOfDay(&tval2); + if (TvalDiff(&tval,&tval2) > retry_time) { + if (!retries) + break; + if (!found && !send_packet(&p)) + return False; + GetTimeOfDay(&tval); + retries--; + } - if ((p2=receive_packet(fd,packet_type,90))) - { - struct nmb_packet *nmb2 = &p2->packet.nmb; + if ((p2=receive_packet(fd,NMB_PACKET,90))) { + struct nmb_packet *nmb2 = &p2->packet.nmb; debug_nmb_packet(p2); - if (nmb->header.name_trn_id != nmb2->header.name_trn_id || - !nmb2->header.response) { - /* its not for us - maybe deal with it later */ - if (fn) - fn(p2); - else - free_packet(p2); - continue; - } + if (nmb->header.name_trn_id != nmb2->header.name_trn_id || + !nmb2->header.response) { + /* its not for us - maybe deal with it later */ + if (fn) + fn(p2); + else + free_packet(p2); + continue; + } if (nmb2->header.opcode != 0 || nmb2->header.nm_flags.bcast || @@ -189,55 +175,53 @@ BOOL name_status(int fd,char *name,int name_type,BOOL recurse, continue; } - retries--; - - _interpret_node_status(&nmb2->answers->rdata[0], master,rname); + if(fn_interpret_node_status) + (*fn_interpret_node_status)(&nmb2->answers->rdata[0],master,rname); free_packet(p2); - if (packet_type == NMB_SOCK_PACKET) close(fd); return(True); } - } - + } - DEBUG(0,("No status response (this is not unusual)\n")); + if(verbose) + DEBUG(0,("No status response (this is not unusual)\n")); -if (packet_type == NMB_SOCK_PACKET) close(fd); return(False); } +/**************************************************************************** + Do a netbios name status query on a host. + The "master" parameter is a hack used for finding workgroups. +**************************************************************************/ + +BOOL name_status(int fd,char *name,int name_type,BOOL recurse, + struct in_addr to_ip,char *master,char *rname, + void (*fn)(struct packet_struct *)) +{ + return internal_name_status(fd,name,name_type,recurse, + to_ip,master,rname,True, + _interpret_node_status, fn); +} /**************************************************************************** - do a netbios name query to find someones IP - returns an array of IP addresses or NULL if none - *count will be set to the number of addresses returned - ****************************************************************************/ + Do a netbios name query to find someones IP. + Returns an array of IP addresses or NULL if none. + *count will be set to the number of addresses returned. +****************************************************************************/ + struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse, struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *)) { BOOL found=False; int i, retries = 3; - int retry_time = bcast?2000:2000; + int retry_time = bcast?250:2000; struct timeval tval; struct packet_struct p; struct packet_struct *p2; struct nmb_packet *nmb = &p.packet.nmb; + static int name_trn_id = 0; struct in_addr *ip_list = NULL; - BOOL packet_type = NMB_PACKET; - BOOL first_send = True; - - if (fd == -1) - { - retries = 1; - packet_type = NMB_SOCK_PACKET; - fd = get_nmb_sock(); - - if (fd < 0) - { - return NULL; - } - } - bzero((char *)&p,sizeof(p)); + memset((char *)&p,'\0',sizeof(p)); (*count) = 0; if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + @@ -267,27 +251,30 @@ struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOO p.port = NMB_PORT; p.fd = fd; p.timestamp = time(NULL); - p.packet_type = packet_type; + p.packet_type = NMB_PACKET; + + GetTimeOfDay(&tval); - GetTimeOfDay(&tval); + if (!send_packet(&p)) + return NULL; - while (retries >= 0) + retries--; + + while (1) { struct timeval tval2; - GetTimeOfDay(&tval2); - if (first_send || TvalDiff(&tval,&tval2) > retry_time) + if (TvalDiff(&tval,&tval2) > retry_time) { - first_send = False; + if (!retries) + break; if (!found && !send_packet(&p)) - { - if (packet_type == NMB_SOCK_PACKET) close(fd); return NULL; - } GetTimeOfDay(&tval); + retries--; } - if ((p2=receive_packet(fd,packet_type,90))) + if ((p2=receive_packet(fd,NMB_PACKET,90))) { struct nmb_packet *nmb2 = &p2->packet.nmb; debug_nmb_packet(p2); @@ -295,8 +282,6 @@ struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOO if (nmb->header.name_trn_id != nmb2->header.name_trn_id || !nmb2->header.response) { - DEBUG(10,("packet not for us (received %d, expected %d\n", - nmb2->header.name_trn_id, nmb->header.name_trn_id)); /* * Its not for us - maybe deal with it later * (put it on the queue?). @@ -305,12 +290,9 @@ struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOO fn(p2); else free_packet(p2); - continue; } - retries--; - if (nmb2->header.opcode != 0 || nmb2->header.nm_flags.bcast || nmb2->header.rcode || @@ -345,15 +327,16 @@ struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOO if (fn) break; - if(found) - { - DEBUG(10,("returning OK\n")); + /* + * If we're doing a unicast lookup we only + * expect one reply. Don't wait the full 2 + * seconds if we got one. JRA. + */ + if(!bcast && found) break; - } } } - if (packet_type == NMB_SOCK_PACKET) close(fd); return ip_list; } @@ -375,6 +358,7 @@ FILE *startlmhosts(char *fname) /******************************************************** Parse the next line in the lmhosts file. *********************************************************/ + BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr) { pstring line; @@ -439,7 +423,7 @@ BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipad char *endptr; ptr++; - *name_type = (int)strtol(ptr, &endptr,0); + *name_type = (int)strtol(ptr, &endptr, 16); if(!*ptr || (endptr == ptr)) { @@ -465,108 +449,107 @@ void endlmhosts(FILE *fp) fclose(fp); } - - /******************************************************** -resolve via "bcast" method + Resolve via "bcast" method. *********************************************************/ -static BOOL resolve_bcast(const char *name, struct in_addr *return_ip, int name_type) + +static BOOL resolve_bcast(const char *name, int name_type, + struct in_addr **return_ip_list, int *return_count) { int sock, i; + int num_interfaces = iface_count(); + + *return_ip_list = NULL; + *return_count = 0; /* * "bcast" means do a broadcast lookup on all the local interfaces. */ - DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name)); + DEBUG(3,("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()) ); - - if (sock != -1) { - struct in_addr *iplist = NULL; - int count; - int num_interfaces = iface_count(); - set_socket_options(sock,"SO_BROADCAST"); - /* - * Lookup the name on all the interfaces, return on - * the first successful match. - */ - for( i = 0; i < num_interfaces; i++) { - struct in_addr sendto_ip; - /* Done this way to fix compiler error on IRIX 5.x */ - sendto_ip = *iface_bcast(*iface_n_ip(i)); - iplist = name_query(sock, name, name_type, True, - True, sendto_ip, &count, NULL); - if(iplist != NULL) { - *return_ip = iplist[0]; - free((char *)iplist); - close(sock); - return True; - } + interpret_addr(lp_socket_address()), True ); + + if (sock == -1) return False; + + set_socket_options(sock,"SO_BROADCAST"); + /* + * Lookup the name on all the interfaces, return on + * the first successful match. + */ + for( i = num_interfaces-1; i >= 0; i--) { + struct in_addr sendto_ip; + /* Done this way to fix compiler error on IRIX 5.x */ + sendto_ip = *iface_bcast(*iface_n_ip(i)); + *return_ip_list = name_query(sock, name, name_type, True, + True, sendto_ip, return_count, NULL); + if(*return_ip_list != NULL) { + close(sock); + return True; } - close(sock); } + close(sock); return False; } - - /******************************************************** -resolve via "wins" method + Resolve via "wins" method. *********************************************************/ -static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type) + +static BOOL resolve_wins(const char *name, int name_type, + struct in_addr **return_iplist, int *return_count) { - int sock; - struct in_addr wins_ip; - BOOL wins_ismyip; + int sock; + struct in_addr wins_ip; + BOOL wins_ismyip; - /* - * "wins" means do a unicast lookup to the WINS server. - * Ignore if there is no WINS server specified or if the - * WINS server is one of our interfaces (if we're being - * called from within nmbd - we can't do this call as we - * would then block). - */ + *return_iplist = NULL; + *return_count = 0; + + /* + * "wins" means do a unicast lookup to the WINS server. + * Ignore if there is no WINS server specified or if the + * WINS server is one of our interfaces (if we're being + * called from within nmbd - we can't do this call as we + * would then block). + */ - DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name)); + DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type)); - if(!*lp_wins_server()) { - DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n")); - return False; - } + if(!*lp_wins_server()) { + DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS server present.\n")); + return False; + } - wins_ip = *interpret_addr2(lp_wins_server()); - wins_ismyip = ismyip(wins_ip); + wins_ip = *interpret_addr2(lp_wins_server()); + wins_ismyip = ismyip(wins_ip); - if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) { - sock = open_socket_in( SOCK_DGRAM, 0, 3, - interpret_addr(lp_socket_address()) ); + if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) { + sock = open_socket_in( SOCK_DGRAM, 0, 3, + interpret_addr(lp_socket_address()), True ); - if (sock != -1) { - struct in_addr *iplist = NULL; - int count; - iplist = name_query(sock, name, name_type, False, - True, wins_ip, &count, NULL); - if(iplist != NULL) { - *return_ip = iplist[0]; - free((char *)iplist); - close(sock); - return True; - } - close(sock); - } - } + if (sock != -1) { + *return_iplist = name_query(sock, name, name_type, False, + True, wins_ip, return_count, NULL); + if(*return_iplist != NULL) { + close(sock); + return True; + } + close(sock); + } + } - return False; + return False; } - /******************************************************** -resolve via "lmhosts" method + Resolve via "lmhosts" method. *********************************************************/ -static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type) + +static BOOL resolve_lmhosts(const char *name, int name_type, + struct in_addr **return_iplist, int *return_count) { /* * "lmhosts" means parse the local lmhosts file. @@ -575,15 +558,27 @@ static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int nam FILE *fp; pstring lmhost_name; int name_type2; + struct in_addr return_ip; + + *return_iplist = NULL; + *return_count = 0; - DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name)); + DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type)); fp = startlmhosts( LMHOSTSFILE ); if(fp) { - while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) { + while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip)) { if (strequal(name, lmhost_name) && - name_type == name_type2) { + ((name_type2 == -1) || (name_type == name_type2)) + ) { endlmhosts(fp); + *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr)); + if(*return_iplist == NULL) { + DEBUG(3,("resolve_lmhosts: malloc fail !\n")); + return False; + } + **return_iplist = return_ip; + *return_count = 1; return True; } } @@ -594,89 +589,94 @@ static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int nam /******************************************************** -resolve via "hosts" method + Resolve via "hosts" method. *********************************************************/ -static BOOL resolve_hosts(const char *name, struct in_addr *return_ip) + +static BOOL resolve_hosts(const char *name, + struct in_addr **return_iplist, int *return_count) { /* * "host" means do a localhost, or dns lookup. */ struct hostent *hp; - DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name)); + *return_iplist = NULL; + *return_count = 0; + + DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name)); if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) { - putip((char *)return_ip,(char *)hp->h_addr); + struct in_addr return_ip; + putip((char *)&return_ip,(char *)hp->h_addr); + *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr)); + if(*return_iplist == NULL) { + DEBUG(3,("resolve_hosts: malloc fail !\n")); + return False; + } + **return_iplist = return_ip; + *return_count = 1; return True; } return False; } - /******************************************************** - Resolve a name into an IP address. Use this function if - the string is either an IP address, DNS or host name - or NetBIOS name. This uses the name switch in the + Internal interface to resolve a name into an IP address. + Use this function if the string is either an IP address, DNS + or host name or NetBIOS name. This uses the name switch in the smb.conf to determine the order of name resolution. *********************************************************/ -BOOL is_ip_address(const char *name) -{ - int i; - for (i=0; name[i]; i++) - if (!(isdigit((int)name[i]) || name[i] == '.')) - return False; - - return True; -} -/******************************************************** - Resolve a name into an IP address. Use this function if - the string is either an IP address, DNS or host name - or NetBIOS name. This uses the name switch in the - smb.conf to determine the order of name resolution. -*********************************************************/ -BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type) +static BOOL internal_resolve_name(const char *name, int name_type, + struct in_addr **return_iplist, int *return_count) { pstring name_resolve_list; fstring tok; char *ptr; - - if (strcmp(name,"0.0.0.0") == 0) { - return_ip->s_addr = 0; - return True; - } - if (strcmp(name,"255.255.255.255") == 0) { - return_ip->s_addr = 0xFFFFFFFF; - return True; - } - - /* if it's in the form of an IP address then get the lib to interpret it */ - if (is_ip_address(name)) { - return_ip->s_addr = inet_addr(name); + BOOL allones = (strcmp(name,"255.255.255.255") == 0); + BOOL allzeros = (strcmp(name,"0.0.0.0") == 0); + BOOL is_address = is_ipaddress(name); + *return_iplist = NULL; + *return_count = 0; + + if (allzeros || allones || is_address) { + *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr)); + if(*return_iplist == NULL) { + DEBUG(3,("internal_resolve_name: malloc fail !\n")); + return False; + } + if(is_address) { + /* if it's in the form of an IP address then get the lib to interpret it */ + (*return_iplist)->s_addr = inet_addr(name); + } else { + (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0; + *return_count = 1; + } return True; } - + pstrcpy(name_resolve_list, lp_name_resolve_order()); ptr = name_resolve_list; - if (!ptr || !*ptr) ptr = "host"; + if (!ptr || !*ptr) + ptr = "host"; while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) { if((strequal(tok, "host") || strequal(tok, "hosts"))) { - if (name_type == 0x20 && resolve_hosts(name, return_ip)) { + if (name_type == 0x20 && resolve_hosts(name, return_iplist, return_count)) { return True; } } else if(strequal( tok, "lmhosts")) { - if (resolve_lmhosts(name, return_ip, name_type)) { + if (resolve_lmhosts(name, name_type, return_iplist, return_count)) { return True; } } else if(strequal( tok, "wins")) { /* don't resolve 1D via WINS */ if (name_type != 0x1D && - resolve_wins(name, return_ip, name_type)) { + resolve_wins(name, name_type, return_iplist, return_count)) { return True; } } else if(strequal( tok, "bcast")) { - if (resolve_bcast(name, return_ip, name_type)) { + if (resolve_bcast(name, name_type, return_iplist, return_count)) { return True; } } else { @@ -684,50 +684,319 @@ BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type) } } + if((*return_iplist) != NULL) { + free((char *)(*return_iplist)); + *return_iplist = NULL; + } return False; } /******************************************************** - resolve a name of format \\server_name or \\ipaddress - into a name. also, cut the \\ from the front for us. + Internal interface to resolve a name into one IP address. + Use this function if the string is either an IP address, DNS + or host name or NetBIOS name. This uses the name switch in the + smb.conf to determine the order of name resolution. *********************************************************/ -BOOL resolve_srv_name(const char* srv_name, fstring dest_host, - struct in_addr *ip) -{ - BOOL ret; - const char *sv_name = srv_name; - DEBUG(10,("resolve_srv_name: %s\n", srv_name)); +BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type) +{ + struct in_addr *ip_list = NULL; + int count = 0; - if (srv_name == NULL || strequal("\\\\.", srv_name)) - { - fstrcpy(dest_host, global_myname); - ip = interpret_addr2("127.0.0.1"); + if(internal_resolve_name(name, name_type, &ip_list, &count)) { + *return_ip = ip_list[0]; + free((char *)ip_list); return True; } + if(ip_list != NULL) + free((char *)ip_list); + return False; +} - if (strnequal("\\\\", srv_name, 2)) - { - sv_name = &srv_name[2]; - } +/******************************************************** + Find the IP address of the master browser or DMB for a workgroup. +*********************************************************/ - fstrcpy(dest_host, sv_name); - ret = resolve_name(dest_host, ip, 0x20); - - if (is_ip_address(dest_host)) - { - fstrcpy(dest_host, "*SMBSERVER"); +BOOL find_master_ip(char *group, struct in_addr *master_ip) +{ + struct in_addr *ip_list = NULL; + int count = 0; + + if (internal_resolve_name(group, 0x1D, &ip_list, &count)) { + *master_ip = ip_list[0]; + free((char *)ip_list); + return True; } - - return ret; + if(internal_resolve_name(group, 0x1B, &ip_list, &count)) { + *master_ip = ip_list[0]; + free((char *)ip_list); + return True; + } + + if(ip_list != NULL) + free((char *)ip_list); + return False; } /******************************************************** -find the IP address of the master browser or DMB for a workgroup + Internal function to extract the MACHINE<0x20> name. *********************************************************/ -BOOL find_master_ip(char *group, struct in_addr *master_ip) + +static void _lookup_pdc_name(char *p, char *master,char *rname) +{ + int numnames = CVAL(p,0); + + *rname = '\0'; + + p += 1; + while (numnames--) { + int type = CVAL(p,15); + if(type == 0x20) { + StrnCpy(rname,p,15); + trim_string(rname,NULL," "); + return; + } + p += 18; + } +} + +/******************************************************** + Lookup a PDC name given a Domain name and IP address. +*********************************************************/ + +BOOL lookup_pdc_name(const char *srcname, const char *domain, struct in_addr *pdc_ip, char *ret_name) { - if (resolve_name(group, master_ip, 0x1D)) return True; +#if !defined(I_HATE_WINDOWS_REPLY_CODE) + + fstring pdc_name; + BOOL ret; + + /* + * Due to the fact win WinNT *sucks* we must do a node status + * query here... JRA. + */ - return resolve_name(group, master_ip, 0x1B); + int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True ); + + if(sock == -1) + return False; + + *pdc_name = '\0'; + + ret = internal_name_status(sock,"*SMBSERVER",0x20,True, + *pdc_ip,NULL,pdc_name,False, + _lookup_pdc_name,NULL); + + close(sock); + + if(ret && *pdc_name) { + fstrcpy(ret_name, pdc_name); + return True; + } + + return False; + +#else /* defined(I_HATE_WINDOWS_REPLY_CODE) */ + /* + * Sigh. I *love* this code, it took me ages to get right and it's + * completely *USELESS* because NT 4.x refuses to send the mailslot + * reply back to the correct port (it always uses 138). + * I hate NT when it does these things... JRA. + */ + + int retries = 3; + int retry_time = 2000; + struct timeval tval; + struct packet_struct p; + struct dgram_packet *dgram = &p.packet.dgram; + char *ptr,*p2; + char tmp[4]; + int len; + struct sockaddr_in sock_name; + int sock_len = sizeof(sock_name); + const char *mailslot = "\\MAILSLOT\\NET\\NETLOGON"; + static int name_trn_id = 0; + char buffer[1024]; + char *bufp; + int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True ); + + if(sock == -1) + return False; + + /* Find out the transient UDP port we have been allocated. */ + if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) { + DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n", + strerror(errno))); + close(sock); + return False; + } + + /* + * Create the request data. + */ + + memset(buffer,'\0',sizeof(buffer)); + bufp = buffer; + SSVAL(bufp,0,QUERYFORPDC); + bufp += 2; + fstrcpy(bufp,srcname); + bufp += (strlen(bufp) + 1); + fstrcpy(bufp,"\\MAILSLOT\\NET\\GETDC411"); + bufp += (strlen(bufp) + 1); + bufp = align2(bufp, buffer); + dos_PutUniCode(bufp, srcname, sizeof(buffer) - (bufp - buffer) - 1); + bufp = skip_unicode_string(bufp, 1); + SIVAL(bufp,0,1); + SSVAL(bufp,4,0xFFFF); + SSVAL(bufp,6,0xFFFF); + bufp += 8; + len = PTR_DIFF(bufp,buffer); + + if (!name_trn_id) + name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)getpid()%(unsigned)100); + name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF; + + memset((char *)&p,'\0',sizeof(p)); + + /* DIRECT GROUP or UNIQUE datagram. */ + dgram->header.msg_type = 0x10; + dgram->header.flags.node_type = M_NODE; + dgram->header.flags.first = True; + dgram->header.flags.more = False; + dgram->header.dgm_id = name_trn_id; + dgram->header.source_ip = sock_name.sin_addr; + dgram->header.source_port = ntohs(sock_name.sin_port); + dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */ + dgram->header.packet_offset = 0; + + make_nmb_name(&dgram->source_name,srcname,0,scope); + make_nmb_name(&dgram->dest_name,domain,0x1B,scope); + + ptr = &dgram->data[0]; + + /* Setup the smb part. */ + ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */ + memcpy(tmp,ptr,4); + set_message(ptr,17,17 + len,True); + memcpy(ptr,tmp,4); + + CVAL(ptr,smb_com) = SMBtrans; + SSVAL(ptr,smb_vwv1,len); + SSVAL(ptr,smb_vwv11,len); + SSVAL(ptr,smb_vwv12,70 + strlen(mailslot)); + SSVAL(ptr,smb_vwv13,3); + SSVAL(ptr,smb_vwv14,1); + SSVAL(ptr,smb_vwv15,1); + SSVAL(ptr,smb_vwv16,2); + p2 = smb_buf(ptr); + pstrcpy(p2,mailslot); + p2 = skip_string(p2,1); + + memcpy(p2,buffer,len); + p2 += len; + + dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */ + + p.ip = *pdc_ip; + p.port = DGRAM_PORT; + p.fd = sock; + p.timestamp = time(NULL); + p.packet_type = DGRAM_PACKET; + + GetTimeOfDay(&tval); + + if (!send_packet(&p)) { + DEBUG(0,("lookup_pdc_name: send_packet failed.\n")); + close(sock); + return False; + } + + retries--; + + while (1) { + struct timeval tval2; + struct packet_struct *p_ret; + + GetTimeOfDay(&tval2); + if (TvalDiff(&tval,&tval2) > retry_time) { + if (!retries) + break; + if (!send_packet(&p)) { + DEBUG(0,("lookup_pdc_name: send_packet failed.\n")); + close(sock); + return False; + } + GetTimeOfDay(&tval); + retries--; + } + + if ((p_ret = receive_packet(sock,NMB_PACKET,90))) { + struct nmb_packet *nmb2 = &p_ret->packet.nmb; + struct dgram_packet *dgram2 = &p_ret->packet.dgram; + char *buf; + char *buf2; + + debug_nmb_packet(p_ret); + + if (memcmp(&p.ip, &p_ret->ip, sizeof(p.ip))) { + /* + * Not for us. + */ + DEBUG(0,("lookup_pdc_name: datagram return IP %s doesn't match\n", inet_ntoa(p_ret->ip) )); + free_packet(p_ret); + continue; + } + + buf = &dgram2->data[0]; + buf -= 4; + + if (CVAL(buf,smb_com) != SMBtrans) { + DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)CVAL(buf,smb_com), + (unsigned int)SMBtrans )); + free_packet(p_ret); + continue; + } + + len = SVAL(buf,smb_vwv11); + buf2 = smb_base(buf) + SVAL(buf,smb_vwv12); + + if (len <= 0) { + DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len )); + free_packet(p_ret); + continue; + } + + DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n", + nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name), + inet_ntoa(p_ret->ip), smb_buf(buf),CVAL(buf2,0),len)); + + if(SVAL(buf,0) != QUERYFORPDC_R) { + DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n", + (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R )); + free_packet(p_ret); + continue; + } + + buf += 2; + /* Note this is safe as it is a bounded strcpy. */ + fstrcpy(ret_name, buf); + ret_name[sizeof(fstring)-1] = '\0'; + close(sock); + free_packet(p_ret); + return True; + } + } + + close(sock); + return False; +#endif /* I_HATE_WINDOWS_REPLY_CODE */ +} + +/******************************************************** + Get the IP address list of the PDC/BDC's of a Domain. +*********************************************************/ + +BOOL get_dc_list(char *group, struct in_addr **ip_list, int *count) +{ + return internal_resolve_name(group, 0x1C, ip_list, count); } -- cgit