1
0
mirror of https://github.com/samba-team/samba.git synced 2025-07-30 19:42:05 +03:00

added suppport for unexpected udp/138 packets

I also fixed up the lookup_pdc_name() code so that it now works, even
with a NT server that insists on replying to udp/138.

The method I used to match packets was to use the mailslot string as a
datagram ID. The true dgm_id doesn't work as NT doesn't set it
correctly. uggh.

PS: Jeremy, I had to change your code quite a bit, are you sure this
worked with a Samba PDC?? The code looked broken, it got the offsets
wrong in the SMB portion of the packet and filled in the IP
incorrectly.
(This used to be commit 32f66f4ea6)
This commit is contained in:
Andrew Tridgell
2000-01-03 06:30:50 +00:00
parent 8d1d27b43c
commit 632b4f806e
6 changed files with 326 additions and 330 deletions

View File

@ -161,7 +161,7 @@ static BOOL internal_name_status(int fd,char *name,int name_type,BOOL recurse,
retries--;
}
if ((p2=receive_reply_packet(fd,90,nmb->header.name_trn_id))) {
if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
struct nmb_packet *nmb2 = &p2->packet.nmb;
debug_nmb_packet(p2);
@ -269,7 +269,7 @@ struct in_addr *name_query(int fd,const char *name,int name_type,
retries--;
}
if ((p2=receive_reply_packet(fd,90,nmb->header.name_trn_id))) {
if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
struct nmb_packet *nmb2 = &p2->packet.nmb;
debug_nmb_packet(p2);
@ -712,259 +712,189 @@ BOOL find_master_ip(char *group, struct in_addr *master_ip)
return False;
}
/********************************************************
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;
}
}
/********************************************************
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 !defined(I_HATE_WINDOWS_REPLY_CODE)
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";
char *mailslot_name;
char buffer[1024];
char *bufp;
int dgm_id = generate_trn_id();
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;
}
fstring pdc_name;
BOOL ret;
/*
* Create the request data.
*/
/*
* Due to the fact win WinNT *sucks* we must do a node status
* query here... JRA.
*/
memset(buffer,'\0',sizeof(buffer));
bufp = buffer;
SSVAL(bufp,0,QUERYFORPDC);
bufp += 2;
fstrcpy(bufp,srcname);
bufp += (strlen(bufp) + 1);
slprintf(bufp, sizeof(fstring), "\\MAILSLOT\\NET\\GETDC%d", dgm_id);
mailslot_name = bufp;
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);
int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
memset((char *)&p,'\0',sizeof(p));
if(sock == -1)
return False;
/* 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 = dgm_id;
dgram->header.source_ip = *iface_ip(*pdc_ip);
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);
*pdc_name = '\0';
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--;
}
ret = internal_name_status(sock,"*SMBSERVER",0x20,True,
*pdc_ip,NULL,pdc_name,False,
_lookup_pdc_name);
if ((p_ret = receive_dgram_packet(sock,90,mailslot_name))) {
struct dgram_packet *dgram2 = &p_ret->packet.dgram;
char *buf;
char *buf2;
close(sock);
buf = &dgram2->data[0];
buf -= 4;
if(ret && *pdc_name) {
fstrcpy(ret_name, pdc_name);
return True;
}
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;
}
return False;
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),SVAL(buf2,0),len));
#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.
*/
if(SVAL(buf2,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;
}
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";
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);
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 = generate_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 */
buf2 += 2;
/* Note this is safe as it is a bounded strcpy. */
fstrcpy(ret_name, buf2);
ret_name[sizeof(fstring)-1] = '\0';
close(sock);
free_packet(p_ret);
return True;
}
}
close(sock);
return False;
}
/********************************************************
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);