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