summaryrefslogtreecommitdiffstats
path: root/source/nmbsync.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/nmbsync.c')
-rw-r--r--source/nmbsync.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/source/nmbsync.c b/source/nmbsync.c
new file mode 100644
index 00000000000..5a77d6cc486
--- /dev/null
+++ b/source/nmbsync.c
@@ -0,0 +1,303 @@
+/*
+ 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);
+}