1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

implemented a much nicer name_status() interface. It now returns a

list of structures rather than the dodgy parsing code we had before

this also gets smbw working correctly with no initial workgroup (using
name_status_find on __MSBROWSE__ returns)
This commit is contained in:
Andrew Tridgell 0001-01-01 00:00:00 +00:00
parent c25533de99
commit f2be88a873
5 changed files with 197 additions and 176 deletions

View File

@ -840,8 +840,9 @@ BOOL deal_with_creds(uchar sess_key[8],
/*The following definitions come from libsmb/namequery.c */
BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
struct in_addr to_ip,char *master,char *rname);
struct node_status *name_status_query(int fd,struct nmb_name *name,
struct in_addr to_ip, int *num_names);
BOOL name_status_find(int type, struct in_addr to_ip, char *name);
struct in_addr *name_query(int fd,const char *name,int name_type,
BOOL bcast,BOOL recurse,
struct in_addr to_ip, int *count);

View File

@ -1553,6 +1553,16 @@ struct nmb_name {
unsigned int name_type;
};
/* A netbios node status array element. */
struct node_status {
char name[16];
unsigned char type;
unsigned char flags;
};
#define AGENT_CMD_CON 0
#define AGENT_CMD_CON_ANON 2
#define AGENT_CMD_CON_REUSE 1

View File

@ -45,168 +45,155 @@ static int generate_trn_id(void)
/****************************************************************************
Interpret a node status response.
parse a node status response into an array of structures
****************************************************************************/
static void _interpret_node_status(char *p, char *master,char *rname)
static struct node_status *parse_node_status(char *p, int *num_names)
{
int numnames = CVAL(p,0);
DEBUG(1,("received %d names\n",numnames));
struct node_status *ret;
int i;
if (rname) *rname = 0;
if (master) *master = 0;
*num_names = CVAL(p,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;
if (*num_names == 0) return NULL;
fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
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,"<DEREGISTERING> ");
if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names));
if (!ret) return NULL;
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," ");
}
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)));
p++;
for (i=0;i< *num_names;i++) {
StrnCpy(ret[i].name,p,15);
trim_string(ret[i].name,NULL," ");
ret[i].type = CVAL(p,15);
ret[i].flags = p[16];
p += 18;
}
return ret;
}
/****************************************************************************
Internal function handling a netbios name status query on a host.
do a NBT node status query on an open socket and return an array of
structures holding the returned names or NULL if the query failed
**************************************************************************/
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 *))
struct node_status *name_status_query(int fd,struct nmb_name *name,
struct in_addr to_ip, int *num_names)
{
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;
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;
memset((char *)&p,'\0',sizeof(p));
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->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;
make_nmb_name(&nmb->question.question_name,name,name_type);
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;
nmb->question.question_type = 0x21;
nmb->question.question_class = 0x1;
retries--;
p.ip = to_ip;
p.port = NMB_PORT;
p.fd = fd;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
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--;
}
GetTimeOfDay(&tval);
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) {
/* XXXX what do we do with this? could be a
redirect, but we'll discard it for the
moment */
free_packet(p2);
continue;
}
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_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) {
/* XXXX what do we do with this? could be a
redirect, but we'll discard it for the
moment */
free_packet(p2);
continue;
}
if(fn_interpret_node_status)
(*fn_interpret_node_status)(&nmb2->answers->rdata[0],master,rname);
free_packet(p2);
return(True);
}
}
if(verbose)
DEBUG(0,("No status response (this is not unusual)\n"));
return(False);
ret = parse_node_status(&nmb2->answers->rdata[0], num_names);
free_packet(p2);
return ret;
}
}
return NULL;
}
/****************************************************************************
Do a netbios name status query on a host.
The "master" parameter is a hack used for finding workgroups.
find the first type XX name in a node status reply - used for finding
a servers name given its IP
return the matched name in *name
**************************************************************************/
BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
struct in_addr to_ip,char *master,char *rname)
BOOL name_status_find(int type, struct in_addr to_ip, char *name)
{
return internal_name_status(fd,name,name_type,recurse,
to_ip,master,rname,True,
_interpret_node_status);
struct node_status *status;
struct nmb_name nname;
int count, i;
int sock;
sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True);
if (sock == -1) return False;
make_nmb_name(&nname, "*", 0);
status = name_status_query(sock, &nname, to_ip, &count);
close(sock);
if (!status) return False;
for (i=0;i<count;i++) {
if (status[i].type == type) break;
}
if (i == count) return False;
StrnCpy(name, status[i].name, 15);
free(status);
return True;
}
/****************************************************************************
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)
@ -822,30 +809,6 @@ BOOL find_master_ip(char *group, struct in_addr *master_ip)
return False;
}
#if !defined(I_HATE_WINDOWS_REPLY_CODE)
/********************************************************
Internal function to extract the MACHINE<0x20> name.
*********************************************************/
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;
}
}
#endif /* I_HATE_WINDOWS_REPLY_CODE */
/********************************************************
Lookup a PDC name given a Domain name and IP address.
*********************************************************/
@ -862,17 +825,9 @@ BOOL lookup_pdc_name(const char *srcname, const char *domain, struct in_addr *pd
* query here... JRA.
*/
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);
close(sock);
ret = name_status_find(0x20,*pdc_ip,pdc_name);
if(ret && *pdc_name) {
fstrcpy(ret_name, pdc_name);

View File

@ -261,6 +261,7 @@ static char *smbw_find_workgroup(void)
char *p;
struct in_addr *ip_list = NULL;
int count = 0;
int i;
/* first off see if an existing workgroup name exists */
p = smbw_getshared("WORKGROUP");
@ -273,12 +274,21 @@ static char *smbw_find_workgroup(void)
if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
DEBUG(1,("No workgroups found!"));
return p;
}
free((char *)ip_list);
for (i=0;i<count;i++) {
static fstring name;
if (name_status_find(0x1d, ip_list[i], name)) {
slprintf(server, sizeof(server), "%s#1D", name);
if (smbw_server(server, "IPC$")) {
free(ip_list);
return name;
}
}
}
free(ip_list);
DEBUG(0,("Need to do node status code"));
return p;
}

View File

@ -80,6 +80,55 @@ static void usage(void)
printf("\n");
}
/****************************************************************************
turn a node status flags field into a string
****************************************************************************/
static char *node_status_flags(unsigned char flags)
{
static fstring ret;
fstrcpy(ret,"");
fstrcat(ret, (flags & 0x80) ? "<GROUP> " : " ");
if ((flags & 0x60) == 0x00) fstrcat(ret,"B ");
if ((flags & 0x60) == 0x20) fstrcat(ret,"P ");
if ((flags & 0x60) == 0x40) fstrcat(ret,"M ");
if ((flags & 0x60) == 0x60) fstrcat(ret,"H ");
if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> ");
if (flags & 0x08) fstrcat(ret,"<CONFLICT> ");
if (flags & 0x04) fstrcat(ret,"<ACTIVE> ");
if (flags & 0x02) fstrcat(ret,"<PERMANENT> ");
return ret;
}
/****************************************************************************
do a node status query
****************************************************************************/
static void do_node_status(int fd, char *name, int type, struct in_addr ip)
{
struct nmb_name nname;
int count, i, j;
struct node_status *status;
fstring cleanname;
printf("Looking up status of %s\n",inet_ntoa(ip));
make_nmb_name(&nname, name, type);
status = name_status_query(fd,&nname,ip, &count);
if (status) {
for (i=0;i<count;i++) {
fstrcpy(cleanname, status[i].name);
for (j=0;cleanname[j];j++) {
if (!isprint(cleanname[j])) cleanname[j] = '.';
}
printf("\t%-15s <%02x> - %s\n",
cleanname,status[i].type,
node_status_flags(status[i].flags));
}
free(status);
}
printf("\n");
}
/****************************************************************************
send out one query
@ -125,9 +174,7 @@ static BOOL query_one(char *lookup, unsigned int lookup_type)
was valid - ie. name_query returned true.
*/
if (find_status) {
printf("Looking up status of %s\n",inet_ntoa(ip_list[0]));
name_status(ServerFD,lookup,lookup_type,True,ip_list[0],NULL,NULL);
printf("\n");
do_node_status(ServerFD, lookup, lookup_type, ip_list[0]);
}
safe_free(ip_list);
@ -245,9 +292,7 @@ int main(int argc,char *argv[])
{
fstrcpy(lookup,"*");
ip = *interpret_addr2(argv[i]);
printf("Looking up status of %s\n",inet_ntoa(ip));
name_status(ServerFD,lookup,lookup_type,True,ip,NULL,NULL);
printf("\n");
do_node_status(ServerFD, lookup, lookup_type, ip);
continue;
}