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