Rolled back tree state to 11:59pm 8th November 1997 EST to
[sfrench/samba-autobuild/.git] / source / libsmb / clientgen.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client generic functions
5    Copyright (C) Andrew Tridgell 1994-1997
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 #ifdef SYSLOG
23 #undef SYSLOG
24 #endif
25
26 #include "includes.h"
27
28
29 extern int DEBUGLEVEL;
30
31 /****************************************************************************
32 setup basics in a outgoing packet
33 ****************************************************************************/
34 static void cli_setup_packet(struct cli_state *cli)
35 {
36         SSVAL(cli->outbuf,smb_pid,cli->pid);
37         SSVAL(cli->outbuf,smb_uid,cli->uid);
38         SSVAL(cli->outbuf,smb_mid,cli->mid);
39         if (cli->protocol > PROTOCOL_CORE) {
40                 SCVAL(cli->outbuf,smb_flg,0x8);
41                 SSVAL(cli->outbuf,smb_flg2,0x1);
42         }
43 }
44
45
46 /****************************************************************************
47   send a SMB trans or trans2 request
48   ****************************************************************************/
49 static BOOL cli_send_trans(struct cli_state *cli,
50                            int trans, char *name, int fid, int flags,
51                            char *data,char *param,uint16 *setup, int ldata,int lparam,
52                            int lsetup,int mdata,int mparam,int msetup)
53 {
54         int i;
55         int this_ldata,this_lparam;
56         int tot_data=0,tot_param=0;
57         char *outdata,*outparam;
58         char *p;
59
60         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
61         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
62
63         bzero(cli->outbuf,smb_size);
64         set_message(cli->outbuf,14+lsetup,0,True);
65         CVAL(cli->outbuf,smb_com) = trans;
66         SSVAL(cli->outbuf,smb_tid, cli->cnum);
67         cli_setup_packet(cli);
68
69         outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
70         outdata = outparam+this_lparam;
71
72         /* primary request */
73         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
74         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
75         SSVAL(cli->outbuf,smb_mprcnt,mparam);   /* mprcnt */
76         SSVAL(cli->outbuf,smb_mdrcnt,mdata);    /* mdrcnt */
77         SCVAL(cli->outbuf,smb_msrcnt,msetup);   /* msrcnt */
78         SSVAL(cli->outbuf,smb_flags,flags);     /* flags */
79         SIVAL(cli->outbuf,smb_timeout,0);               /* timeout */
80         SSVAL(cli->outbuf,smb_pscnt,this_lparam);       /* pscnt */
81         SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
82         SSVAL(cli->outbuf,smb_dscnt,this_ldata);        /* dscnt */
83         SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
84         SCVAL(cli->outbuf,smb_suwcnt,lsetup);   /* suwcnt */
85         for (i=0;i<lsetup;i++)          /* setup[] */
86                 SSVAL(cli->outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
87         p = smb_buf(cli->outbuf);
88         if (trans==SMBtrans) {
89                 strcpy(p,name);                 /* name[] */
90         } else {
91                 *p++ = 0;  /* put in a null smb_name */
92                 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
93         }
94         if (this_lparam)                        /* param[] */
95                 memcpy(outparam,param,this_lparam);
96         if (this_ldata)                 /* data[] */
97                 memcpy(outdata,data,this_ldata);
98         set_message(cli->outbuf,14+lsetup,              /* wcnt, bcc */
99                     PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
100
101         show_msg(cli->outbuf);
102         send_smb(cli->fd,cli->outbuf);
103
104         if (this_ldata < ldata || this_lparam < lparam) {
105                 /* receive interim response */
106                 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout) || 
107                     CVAL(cli->inbuf,smb_rcls) != 0) {
108                         return(False);
109                 }      
110
111                 tot_data = this_ldata;
112                 tot_param = this_lparam;
113                 
114                 while (tot_data < ldata || tot_param < lparam)  {
115                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
116                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
117
118                         set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
119                         CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
120                         
121                         outparam = smb_buf(cli->outbuf);
122                         outdata = outparam+this_lparam;
123                         
124                         /* secondary request */
125                         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
126                         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
127                         SSVAL(cli->outbuf,smb_spscnt,this_lparam);      /* pscnt */
128                         SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
129                         SSVAL(cli->outbuf,smb_spsdisp,tot_param);       /* psdisp */
130                         SSVAL(cli->outbuf,smb_sdscnt,this_ldata);       /* dscnt */
131                         SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
132                         SSVAL(cli->outbuf,smb_sdsdisp,tot_data);        /* dsdisp */
133                         if (trans==SMBtrans2)
134                                 SSVAL(cli->outbuf,smb_sfid,fid);                /* fid */
135                         if (this_lparam)                        /* param[] */
136                                 memcpy(outparam,param,this_lparam);
137                         if (this_ldata)                 /* data[] */
138                                 memcpy(outdata,data,this_ldata);
139                         set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
140                                     PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
141                         
142                         show_msg(cli->outbuf);
143                         send_smb(cli->fd,cli->outbuf);
144                         
145                         tot_data += this_ldata;
146                         tot_param += this_lparam;
147                 }
148         }
149
150         return(True);
151 }
152
153
154 /****************************************************************************
155   receive a SMB trans or trans2 response allocating the necessary memory
156   ****************************************************************************/
157 static BOOL cli_receive_trans(struct cli_state *cli,
158                               int trans,int *data_len,
159                               int *param_len, char **data,char **param)
160 {
161         int total_data=0;
162         int total_param=0;
163         int this_data,this_param;
164         
165         *data_len = *param_len = 0;
166         
167         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
168                 return False;
169
170         show_msg(cli->inbuf);
171         
172         /* sanity check */
173         if (CVAL(cli->inbuf,smb_com) != trans) {
174                 DEBUG(0,("Expected %s response, got command 0x%02x\n",
175                          trans==SMBtrans?"SMBtrans":"SMBtrans2", 
176                          CVAL(cli->inbuf,smb_com)));
177                 return(False);
178         }
179         if (CVAL(cli->inbuf,smb_rcls) != 0)
180                 return(False);
181
182         /* parse out the lengths */
183         total_data = SVAL(cli->inbuf,smb_tdrcnt);
184         total_param = SVAL(cli->inbuf,smb_tprcnt);
185
186         /* allocate it */
187         *data = Realloc(*data,total_data);
188         *param = Realloc(*param,total_param);
189
190         while (1)  {
191                 this_data = SVAL(cli->inbuf,smb_drcnt);
192                 this_param = SVAL(cli->inbuf,smb_prcnt);
193
194                 if (this_data + *data_len > total_data ||
195                     this_param + *param_len > total_param) {
196                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
197                         return False;
198                 }
199
200                 if (this_data)
201                         memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
202                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
203                                this_data);
204                 if (this_param)
205                         memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
206                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
207                                this_param);
208                 *data_len += this_data;
209                 *param_len += this_param;
210
211                 /* parse out the total lengths again - they can shrink! */
212                 total_data = SVAL(cli->inbuf,smb_tdrcnt);
213                 total_param = SVAL(cli->inbuf,smb_tprcnt);
214                 
215                 if (total_data <= *data_len && total_param <= *param_len)
216                         break;
217                 
218                 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
219                         return False;
220
221                 show_msg(cli->inbuf);
222                 
223                 /* sanity check */
224                 if (CVAL(cli->inbuf,smb_com) != trans) {
225                         DEBUG(0,("Expected %s response, got command 0x%02x\n",
226                                  trans==SMBtrans?"SMBtrans":"SMBtrans2", 
227                                  CVAL(cli->inbuf,smb_com)));
228                         return(False);
229                 }
230                 if (CVAL(cli->inbuf,smb_rcls) != 0)
231                         return(False);
232         }
233         
234         return(True);
235 }
236
237
238 /****************************************************************************
239 call a remote api
240 ****************************************************************************/
241 static BOOL cli_api(struct cli_state *cli,
242                     int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt,
243                     int *rdrcnt, char *param,char *data, 
244                     char **rparam, char **rdata)
245 {
246   cli_send_trans(cli,SMBtrans,"\\PIPE\\LANMAN",0,0,
247                  data,param,NULL,
248                  drcnt,prcnt,0,
249                  mdrcnt,mprcnt,0);
250
251   return (cli_receive_trans(cli,SMBtrans,
252                                      rdrcnt,rprcnt,
253                                      rdata,rparam));
254 }
255
256
257 /****************************************************************************
258 perform a NetWkstaUserLogon
259 ****************************************************************************/
260 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
261 {
262         char *rparam = NULL;
263         char *rdata = NULL;
264         char *p;
265         int rdrcnt,rprcnt;
266         pstring param;
267
268         memset(param, 0, sizeof(param));
269         
270         /* send a SMBtrans command with api NetWkstaUserLogon */
271         p = param;
272         SSVAL(p,0,132); /* api number */
273         p += 2;
274         strcpy(p,"OOWb54WrLh");
275         p = skip_string(p,1);
276         strcpy(p,"WB21BWDWWDDDDDDDzzzD");
277         p = skip_string(p,1);
278         SSVAL(p,0,1);
279         p += 2;
280         strcpy(p,user);
281         strupper(p);
282         p += 21; p++; p += 15; p++; 
283         strcpy(p, workstation); 
284         strupper(p);
285         p += 16;
286         SSVAL(p, 0, BUFFER_SIZE);
287         p += 2;
288         SSVAL(p, 0, BUFFER_SIZE);
289         p += 2;
290         
291         cli->error = -1;
292         
293         if (cli_api(cli, PTR_DIFF(p,param),0,
294                     1024,BUFFER_SIZE,
295                     &rprcnt,&rdrcnt,
296                     param,NULL,
297                     &rparam,&rdata)) {
298                 cli->error = SVAL(rparam,0);
299                 p = rdata;
300                 
301                 if (cli->error == 0) {
302                         DEBUG(4,("NetWkstaUserLogon success\n"));
303                         cli->privilages = SVAL(p, 24);
304                         fstrcpy(cli->eff_name,p+2);
305                 } else {
306                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->error));
307                 }
308         }
309         
310         if (rparam) free(rparam);
311         if (rdata) free(rdata);
312         return cli->error == 0;
313 }
314
315
316 /****************************************************************************
317 call a NetServerEnum for the specified workgroup and servertype mask.
318 This function then calls the specified callback function for each name returned.
319
320 The callback function takes 3 arguments: the machine name, the server type and
321 the comment.
322 ****************************************************************************/
323 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
324                        void (*fn)(char *, uint32, char *))
325 {
326         char *rparam = NULL;
327         char *rdata = NULL;
328         int rdrcnt,rprcnt;
329         char *p;
330         pstring param;
331         int uLevel = 1;
332         int count = -1;
333   
334         /* send a SMBtrans command with api NetServerEnum */
335         p = param;
336         SSVAL(p,0,0x68); /* api number */
337         p += 2;
338         strcpy(p,"WrLehDz");
339         p = skip_string(p,1);
340   
341         strcpy(p,"B16BBDz");
342   
343         p = skip_string(p,1);
344         SSVAL(p,0,uLevel);
345         SSVAL(p,2,BUFFER_SIZE);
346         p += 4;
347         SIVAL(p,0,stype);
348         p += 4;
349         
350         pstrcpy(p, workgroup);
351         p = skip_string(p,1);
352         
353         if (cli_api(cli, 
354                     PTR_DIFF(p,param), /* param count */
355                     8, /*data count */
356                     0, /* mprcount */
357                     BUFFER_SIZE, /* mdrcount */
358                     &rprcnt,&rdrcnt,
359                     param, NULL, 
360                     &rparam,&rdata)) {
361                 int res = SVAL(rparam,0);
362                 int converter=SVAL(rparam,2);
363                 int i;
364                         
365                 if (res == 0) {
366                         count=SVAL(rparam,4);
367                         p = rdata;
368                                         
369                         for (i = 0;i < count;i++, p += 26) {
370                                 char *sname = p;
371                                 int comment_offset = IVAL(p,22) & 0xFFFF;
372                                 char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
373
374                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
375
376                                 fn(sname, stype, cmnt);
377                         }
378                 }
379         }
380   
381         if (rparam) free(rparam);
382         if (rdata) free(rdata);
383         
384         return(count > 0);
385 }
386
387
388
389
390 static  struct {
391     int prot;
392     char *name;
393   }
394 prots[] = 
395     {
396       {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
397       {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
398       {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
399       {PROTOCOL_LANMAN1,"LANMAN1.0"},
400       {PROTOCOL_LANMAN2,"LM1.2X002"},
401       {PROTOCOL_LANMAN2,"Samba"},
402       {PROTOCOL_NT1,"NT LM 0.12"},
403       {PROTOCOL_NT1,"NT LANMAN 1.0"},
404       {-1,NULL}
405     };
406
407
408 /****************************************************************************
409 send a session setup
410 ****************************************************************************/
411 BOOL cli_session_setup(struct cli_state *cli, 
412                        char *user, 
413                        char *pass, int passlen,
414                        char *ntpass, int ntpasslen,
415                        char *workgroup)
416 {
417         char *p;
418         fstring pword;
419
420         if (cli->protocol < PROTOCOL_LANMAN1)
421                 return False;
422
423         if (passlen > sizeof(pword)-1) {
424                 return False;
425         }
426
427         if ((cli->sec_mode & 2) && *pass && passlen != 24) {
428                 passlen = 24;
429                 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
430         } else {
431                 memcpy(pword, pass, passlen);
432         }
433
434         /* if in share level security then don't send a password now */
435         if (!(cli->sec_mode & 1)) {fstrcpy(pword, "");passlen=1;} 
436
437         /* send a session setup command */
438         bzero(cli->outbuf,smb_size);
439
440         if (cli->protocol < PROTOCOL_NT1) {
441                 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
442                 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
443                 cli_setup_packet(cli);
444
445                 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
446                 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
447                 SSVAL(cli->outbuf,smb_vwv3,2);
448                 SSVAL(cli->outbuf,smb_vwv4,1);
449                 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
450                 SSVAL(cli->outbuf,smb_vwv7,passlen);
451                 p = smb_buf(cli->outbuf);
452                 memcpy(p,pword,passlen);
453                 p += passlen;
454                 strcpy(p,user);
455                 strupper(p);
456         } else {
457                 set_message(cli->outbuf,13,0,True);
458                 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
459                 cli_setup_packet(cli);
460                 
461                 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
462                 SSVAL(cli->outbuf,smb_vwv2,BUFFER_SIZE);
463                 SSVAL(cli->outbuf,smb_vwv3,2);
464                 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
465                 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
466                 SSVAL(cli->outbuf,smb_vwv7,passlen);
467                 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
468                 p = smb_buf(cli->outbuf);
469                 memcpy(p,pword,passlen); 
470                 p += SVAL(cli->outbuf,smb_vwv7);
471                 memcpy(p,ntpass,ntpasslen); 
472                 p += SVAL(cli->outbuf,smb_vwv8);
473                 strcpy(p,user);
474                 strupper(p);
475                 p = skip_string(p,1);
476                 strcpy(p,workgroup);
477                 strupper(p);
478                 p = skip_string(p,1);
479                 strcpy(p,"Unix");p = skip_string(p,1);
480                 strcpy(p,"Samba");p = skip_string(p,1);
481                 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
482         }
483
484       send_smb(cli->fd,cli->outbuf);
485       if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
486               return False;
487
488       show_msg(cli->inbuf);
489
490       if (CVAL(cli->inbuf,smb_rcls) != 0) {
491               return False;
492       }
493
494       /* use the returned uid from now on */
495       cli->uid = SVAL(cli->inbuf,smb_uid);
496
497       return True;
498 }
499
500
501 /****************************************************************************
502 send a tconX
503 ****************************************************************************/
504 BOOL cli_send_tconX(struct cli_state *cli, 
505                     char *share, char *dev, char *pass, int passlen)
506 {
507         fstring fullshare, pword;
508         char *p;
509         bzero(cli->outbuf,smb_size);
510         bzero(cli->inbuf,smb_size);
511
512         if (cli->sec_mode & 1) {
513                 passlen = 1;
514                 pass = "";
515         }
516
517         if ((cli->sec_mode & 2) && *pass && passlen != 24) {
518                 passlen = 24;
519                 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
520         } else {
521                 memcpy(pword, pass, passlen);
522         }
523
524         sprintf(fullshare, "\\\\%s\\%s", cli->desthost, share);
525
526         set_message(cli->outbuf,4,
527                     2 + strlen(fullshare) + passlen + strlen(dev),True);
528         CVAL(cli->outbuf,smb_com) = SMBtconX;
529         cli_setup_packet(cli);
530
531         SSVAL(cli->outbuf,smb_vwv0,0xFF);
532         SSVAL(cli->outbuf,smb_vwv3,passlen);
533
534         p = smb_buf(cli->outbuf);
535         memcpy(p,pword,passlen);
536         p += passlen;
537         strcpy(p,fullshare);
538         p = skip_string(p,1);
539         strcpy(p,dev);
540
541         SCVAL(cli->inbuf,smb_rcls, 1);
542
543         send_smb(cli->fd,cli->outbuf);
544         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
545                 return False;
546
547         if (CVAL(cli->inbuf,smb_rcls) != 0) {
548                 return False;
549         }
550
551         cli->cnum = SVAL(cli->inbuf,smb_tid);
552         return True;
553 }
554
555
556 /****************************************************************************
557 send a tree disconnect
558 ****************************************************************************/
559 BOOL cli_tdis(struct cli_state *cli)
560 {
561         bzero(cli->outbuf,smb_size);
562         set_message(cli->outbuf,0,0,True);
563         CVAL(cli->outbuf,smb_com) = SMBtdis;
564         SSVAL(cli->outbuf,smb_tid,cli->cnum);
565         cli_setup_packet(cli);
566         
567         send_smb(cli->fd,cli->outbuf);
568         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
569                 return False;
570         
571         return CVAL(cli->inbuf,smb_rcls) == 0;
572 }
573
574 /****************************************************************************
575 delete a file
576 ****************************************************************************/
577 BOOL cli_unlink(struct cli_state *cli, char *fname)
578 {
579         char *p;
580
581         bzero(cli->outbuf,smb_size);
582         bzero(cli->inbuf,smb_size);
583
584         set_message(cli->outbuf,1, 2 + strlen(fname),True);
585
586         CVAL(cli->outbuf,smb_com) = SMBunlink;
587         SSVAL(cli->outbuf,smb_tid,cli->cnum);
588         cli_setup_packet(cli);
589
590         SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
591   
592         p = smb_buf(cli->outbuf);
593         *p++ = 4;      
594         strcpy(p,fname);
595         p = skip_string(p,1);
596
597         send_smb(cli->fd,cli->outbuf);
598         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
599                 return False;
600         }
601
602         if (CVAL(cli->inbuf,smb_rcls) != 0) {
603                 return False;
604         }
605
606         return True;
607 }
608
609
610
611 /****************************************************************************
612 open a file
613 ****************************************************************************/
614 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
615 {
616         char *p;
617         unsigned openfn=0;
618         unsigned accessmode=0;
619
620         if (flags & O_CREAT)
621                 openfn |= (1<<4);
622         if (!(flags & O_EXCL)) {
623                 if (flags & O_TRUNC)
624                         openfn |= (1<<1);
625                 else
626                         openfn |= (1<<0);
627         }
628
629         accessmode = (share_mode<<4);
630
631         if ((flags & O_RDWR) == O_RDWR) {
632                 accessmode |= 2;
633         } else if ((flags & O_WRONLY) == O_WRONLY) {
634                 accessmode |= 1;
635         } 
636
637         bzero(cli->outbuf,smb_size);
638         bzero(cli->inbuf,smb_size);
639
640         set_message(cli->outbuf,15,1 + strlen(fname),True);
641
642         CVAL(cli->outbuf,smb_com) = SMBopenX;
643         SSVAL(cli->outbuf,smb_tid,cli->cnum);
644         cli_setup_packet(cli);
645
646         SSVAL(cli->outbuf,smb_vwv0,0xFF);
647         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
648         SSVAL(cli->outbuf,smb_vwv3,accessmode);
649         SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
650         SSVAL(cli->outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
651         SSVAL(cli->outbuf,smb_vwv8,openfn);
652   
653         p = smb_buf(cli->outbuf);
654         strcpy(p,fname);
655         p = skip_string(p,1);
656
657         send_smb(cli->fd,cli->outbuf);
658         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
659                 return -1;
660         }
661
662         if (CVAL(cli->inbuf,smb_rcls) != 0) {
663                 return -1;
664         }
665
666         return SVAL(cli->inbuf,smb_vwv2);
667 }
668
669
670
671
672 /****************************************************************************
673   close a file
674 ****************************************************************************/
675 BOOL cli_close(struct cli_state *cli, int fnum)
676 {
677         bzero(cli->outbuf,smb_size);
678         bzero(cli->inbuf,smb_size);
679
680         set_message(cli->outbuf,3,0,True);
681
682         CVAL(cli->outbuf,smb_com) = SMBclose;
683         SSVAL(cli->outbuf,smb_tid,cli->cnum);
684         cli_setup_packet(cli);
685
686         SSVAL(cli->outbuf,smb_vwv0,fnum);
687         SSVAL(cli->outbuf,smb_vwv1,0);
688         SSVAL(cli->outbuf,smb_vwv2,0);
689
690         send_smb(cli->fd,cli->outbuf);
691         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
692                 return False;
693         }
694
695         if (CVAL(cli->inbuf,smb_rcls) != 0) {
696                 return False;
697         }
698
699         return True;
700 }
701
702
703 /****************************************************************************
704   lock a file
705 ****************************************************************************/
706 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
707 {
708         char *p;
709
710         bzero(cli->outbuf,smb_size);
711         bzero(cli->inbuf,smb_size);
712
713         set_message(cli->outbuf,8,10,True);
714
715         CVAL(cli->outbuf,smb_com) = SMBlockingX;
716         SSVAL(cli->outbuf,smb_tid,cli->cnum);
717         cli_setup_packet(cli);
718
719         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
720         SSVAL(cli->outbuf,smb_vwv2,fnum);
721         CVAL(cli->outbuf,smb_vwv3) = 0;
722         SIVALS(cli->outbuf, smb_vwv4, timeout);
723         SSVAL(cli->outbuf,smb_vwv6,0);
724         SSVAL(cli->outbuf,smb_vwv7,1);
725
726         p = smb_buf(cli->outbuf);
727         SSVAL(p, 0, cli->pid);
728         SIVAL(p, 2, offset);
729         SIVAL(p, 6, len);
730
731         send_smb(cli->fd,cli->outbuf);
732         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
733                 return False;
734         }
735
736         if (CVAL(cli->inbuf,smb_rcls) != 0) {
737                 return False;
738         }
739
740         return True;
741 }
742
743 /****************************************************************************
744   unlock a file
745 ****************************************************************************/
746 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
747 {
748         char *p;
749
750         bzero(cli->outbuf,smb_size);
751         bzero(cli->inbuf,smb_size);
752
753         set_message(cli->outbuf,8,10,True);
754
755         CVAL(cli->outbuf,smb_com) = SMBlockingX;
756         SSVAL(cli->outbuf,smb_tid,cli->cnum);
757         cli_setup_packet(cli);
758
759         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
760         SSVAL(cli->outbuf,smb_vwv2,fnum);
761         CVAL(cli->outbuf,smb_vwv3) = 0;
762         SIVALS(cli->outbuf, smb_vwv4, timeout);
763         SSVAL(cli->outbuf,smb_vwv6,1);
764         SSVAL(cli->outbuf,smb_vwv7,0);
765
766         p = smb_buf(cli->outbuf);
767         SSVAL(p, 0, cli->pid);
768         SIVAL(p, 2, offset);
769         SIVAL(p, 6, len);
770
771         send_smb(cli->fd,cli->outbuf);
772         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
773                 return False;
774         }
775
776         if (CVAL(cli->inbuf,smb_rcls) != 0) {
777                 return False;
778         }
779
780         return True;
781 }
782
783
784 /****************************************************************************
785   read from a file
786 ****************************************************************************/
787 int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
788 {
789         char *p;
790
791         bzero(cli->outbuf,smb_size);
792         bzero(cli->inbuf,smb_size);
793
794         set_message(cli->outbuf,10,0,True);
795
796         CVAL(cli->outbuf,smb_com) = SMBreadX;
797         SSVAL(cli->outbuf,smb_tid,cli->cnum);
798         cli_setup_packet(cli);
799
800         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
801         SSVAL(cli->outbuf,smb_vwv2,fnum);
802         SIVAL(cli->outbuf,smb_vwv3,offset);
803         SSVAL(cli->outbuf,smb_vwv5,size);
804         SSVAL(cli->outbuf,smb_vwv6,size);
805
806         send_smb(cli->fd,cli->outbuf);
807         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
808                 return -1;
809         }
810
811         if (CVAL(cli->inbuf,smb_rcls) != 0) {
812                 return -1;
813         }
814
815         size = SVAL(cli->inbuf, smb_vwv5);
816         p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
817
818         memcpy(buf, p, size);
819
820         return size;
821 }
822
823
824 /****************************************************************************
825   write to a file
826 ****************************************************************************/
827 int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
828 {
829         char *p;
830
831         bzero(cli->outbuf,smb_size);
832         bzero(cli->inbuf,smb_size);
833
834         set_message(cli->outbuf,12,size,True);
835
836         CVAL(cli->outbuf,smb_com) = SMBwriteX;
837         SSVAL(cli->outbuf,smb_tid,cli->cnum);
838         cli_setup_packet(cli);
839
840         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
841         SSVAL(cli->outbuf,smb_vwv2,fnum);
842         SIVAL(cli->outbuf,smb_vwv3,offset);
843
844         SSVAL(cli->outbuf,smb_vwv10,size);
845         SSVAL(cli->outbuf,smb_vwv11,smb_buf(cli->outbuf) - smb_base(cli->outbuf));
846
847         p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
848         memcpy(p, buf, size);
849
850         send_smb(cli->fd,cli->outbuf);
851         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
852                 return -1;
853         }
854
855         if (CVAL(cli->inbuf,smb_rcls) != 0) {
856                 return -1;
857         }
858
859         return SVAL(cli->inbuf, smb_vwv2);
860 }
861
862
863 /****************************************************************************
864 send a negprot command
865 ****************************************************************************/
866 BOOL cli_negprot(struct cli_state *cli)
867 {
868         char *p;
869         int numprots;
870         int plength;
871
872         bzero(cli->outbuf,smb_size);
873
874         /* setup the protocol strings */
875         for (plength=0,numprots=0;
876              prots[numprots].name && prots[numprots].prot<=cli->protocol;
877              numprots++)
878                 plength += strlen(prots[numprots].name)+2;
879     
880         set_message(cli->outbuf,0,plength,True);
881
882         p = smb_buf(cli->outbuf);
883         for (numprots=0;
884              prots[numprots].name && prots[numprots].prot<=cli->protocol;
885              numprots++) {
886                 *p++ = 2;
887                 strcpy(p,prots[numprots].name);
888                 p += strlen(p) + 1;
889         }
890
891         CVAL(cli->outbuf,smb_com) = SMBnegprot;
892         cli_setup_packet(cli);
893
894         CVAL(smb_buf(cli->outbuf),0) = 2;
895
896         send_smb(cli->fd,cli->outbuf);
897         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
898                 return False;
899
900         show_msg(cli->inbuf);
901
902         if (CVAL(cli->inbuf,smb_rcls) != 0 || 
903             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
904                 return(False);
905         }
906
907         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
908
909
910         if (cli->protocol < PROTOCOL_NT1) {    
911                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
912                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
913                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
914                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
915                 /* this time is converted to GMT by make_unix_date */
916                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
917                 if (cli->protocol >= PROTOCOL_COREPLUS) {
918                         cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
919                         cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
920                 }
921                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
922         } else {
923                 /* NT protocol */
924                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
925                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
926                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
927                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
928                 /* this time arrives in real GMT */
929                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
930                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
931                 if (IVAL(cli->inbuf,smb_vwv9+1) & 1)
932                         cli->readbraw_supported = 
933                                 cli->writebraw_supported = True;      
934         }
935
936         return True;
937 }
938
939
940 /****************************************************************************
941   send a session request
942 ****************************************************************************/
943 BOOL cli_session_request(struct cli_state *cli, char *host, int name_type,
944                          char *myname)
945 {
946         fstring dest;
947         char *p;
948         int len = 4;
949         /* send a session request (RFC 1002) */
950
951         fstrcpy(dest,host);
952   
953         p = strchr(dest,'.');
954         if (p) *p = 0;
955
956         fstrcpy(cli->desthost, dest);
957
958         /* put in the destination name */
959         p = cli->outbuf+len;
960         name_mangle(dest,p,name_type);
961         len += name_len(p);
962
963         /* and my name */
964         p = cli->outbuf+len;
965         name_mangle(myname,p,0);
966         len += name_len(p);
967
968         /* setup the packet length */
969         _smb_setlen(cli->outbuf,len);
970         CVAL(cli->outbuf,0) = 0x81;
971
972         send_smb(cli->fd,cli->outbuf);
973         DEBUG(5,("Sent session request\n"));
974
975         if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
976                 return False;
977
978         if (CVAL(cli->inbuf,0) != 0x82) {
979                 cli->error = CVAL(cli->inbuf,0);
980                 return False;
981         }
982         return(True);
983 }
984
985
986 /****************************************************************************
987 open the client sockets
988 ****************************************************************************/
989 BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
990 {
991         struct in_addr dest_ip;
992
993         fstrcpy(cli->desthost, host);
994         
995         if (!ip) {
996                 struct hostent *hp;
997
998                 if ((hp = Get_Hostbyname(cli->desthost)) == 0) {
999                         return False;
1000                 }
1001
1002                 putip((char *)&dest_ip,(char *)hp->h_addr);
1003         } else {
1004                 dest_ip = *ip;
1005         }
1006
1007
1008         cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout);
1009         if (cli->fd == -1)
1010                 return False;
1011
1012         return True;
1013 }
1014
1015
1016 /****************************************************************************
1017 initialise a client structure
1018 ****************************************************************************/
1019 BOOL cli_initialise(struct cli_state *cli)
1020 {
1021         if (cli->initialised) cli_shutdown(cli);
1022
1023         memset(cli, 0, sizeof(*cli));
1024         cli->fd = -1;
1025         cli->cnum = -1;
1026         cli->pid = getpid();
1027         cli->mid = 1;
1028         cli->uid = getuid();
1029         cli->protocol = PROTOCOL_NT1;
1030         cli->timeout = 20000;
1031         cli->bufsize = 0x10000;
1032         cli->max_xmit = cli->bufsize - 4;
1033         cli->outbuf = (char *)malloc(cli->bufsize);
1034         cli->inbuf = (char *)malloc(cli->bufsize);
1035         if (!cli->outbuf || !cli->inbuf) return False;
1036         cli->initialised = 1;
1037         return True;
1038 }
1039
1040 /****************************************************************************
1041 shutdown a client structure
1042 ****************************************************************************/
1043 void cli_shutdown(struct cli_state *cli)
1044 {
1045         if (cli->outbuf) free(cli->outbuf);
1046         if (cli->inbuf) free(cli->inbuf);
1047         if (cli->fd != -1) close(cli->fd);
1048         memset(cli, 0, sizeof(*cli));
1049 }
1050
1051 /****************************************************************************
1052   return a description of the error
1053 ****************************************************************************/
1054 char *cli_errstr(struct cli_state *cli)
1055 {
1056         return smb_errstr(cli->inbuf);
1057 }
1058
1059 /****************************************************************************
1060   return error codes for the last packet
1061 ****************************************************************************/
1062 void cli_error(struct cli_state *cli, int *eclass, int *num)
1063 {
1064         *eclass = CVAL(cli->inbuf,smb_rcls);
1065         *num = SVAL(cli->inbuf,smb_err);
1066 }
1067
1068 /****************************************************************************
1069 set socket options on a open connection
1070 ****************************************************************************/
1071 void cli_sockopt(struct cli_state *cli, char *options)
1072 {
1073         set_socket_options(cli->fd, options);
1074 }
1075
1076 /****************************************************************************
1077 set the PID to use for smb messages. Return the old pid.
1078 ****************************************************************************/
1079 int cli_setpid(struct cli_state *cli, int pid)
1080 {
1081         int ret = cli->pid;
1082         cli->pid = pid;
1083         return ret;
1084 }