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