mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
0e8fd33987
(This used to be commit 291551d807
)
304 lines
7.5 KiB
C
304 lines
7.5 KiB
C
/*
|
|
Unix SMB/Netbios implementation.
|
|
Version 1.9.
|
|
NBT netbios routines to synchronise browse lists
|
|
Copyright (C) Andrew Tridgell 1994-1995
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "loadparm.h"
|
|
#include "nameserv.h"
|
|
|
|
extern int DEBUGLEVEL;
|
|
|
|
struct server_record *add_server_entry(char *name,int servertype,
|
|
int ttl,char *comment,BOOL replace);
|
|
|
|
|
|
/****************************************************************************
|
|
call a remote api
|
|
****************************************************************************/
|
|
static BOOL call_remote_api(int fd,int cnum,int uid,int timeout,
|
|
char *inbuf,char *outbuf,
|
|
int prcnt,int drcnt,
|
|
int mprcnt,int mdrcnt,
|
|
int *rprcnt,int *rdrcnt,
|
|
char *param,char *data,
|
|
char **rparam,char **rdata)
|
|
{
|
|
char *p1,*p2;
|
|
|
|
/* send a SMBtrans command */
|
|
bzero(outbuf,smb_size);
|
|
set_message(outbuf,14,0,True);
|
|
CVAL(outbuf,smb_com) = SMBtrans;
|
|
SSVAL(outbuf,smb_tid,cnum);
|
|
SSVAL(outbuf,smb_uid,uid);
|
|
|
|
p1 = smb_buf(outbuf);
|
|
strcpy(p1,"\\PIPE\\LANMAN");
|
|
p1 = skip_string(p1,1);
|
|
p2 = p1 + prcnt;
|
|
|
|
if (prcnt > 0)
|
|
memcpy(p1,param,prcnt);
|
|
if (drcnt > 0)
|
|
memcpy(p2,data,drcnt);
|
|
|
|
SSVAL(outbuf,smb_vwv0,prcnt); /* param count */
|
|
SSVAL(outbuf,smb_vwv1,drcnt); /* data count */
|
|
SSVAL(outbuf,smb_vwv2,mprcnt); /* mprcnt */
|
|
SSVAL(outbuf,smb_vwv3,mdrcnt); /* mdrcnt */
|
|
SSVAL(outbuf,smb_vwv4,0); /* msrcnt */
|
|
SSVAL(outbuf,smb_vwv5,0); /* flags */
|
|
SSVAL(outbuf,smb_vwv9,prcnt); /* pscnt */
|
|
SSVAL(outbuf,smb_vwv10,smb_offset(p1,outbuf)); /* psoff */
|
|
SSVAL(outbuf,smb_vwv11,drcnt); /* dscnt */
|
|
SSVAL(outbuf,smb_vwv12,smb_offset(p2,outbuf)); /* dsoff */
|
|
CVAL(outbuf,smb_vwv13) = 0; /* suwcnt */
|
|
|
|
set_message(outbuf,14,PTR_DIFF(p2+drcnt,smb_buf(outbuf)),False);
|
|
|
|
send_smb(fd,outbuf);
|
|
|
|
if (receive_smb(fd,inbuf,timeout) &&
|
|
CVAL(inbuf,smb_rcls) == 0)
|
|
{
|
|
if (rparam)
|
|
*rparam = inbuf+4 + SVAL(inbuf,smb_vwv4);
|
|
if (rdata)
|
|
*rdata = inbuf+4 + SVAL(inbuf,smb_vwv7);
|
|
if (rprcnt)
|
|
*rprcnt = SVAL(inbuf,smb_vwv3);
|
|
if (rdrcnt)
|
|
*rdrcnt = SVAL(inbuf,smb_vwv6);
|
|
return(True);
|
|
}
|
|
|
|
return(False);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
synchronise browse lists with another browse server
|
|
******************************************************************/
|
|
void sync_browse_lists(char *name,int name_type,char *myname,
|
|
char *domain,struct in_addr ip)
|
|
{
|
|
char *protocol = "LM1.2X002";
|
|
char *service = "IPC$";
|
|
char *dev = "IPC";
|
|
int timeout=2000;
|
|
char *inbuf=NULL;
|
|
pstring outbuf;
|
|
char *p;
|
|
int len;
|
|
uint32 sesskey;
|
|
int cnum,uid;
|
|
BOOL ret;
|
|
|
|
int fd = open_socket_out(SOCK_STREAM, &ip, SMB_PORT);
|
|
if (fd < 0) {
|
|
DEBUG(3,("Failed to connect to %s at %s\n",name,inet_ntoa(ip)));
|
|
return;
|
|
}
|
|
|
|
if (!(inbuf = (char *)malloc(0xFFFF+1024))) return;
|
|
|
|
/* put in the destination name */
|
|
len = 4;
|
|
p = outbuf+len;
|
|
name_mangle(name,p,name_type);
|
|
len += name_len(p);
|
|
|
|
/* and my name */
|
|
p = outbuf+len;
|
|
name_mangle(myname,p,0x20);
|
|
len += name_len(p);
|
|
|
|
_smb_setlen(outbuf,len);
|
|
CVAL(outbuf,0) = 0x81;
|
|
|
|
send_smb(fd,outbuf);
|
|
receive_smb(fd,inbuf,5000);
|
|
|
|
bzero(outbuf,smb_size);
|
|
|
|
/* setup the protocol string */
|
|
set_message(outbuf,0,strlen(protocol)+2,True);
|
|
p = smb_buf(outbuf);
|
|
*p++ = 2;
|
|
strcpy(p,protocol);
|
|
|
|
CVAL(outbuf,smb_com) = SMBnegprot;
|
|
CVAL(outbuf,smb_flg) = 0x8;
|
|
SSVAL(outbuf,smb_flg2,0x1);
|
|
|
|
send_smb(fd,outbuf);
|
|
bzero(inbuf,smb_size);
|
|
ret = receive_smb(fd,inbuf,timeout);
|
|
|
|
if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
|
|
DEBUG(3,("%s rejected the protocol\n",name));
|
|
close(fd);
|
|
if (inbuf) free(inbuf);
|
|
return;
|
|
}
|
|
|
|
sesskey = IVAL(inbuf,smb_vwv6);
|
|
|
|
bzero(outbuf,smb_size);
|
|
set_message(outbuf,10,2,True);
|
|
CVAL(outbuf,smb_com) = SMBsesssetupX;
|
|
|
|
CVAL(outbuf,smb_vwv0) = 0xFF;
|
|
SSVAL(outbuf,smb_vwv2,0xFFFF);
|
|
SSVAL(outbuf,smb_vwv3,2);
|
|
SSVAL(outbuf,smb_vwv4,1);
|
|
SIVAL(outbuf,smb_vwv5,sesskey);
|
|
SSVAL(outbuf,smb_vwv7,1);
|
|
|
|
send_smb(fd,outbuf);
|
|
bzero(inbuf,smb_size);
|
|
ret = receive_smb(fd,inbuf,timeout);
|
|
if (!ret || CVAL(inbuf,smb_rcls)) {
|
|
DEBUG(3,("%s rejected session setup\n",name));
|
|
close(fd);
|
|
if (inbuf) free(inbuf);
|
|
return;
|
|
}
|
|
|
|
uid = SVAL(inbuf,smb_uid);
|
|
|
|
bzero(outbuf,smb_size);
|
|
set_message(outbuf,4,2 + (2 + strlen(name) + 1 + strlen(service)) +
|
|
1 + strlen(dev),True);
|
|
CVAL(outbuf,smb_com) = SMBtconX;
|
|
SSVAL(outbuf,smb_uid,uid);
|
|
|
|
SSVAL(outbuf,smb_vwv0,0xFF);
|
|
SSVAL(outbuf,smb_vwv3,1);
|
|
|
|
p = smb_buf(outbuf) + 1;
|
|
strcpy(p, "\\\\");
|
|
strcat(p, name);
|
|
strcat(p, "\\");
|
|
strcat(p,service);
|
|
p = skip_string(p,1);
|
|
strcpy(p,dev);
|
|
|
|
send_smb(fd,outbuf);
|
|
bzero(inbuf,smb_size);
|
|
ret = receive_smb(fd,inbuf,timeout);
|
|
if (!ret || CVAL(inbuf,smb_rcls)) {
|
|
DEBUG(3,("%s rejected IPC connect (%d,%d)\n",name,
|
|
CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err)));
|
|
close(fd);
|
|
if (inbuf) free(inbuf);
|
|
return;
|
|
}
|
|
|
|
cnum = SVAL(inbuf,smb_tid);
|
|
|
|
/* now I need to send a NetServerEnum */
|
|
{
|
|
fstring param;
|
|
uint32 *typep;
|
|
char *rparam,*rdata;
|
|
|
|
p = param;
|
|
SSVAL(p,0,0x68); /* api number */
|
|
p += 2;
|
|
strcpy(p,"WrLehDz");
|
|
p = skip_string(p,1);
|
|
|
|
strcpy(p,"B16BBDz");
|
|
|
|
p = skip_string(p,1);
|
|
SSVAL(p,0,1); /* level 1 */
|
|
SSVAL(p,2,0xFFFF - 500); /* buf length */
|
|
p += 4;
|
|
typep = (uint32 *)p;
|
|
p += 4;
|
|
strcpy(p,domain);
|
|
strupper(p);
|
|
p = skip_string(p,1);
|
|
|
|
SIVAL(typep,0,0x80000000); /* domain list */
|
|
|
|
if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
|
|
PTR_DIFF(p,param),0,
|
|
8,0xFFFF - 500,
|
|
NULL,NULL,
|
|
param,NULL,
|
|
&rparam,&rdata) && SVAL(rparam,0)==0)
|
|
{
|
|
int converter=SVAL(rparam,2);
|
|
int count=SVAL(rparam,4);
|
|
int i;
|
|
char *p2 = rdata;
|
|
for (i=0;i<count;i++) {
|
|
char *sname = p2;
|
|
uint32 type = IVAL(p2,18);
|
|
int comment_offset = IVAL(p2,22) & 0xFFFF;
|
|
char *comment = comment_offset?(rdata+comment_offset-converter):"";
|
|
|
|
add_server_entry(sname,type,lp_max_ttl(),comment,False);
|
|
p2 += 26;
|
|
}
|
|
}
|
|
|
|
SIVAL(typep,0,0xFFFFFFFF); /* server list */
|
|
|
|
if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
|
|
PTR_DIFF(p,param),0,
|
|
8,0xFFFF - 500,
|
|
NULL,NULL,
|
|
param,NULL,
|
|
&rparam,&rdata) && SVAL(rparam,0)==0)
|
|
{
|
|
int converter=SVAL(rparam,2);
|
|
int count=SVAL(rparam,4);
|
|
int i;
|
|
|
|
p = rdata;
|
|
for (i=0;i<count;i++) {
|
|
char *sname = p;
|
|
uint32 type = IVAL(p,18);
|
|
int comment_offset = IVAL(p,22) & 0xFFFF;
|
|
char *comment = comment_offset?(rdata+comment_offset-converter):"";
|
|
|
|
add_server_entry(sname,type,lp_max_ttl(),comment,False);
|
|
p += 26;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* close up */
|
|
bzero(outbuf,smb_size);
|
|
set_message(outbuf,0,0,True);
|
|
CVAL(outbuf,smb_com) = SMBtdis;
|
|
SSVAL(outbuf,smb_uid,uid);
|
|
SSVAL(outbuf,smb_tid,cnum);
|
|
send_smb(fd,outbuf);
|
|
receive_smb(fd,inbuf,1000);
|
|
|
|
close(fd);
|
|
if (inbuf) free(inbuf);
|
|
}
|