added unlink() and rename() support to smbwrapper
[ira/wip.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-1998
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 #define NO_SYSLOG
23
24 #include "includes.h"
25 #include "trans2.h"
26
27
28 extern int DEBUGLEVEL;
29
30 /*****************************************************
31  RAP error codes - a small start but will be extended.
32 *******************************************************/
33
34 struct
35 {
36   int err;
37   char *message;
38 } rap_errmap[] =
39 {
40   {5,    "User has insufficient privilege" },
41   {86,   "The specified password is invalid" },
42   {2226, "Operation only permitted on a Primary Domain Controller"  },
43   {2242, "The password of this user has expired." },
44   {2243, "The password of this user cannot change." },
45   {2244, "This password cannot be used now (password history conflict)." },
46   {2245, "The password is shorter than required." },
47   {2246, "The password of this user is too recent to change."},
48   {0, NULL}
49 };  
50
51 /****************************************************************************
52   return a description of an SMB error
53 ****************************************************************************/
54 static char *cli_smb_errstr(struct cli_state *cli)
55 {
56         return smb_errstr(cli->inbuf);
57 }
58
59 /******************************************************
60  Return an error message - either an SMB error or a RAP
61  error.
62 *******************************************************/
63     
64 char *cli_errstr(struct cli_state *cli)
65 {   
66         static fstring error_message;
67         uint8 errclass;
68         uint32 errnum;
69         int i;      
70
71         /*  
72          * Errors are of three kinds - smb errors,
73          * dealt with by cli_smb_errstr, NT errors,
74          * whose code is in cli.nt_error, and rap
75          * errors, whose error code is in cli.rap_error.
76          */ 
77
78         cli_error(cli, &errclass, &errnum);
79
80         if (errclass != 0)
81         {
82                 return cli_smb_errstr(cli);
83         }
84
85         /*
86          * Was it an NT error ?
87          */
88
89         if (cli->nt_error)
90         {
91                 char *nt_msg = get_nt_error_msg(cli->nt_error);
92
93                 if (nt_msg == NULL)
94                 {
95                         slprintf(error_message, sizeof(fstring) - 1, "NT code %d", cli->nt_error);
96                 }
97                 else
98                 {
99                         fstrcpy(error_message, nt_msg);
100                 }
101
102                 return error_message;
103         }
104
105         /*
106          * Must have been a rap error.
107          */
108
109         slprintf(error_message, sizeof(error_message) - 1, "code %d", cli->rap_error);
110
111         for (i = 0; rap_errmap[i].message != NULL; i++)
112         {
113                 if (rap_errmap[i].err == cli->rap_error)
114                 {
115                         fstrcpy( error_message, rap_errmap[i].message);
116                         break;
117                 }
118         } 
119
120         return error_message;
121 }
122
123 /****************************************************************************
124 setup basics in a outgoing packet
125 ****************************************************************************/
126 static void cli_setup_packet(struct cli_state *cli)
127 {
128         cli->rap_error = 0;
129         cli->nt_error = 0;
130         SSVAL(cli->outbuf,smb_pid,cli->pid);
131         SSVAL(cli->outbuf,smb_uid,cli->vuid);
132         SSVAL(cli->outbuf,smb_mid,cli->mid);
133         if (cli->protocol > PROTOCOL_CORE) {
134                 SCVAL(cli->outbuf,smb_flg,0x8);
135                 SSVAL(cli->outbuf,smb_flg2,0x1);
136         }
137 }
138
139
140 /****************************************************************************
141   send a SMB trans or trans2 request
142   ****************************************************************************/
143 static BOOL cli_send_trans(struct cli_state *cli, int trans, 
144                            char *name, int pipe_name_len, 
145                            int fid, int flags,
146                            uint16 *setup, int lsetup, int msetup,
147                            char *param, int lparam, int mparam,
148                            char *data, int ldata, int mdata)
149 {
150         int i;
151         int this_ldata,this_lparam;
152         int tot_data=0,tot_param=0;
153         char *outdata,*outparam;
154         char *p;
155
156         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
157         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
158
159         bzero(cli->outbuf,smb_size);
160         set_message(cli->outbuf,14+lsetup,0,True);
161         CVAL(cli->outbuf,smb_com) = trans;
162         SSVAL(cli->outbuf,smb_tid, cli->cnum);
163         cli_setup_packet(cli);
164
165         outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 3);
166         outdata = outparam+this_lparam;
167
168         /* primary request */
169         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
170         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
171         SSVAL(cli->outbuf,smb_mprcnt,mparam);   /* mprcnt */
172         SSVAL(cli->outbuf,smb_mdrcnt,mdata);    /* mdrcnt */
173         SCVAL(cli->outbuf,smb_msrcnt,msetup);   /* msrcnt */
174         SSVAL(cli->outbuf,smb_flags,flags);     /* flags */
175         SIVAL(cli->outbuf,smb_timeout,0);               /* timeout */
176         SSVAL(cli->outbuf,smb_pscnt,this_lparam);       /* pscnt */
177         SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
178         SSVAL(cli->outbuf,smb_dscnt,this_ldata);        /* dscnt */
179         SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
180         SCVAL(cli->outbuf,smb_suwcnt,lsetup);   /* suwcnt */
181         for (i=0;i<lsetup;i++)          /* setup[] */
182                 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
183         p = smb_buf(cli->outbuf);
184         if (trans==SMBtrans) {
185                 memcpy(p,name, pipe_name_len + 1);  /* name[] */
186         } else {
187                 *p++ = 0;  /* put in a null smb_name */
188                 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
189         }
190         if (this_lparam)                        /* param[] */
191                 memcpy(outparam,param,this_lparam);
192         if (this_ldata)                 /* data[] */
193                 memcpy(outdata,data,this_ldata);
194         set_message(cli->outbuf,14+lsetup,              /* wcnt, bcc */
195                     PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
196
197         show_msg(cli->outbuf);
198         send_smb(cli->fd,cli->outbuf);
199
200         if (this_ldata < ldata || this_lparam < lparam) {
201                 /* receive interim response */
202                 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout) || 
203                     CVAL(cli->inbuf,smb_rcls) != 0) {
204                         return(False);
205                 }      
206
207                 tot_data = this_ldata;
208                 tot_param = this_lparam;
209                 
210                 while (tot_data < ldata || tot_param < lparam)  {
211                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
212                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
213
214                         set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
215                         CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
216                         
217                         outparam = smb_buf(cli->outbuf);
218                         outdata = outparam+this_lparam;
219                         
220                         /* secondary request */
221                         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
222                         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
223                         SSVAL(cli->outbuf,smb_spscnt,this_lparam);      /* pscnt */
224                         SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
225                         SSVAL(cli->outbuf,smb_spsdisp,tot_param);       /* psdisp */
226                         SSVAL(cli->outbuf,smb_sdscnt,this_ldata);       /* dscnt */
227                         SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
228                         SSVAL(cli->outbuf,smb_sdsdisp,tot_data);        /* dsdisp */
229                         if (trans==SMBtrans2)
230                                 SSVALS(cli->outbuf,smb_sfid,fid);               /* fid */
231                         if (this_lparam)                        /* param[] */
232                                 memcpy(outparam,param,this_lparam);
233                         if (this_ldata)                 /* data[] */
234                                 memcpy(outdata,data,this_ldata);
235                         set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
236                                     PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
237                         
238                         show_msg(cli->outbuf);
239                         send_smb(cli->fd,cli->outbuf);
240                         
241                         tot_data += this_ldata;
242                         tot_param += this_lparam;
243                 }
244         }
245
246         return(True);
247 }
248
249
250 /****************************************************************************
251   receive a SMB trans or trans2 response allocating the necessary memory
252   ****************************************************************************/
253 static BOOL cli_receive_trans(struct cli_state *cli,int trans,
254                               char **param, int *param_len,
255                               char **data, int *data_len)
256 {
257         int total_data=0;
258         int total_param=0;
259         int this_data,this_param;
260         
261         *data_len = *param_len = 0;
262         
263         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
264                 return False;
265
266         show_msg(cli->inbuf);
267         
268         /* sanity check */
269         if (CVAL(cli->inbuf,smb_com) != trans) {
270                 DEBUG(0,("Expected %s response, got command 0x%02x\n",
271                          trans==SMBtrans?"SMBtrans":"SMBtrans2", 
272                          CVAL(cli->inbuf,smb_com)));
273                 return(False);
274         }
275
276         if (cli_error(cli, NULL, NULL))
277         {
278                 return(False);
279         }
280
281         /* parse out the lengths */
282         total_data = SVAL(cli->inbuf,smb_tdrcnt);
283         total_param = SVAL(cli->inbuf,smb_tprcnt);
284
285         /* allocate it */
286         *data = Realloc(*data,total_data);
287         *param = Realloc(*param,total_param);
288
289         while (1)  {
290                 this_data = SVAL(cli->inbuf,smb_drcnt);
291                 this_param = SVAL(cli->inbuf,smb_prcnt);
292
293                 if (this_data + *data_len > total_data ||
294                     this_param + *param_len > total_param) {
295                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
296                         return False;
297                 }
298
299                 if (this_data)
300                         memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
301                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
302                                this_data);
303                 if (this_param)
304                         memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
305                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
306                                this_param);
307                 *data_len += this_data;
308                 *param_len += this_param;
309
310                 /* parse out the total lengths again - they can shrink! */
311                 total_data = SVAL(cli->inbuf,smb_tdrcnt);
312                 total_param = SVAL(cli->inbuf,smb_tprcnt);
313                 
314                 if (total_data <= *data_len && total_param <= *param_len)
315                         break;
316                 
317                 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
318                         return False;
319
320                 show_msg(cli->inbuf);
321                 
322                 /* sanity check */
323                 if (CVAL(cli->inbuf,smb_com) != trans) {
324                         DEBUG(0,("Expected %s response, got command 0x%02x\n",
325                                  trans==SMBtrans?"SMBtrans":"SMBtrans2", 
326                                  CVAL(cli->inbuf,smb_com)));
327                         return(False);
328                 }
329                 if (cli_error(cli, NULL, NULL))
330                 {
331                         return(False);
332                 }
333         }
334         
335         return(True);
336 }
337
338 /****************************************************************************
339 Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
340 ****************************************************************************/
341 BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, int pipe_name_len,
342                   uint16 *setup, uint32 setup_count, uint32 max_setup_count,
343                   char *params, uint32 param_count, uint32 max_param_count,
344                   char *data, uint32 data_count, uint32 max_data_count,
345                   char **rparam, uint32 *rparam_count,
346                   char **rdata, uint32 *rdata_count)
347 {
348   if (pipe_name_len == 0)
349     pipe_name_len = strlen(pipe_name);
350
351   cli_send_trans(cli, SMBtrans, 
352                  pipe_name, pipe_name_len,
353                  0,0,                         /* fid, flags */
354                  setup, setup_count, max_setup_count,
355                  params, param_count, max_param_count,
356                  data, data_count, max_data_count);
357
358   return (cli_receive_trans(cli, SMBtrans, 
359                             rparam, (int *)rparam_count,
360                             rdata, (int *)rdata_count));
361 }
362
363 /****************************************************************************
364 call a remote api
365 ****************************************************************************/
366 BOOL cli_api(struct cli_state *cli,
367              char *param, int prcnt, int mprcnt,
368              char *data, int drcnt, int mdrcnt,
369              char **rparam, int *rprcnt,
370              char **rdata, int *rdrcnt)
371 {
372   cli_send_trans(cli,SMBtrans,
373                  PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
374                  0,0,                             /* fid, flags */
375                  NULL,0,0,                /* Setup, length, max */
376                  param, prcnt, mprcnt,    /* Params, length, max */
377                  data, drcnt, mdrcnt      /* Data, length, max */ 
378                 );
379
380   return (cli_receive_trans(cli,SMBtrans,
381                             rparam, rprcnt,
382                             rdata, rdrcnt));
383 }
384
385
386 /****************************************************************************
387 perform a NetWkstaUserLogon
388 ****************************************************************************/
389 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
390 {
391         char *rparam = NULL;
392         char *rdata = NULL;
393         char *p;
394         int rdrcnt,rprcnt;
395         pstring param;
396
397         memset(param, 0, sizeof(param));
398         
399         /* send a SMBtrans command with api NetWkstaUserLogon */
400         p = param;
401         SSVAL(p,0,132); /* api number */
402         p += 2;
403         pstrcpy(p,"OOWb54WrLh");
404         p = skip_string(p,1);
405         pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
406         p = skip_string(p,1);
407         SSVAL(p,0,1);
408         p += 2;
409         pstrcpy(p,user);
410         strupper(p);
411         p += 21;
412     p++;
413     p += 15;
414     p++; 
415         pstrcpy(p, workstation); 
416         strupper(p);
417         p += 16;
418         SSVAL(p, 0, BUFFER_SIZE);
419         p += 2;
420         SSVAL(p, 0, BUFFER_SIZE);
421         p += 2;
422         
423         if (cli_api(cli, 
424                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
425                     NULL, 0, BUFFER_SIZE,           /* data, length, max */
426                     &rparam, &rprcnt,               /* return params, return size */
427                     &rdata, &rdrcnt                 /* return data, return size */
428                    )) {
429                 cli->rap_error = SVAL(rparam,0);
430                 p = rdata;
431                 
432                 if (cli->rap_error == 0) {
433                         DEBUG(4,("NetWkstaUserLogon success\n"));
434                         cli->privilages = SVAL(p, 24);
435                         fstrcpy(cli->eff_name,p+2);
436                 } else {
437                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
438                 }
439         }
440         
441         if (rparam)
442       free(rparam);
443         if (rdata)
444       free(rdata);
445         return (cli->rap_error == 0);
446 }
447
448 /****************************************************************************
449 call a NetShareEnum - try and browse available connections on a host
450 ****************************************************************************/
451 BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, char *))
452 {
453   char *rparam = NULL;
454   char *rdata = NULL;
455   char *p;
456   int rdrcnt,rprcnt;
457   pstring param;
458   int count = -1;
459
460   /* now send a SMBtrans command with api RNetShareEnum */
461   p = param;
462   SSVAL(p,0,0); /* api number */
463   p += 2;
464   pstrcpy(p,"WrLeh");
465   p = skip_string(p,1);
466   pstrcpy(p,"B13BWz");
467   p = skip_string(p,1);
468   SSVAL(p,0,1);
469   SSVAL(p,2,BUFFER_SIZE);
470   p += 4;
471
472   if (cli_api(cli, 
473               param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
474               NULL, 0, BUFFER_SIZE,            /* data, length, maxlen */
475               &rparam, &rprcnt,                /* return params, length */
476               &rdata, &rdrcnt))                /* return data, length */
477     {
478       int res = SVAL(rparam,0);
479       int converter=SVAL(rparam,2);
480       int i;
481       
482       if (res == 0)
483         {
484           count=SVAL(rparam,4);
485           p = rdata;
486
487           for (i=0;i<count;i++,p+=20)
488             {
489               char *sname = p;
490               int type = SVAL(p,14);
491               int comment_offset = IVAL(p,16) & 0xFFFF;
492               char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
493               fn(sname, type, cmnt);
494             }
495         }
496     }
497   
498   if (rparam)
499     free(rparam);
500   if (rdata)
501     free(rdata);
502
503   return count;
504 }
505
506
507 /****************************************************************************
508 call a NetServerEnum for the specified workgroup and servertype mask.
509 This function then calls the specified callback function for each name returned.
510
511 The callback function takes 3 arguments: the machine name, the server type and
512 the comment.
513 ****************************************************************************/
514 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
515                        void (*fn)(char *, uint32, char *))
516 {
517         char *rparam = NULL;
518         char *rdata = NULL;
519         int rdrcnt,rprcnt;
520         char *p;
521         pstring param;
522         int uLevel = 1;
523         int count = -1;
524   
525         /* send a SMBtrans command with api NetServerEnum */
526         p = param;
527         SSVAL(p,0,0x68); /* api number */
528         p += 2;
529         pstrcpy(p,"WrLehDz");
530         p = skip_string(p,1);
531   
532         pstrcpy(p,"B16BBDz");
533   
534         p = skip_string(p,1);
535         SSVAL(p,0,uLevel);
536         SSVAL(p,2,BUFFER_SIZE);
537         p += 4;
538         SIVAL(p,0,stype);
539         p += 4;
540         
541         pstrcpy(p, workgroup);
542         p = skip_string(p,1);
543         
544         if (cli_api(cli, 
545                     param, PTR_DIFF(p,param), 8,        /* params, length, max */
546                     NULL, 0, BUFFER_SIZE,               /* data, length, max */
547                     &rparam, &rprcnt,                   /* return params, return size */
548                     &rdata, &rdrcnt                     /* return data, return size */
549                    )) {
550                 int res = SVAL(rparam,0);
551                 int converter=SVAL(rparam,2);
552                 int i;
553                         
554                 if (res == 0) {
555                         count=SVAL(rparam,4);
556                         p = rdata;
557                                         
558                         for (i = 0;i < count;i++, p += 26) {
559                                 char *sname = p;
560                                 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
561                                 char *cmnt = comment_offset?(rdata+comment_offset):"";
562                                 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
563
564                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
565
566                                 fn(sname, stype, cmnt);
567                         }
568                 }
569         }
570   
571         if (rparam)
572       free(rparam);
573         if (rdata)
574       free(rdata);
575         
576         return(count > 0);
577 }
578
579
580
581
582 static  struct {
583     int prot;
584     char *name;
585   }
586 prots[] = 
587     {
588       {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
589       {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
590       {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
591       {PROTOCOL_LANMAN1,"LANMAN1.0"},
592       {PROTOCOL_LANMAN2,"LM1.2X002"},
593       {PROTOCOL_LANMAN2,"Samba"},
594       {PROTOCOL_NT1,"NT LM 0.12"},
595       {PROTOCOL_NT1,"NT LANMAN 1.0"},
596       {-1,NULL}
597     };
598
599
600 /****************************************************************************
601 send a session setup
602 ****************************************************************************/
603 BOOL cli_session_setup(struct cli_state *cli, 
604                        char *user, 
605                        char *pass, int passlen,
606                        char *ntpass, int ntpasslen,
607                        char *workgroup)
608 {
609         char *p;
610         fstring pword, ntpword;
611
612         if (cli->protocol < PROTOCOL_LANMAN1)
613                 return True;
614
615         if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
616                 return False;
617         }
618
619         if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
620           /* Null session connect. */
621           pword[0] = '\0';
622           ntpword[0] = '\0';
623         } else {
624           if ((cli->sec_mode & 2) && passlen != 24) {
625             passlen = 24;
626             ntpasslen = 24;
627             SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
628             SMBNTencrypt((uchar *)ntpass,(uchar *)cli->cryptkey,(uchar *)ntpword);
629           } else {
630             memcpy(pword, pass, passlen);
631             memcpy(ntpword, ntpass, ntpasslen);
632           }
633         }
634
635         /* if in share level security then don't send a password now */
636         if (!(cli->sec_mode & 1)) {
637                 fstrcpy(pword, "");
638                 passlen=1;
639                 fstrcpy(ntpword, "");
640                 ntpasslen=1;
641         } 
642
643         /* send a session setup command */
644         bzero(cli->outbuf,smb_size);
645
646         if (cli->protocol < PROTOCOL_NT1)
647         {
648                 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
649                 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
650                 cli_setup_packet(cli);
651
652                 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
653                 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
654                 SSVAL(cli->outbuf,smb_vwv3,2);
655                 SSVAL(cli->outbuf,smb_vwv4,1);
656                 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
657                 SSVAL(cli->outbuf,smb_vwv7,passlen);
658                 p = smb_buf(cli->outbuf);
659                 memcpy(p,pword,passlen);
660                 p += passlen;
661                 pstrcpy(p,user);
662                 strupper(p);
663         }
664         else
665         {
666                 set_message(cli->outbuf,13,0,True);
667                 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
668                 cli_setup_packet(cli);
669                 
670                 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
671                 SSVAL(cli->outbuf,smb_vwv2,BUFFER_SIZE);
672                 SSVAL(cli->outbuf,smb_vwv3,2);
673                 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
674                 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
675                 SSVAL(cli->outbuf,smb_vwv7,passlen);
676                 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
677                 SSVAL(cli->outbuf,smb_vwv11,CAP_STATUS32);
678                 p = smb_buf(cli->outbuf);
679                 memcpy(p,pword,passlen); 
680                 p += SVAL(cli->outbuf,smb_vwv7);
681                 memcpy(p,ntpword,ntpasslen); 
682                 p += SVAL(cli->outbuf,smb_vwv8);
683                 pstrcpy(p,user);
684                 strupper(p);
685                 p = skip_string(p,1);
686                 pstrcpy(p,workgroup);
687                 strupper(p);
688                 p = skip_string(p,1);
689                 pstrcpy(p,"Unix");p = skip_string(p,1);
690                 pstrcpy(p,"Samba");p = skip_string(p,1);
691                 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
692         }
693
694       send_smb(cli->fd,cli->outbuf);
695       if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
696               return False;
697
698       show_msg(cli->inbuf);
699
700       if (CVAL(cli->inbuf,smb_rcls) != 0) {
701               return False;
702       }
703
704       /* use the returned vuid from now on */
705       cli->vuid = SVAL(cli->inbuf,smb_uid);
706
707       return True;
708 }
709
710 /****************************************************************************
711  Send a uloggoff.
712 *****************************************************************************/
713
714 BOOL cli_ulogoff(struct cli_state *cli)
715 {
716         bzero(cli->outbuf,smb_size);
717         set_message(cli->outbuf,2,0,True);
718         CVAL(cli->outbuf,smb_com) = SMBulogoffX;
719         cli_setup_packet(cli);
720         SSVAL(cli->outbuf,smb_vwv0,0xFF);
721         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
722
723         send_smb(cli->fd,cli->outbuf);
724         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
725                 return False;
726
727         return CVAL(cli->inbuf,smb_rcls) == 0;
728 }
729
730 /****************************************************************************
731 send a tconX
732 ****************************************************************************/
733 BOOL cli_send_tconX(struct cli_state *cli, 
734                     char *share, char *dev, char *pass, int passlen)
735 {
736         fstring fullshare, pword;
737         char *p;
738         bzero(cli->outbuf,smb_size);
739         bzero(cli->inbuf,smb_size);
740
741         if (cli->sec_mode & 1) {
742                 passlen = 1;
743                 pass = "";
744         }
745
746         if ((cli->sec_mode & 2) && *pass && passlen != 24) {
747                 passlen = 24;
748                 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
749         } else {
750                 memcpy(pword, pass, passlen);
751         }
752
753         slprintf(fullshare, sizeof(fullshare)-1,
754                  "\\\\%s\\%s", cli->desthost, share);
755
756         set_message(cli->outbuf,4,
757                     2 + strlen(fullshare) + passlen + strlen(dev),True);
758         CVAL(cli->outbuf,smb_com) = SMBtconX;
759         cli_setup_packet(cli);
760
761         SSVAL(cli->outbuf,smb_vwv0,0xFF);
762         SSVAL(cli->outbuf,smb_vwv3,passlen);
763
764         p = smb_buf(cli->outbuf);
765         memcpy(p,pword,passlen);
766         p += passlen;
767         fstrcpy(p,fullshare);
768         p = skip_string(p,1);
769         pstrcpy(p,dev);
770
771         SCVAL(cli->inbuf,smb_rcls, 1);
772
773         send_smb(cli->fd,cli->outbuf);
774         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
775                 return False;
776
777         if (CVAL(cli->inbuf,smb_rcls) != 0) {
778                 return False;
779         }
780
781         if (cli->protocol >= PROTOCOL_NT1 &&
782             smb_buflen(cli->inbuf) == 3) {
783                 /* almost certainly win95 - enable bug fixes */
784                 cli->win95 = True;
785         }
786
787         cli->cnum = SVAL(cli->inbuf,smb_tid);
788         return True;
789 }
790
791
792 /****************************************************************************
793 send a tree disconnect
794 ****************************************************************************/
795 BOOL cli_tdis(struct cli_state *cli)
796 {
797         bzero(cli->outbuf,smb_size);
798         set_message(cli->outbuf,0,0,True);
799         CVAL(cli->outbuf,smb_com) = SMBtdis;
800         SSVAL(cli->outbuf,smb_tid,cli->cnum);
801         cli_setup_packet(cli);
802         
803         send_smb(cli->fd,cli->outbuf);
804         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
805                 return False;
806         
807         return CVAL(cli->inbuf,smb_rcls) == 0;
808 }
809
810 /****************************************************************************
811 rename a file
812 ****************************************************************************/
813 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
814 {
815         char *p;
816
817         bzero(cli->outbuf,smb_size);
818         bzero(cli->inbuf,smb_size);
819
820         set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True);
821
822         CVAL(cli->outbuf,smb_com) = SMBmv;
823         SSVAL(cli->outbuf,smb_tid,cli->cnum);
824         cli_setup_packet(cli);
825
826         SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
827
828         p = smb_buf(cli->outbuf);
829         *p++ = 4;
830         pstrcpy(p,fname_src);
831         p = skip_string(p,1);
832         *p++ = 4;
833         pstrcpy(p,fname_dst);
834
835         send_smb(cli->fd,cli->outbuf);
836         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
837                 return False;
838         }
839
840         if (CVAL(cli->inbuf,smb_rcls) != 0) {
841                 return False;
842         }
843
844         return True;
845 }
846
847 /****************************************************************************
848 delete a file
849 ****************************************************************************/
850 BOOL cli_unlink(struct cli_state *cli, char *fname)
851 {
852         char *p;
853
854         bzero(cli->outbuf,smb_size);
855         bzero(cli->inbuf,smb_size);
856
857         set_message(cli->outbuf,1, 2 + strlen(fname),True);
858
859         CVAL(cli->outbuf,smb_com) = SMBunlink;
860         SSVAL(cli->outbuf,smb_tid,cli->cnum);
861         cli_setup_packet(cli);
862
863         SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
864   
865         p = smb_buf(cli->outbuf);
866         *p++ = 4;      
867         pstrcpy(p,fname);
868
869         send_smb(cli->fd,cli->outbuf);
870         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
871                 return False;
872         }
873
874         if (CVAL(cli->inbuf,smb_rcls) != 0) {
875                 return False;
876         }
877
878         return True;
879 }
880
881 /****************************************************************************
882 create a directory
883 ****************************************************************************/
884 BOOL cli_mkdir(struct cli_state *cli, char *dname)
885 {
886         char *p;
887
888         bzero(cli->outbuf,smb_size);
889         bzero(cli->inbuf,smb_size);
890
891         set_message(cli->outbuf,0, 2 + strlen(dname),True);
892
893         CVAL(cli->outbuf,smb_com) = SMBmkdir;
894         SSVAL(cli->outbuf,smb_tid,cli->cnum);
895         cli_setup_packet(cli);
896
897         p = smb_buf(cli->outbuf);
898         *p++ = 4;      
899         pstrcpy(p,dname);
900
901         send_smb(cli->fd,cli->outbuf);
902         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
903                 return False;
904         }
905
906         if (CVAL(cli->inbuf,smb_rcls) != 0) {
907                 return False;
908         }
909
910         return True;
911 }
912
913 /****************************************************************************
914 remove a directory
915 ****************************************************************************/
916 BOOL cli_rmdir(struct cli_state *cli, char *dname)
917 {
918         char *p;
919
920         bzero(cli->outbuf,smb_size);
921         bzero(cli->inbuf,smb_size);
922
923         set_message(cli->outbuf,0, 2 + strlen(dname),True);
924
925         CVAL(cli->outbuf,smb_com) = SMBrmdir;
926         SSVAL(cli->outbuf,smb_tid,cli->cnum);
927         cli_setup_packet(cli);
928
929         p = smb_buf(cli->outbuf);
930         *p++ = 4;      
931         pstrcpy(p,dname);
932
933         send_smb(cli->fd,cli->outbuf);
934         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
935                 return False;
936         }
937
938         if (CVAL(cli->inbuf,smb_rcls) != 0) {
939                 return False;
940         }
941
942         return True;
943 }
944
945
946
947 /****************************************************************************
948 open a file
949 ****************************************************************************/
950 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
951 {
952         char *p;
953         unsigned openfn=0;
954         unsigned accessmode=0;
955
956         if (flags & O_CREAT)
957                 openfn |= (1<<4);
958         if (!(flags & O_EXCL)) {
959                 if (flags & O_TRUNC)
960                         openfn |= (1<<1);
961                 else
962                         openfn |= (1<<0);
963         }
964
965         accessmode = (share_mode<<4);
966
967         if ((flags & O_RDWR) == O_RDWR) {
968                 accessmode |= 2;
969         } else if ((flags & O_WRONLY) == O_WRONLY) {
970                 accessmode |= 1;
971         } 
972
973 #if defined(O_SYNC)
974         if ((flags & O_SYNC) == O_SYNC) {
975                 accessmode |= (1<<14);
976         }
977 #endif /* O_SYNC */
978
979         bzero(cli->outbuf,smb_size);
980         bzero(cli->inbuf,smb_size);
981
982         set_message(cli->outbuf,15,1 + strlen(fname),True);
983
984         CVAL(cli->outbuf,smb_com) = SMBopenX;
985         SSVAL(cli->outbuf,smb_tid,cli->cnum);
986         cli_setup_packet(cli);
987
988         SSVAL(cli->outbuf,smb_vwv0,0xFF);
989         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
990         SSVAL(cli->outbuf,smb_vwv3,accessmode);
991         SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
992         SSVAL(cli->outbuf,smb_vwv5,0);
993         SSVAL(cli->outbuf,smb_vwv8,openfn);
994   
995         p = smb_buf(cli->outbuf);
996         pstrcpy(p,fname);
997         p = skip_string(p,1);
998
999         send_smb(cli->fd,cli->outbuf);
1000         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1001                 return -1;
1002         }
1003
1004         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1005                 return -1;
1006         }
1007
1008         return SVAL(cli->inbuf,smb_vwv2);
1009 }
1010
1011
1012
1013
1014 /****************************************************************************
1015   close a file
1016 ****************************************************************************/
1017 BOOL cli_close(struct cli_state *cli, int fnum)
1018 {
1019         bzero(cli->outbuf,smb_size);
1020         bzero(cli->inbuf,smb_size);
1021
1022         set_message(cli->outbuf,3,0,True);
1023
1024         CVAL(cli->outbuf,smb_com) = SMBclose;
1025         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1026         cli_setup_packet(cli);
1027
1028         SSVAL(cli->outbuf,smb_vwv0,fnum);
1029         SIVALS(cli->outbuf,smb_vwv1,-1);
1030
1031         send_smb(cli->fd,cli->outbuf);
1032         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1033                 return False;
1034         }
1035
1036         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1037                 return False;
1038         }
1039
1040         return True;
1041 }
1042
1043
1044 /****************************************************************************
1045   lock a file
1046 ****************************************************************************/
1047 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1048 {
1049         char *p;
1050
1051         bzero(cli->outbuf,smb_size);
1052         bzero(cli->inbuf,smb_size);
1053
1054         set_message(cli->outbuf,8,10,True);
1055
1056         CVAL(cli->outbuf,smb_com) = SMBlockingX;
1057         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1058         cli_setup_packet(cli);
1059
1060         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1061         SSVAL(cli->outbuf,smb_vwv2,fnum);
1062         CVAL(cli->outbuf,smb_vwv3) = 0;
1063         SIVALS(cli->outbuf, smb_vwv4, timeout);
1064         SSVAL(cli->outbuf,smb_vwv6,0);
1065         SSVAL(cli->outbuf,smb_vwv7,1);
1066
1067         p = smb_buf(cli->outbuf);
1068         SSVAL(p, 0, cli->pid);
1069         SIVAL(p, 2, offset);
1070         SIVAL(p, 6, len);
1071
1072         send_smb(cli->fd,cli->outbuf);
1073         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1074                 return False;
1075         }
1076
1077         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1078                 return False;
1079         }
1080
1081         return True;
1082 }
1083
1084 /****************************************************************************
1085   unlock a file
1086 ****************************************************************************/
1087 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1088 {
1089         char *p;
1090
1091         bzero(cli->outbuf,smb_size);
1092         bzero(cli->inbuf,smb_size);
1093
1094         set_message(cli->outbuf,8,10,True);
1095
1096         CVAL(cli->outbuf,smb_com) = SMBlockingX;
1097         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1098         cli_setup_packet(cli);
1099
1100         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1101         SSVAL(cli->outbuf,smb_vwv2,fnum);
1102         CVAL(cli->outbuf,smb_vwv3) = 0;
1103         SIVALS(cli->outbuf, smb_vwv4, timeout);
1104         SSVAL(cli->outbuf,smb_vwv6,1);
1105         SSVAL(cli->outbuf,smb_vwv7,0);
1106
1107         p = smb_buf(cli->outbuf);
1108         SSVAL(p, 0, cli->pid);
1109         SIVAL(p, 2, offset);
1110         SIVAL(p, 6, len);
1111
1112         send_smb(cli->fd,cli->outbuf);
1113         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1114                 return False;
1115         }
1116
1117         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1118                 return False;
1119         }
1120
1121         return True;
1122 }
1123
1124
1125 /****************************************************************************
1126   read from a file
1127 ****************************************************************************/
1128 int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
1129 {
1130         char *p;
1131         int total=0;
1132
1133         while (total < size) {
1134                 int size1 = MIN(size-total, cli->max_xmit - (smb_size+32));
1135                 int size2;
1136
1137                 bzero(cli->outbuf,smb_size);
1138                 bzero(cli->inbuf,smb_size);
1139
1140                 set_message(cli->outbuf,10,0,True);
1141                 
1142                 CVAL(cli->outbuf,smb_com) = SMBreadX;
1143                 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1144                 cli_setup_packet(cli);
1145
1146                 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1147                 SSVAL(cli->outbuf,smb_vwv2,fnum);
1148                 SIVAL(cli->outbuf,smb_vwv3,offset+total);
1149                 SSVAL(cli->outbuf,smb_vwv5,size1);
1150                 SSVAL(cli->outbuf,smb_vwv6,size1);
1151
1152                 send_smb(cli->fd,cli->outbuf);
1153                 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1154                         return total?total:-1;
1155                 }
1156
1157                 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1158                         return total?total:-1;
1159                 }
1160
1161                 size2 = SVAL(cli->inbuf, smb_vwv5);
1162                 if (size2 > size1) {
1163                         DEBUG(0,("server returned more than we wanted!\n"));
1164                         exit(1);
1165                 }
1166                 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1167
1168                 if (size2 <= 0) break;
1169
1170                 memcpy(buf+total, p, size2);
1171
1172                 total += size2;
1173         }
1174
1175         return total;
1176 }
1177
1178
1179 /****************************************************************************
1180   write to a file
1181 ****************************************************************************/
1182 int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
1183 {
1184         char *p;
1185         int total=0;
1186
1187         while (total < size) {
1188                 int size1 = MIN(size-total, cli->max_xmit - (smb_size+32));
1189                 int size2;
1190
1191                 bzero(cli->outbuf,smb_size);
1192                 bzero(cli->inbuf,smb_size);
1193
1194                 set_message(cli->outbuf,12,size1,True);
1195
1196                 CVAL(cli->outbuf,smb_com) = SMBwriteX;
1197                 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1198                 cli_setup_packet(cli);
1199
1200                 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1201                 SSVAL(cli->outbuf,smb_vwv2,fnum);
1202                 SIVAL(cli->outbuf,smb_vwv3,offset+total);
1203
1204                 SSVAL(cli->outbuf,smb_vwv10,size1);
1205                 SSVAL(cli->outbuf,smb_vwv11,
1206                       smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1207
1208                 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1209                 memcpy(p, buf+total, size1);
1210
1211                 send_smb(cli->fd,cli->outbuf);
1212                 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1213                         return -1;
1214                 }
1215
1216                 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1217                         return -1;
1218                 }
1219
1220                 size2 = SVAL(cli->inbuf, smb_vwv2);
1221
1222                 if (size2 <= 0) break;
1223
1224                 total += size2;
1225         }
1226
1227         return total;
1228 }
1229
1230
1231 /****************************************************************************
1232 do a SMBgetattrE call
1233 ****************************************************************************/
1234 BOOL cli_getattrE(struct cli_state *cli, int fd, 
1235                   int *attr, uint32 *size, 
1236                   time_t *c_time, time_t *a_time, time_t *m_time)
1237 {
1238         bzero(cli->outbuf,smb_size);
1239         bzero(cli->inbuf,smb_size);
1240
1241         set_message(cli->outbuf,2,0,True);
1242
1243         CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1244         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1245         cli_setup_packet(cli);
1246
1247         SSVAL(cli->outbuf,smb_vwv0,fd);
1248
1249         send_smb(cli->fd,cli->outbuf);
1250         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1251                 return False;
1252         }
1253         
1254         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1255                 return False;
1256         }
1257
1258         if (size) {
1259                 *size = IVAL(cli->inbuf, smb_vwv6);
1260         }
1261
1262         if (attr) {
1263                 *attr = SVAL(cli->inbuf,smb_vwv10);
1264         }
1265
1266         if (c_time) {
1267                 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1268         }
1269
1270         if (a_time) {
1271                 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1272         }
1273
1274         if (m_time) {
1275                 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1276         }
1277
1278         return True;
1279 }
1280
1281
1282 /****************************************************************************
1283 do a SMBgetatr call
1284 ****************************************************************************/
1285 BOOL cli_getatr(struct cli_state *cli, char *fname, 
1286                 uint32 *attr, size_t *size, time_t *t)
1287 {
1288         char *p;
1289
1290         bzero(cli->outbuf,smb_size);
1291         bzero(cli->inbuf,smb_size);
1292
1293         set_message(cli->outbuf,0,strlen(fname)+2,True);
1294
1295         CVAL(cli->outbuf,smb_com) = SMBgetatr;
1296         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1297         cli_setup_packet(cli);
1298
1299         p = smb_buf(cli->outbuf);
1300         *p = 4;
1301         pstrcpy(p+1, fname);
1302
1303         send_smb(cli->fd,cli->outbuf);
1304         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1305                 return False;
1306         }
1307         
1308         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1309                 return False;
1310         }
1311
1312         if (size) {
1313                 *size = IVAL(cli->inbuf, smb_vwv3);
1314         }
1315
1316         if (t) {
1317                 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1318         }
1319
1320         if (attr) {
1321                 *attr = SVAL(cli->inbuf,smb_vwv0);
1322         }
1323
1324
1325         return True;
1326 }
1327
1328
1329 /****************************************************************************
1330 do a SMBsetatr call
1331 ****************************************************************************/
1332 BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t)
1333 {
1334         char *p;
1335
1336         bzero(cli->outbuf,smb_size);
1337         bzero(cli->inbuf,smb_size);
1338
1339         set_message(cli->outbuf,8,strlen(fname)+4,True);
1340
1341         CVAL(cli->outbuf,smb_com) = SMBsetatr;
1342         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1343         cli_setup_packet(cli);
1344
1345         SSVAL(cli->outbuf,smb_vwv0, attr);
1346         put_dos_date3(cli->outbuf,smb_vwv1, t);
1347
1348         p = smb_buf(cli->outbuf);
1349         *p = 4;
1350         pstrcpy(p+1, fname);
1351         p = skip_string(p,1);
1352         *p = 4;
1353
1354         send_smb(cli->fd,cli->outbuf);
1355         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1356                 return False;
1357         }
1358         
1359         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1360                 return False;
1361         }
1362
1363         return True;
1364 }
1365
1366 /****************************************************************************
1367 send a qpathinfo call
1368 ****************************************************************************/
1369 BOOL cli_qpathinfo(struct cli_state *cli, char *fname, 
1370                    time_t *c_time, time_t *a_time, time_t *m_time, 
1371                    size_t *size, uint32 *mode)
1372 {
1373         int data_len = 0;
1374         int param_len = 0;
1375         uint16 setup = TRANSACT2_QPATHINFO;
1376         pstring param;
1377         char *rparam=NULL, *rdata=NULL;
1378         int count=8;
1379         BOOL ret;
1380         time_t (*date_fn)(void *);
1381
1382         param_len = strlen(fname) + 7;
1383
1384         memset(param, 0, param_len);
1385         SSVAL(param, 0, SMB_INFO_STANDARD);
1386         pstrcpy(&param[6], fname);
1387
1388         do {
1389                 ret = (cli_send_trans(cli, SMBtrans2, 
1390                                       NULL, 0,        /* Name, length */
1391                                       -1, 0,          /* fid, flags */
1392                                       &setup, 1, 0,   /* setup, length, max */
1393                                       param, param_len, 10, /* param, length, max */
1394                                       NULL, data_len, cli->max_xmit /* data, length, max */
1395                                       ) &&
1396                        cli_receive_trans(cli, SMBtrans2, 
1397                                          &rparam, &param_len,
1398                                          &rdata, &data_len));
1399                 if (!ret) {
1400                         /* we need to work around a Win95 bug - sometimes
1401                            it gives ERRSRV/ERRerror temprarily */
1402                         uint8 eclass;
1403                         uint32 ecode;
1404                         cli_error(cli, &eclass, &ecode);
1405                         if (eclass != ERRSRV || ecode != ERRerror) break;
1406                         msleep(100);
1407                 }
1408         } while (count-- && ret==False);
1409
1410         if (!ret || !rdata || data_len < 22) {
1411                 return False;
1412         }
1413
1414         if (cli->win95) {
1415                 date_fn = make_unix_date;
1416         } else {
1417                 date_fn = make_unix_date2;
1418         }
1419
1420         if (c_time) {
1421                 *c_time = date_fn(rdata+0);
1422         }
1423         if (a_time) {
1424                 *a_time = date_fn(rdata+4);
1425         }
1426         if (m_time) {
1427                 *m_time = date_fn(rdata+8);
1428         }
1429         if (size) {
1430                 *size = IVAL(rdata, 12);
1431         }
1432         if (mode) {
1433                 *mode = SVAL(rdata,l1_attrFile);
1434         }
1435
1436         if (rdata) free(rdata);
1437         if (rparam) free(rparam);
1438         return True;
1439 }
1440
1441 /****************************************************************************
1442 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1443 ****************************************************************************/
1444 BOOL cli_qpathinfo2(struct cli_state *cli, char *fname, 
1445                     time_t *c_time, time_t *a_time, time_t *m_time, 
1446                     time_t *w_time, uint32 *size)
1447 {
1448         int data_len = 0;
1449         int param_len = 0;
1450         uint16 setup = TRANSACT2_QPATHINFO;
1451         pstring param;
1452         char *rparam=NULL, *rdata=NULL;
1453
1454         param_len = strlen(fname) + 7;
1455
1456         memset(param, 0, param_len);
1457         SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1458         pstrcpy(&param[6], fname);
1459
1460         if (!cli_send_trans(cli, SMBtrans2, 
1461                             NULL, 0,                      /* name, length */
1462                             -1, 0,                        /* fid, flags */
1463                             &setup, 1, 0,                 /* setup, length, max */
1464                             param, param_len, 10,         /* param, length, max */
1465                             NULL, data_len, cli->max_xmit /* data, length, max */
1466                            )) {
1467                 return False;
1468         }
1469
1470         if (!cli_receive_trans(cli, SMBtrans2,
1471                                &rparam, &param_len,
1472                                &rdata, &data_len)) {
1473                 return False;
1474         }
1475
1476         if (!rdata || data_len < 22) {
1477                 return False;
1478         }
1479
1480         if (c_time) {
1481                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1482         }
1483         if (a_time) {
1484                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1485         }
1486         if (m_time) {
1487                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1488         }
1489         if (w_time) {
1490                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1491         }
1492         if (size) {
1493                 *size = IVAL(rdata, 40);
1494         }
1495
1496         if (rdata) free(rdata);
1497         if (rparam) free(rparam);
1498         return True;
1499 }
1500
1501
1502 /****************************************************************************
1503 send a qfileinfo call
1504 ****************************************************************************/
1505 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
1506                    time_t *c_time, time_t *a_time, time_t *m_time, 
1507                    uint32 *size, int *mode)
1508 {
1509         int data_len = 0;
1510         int param_len = 0;
1511         uint16 setup = TRANSACT2_QFILEINFO;
1512         pstring param;
1513         char *rparam=NULL, *rdata=NULL;
1514
1515         param_len = 4;
1516
1517         memset(param, 0, param_len);
1518         SSVAL(param, 0, fnum);
1519         SSVAL(param, 2, SMB_INFO_STANDARD);
1520
1521         if (!cli_send_trans(cli, SMBtrans2, 
1522                             NULL, 0,                        /* name, length */
1523                             -1, 0,                          /* fid, flags */
1524                             &setup, 1, 0,                   /* setup, length, max */
1525                             param, param_len, 2,            /* param, length, max */
1526                             NULL, data_len, cli->max_xmit   /* data, length, max */
1527                            )) {
1528                 return False;
1529         }
1530
1531         if (!cli_receive_trans(cli, SMBtrans2,
1532                                &rparam, &param_len,
1533                                &rdata, &data_len)) {
1534                 return False;
1535         }
1536
1537         if (!rdata || data_len < 22) {
1538                 return False;
1539         }
1540
1541         if (c_time) {
1542                 *c_time = make_unix_date2(rdata+0);
1543         }
1544         if (a_time) {
1545                 *a_time = make_unix_date2(rdata+4);
1546         }
1547         if (m_time) {
1548                 *m_time = make_unix_date2(rdata+8);
1549         }
1550         if (size) {
1551                 *size = IVAL(rdata, 12);
1552         }
1553         if (mode) {
1554                 *mode = SVAL(rdata,l1_attrFile);
1555         }
1556
1557         if (rdata) free(rdata);
1558         if (rparam) free(rparam);
1559         return True;
1560 }
1561
1562
1563 /****************************************************************************
1564 interpret a long filename structure - this is mostly guesses at the moment
1565 The length of the structure is returned
1566 The structure of a long filename depends on the info level. 260 is used
1567 by NT and 2 is used by OS/2
1568 ****************************************************************************/
1569 static int interpret_long_filename(int level,char *p,file_info *finfo)
1570 {
1571         extern file_info def_finfo;
1572
1573         if (finfo)
1574                 memcpy(finfo,&def_finfo,sizeof(*finfo));
1575
1576         switch (level)
1577                 {
1578                 case 1: /* OS/2 understands this */
1579                         if (finfo) {
1580                                 /* these dates are converted to GMT by make_unix_date */
1581                                 finfo->ctime = make_unix_date2(p+4);
1582                                 finfo->atime = make_unix_date2(p+8);
1583                                 finfo->mtime = make_unix_date2(p+12);
1584                                 finfo->size = IVAL(p,16);
1585                                 finfo->mode = CVAL(p,24);
1586                                 pstrcpy(finfo->name,p+27);
1587                         }
1588                         return(28 + CVAL(p,26));
1589
1590                 case 2: /* this is what OS/2 uses mostly */
1591                         if (finfo) {
1592                                 /* these dates are converted to GMT by make_unix_date */
1593                                 finfo->ctime = make_unix_date2(p+4);
1594                                 finfo->atime = make_unix_date2(p+8);
1595                                 finfo->mtime = make_unix_date2(p+12);
1596                                 finfo->size = IVAL(p,16);
1597                                 finfo->mode = CVAL(p,24);
1598                                 pstrcpy(finfo->name,p+31);
1599                         }
1600                         return(32 + CVAL(p,30));
1601
1602                         /* levels 3 and 4 are untested */
1603                 case 3:
1604                         if (finfo) {
1605                                 /* these dates are probably like the other ones */
1606                                 finfo->ctime = make_unix_date2(p+8);
1607                                 finfo->atime = make_unix_date2(p+12);
1608                                 finfo->mtime = make_unix_date2(p+16);
1609                                 finfo->size = IVAL(p,20);
1610                                 finfo->mode = CVAL(p,28);
1611                                 pstrcpy(finfo->name,p+33);
1612                         }
1613                         return(SVAL(p,4)+4);
1614                         
1615                 case 4:
1616                         if (finfo) {
1617                                 /* these dates are probably like the other ones */
1618                                 finfo->ctime = make_unix_date2(p+8);
1619                                 finfo->atime = make_unix_date2(p+12);
1620                                 finfo->mtime = make_unix_date2(p+16);
1621                                 finfo->size = IVAL(p,20);
1622                                 finfo->mode = CVAL(p,28);
1623                                 pstrcpy(finfo->name,p+37);
1624                         }
1625                         return(SVAL(p,4)+4);
1626                         
1627                 case 260: /* NT uses this, but also accepts 2 */
1628                         if (finfo) {
1629                                 int ret = SVAL(p,0);
1630                                 int namelen;
1631                                 p += 4; /* next entry offset */
1632                                 p += 4; /* fileindex */
1633                                 
1634                                 /* these dates appear to arrive in a
1635                                    weird way. It seems to be localtime
1636                                    plus the serverzone given in the
1637                                    initial connect. This is GMT when
1638                                    DST is not in effect and one hour
1639                                    from GMT otherwise. Can this really
1640                                    be right??
1641
1642                                    I suppose this could be called
1643                                    kludge-GMT. Is is the GMT you get
1644                                    by using the current DST setting on
1645                                    a different localtime. It will be
1646                                    cheap to calculate, I suppose, as
1647                                    no DST tables will be needed */
1648
1649                                 finfo->ctime = interpret_long_date(p); p += 8;
1650                                 finfo->atime = interpret_long_date(p); p += 8;
1651                                 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
1652                                 finfo->size = IVAL(p,0); p += 8;
1653                                 p += 8; /* alloc size */
1654                                 finfo->mode = CVAL(p,0); p += 4;
1655                                 namelen = IVAL(p,0); p += 4;
1656                                 p += 4; /* EA size */
1657                                 p += 2; /* short name len? */
1658                                 p += 24; /* short name? */        
1659                                 StrnCpy(finfo->name,p,namelen);
1660                                 return(ret);
1661                         }
1662                         return(SVAL(p,0));
1663                 }
1664         
1665         DEBUG(1,("Unknown long filename format %d\n",level));
1666         return(SVAL(p,0));
1667 }
1668
1669
1670 /****************************************************************************
1671   do a directory listing, calling fn on each file found
1672   ****************************************************************************/
1673 int cli_list(struct cli_state *cli,char *Mask,int attribute,void (*fn)(file_info *))
1674 {
1675         int max_matches = 512;
1676         /* NT uses 260, OS/2 uses 2. Both accept 1. */
1677         int info_level = cli->protocol<PROTOCOL_NT1?1:260; 
1678         char *p, *p2;
1679         pstring mask;
1680         file_info finfo;
1681         int i;
1682         char *dirlist = NULL;
1683         int dirlist_len = 0;
1684         int total_received = -1;
1685         BOOL First = True;
1686         int ff_resume_key = 0;
1687         int ff_searchcount=0;
1688         int ff_eos=0;
1689         int ff_lastname=0;
1690         int ff_dir_handle=0;
1691         int loop_count = 0;
1692         char *rparam=NULL, *rdata=NULL;
1693         int param_len, data_len;
1694         
1695         uint16 setup;
1696         pstring param;
1697         
1698         pstrcpy(mask,Mask);
1699         
1700         while (ff_eos == 0) {
1701                 loop_count++;
1702                 if (loop_count > 200) {
1703                         DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
1704                         break;
1705                 }
1706
1707                 param_len = 12+strlen(mask)+1;
1708
1709                 if (First) {
1710                         setup = TRANSACT2_FINDFIRST;
1711                         SSVAL(param,0,attribute); /* attribute */
1712                         SSVAL(param,2,max_matches); /* max count */
1713                         SSVAL(param,4,8+4+2);   /* resume required + close on end + continue */
1714                         SSVAL(param,6,info_level); 
1715                         SIVAL(param,8,0);
1716                         pstrcpy(param+12,mask);
1717                 } else {
1718                         setup = TRANSACT2_FINDNEXT;
1719                         SSVAL(param,0,ff_dir_handle);
1720                         SSVAL(param,2,max_matches); /* max count */
1721                         SSVAL(param,4,info_level); 
1722                         SIVAL(param,6,ff_resume_key); /* ff_resume_key */
1723                         SSVAL(param,10,8+4+2);  /* resume required + close on end + continue */
1724                         pstrcpy(param+12,mask);
1725
1726                         DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
1727                                  ff_dir_handle,ff_resume_key,ff_lastname,mask));
1728                 }
1729
1730                 if (!cli_send_trans(cli, SMBtrans2, 
1731                                     NULL, 0,                /* Name, length */
1732                                     -1, 0,                  /* fid, flags */
1733                                     &setup, 1, 0,           /* setup, length, max */
1734                                     param, param_len, 10,   /* param, length, max */
1735                                     NULL, 0, 
1736                                     cli->max_xmit /* data, length, max */
1737                                     )) {
1738                         break;
1739                 }
1740
1741                 if (!cli_receive_trans(cli, SMBtrans2, 
1742                                        &rparam, &param_len,
1743                                        &rdata, &data_len)) {
1744                         /* we need to work around a Win95 bug - sometimes
1745                            it gives ERRSRV/ERRerror temprarily */
1746                         uint8 eclass;
1747                         uint32 ecode;
1748                         cli_error(cli, &eclass, &ecode);
1749                         if (eclass != ERRSRV || ecode != ERRerror) break;
1750                         msleep(100);
1751                         continue;
1752                 }
1753
1754                 if (total_received == -1) total_received = 0;
1755
1756                 /* parse out some important return info */
1757                 p = rparam;
1758                 if (First) {
1759                         ff_dir_handle = SVAL(p,0);
1760                         ff_searchcount = SVAL(p,2);
1761                         ff_eos = SVAL(p,4);
1762                         ff_lastname = SVAL(p,8);
1763                 } else {
1764                         ff_searchcount = SVAL(p,0);
1765                         ff_eos = SVAL(p,2);
1766                         ff_lastname = SVAL(p,6);
1767                 }
1768
1769                 if (ff_searchcount == 0) 
1770                         break;
1771
1772                 /* point to the data bytes */
1773                 p = rdata;
1774
1775                 /* we might need the lastname for continuations */
1776                 if (ff_lastname > 0) {
1777                         switch(info_level)
1778                                 {
1779                                 case 260:
1780                                         ff_resume_key =0;
1781                                         StrnCpy(mask,p+ff_lastname,
1782                                                 data_len-ff_lastname);
1783                                         break;
1784                                 case 1:
1785                                         pstrcpy(mask,p + ff_lastname + 1);
1786                                         ff_resume_key = 0;
1787                                         break;
1788                                 }
1789                 } else {
1790                         pstrcpy(mask,"");
1791                 }
1792   
1793                 /* and add them to the dirlist pool */
1794                 dirlist = Realloc(dirlist,dirlist_len + data_len);
1795
1796                 if (!dirlist) {
1797                         DEBUG(0,("Failed to expand dirlist\n"));
1798                         break;
1799                 }
1800
1801                 /* put in a length for the last entry, to ensure we can chain entries 
1802                    into the next packet */
1803                 for (p2=p,i=0;i<(ff_searchcount-1);i++)
1804                         p2 += interpret_long_filename(info_level,p2,NULL);
1805                 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
1806
1807                 /* grab the data for later use */
1808                 memcpy(dirlist+dirlist_len,p,data_len);
1809                 dirlist_len += data_len;
1810
1811                 total_received += ff_searchcount;
1812
1813                 if (rdata) free(rdata); rdata = NULL;
1814                 if (rparam) free(rparam); rparam = NULL;
1815                 
1816                 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
1817                          ff_searchcount,ff_eos,ff_resume_key));
1818
1819                 First = False;
1820         }
1821
1822         for (p=dirlist,i=0;i<total_received;i++) {
1823                 p += interpret_long_filename(info_level,p,&finfo);
1824                 fn(&finfo);
1825         }
1826
1827         /* free up the dirlist buffer */
1828         if (dirlist) free(dirlist);
1829         return(total_received);
1830 }
1831
1832
1833 /****************************************************************************
1834 Send a SamOEMChangePassword command
1835 ****************************************************************************/
1836
1837 BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password,
1838                              char *old_password)
1839 {
1840   char param[16+sizeof(fstring)];
1841   char data[532];
1842   char *p = param;
1843   fstring upper_case_old_pw;
1844   fstring upper_case_new_pw;
1845   unsigned char old_pw_hash[16];
1846   unsigned char new_pw_hash[16];
1847   int data_len;
1848   int param_len = 0;
1849   int new_pw_len = strlen(new_password);
1850   char *rparam = NULL;
1851   char *rdata = NULL;
1852   int rprcnt, rdrcnt;
1853
1854   if (strlen(user) >= sizeof(fstring)-1) {
1855     DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
1856     return False;
1857   }
1858
1859   if (new_pw_len > 512) {
1860     DEBUG(0,("cli_oem_change_password: new password for user %s is too long.\n", user));
1861     return False;
1862   }
1863
1864   SSVAL(p,0,214); /* SamOEMChangePassword command. */
1865   p += 2;
1866   pstrcpy(p, "zsT");
1867   p = skip_string(p,1);
1868   pstrcpy(p, "B516B16");
1869   p = skip_string(p,1);
1870   pstrcpy(p,user);
1871   p = skip_string(p,1);
1872   SSVAL(p,0,532);
1873   p += 2;
1874
1875   param_len = PTR_DIFF(p,param);
1876
1877   /*
1878    * Now setup the data area.
1879    * We need to generate a random fill
1880    * for this area to make it harder to
1881    * decrypt. JRA.
1882    */
1883   generate_random_buffer((unsigned char *)data, sizeof(data), False);
1884   fstrcpy( &data[512 - new_pw_len], new_password);
1885   SIVAL(data, 512, new_pw_len);
1886
1887   /*
1888    * Get the Lanman hash of the old password, we
1889    * use this as the key to SamOEMHash().
1890    */
1891   memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
1892   fstrcpy(upper_case_old_pw, old_password);
1893   strupper(upper_case_old_pw);
1894   E_P16((uchar *)upper_case_old_pw, old_pw_hash);
1895
1896   SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True);
1897
1898   /* 
1899    * Now place the old password hash in the data.
1900    */
1901   memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
1902   fstrcpy(upper_case_new_pw, new_password);
1903   strupper(upper_case_new_pw);
1904
1905   E_P16((uchar *)upper_case_new_pw, new_pw_hash);
1906
1907   E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
1908
1909   data_len = 532;
1910     
1911   if (cli_send_trans(cli,SMBtrans,
1912                     PIPE_LANMAN,strlen(PIPE_LANMAN),      /* name, length */
1913                     0,0,                                  /* fid, flags */
1914                     NULL,0,0,                             /* setup, length, max */
1915                     param,param_len,2,                    /* param, length, max */
1916                     data,data_len,0                       /* data, length, max */
1917                    ) == False) {
1918     DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
1919               user ));
1920     return False;
1921   }
1922
1923   if (cli_receive_trans(cli,SMBtrans,
1924                        &rparam, &rprcnt,
1925                        &rdata, &rdrcnt)) {
1926     if (rparam)
1927       cli->rap_error = SVAL(rparam,0);
1928   }
1929
1930   if (rparam)
1931     free(rparam);
1932   if (rdata)
1933     free(rdata);
1934
1935   return (cli->rap_error == 0);
1936 }
1937
1938 /****************************************************************************
1939 send a negprot command
1940 ****************************************************************************/
1941 BOOL cli_negprot(struct cli_state *cli)
1942 {
1943         char *p;
1944         int numprots;
1945         int plength;
1946
1947         bzero(cli->outbuf,smb_size);
1948
1949         /* setup the protocol strings */
1950         for (plength=0,numprots=0;
1951              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1952              numprots++)
1953                 plength += strlen(prots[numprots].name)+2;
1954     
1955         set_message(cli->outbuf,0,plength,True);
1956
1957         p = smb_buf(cli->outbuf);
1958         for (numprots=0;
1959              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1960              numprots++) {
1961                 *p++ = 2;
1962                 pstrcpy(p,prots[numprots].name);
1963                 p += strlen(p) + 1;
1964         }
1965
1966         CVAL(cli->outbuf,smb_com) = SMBnegprot;
1967         cli_setup_packet(cli);
1968
1969         CVAL(smb_buf(cli->outbuf),0) = 2;
1970
1971         send_smb(cli->fd,cli->outbuf);
1972         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
1973                 return False;
1974
1975         show_msg(cli->inbuf);
1976
1977         if (CVAL(cli->inbuf,smb_rcls) != 0 || 
1978             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
1979                 return(False);
1980         }
1981
1982         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
1983
1984
1985         if (cli->protocol >= PROTOCOL_NT1) {    
1986                 /* NT protocol */
1987                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
1988                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
1989                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
1990                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
1991                 /* this time arrives in real GMT */
1992                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1993                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
1994                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1995                 if (cli->capabilities & 1) {
1996                         cli->readbraw_supported = True;
1997                         cli->writebraw_supported = True;      
1998                 }
1999         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2000                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2001                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2002                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2003                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
2004                 /* this time is converted to GMT by make_unix_date */
2005                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2006                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2007                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2008                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2009         } else {
2010                 /* the old core protocol */
2011                 cli->sec_mode = 0;
2012                 cli->serverzone = TimeDiff(time(NULL));
2013         }
2014
2015         return True;
2016 }
2017
2018
2019 /****************************************************************************
2020   send a session request.  see rfc1002.txt 4.3 and 4.3.2
2021 ****************************************************************************/
2022 BOOL cli_session_request(struct cli_state *cli,
2023                         struct nmb_name *calling, struct nmb_name *called)
2024 {
2025         char *p;
2026         int len = 4;
2027         /* send a session request (RFC 1002) */
2028
2029         memcpy(&(cli->calling), calling, sizeof(*calling));
2030         memcpy(&(cli->called ), called , sizeof(*called ));
2031   
2032         /* put in the destination name */
2033         p = cli->outbuf+len;
2034         name_mangle(cli->called .name, p, cli->called .name_type);
2035         len += name_len(p);
2036
2037         /* and my name */
2038         p = cli->outbuf+len;
2039         name_mangle(cli->calling.name, p, cli->calling.name_type);
2040         len += name_len(p);
2041
2042         /* setup the packet length */
2043         _smb_setlen(cli->outbuf,len);
2044         CVAL(cli->outbuf,0) = 0x81;
2045
2046 #ifdef WITH_SSL
2047 retry:
2048 #endif /* WITH_SSL */
2049
2050         send_smb(cli->fd,cli->outbuf);
2051         DEBUG(5,("Sent session request\n"));
2052
2053         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
2054                 return False;
2055
2056 #ifdef WITH_SSL
2057     if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2058         if (!sslutil_fd_is_ssl(cli->fd)){
2059             if (sslutil_connect(cli->fd) == 0)
2060                 goto retry;
2061         }
2062     }
2063 #endif /* WITH_SSL */
2064
2065         if (CVAL(cli->inbuf,0) != 0x82) {
2066                 /* This is the wrong place to put the error... JRA. */
2067                 cli->rap_error = CVAL(cli->inbuf,0);
2068                 return False;
2069         }
2070         return(True);
2071 }
2072
2073
2074 /****************************************************************************
2075 open the client sockets
2076 ****************************************************************************/
2077 BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
2078 {
2079         struct in_addr dest_ip;
2080         extern struct in_addr ipzero;
2081
2082         fstrcpy(cli->desthost, host);
2083         
2084         if (!ip || ip_equal(*ip, ipzero)) {
2085                 if (!resolve_name( cli->desthost, &dest_ip)) {
2086                         return False;
2087                 }
2088         } else {
2089                 dest_ip = *ip;
2090         }
2091
2092
2093         cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout);
2094         if (cli->fd == -1)
2095                 return False;
2096
2097         return True;
2098 }
2099
2100
2101 /****************************************************************************
2102 initialise a client structure
2103 ****************************************************************************/
2104 BOOL cli_initialise(struct cli_state *cli)
2105 {
2106         if (cli->initialised)
2107       cli_shutdown(cli);
2108
2109         memset(cli, 0, sizeof(*cli));
2110         cli->fd = -1;
2111         cli->cnum = -1;
2112         cli->pid = (uint16)getpid();
2113         cli->mid = 1;
2114         cli->vuid = UID_FIELD_INVALID;
2115         cli->protocol = PROTOCOL_NT1;
2116         cli->timeout = 20000;
2117         cli->bufsize = 0x10000;
2118         cli->max_xmit = cli->bufsize - 4;
2119         cli->outbuf = (char *)malloc(cli->bufsize);
2120         cli->inbuf = (char *)malloc(cli->bufsize);
2121         if (!cli->outbuf || !cli->inbuf)
2122       return False;
2123         cli->initialised = 1;
2124         return True;
2125 }
2126
2127 /****************************************************************************
2128 shutdown a client structure
2129 ****************************************************************************/
2130 void cli_shutdown(struct cli_state *cli)
2131 {
2132         if (cli->outbuf)
2133       free(cli->outbuf);
2134         if (cli->inbuf)
2135       free(cli->inbuf);
2136 #ifdef WITH_SSL
2137     if (cli->fd != -1)
2138       sslutil_disconnect(cli->fd);
2139 #endif /* WITH_SSL */
2140         if (cli->fd != -1) 
2141       close(cli->fd);
2142         memset(cli, 0, sizeof(*cli));
2143 }
2144
2145
2146 /****************************************************************************
2147   return error codes for the last packet
2148   returns 0 if there was no error and the bext approx of a unix errno
2149   otherwise
2150 ****************************************************************************/
2151 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
2152 {
2153         int  flgs2 = SVAL(cli->inbuf,smb_flg2);
2154         char rcls;
2155         int code;
2156
2157         if (eclass) *eclass = 0;
2158         if (num   ) *num = 0;
2159
2160         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
2161                 /* 32 bit error codes detected */
2162                 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2163                 if (num) *num = nt_err;
2164                 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2165                 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2166
2167                 switch (nt_err & 0xFFFFFF) {
2168                 case NT_STATUS_ACCESS_VIOLATION: return EACCES;
2169                 case NT_STATUS_NO_SUCH_FILE: return ENOENT;
2170                 case NT_STATUS_NO_SUCH_DEVICE: return ENODEV;
2171                 case NT_STATUS_INVALID_HANDLE: return EBADF;
2172                 case NT_STATUS_NO_MEMORY: return ENOMEM;
2173                 case NT_STATUS_ACCESS_DENIED: return EACCES;
2174                 case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2175                 }
2176
2177                 /* for all other cases - a default code */
2178                 return EINVAL;
2179         }
2180
2181         rcls  = CVAL(cli->inbuf,smb_rcls);
2182         code  = SVAL(cli->inbuf,smb_err);
2183         if (rcls == 0) return 0;
2184
2185         if (eclass) *eclass = rcls;
2186         if (num   ) *num    = code;
2187
2188         if (rcls == ERRDOS) {
2189                 switch (code) {
2190                 case ERRbadfile: return ENOENT;
2191                 case ERRnoaccess: return EPERM;
2192                 }
2193         }
2194         if (rcls == ERRSRV) {
2195                 switch (code) {
2196                 case ERRbadpw: return EPERM;
2197                 }
2198         }
2199         /* for other cases */
2200         return EINVAL;
2201 }
2202
2203 /****************************************************************************
2204 set socket options on a open connection
2205 ****************************************************************************/
2206 void cli_sockopt(struct cli_state *cli, char *options)
2207 {
2208         set_socket_options(cli->fd, options);
2209 }
2210
2211 /****************************************************************************
2212 set the PID to use for smb messages. Return the old pid.
2213 ****************************************************************************/
2214 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2215 {
2216         uint16 ret = cli->pid;
2217         cli->pid = pid;
2218         return ret;
2219 }
2220
2221 /****************************************************************************
2222 establishes a connection right up to doing tconX, reading in a password.
2223 ****************************************************************************/
2224 BOOL cli_reestablish_connection(struct cli_state *cli)
2225 {
2226         struct nmb_name calling;
2227         struct nmb_name called;
2228         fstring dest_host;
2229         struct in_addr dest_ip;
2230         fstring share;
2231         fstring dev;
2232         BOOL do_tcon = False;
2233
2234         if (!cli->initialised || cli->fd == -1)
2235         {
2236                 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2237                 return False;
2238         }
2239
2240         /* copy the parameters necessary to re-establish the connection */
2241
2242         if (cli->cnum != 0)
2243         {
2244                 fstrcpy(share, cli->share);
2245                 fstrcpy(dev  , cli->dev);
2246                 do_tcon = True;
2247         }
2248
2249         memcpy(&called , &(cli->called ), sizeof(called ));
2250         memcpy(&calling, &(cli->calling), sizeof(calling));
2251         fstrcpy(dest_host, cli->full_dest_host_name);
2252         dest_ip = cli->dest_ip;
2253
2254         DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2255                           namestr(&calling), namestr(&called), inet_ntoa(dest_ip),
2256                       cli->user_name, cli->domain));
2257
2258         return cli_establish_connection(cli,
2259                                         dest_host, &dest_ip,
2260                                         &calling, &called,
2261                                         share, dev, False, do_tcon);
2262 }
2263
2264 /****************************************************************************
2265 establishes a connection right up to doing tconX, reading in a password.
2266 ****************************************************************************/
2267 BOOL cli_establish_connection(struct cli_state *cli, 
2268                                 char *dest_host, struct in_addr *dest_ip,
2269                                 struct nmb_name *calling, struct nmb_name *called,
2270                                 char *service, char *service_type,
2271                                 BOOL do_shutdown, BOOL do_tcon)
2272 {
2273         DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2274                           namestr(calling), namestr(called), inet_ntoa(*dest_ip),
2275                       cli->user_name, cli->domain));
2276
2277         /* establish connection */
2278
2279         if ((!cli->initialised))
2280         {
2281                 return False;
2282         }
2283
2284         if (cli->fd == -1)
2285         {
2286                 if (!cli_connect(cli, dest_host, dest_ip))
2287                 {
2288                         DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2289                                           namestr(calling), inet_ntoa(*dest_ip)));
2290                         return False;
2291                 }
2292         }
2293
2294         if (!cli_session_request(cli, calling, called))
2295         {
2296                 DEBUG(1,("failed session request\n"));
2297                 if (do_shutdown)
2298           cli_shutdown(cli);
2299                 return False;
2300         }
2301
2302         if (!cli_negprot(cli))
2303         {
2304                 DEBUG(1,("failed negprot\n"));
2305                 if (do_shutdown)
2306           cli_shutdown(cli);
2307                 return False;
2308         }
2309
2310         if (cli->pwd.cleartext || cli->pwd.null_pwd)
2311         {
2312                 /* attempt clear-text session */
2313
2314                 fstring passwd;
2315
2316                 pwd_get_cleartext(&(cli->pwd), passwd);
2317
2318                 /* attempt clear-text session */
2319                 if (!cli_session_setup(cli, cli->user_name,
2320                                passwd, strlen(passwd),
2321                                NULL, 0,
2322                                cli->domain))
2323                 {
2324                         DEBUG(1,("failed session setup\n"));
2325                         if (do_shutdown)
2326               cli_shutdown(cli);
2327                         return False;
2328                 }
2329                 if (do_tcon)
2330                 {
2331                         if (!cli_send_tconX(cli, service, service_type,
2332                                             (char*)passwd, strlen(passwd)))
2333                         {
2334                                 DEBUG(1,("failed tcon_X\n"));
2335                                 if (do_shutdown)
2336                   cli_shutdown(cli);
2337                                 return False;
2338                         }
2339                 }
2340         }
2341         else
2342         {
2343                 /* attempt encrypted session */
2344                 unsigned char nt_sess_pwd[24];
2345                 unsigned char lm_sess_pwd[24];
2346
2347                 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2348                 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
2349                 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
2350
2351                 /* attempt encrypted session */
2352                 if (!cli_session_setup(cli, cli->user_name,
2353                                (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
2354                                (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
2355                                cli->domain))
2356                 {
2357                         DEBUG(1,("failed session setup\n"));
2358                         if (do_shutdown)
2359               cli_shutdown(cli);
2360                         return False;
2361                 }
2362
2363                 if (do_tcon)
2364                 {
2365                         if (!cli_send_tconX(cli, service, service_type,
2366                                             (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
2367                         {
2368                                 DEBUG(1,("failed tcon_X\n"));
2369                                 if (do_shutdown)
2370                   cli_shutdown(cli);
2371                                 return False;
2372                         }
2373                 }
2374         }
2375
2376         if (do_shutdown)
2377       cli_shutdown(cli);
2378
2379         return True;
2380 }