fix a dst bug, we had a sign wrong in the calculation :-(
[bbaumbach/samba-autobuild/.git] / source3 / nmbsync.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NBT netbios routines to synchronise browse lists
5    Copyright (C) Andrew Tridgell 1994-1995
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 */
22
23 #include "includes.h"
24 #include "loadparm.h"
25 #include "nameserv.h"
26
27 extern int DEBUGLEVEL;
28
29 struct server_record *add_server_entry(char *name,int servertype,
30                                        int ttl,char *comment,BOOL replace);
31
32
33 /****************************************************************************
34 call a remote api
35 ****************************************************************************/
36 static BOOL call_remote_api(int fd,int cnum,int uid,int timeout,
37                             char *inbuf,char *outbuf,
38                             int prcnt,int drcnt,
39                             int mprcnt,int mdrcnt,
40                             int *rprcnt,int *rdrcnt,
41                             char *param,char *data,
42                             char **rparam,char **rdata)
43 {
44   char *p1,*p2;
45
46   /* send a SMBtrans command */
47   bzero(outbuf,smb_size);
48   set_message(outbuf,14,0,True);
49   CVAL(outbuf,smb_com) = SMBtrans;
50   SSVAL(outbuf,smb_tid,cnum);
51   SSVAL(outbuf,smb_uid,uid);
52
53   p1 = smb_buf(outbuf);
54   strcpy(p1,"\\PIPE\\LANMAN");
55   p1 = skip_string(p1,1);
56   p2 = p1 + prcnt;
57
58   if (prcnt > 0)
59     memcpy(p1,param,prcnt);
60   if (drcnt > 0)
61     memcpy(p2,data,drcnt);
62
63   SSVAL(outbuf,smb_vwv0,prcnt); /* param count */
64   SSVAL(outbuf,smb_vwv1,drcnt); /* data count */
65   SSVAL(outbuf,smb_vwv2,mprcnt); /* mprcnt */
66   SSVAL(outbuf,smb_vwv3,mdrcnt); /* mdrcnt */
67   SSVAL(outbuf,smb_vwv4,0); /* msrcnt */
68   SSVAL(outbuf,smb_vwv5,0); /* flags */
69   SSVAL(outbuf,smb_vwv9,prcnt); /* pscnt */
70   SSVAL(outbuf,smb_vwv10,smb_offset(p1,outbuf)); /* psoff */
71   SSVAL(outbuf,smb_vwv11,drcnt); /* dscnt */
72   SSVAL(outbuf,smb_vwv12,smb_offset(p2,outbuf)); /* dsoff */
73   CVAL(outbuf,smb_vwv13) = 0; /* suwcnt */
74
75   set_message(outbuf,14,PTR_DIFF(p2+drcnt,smb_buf(outbuf)),False);
76
77   send_smb(fd,outbuf);
78   
79   if (receive_smb(fd,inbuf,timeout) &&
80       CVAL(inbuf,smb_rcls) == 0)
81     {
82       if (rparam)
83         *rparam = inbuf+4 + SVAL(inbuf,smb_vwv4);
84       if (rdata)
85         *rdata = inbuf+4 + SVAL(inbuf,smb_vwv7);
86       if (rprcnt)
87         *rprcnt = SVAL(inbuf,smb_vwv3);
88       if (rdrcnt)
89         *rdrcnt = SVAL(inbuf,smb_vwv6);
90       return(True);
91     }
92
93   return(False);
94 }
95
96
97 /*******************************************************************
98   synchronise browse lists with another browse server
99   ******************************************************************/
100 void sync_browse_lists(char *name,int name_type,char *myname,
101                        char *domain,struct in_addr ip)
102 {
103   char *protocol = "LM1.2X002";
104   char *service = "IPC$";
105   char *dev = "IPC";
106   int timeout=2000;
107   char *inbuf=NULL;
108   pstring outbuf;
109   char *p;
110   int len;
111   uint32 sesskey;
112   int cnum,uid;
113   BOOL ret;
114
115   int fd = open_socket_out(SOCK_STREAM, &ip, SMB_PORT);
116   if (fd < 0) {
117     DEBUG(3,("Failed to connect to %s at %s\n",name,inet_ntoa(ip)));
118     return;
119   }
120
121   if (!(inbuf = (char *)malloc(0xFFFF+1024))) return;  
122
123   /* put in the destination name */
124   len = 4;
125   p = outbuf+len;
126   name_mangle(name,p,name_type);
127   len += name_len(p);
128
129   /* and my name */
130   p = outbuf+len;
131   name_mangle(myname,p,0x20);
132   len += name_len(p);
133
134   _smb_setlen(outbuf,len);
135   CVAL(outbuf,0) = 0x81;
136
137   send_smb(fd,outbuf);
138   receive_smb(fd,inbuf,5000);
139   
140   bzero(outbuf,smb_size);
141
142   /* setup the protocol string */
143   set_message(outbuf,0,strlen(protocol)+2,True);
144   p = smb_buf(outbuf);
145   *p++ = 2;
146   strcpy(p,protocol);
147
148   CVAL(outbuf,smb_com) = SMBnegprot;
149   CVAL(outbuf,smb_flg) = 0x8;
150   SSVAL(outbuf,smb_flg2,0x1);
151
152   send_smb(fd,outbuf);
153   bzero(inbuf,smb_size);
154   ret = receive_smb(fd,inbuf,timeout);
155   
156   if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
157     DEBUG(3,("%s rejected the protocol\n",name));
158     close(fd);
159     if (inbuf) free(inbuf);
160     return;
161   }
162
163   sesskey = IVAL(inbuf,smb_vwv6);
164
165   bzero(outbuf,smb_size);
166   set_message(outbuf,10,2,True);
167   CVAL(outbuf,smb_com) = SMBsesssetupX;
168
169   CVAL(outbuf,smb_vwv0) = 0xFF;
170   SSVAL(outbuf,smb_vwv2,0xFFFF);
171   SSVAL(outbuf,smb_vwv3,2);
172   SSVAL(outbuf,smb_vwv4,1);
173   SIVAL(outbuf,smb_vwv5,sesskey);
174   SSVAL(outbuf,smb_vwv7,1);
175
176   send_smb(fd,outbuf);
177   bzero(inbuf,smb_size);
178   ret = receive_smb(fd,inbuf,timeout);
179   if (!ret || CVAL(inbuf,smb_rcls)) {
180     DEBUG(3,("%s rejected session setup\n",name));
181     close(fd);
182     if (inbuf) free(inbuf);
183     return;
184   }
185
186   uid = SVAL(inbuf,smb_uid);
187
188   bzero(outbuf,smb_size);
189   set_message(outbuf,4,2 + (2 + strlen(name) + 1 + strlen(service)) +
190        1 + strlen(dev),True);
191   CVAL(outbuf,smb_com) = SMBtconX;
192   SSVAL(outbuf,smb_uid,uid);
193
194   SSVAL(outbuf,smb_vwv0,0xFF);
195   SSVAL(outbuf,smb_vwv3,1);
196
197   p = smb_buf(outbuf) + 1;
198   strcpy(p, "\\\\");
199   strcat(p, name);
200   strcat(p, "\\");
201   strcat(p,service);
202   p = skip_string(p,1);
203   strcpy(p,dev);
204
205   send_smb(fd,outbuf);
206   bzero(inbuf,smb_size);
207   ret = receive_smb(fd,inbuf,timeout);
208   if (!ret || CVAL(inbuf,smb_rcls)) {
209     DEBUG(3,("%s rejected IPC connect (%d,%d)\n",name,
210              CVAL(inbuf,smb_rcls),SVAL(inbuf,smb_err)));
211     close(fd);
212     if (inbuf) free(inbuf);
213     return;
214   }
215
216   cnum = SVAL(inbuf,smb_tid);
217   
218   /* now I need to send a NetServerEnum */
219   {
220     fstring param;
221     uint32 *typep;
222     char *rparam,*rdata;
223
224     p = param;
225     SSVAL(p,0,0x68); /* api number */
226     p += 2;
227     strcpy(p,"WrLehDz");
228     p = skip_string(p,1);
229
230     strcpy(p,"B16BBDz");
231
232     p = skip_string(p,1);
233     SSVAL(p,0,1); /* level 1 */
234     SSVAL(p,2,0xFFFF - 500); /* buf length */
235     p += 4;
236     typep = (uint32 *)p;
237     p += 4;
238     strcpy(p,domain);
239     strupper(p);
240     p = skip_string(p,1);
241
242     SIVAL(typep,0,0x80000000); /* domain list */
243
244     if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
245                         PTR_DIFF(p,param),0,
246                         8,0xFFFF - 500,
247                         NULL,NULL,
248                         param,NULL,
249                         &rparam,&rdata) && SVAL(rparam,0)==0)
250     {
251       int converter=SVAL(rparam,2);
252       int count=SVAL(rparam,4);
253       int i;
254       char *p2 = rdata;
255       for (i=0;i<count;i++) {
256         char *sname = p2;
257         uint32 type = IVAL(p2,18);
258         int comment_offset = IVAL(p2,22) & 0xFFFF;
259         char *comment = comment_offset?(rdata+comment_offset-converter):"";
260
261         add_server_entry(sname,type,lp_max_ttl(),comment,False);
262         p2 += 26;
263       }
264     }
265
266     SIVAL(typep,0,0xFFFFFFFF); /* server list */
267
268     if (call_remote_api(fd,cnum,uid,timeout,inbuf,outbuf,
269                         PTR_DIFF(p,param),0,
270                         8,0xFFFF - 500,
271                         NULL,NULL,
272                         param,NULL,
273                         &rparam,&rdata) && SVAL(rparam,0)==0)
274     {
275       int converter=SVAL(rparam,2);
276       int count=SVAL(rparam,4);
277       int i;
278
279       p = rdata;
280       for (i=0;i<count;i++) {
281         char *sname = p;
282         uint32 type = IVAL(p,18);
283         int comment_offset = IVAL(p,22) & 0xFFFF;
284         char *comment = comment_offset?(rdata+comment_offset-converter):"";
285
286         add_server_entry(sname,type,lp_max_ttl(),comment,False);
287         p += 26;
288       }
289     }
290   }
291
292   /* close up */
293   bzero(outbuf,smb_size);
294   set_message(outbuf,0,0,True);
295   CVAL(outbuf,smb_com) = SMBtdis;
296   SSVAL(outbuf,smb_uid,uid);
297   SSVAL(outbuf,smb_tid,cnum);
298   send_smb(fd,outbuf);
299   receive_smb(fd,inbuf,1000);
300   
301   close(fd);
302   if (inbuf) free(inbuf);
303 }