add support for unlink() on printer shares in smbwrapper. unlink()
[samba.git] / source / libsmb / clientgen.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client generic functions
5    Copyright (C) Andrew Tridgell 1994-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)(char *, uint32, 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         if (cli->sec_mode & 1) {
768                 passlen = 1;
769                 pass = "";
770         }
771
772         if ((cli->sec_mode & 2) && *pass && passlen != 24) {
773                 passlen = 24;
774                 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
775         } else {
776                 memcpy(pword, pass, passlen);
777         }
778
779         slprintf(fullshare, sizeof(fullshare)-1,
780                  "\\\\%s\\%s", cli->desthost, share);
781
782         set_message(cli->outbuf,4,
783                     2 + strlen(fullshare) + passlen + strlen(dev),True);
784         CVAL(cli->outbuf,smb_com) = SMBtconX;
785         cli_setup_packet(cli);
786
787         SSVAL(cli->outbuf,smb_vwv0,0xFF);
788         SSVAL(cli->outbuf,smb_vwv3,passlen);
789
790         p = smb_buf(cli->outbuf);
791         memcpy(p,pword,passlen);
792         p += passlen;
793         fstrcpy(p,fullshare);
794         p = skip_string(p,1);
795         pstrcpy(p,dev);
796
797         SCVAL(cli->inbuf,smb_rcls, 1);
798
799         send_smb(cli->fd,cli->outbuf);
800         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
801                 return False;
802
803         if (CVAL(cli->inbuf,smb_rcls) != 0) {
804                 return False;
805         }
806
807         fstrcpy(cli->dev, smb_buf(cli->inbuf));
808
809         if (cli->protocol >= PROTOCOL_NT1 &&
810             smb_buflen(cli->inbuf) == 3) {
811                 /* almost certainly win95 - enable bug fixes */
812                 cli->win95 = True;
813         }
814
815         cli->cnum = SVAL(cli->inbuf,smb_tid);
816         return True;
817 }
818
819
820 /****************************************************************************
821 send a tree disconnect
822 ****************************************************************************/
823 BOOL cli_tdis(struct cli_state *cli)
824 {
825         bzero(cli->outbuf,smb_size);
826         set_message(cli->outbuf,0,0,True);
827         CVAL(cli->outbuf,smb_com) = SMBtdis;
828         SSVAL(cli->outbuf,smb_tid,cli->cnum);
829         cli_setup_packet(cli);
830         
831         send_smb(cli->fd,cli->outbuf);
832         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
833                 return False;
834         
835         return CVAL(cli->inbuf,smb_rcls) == 0;
836 }
837
838 /****************************************************************************
839 rename a file
840 ****************************************************************************/
841 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
842 {
843         char *p;
844
845         bzero(cli->outbuf,smb_size);
846         bzero(cli->inbuf,smb_size);
847
848         set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True);
849
850         CVAL(cli->outbuf,smb_com) = SMBmv;
851         SSVAL(cli->outbuf,smb_tid,cli->cnum);
852         cli_setup_packet(cli);
853
854         SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
855
856         p = smb_buf(cli->outbuf);
857         *p++ = 4;
858         pstrcpy(p,fname_src);
859         p = skip_string(p,1);
860         *p++ = 4;
861         pstrcpy(p,fname_dst);
862
863         send_smb(cli->fd,cli->outbuf);
864         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
865                 return False;
866         }
867
868         if (CVAL(cli->inbuf,smb_rcls) != 0) {
869                 return False;
870         }
871
872         return True;
873 }
874
875 /****************************************************************************
876 delete a file
877 ****************************************************************************/
878 BOOL cli_unlink(struct cli_state *cli, char *fname)
879 {
880         char *p;
881
882         bzero(cli->outbuf,smb_size);
883         bzero(cli->inbuf,smb_size);
884
885         set_message(cli->outbuf,1, 2 + strlen(fname),True);
886
887         CVAL(cli->outbuf,smb_com) = SMBunlink;
888         SSVAL(cli->outbuf,smb_tid,cli->cnum);
889         cli_setup_packet(cli);
890
891         SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
892   
893         p = smb_buf(cli->outbuf);
894         *p++ = 4;      
895         pstrcpy(p,fname);
896
897         send_smb(cli->fd,cli->outbuf);
898         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
899                 return False;
900         }
901
902         if (CVAL(cli->inbuf,smb_rcls) != 0) {
903                 return False;
904         }
905
906         return True;
907 }
908
909 /****************************************************************************
910 create a directory
911 ****************************************************************************/
912 BOOL cli_mkdir(struct cli_state *cli, char *dname)
913 {
914         char *p;
915
916         bzero(cli->outbuf,smb_size);
917         bzero(cli->inbuf,smb_size);
918
919         set_message(cli->outbuf,0, 2 + strlen(dname),True);
920
921         CVAL(cli->outbuf,smb_com) = SMBmkdir;
922         SSVAL(cli->outbuf,smb_tid,cli->cnum);
923         cli_setup_packet(cli);
924
925         p = smb_buf(cli->outbuf);
926         *p++ = 4;      
927         pstrcpy(p,dname);
928
929         send_smb(cli->fd,cli->outbuf);
930         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
931                 return False;
932         }
933
934         if (CVAL(cli->inbuf,smb_rcls) != 0) {
935                 return False;
936         }
937
938         return True;
939 }
940
941 /****************************************************************************
942 remove a directory
943 ****************************************************************************/
944 BOOL cli_rmdir(struct cli_state *cli, char *dname)
945 {
946         char *p;
947
948         bzero(cli->outbuf,smb_size);
949         bzero(cli->inbuf,smb_size);
950
951         set_message(cli->outbuf,0, 2 + strlen(dname),True);
952
953         CVAL(cli->outbuf,smb_com) = SMBrmdir;
954         SSVAL(cli->outbuf,smb_tid,cli->cnum);
955         cli_setup_packet(cli);
956
957         p = smb_buf(cli->outbuf);
958         *p++ = 4;      
959         pstrcpy(p,dname);
960
961         send_smb(cli->fd,cli->outbuf);
962         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
963                 return False;
964         }
965
966         if (CVAL(cli->inbuf,smb_rcls) != 0) {
967                 return False;
968         }
969
970         return True;
971 }
972
973
974
975 /****************************************************************************
976 open a file
977 ****************************************************************************/
978 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
979 {
980         char *p;
981         unsigned openfn=0;
982         unsigned accessmode=0;
983
984         /* you must open for RW not just write - otherwise getattrE doesn't
985            work! */
986         if ((flags & O_ACCMODE) == O_WRONLY) {
987                 flags = (flags & ~O_ACCMODE) | O_RDWR;
988         }
989
990         if (flags & O_CREAT)
991                 openfn |= (1<<4);
992         if (!(flags & O_EXCL)) {
993                 if (flags & O_TRUNC)
994                         openfn |= (1<<1);
995                 else
996                         openfn |= (1<<0);
997         }
998
999         accessmode = (share_mode<<4);
1000
1001         if ((flags & O_ACCMODE) == O_RDWR) {
1002                 accessmode |= 2;
1003         } else if ((flags & O_ACCMODE) == O_WRONLY) {
1004                 accessmode |= 1;
1005         } 
1006
1007 #if defined(O_SYNC)
1008         if ((flags & O_SYNC) == O_SYNC) {
1009                 accessmode |= (1<<14);
1010         }
1011 #endif /* O_SYNC */
1012
1013         bzero(cli->outbuf,smb_size);
1014         bzero(cli->inbuf,smb_size);
1015
1016         set_message(cli->outbuf,15,1 + strlen(fname),True);
1017
1018         CVAL(cli->outbuf,smb_com) = SMBopenX;
1019         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1020         cli_setup_packet(cli);
1021
1022         SSVAL(cli->outbuf,smb_vwv0,0xFF);
1023         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
1024         SSVAL(cli->outbuf,smb_vwv3,accessmode);
1025         SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1026         SSVAL(cli->outbuf,smb_vwv5,0);
1027         SSVAL(cli->outbuf,smb_vwv8,openfn);
1028   
1029         p = smb_buf(cli->outbuf);
1030         pstrcpy(p,fname);
1031         p = skip_string(p,1);
1032
1033         send_smb(cli->fd,cli->outbuf);
1034         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1035                 return -1;
1036         }
1037
1038         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1039                 return -1;
1040         }
1041
1042         return SVAL(cli->inbuf,smb_vwv2);
1043 }
1044
1045
1046
1047
1048 /****************************************************************************
1049   close a file
1050 ****************************************************************************/
1051 BOOL cli_close(struct cli_state *cli, int fnum)
1052 {
1053         bzero(cli->outbuf,smb_size);
1054         bzero(cli->inbuf,smb_size);
1055
1056         set_message(cli->outbuf,3,0,True);
1057
1058         CVAL(cli->outbuf,smb_com) = SMBclose;
1059         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1060         cli_setup_packet(cli);
1061
1062         SSVAL(cli->outbuf,smb_vwv0,fnum);
1063         SIVALS(cli->outbuf,smb_vwv1,-1);
1064
1065         send_smb(cli->fd,cli->outbuf);
1066         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1067                 return False;
1068         }
1069
1070         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1071                 return False;
1072         }
1073
1074         return True;
1075 }
1076
1077
1078 /****************************************************************************
1079   lock a file
1080 ****************************************************************************/
1081 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1082 {
1083         char *p;
1084
1085         bzero(cli->outbuf,smb_size);
1086         bzero(cli->inbuf,smb_size);
1087
1088         set_message(cli->outbuf,8,10,True);
1089
1090         CVAL(cli->outbuf,smb_com) = SMBlockingX;
1091         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1092         cli_setup_packet(cli);
1093
1094         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1095         SSVAL(cli->outbuf,smb_vwv2,fnum);
1096         CVAL(cli->outbuf,smb_vwv3) = 0;
1097         SIVALS(cli->outbuf, smb_vwv4, timeout);
1098         SSVAL(cli->outbuf,smb_vwv6,0);
1099         SSVAL(cli->outbuf,smb_vwv7,1);
1100
1101         p = smb_buf(cli->outbuf);
1102         SSVAL(p, 0, cli->pid);
1103         SIVAL(p, 2, offset);
1104         SIVAL(p, 6, len);
1105
1106         send_smb(cli->fd,cli->outbuf);
1107         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1108                 return False;
1109         }
1110
1111         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1112                 return False;
1113         }
1114
1115         return True;
1116 }
1117
1118 /****************************************************************************
1119   unlock a file
1120 ****************************************************************************/
1121 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1122 {
1123         char *p;
1124
1125         bzero(cli->outbuf,smb_size);
1126         bzero(cli->inbuf,smb_size);
1127
1128         set_message(cli->outbuf,8,10,True);
1129
1130         CVAL(cli->outbuf,smb_com) = SMBlockingX;
1131         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1132         cli_setup_packet(cli);
1133
1134         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1135         SSVAL(cli->outbuf,smb_vwv2,fnum);
1136         CVAL(cli->outbuf,smb_vwv3) = 0;
1137         SIVALS(cli->outbuf, smb_vwv4, timeout);
1138         SSVAL(cli->outbuf,smb_vwv6,1);
1139         SSVAL(cli->outbuf,smb_vwv7,0);
1140
1141         p = smb_buf(cli->outbuf);
1142         SSVAL(p, 0, cli->pid);
1143         SIVAL(p, 2, offset);
1144         SIVAL(p, 6, len);
1145
1146         send_smb(cli->fd,cli->outbuf);
1147         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1148                 return False;
1149         }
1150
1151         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1152                 return False;
1153         }
1154
1155         return True;
1156 }
1157
1158
1159
1160 /****************************************************************************
1161 issue a single SMBread and don't wait for a reply
1162 ****************************************************************************/
1163 static void cli_issue_read(struct cli_state *cli, int fnum, off_t offset, 
1164                            size_t size, int i)
1165 {
1166         bzero(cli->outbuf,smb_size);
1167         bzero(cli->inbuf,smb_size);
1168
1169         set_message(cli->outbuf,10,0,True);
1170                 
1171         CVAL(cli->outbuf,smb_com) = SMBreadX;
1172         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1173         cli_setup_packet(cli);
1174
1175         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1176         SSVAL(cli->outbuf,smb_vwv2,fnum);
1177         SIVAL(cli->outbuf,smb_vwv3,offset);
1178         SSVAL(cli->outbuf,smb_vwv5,size);
1179         SSVAL(cli->outbuf,smb_vwv6,size);
1180         SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1181
1182         send_smb(cli->fd,cli->outbuf);
1183 }
1184
1185 /****************************************************************************
1186   read from a file
1187 ****************************************************************************/
1188 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1189 {
1190         char *p;
1191         int total = -1;
1192         int issued=0;
1193         int received=0;
1194         int mpx = MAX(cli->max_mux-1, 1);
1195         int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1196         int mid;
1197         int blocks = (size + (block-1)) / block;
1198
1199         while (received < blocks) {
1200                 int size2;
1201
1202                 while (issued - received < mpx && issued < blocks) {
1203                         int size1 = MIN(block, size-issued*block);
1204                         cli_issue_read(cli, fnum, offset+issued*block, size1, issued);
1205                         issued++;
1206                 }
1207
1208                 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1209                         return total;
1210                 }
1211
1212                 received++;
1213                 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1214                 size2 = SVAL(cli->inbuf, smb_vwv5);
1215
1216                 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1217                         blocks = MIN(blocks, mid-1);
1218                         continue;
1219                 }
1220
1221                 if (size2 <= 0) {
1222                         blocks = MIN(blocks, mid-1);
1223                         /* this distinguishes EOF from an error */
1224                         total = MAX(total, 0);
1225                         continue;
1226                 }
1227
1228                 if (size2 > block) {
1229                         DEBUG(0,("server returned more than we wanted!\n"));
1230                         exit(1);
1231                 }
1232                 if (mid >= issued) {
1233                         DEBUG(0,("invalid mid from server!\n"));
1234                         exit(1);
1235                 }
1236                 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1237
1238                 memcpy(buf+mid*block, p, size2);
1239
1240                 total = MAX(total, mid*block + size2);
1241         }
1242
1243         while (received < issued) {
1244                 client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
1245                 received++;
1246         }
1247         
1248         return total;
1249 }
1250
1251
1252 /****************************************************************************
1253 issue a single SMBwrite and don't wait for a reply
1254 ****************************************************************************/
1255 static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, char *buf,
1256                             size_t size, int i)
1257 {
1258         char *p;
1259
1260         bzero(cli->outbuf,smb_size);
1261         bzero(cli->inbuf,smb_size);
1262
1263         set_message(cli->outbuf,12,size,True);
1264         
1265         CVAL(cli->outbuf,smb_com) = SMBwriteX;
1266         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1267         cli_setup_packet(cli);
1268         
1269         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1270         SSVAL(cli->outbuf,smb_vwv2,fnum);
1271         SIVAL(cli->outbuf,smb_vwv3,offset);
1272         
1273         SSVAL(cli->outbuf,smb_vwv10,size);
1274         SSVAL(cli->outbuf,smb_vwv11,
1275               smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1276         
1277         p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1278         memcpy(p, buf, size);
1279
1280         SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1281         
1282         send_smb(cli->fd,cli->outbuf);
1283 }
1284
1285 /****************************************************************************
1286   write to a file
1287 ****************************************************************************/
1288 size_t cli_write(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1289 {
1290         int total = -1;
1291         int issued=0;
1292         int received=0;
1293         int mpx = MAX(cli->max_mux-1, 1);
1294         int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1295         int mid;
1296         int blocks = (size + (block-1)) / block;
1297
1298         while (received < blocks) {
1299                 int size2;
1300
1301                 while (issued - received < mpx && issued < blocks) {
1302                         int size1 = MIN(block, size-issued*block);
1303                         cli_issue_write(cli, fnum, offset+issued*block, buf + issued*block,
1304                                         size1, issued);
1305                         issued++;
1306                 }
1307
1308                 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1309                         return total;
1310                 }
1311
1312                 received++;
1313                 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1314                 size2 = SVAL(cli->inbuf, smb_vwv2);
1315
1316                 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1317                         blocks = MIN(blocks, mid-1);
1318                         continue;
1319                 }
1320
1321                 if (size2 <= 0) {
1322                         blocks = MIN(blocks, mid-1);
1323                         /* this distinguishes EOF from an error */
1324                         total = MAX(total, 0);
1325                         continue;
1326                 }
1327
1328                 total += size2;
1329
1330                 total = MAX(total, mid*block + size2);
1331         }
1332
1333         while (received < issued) {
1334                 client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
1335                 received++;
1336         }
1337         
1338         return total;
1339 }
1340
1341
1342 /****************************************************************************
1343 do a SMBgetattrE call
1344 ****************************************************************************/
1345 BOOL cli_getattrE(struct cli_state *cli, int fd, 
1346                   int *attr, uint32 *size, 
1347                   time_t *c_time, time_t *a_time, time_t *m_time)
1348 {
1349         bzero(cli->outbuf,smb_size);
1350         bzero(cli->inbuf,smb_size);
1351
1352         set_message(cli->outbuf,2,0,True);
1353
1354         CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1355         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1356         cli_setup_packet(cli);
1357
1358         SSVAL(cli->outbuf,smb_vwv0,fd);
1359
1360         send_smb(cli->fd,cli->outbuf);
1361         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1362                 return False;
1363         }
1364         
1365         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1366                 return False;
1367         }
1368
1369         if (size) {
1370                 *size = IVAL(cli->inbuf, smb_vwv6);
1371         }
1372
1373         if (attr) {
1374                 *attr = SVAL(cli->inbuf,smb_vwv10);
1375         }
1376
1377         if (c_time) {
1378                 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1379         }
1380
1381         if (a_time) {
1382                 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1383         }
1384
1385         if (m_time) {
1386                 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1387         }
1388
1389         return True;
1390 }
1391
1392
1393 /****************************************************************************
1394 do a SMBgetatr call
1395 ****************************************************************************/
1396 BOOL cli_getatr(struct cli_state *cli, char *fname, 
1397                 uint32 *attr, size_t *size, time_t *t)
1398 {
1399         char *p;
1400
1401         bzero(cli->outbuf,smb_size);
1402         bzero(cli->inbuf,smb_size);
1403
1404         set_message(cli->outbuf,0,strlen(fname)+2,True);
1405
1406         CVAL(cli->outbuf,smb_com) = SMBgetatr;
1407         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1408         cli_setup_packet(cli);
1409
1410         p = smb_buf(cli->outbuf);
1411         *p = 4;
1412         pstrcpy(p+1, fname);
1413
1414         send_smb(cli->fd,cli->outbuf);
1415         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1416                 return False;
1417         }
1418         
1419         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1420                 return False;
1421         }
1422
1423         if (size) {
1424                 *size = IVAL(cli->inbuf, smb_vwv3);
1425         }
1426
1427         if (t) {
1428                 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1429         }
1430
1431         if (attr) {
1432                 *attr = SVAL(cli->inbuf,smb_vwv0);
1433         }
1434
1435
1436         return True;
1437 }
1438
1439
1440 /****************************************************************************
1441 do a SMBsetatr call
1442 ****************************************************************************/
1443 BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t)
1444 {
1445         char *p;
1446
1447         bzero(cli->outbuf,smb_size);
1448         bzero(cli->inbuf,smb_size);
1449
1450         set_message(cli->outbuf,8,strlen(fname)+4,True);
1451
1452         CVAL(cli->outbuf,smb_com) = SMBsetatr;
1453         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1454         cli_setup_packet(cli);
1455
1456         SSVAL(cli->outbuf,smb_vwv0, attr);
1457         put_dos_date3(cli->outbuf,smb_vwv1, t);
1458
1459         p = smb_buf(cli->outbuf);
1460         *p = 4;
1461         pstrcpy(p+1, fname);
1462         p = skip_string(p,1);
1463         *p = 4;
1464
1465         send_smb(cli->fd,cli->outbuf);
1466         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1467                 return False;
1468         }
1469         
1470         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1471                 return False;
1472         }
1473
1474         return True;
1475 }
1476
1477 /****************************************************************************
1478 send a qpathinfo call
1479 ****************************************************************************/
1480 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
1481                    time_t *c_time, time_t *a_time, time_t *m_time, 
1482                    size_t *size, uint32 *mode)
1483 {
1484         int data_len = 0;
1485         int param_len = 0;
1486         uint16 setup = TRANSACT2_QPATHINFO;
1487         pstring param;
1488         char *rparam=NULL, *rdata=NULL;
1489         int count=8;
1490         BOOL ret;
1491         time_t (*date_fn)(void *);
1492
1493         param_len = strlen(fname) + 7;
1494
1495         memset(param, 0, param_len);
1496         SSVAL(param, 0, SMB_INFO_STANDARD);
1497         pstrcpy(&param[6], fname);
1498
1499         do {
1500                 ret = (cli_send_trans(cli, SMBtrans2, 
1501                                       NULL, 0,        /* Name, length */
1502                                       -1, 0,          /* fid, flags */
1503                                       &setup, 1, 0,   /* setup, length, max */
1504                                       param, param_len, 10, /* param, length, max */
1505                                       NULL, data_len, cli->max_xmit /* data, length, max */
1506                                       ) &&
1507                        cli_receive_trans(cli, SMBtrans2, 
1508                                          &rparam, &param_len,
1509                                          &rdata, &data_len));
1510                 if (!ret) {
1511                         /* we need to work around a Win95 bug - sometimes
1512                            it gives ERRSRV/ERRerror temprarily */
1513                         uint8 eclass;
1514                         uint32 ecode;
1515                         cli_error(cli, &eclass, &ecode);
1516                         if (eclass != ERRSRV || ecode != ERRerror) break;
1517                         msleep(100);
1518                 }
1519         } while (count-- && ret==False);
1520
1521         if (!ret || !rdata || data_len < 22) {
1522                 return False;
1523         }
1524
1525         if (cli->win95) {
1526                 date_fn = make_unix_date;
1527         } else {
1528                 date_fn = make_unix_date2;
1529         }
1530
1531         if (c_time) {
1532                 *c_time = date_fn(rdata+0);
1533         }
1534         if (a_time) {
1535                 *a_time = date_fn(rdata+4);
1536         }
1537         if (m_time) {
1538                 *m_time = date_fn(rdata+8);
1539         }
1540         if (size) {
1541                 *size = IVAL(rdata, 12);
1542         }
1543         if (mode) {
1544                 *mode = SVAL(rdata,l1_attrFile);
1545         }
1546
1547         if (rdata) free(rdata);
1548         if (rparam) free(rparam);
1549         return True;
1550 }
1551
1552 /****************************************************************************
1553 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1554 ****************************************************************************/
1555 BOOL cli_qpathinfo2(struct cli_state *cli, char *fname, 
1556                     time_t *c_time, time_t *a_time, time_t *m_time, 
1557                     time_t *w_time, uint32 *size)
1558 {
1559         int data_len = 0;
1560         int param_len = 0;
1561         uint16 setup = TRANSACT2_QPATHINFO;
1562         pstring param;
1563         char *rparam=NULL, *rdata=NULL;
1564
1565         param_len = strlen(fname) + 7;
1566
1567         memset(param, 0, param_len);
1568         SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1569         pstrcpy(&param[6], fname);
1570
1571         if (!cli_send_trans(cli, SMBtrans2, 
1572                             NULL, 0,                      /* name, length */
1573                             -1, 0,                        /* fid, flags */
1574                             &setup, 1, 0,                 /* setup, length, max */
1575                             param, param_len, 10,         /* param, length, max */
1576                             NULL, data_len, cli->max_xmit /* data, length, max */
1577                            )) {
1578                 return False;
1579         }
1580
1581         if (!cli_receive_trans(cli, SMBtrans2,
1582                                &rparam, &param_len,
1583                                &rdata, &data_len)) {
1584                 return False;
1585         }
1586
1587         if (!rdata || data_len < 22) {
1588                 return False;
1589         }
1590
1591         if (c_time) {
1592                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1593         }
1594         if (a_time) {
1595                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1596         }
1597         if (m_time) {
1598                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1599         }
1600         if (w_time) {
1601                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1602         }
1603         if (size) {
1604                 *size = IVAL(rdata, 40);
1605         }
1606
1607         if (rdata) free(rdata);
1608         if (rparam) free(rparam);
1609         return True;
1610 }
1611
1612
1613 /****************************************************************************
1614 send a qfileinfo call
1615 ****************************************************************************/
1616 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
1617                    uint32 *mode, size_t *size,
1618                    time_t *c_time, time_t *a_time, time_t *m_time)
1619 {
1620         int data_len = 0;
1621         int param_len = 0;
1622         uint16 setup = TRANSACT2_QFILEINFO;
1623         pstring param;
1624         char *rparam=NULL, *rdata=NULL;
1625
1626         param_len = 4;
1627
1628         memset(param, 0, param_len);
1629         SSVAL(param, 0, fnum);
1630         SSVAL(param, 2, SMB_INFO_STANDARD);
1631
1632         if (!cli_send_trans(cli, SMBtrans2, 
1633                             NULL, 0,                        /* name, length */
1634                             -1, 0,                          /* fid, flags */
1635                             &setup, 1, 0,                   /* setup, length, max */
1636                             param, param_len, 2,            /* param, length, max */
1637                             NULL, data_len, cli->max_xmit   /* data, length, max */
1638                            )) {
1639                 return False;
1640         }
1641
1642         if (!cli_receive_trans(cli, SMBtrans2,
1643                                &rparam, &param_len,
1644                                &rdata, &data_len)) {
1645                 return False;
1646         }
1647
1648         if (!rdata || data_len < 22) {
1649                 return False;
1650         }
1651
1652         if (c_time) {
1653                 *c_time = make_unix_date2(rdata+0);
1654         }
1655         if (a_time) {
1656                 *a_time = make_unix_date2(rdata+4);
1657         }
1658         if (m_time) {
1659                 *m_time = make_unix_date2(rdata+8);
1660         }
1661         if (size) {
1662                 *size = IVAL(rdata, 12);
1663         }
1664         if (mode) {
1665                 *mode = SVAL(rdata,l1_attrFile);
1666         }
1667
1668         if (rdata) free(rdata);
1669         if (rparam) free(rparam);
1670         return True;
1671 }
1672
1673
1674 /****************************************************************************
1675 interpret a long filename structure - this is mostly guesses at the moment
1676 The length of the structure is returned
1677 The structure of a long filename depends on the info level. 260 is used
1678 by NT and 2 is used by OS/2
1679 ****************************************************************************/
1680 static int interpret_long_filename(int level,char *p,file_info *finfo)
1681 {
1682         extern file_info def_finfo;
1683
1684         if (finfo)
1685                 memcpy(finfo,&def_finfo,sizeof(*finfo));
1686
1687         switch (level)
1688                 {
1689                 case 1: /* OS/2 understands this */
1690                         if (finfo) {
1691                                 /* these dates are converted to GMT by make_unix_date */
1692                                 finfo->ctime = make_unix_date2(p+4);
1693                                 finfo->atime = make_unix_date2(p+8);
1694                                 finfo->mtime = make_unix_date2(p+12);
1695                                 finfo->size = IVAL(p,16);
1696                                 finfo->mode = CVAL(p,24);
1697                                 pstrcpy(finfo->name,p+27);
1698                         }
1699                         return(28 + CVAL(p,26));
1700
1701                 case 2: /* this is what OS/2 uses mostly */
1702                         if (finfo) {
1703                                 /* these dates are converted to GMT by make_unix_date */
1704                                 finfo->ctime = make_unix_date2(p+4);
1705                                 finfo->atime = make_unix_date2(p+8);
1706                                 finfo->mtime = make_unix_date2(p+12);
1707                                 finfo->size = IVAL(p,16);
1708                                 finfo->mode = CVAL(p,24);
1709                                 pstrcpy(finfo->name,p+31);
1710                         }
1711                         return(32 + CVAL(p,30));
1712
1713                         /* levels 3 and 4 are untested */
1714                 case 3:
1715                         if (finfo) {
1716                                 /* these dates are probably like the other ones */
1717                                 finfo->ctime = make_unix_date2(p+8);
1718                                 finfo->atime = make_unix_date2(p+12);
1719                                 finfo->mtime = make_unix_date2(p+16);
1720                                 finfo->size = IVAL(p,20);
1721                                 finfo->mode = CVAL(p,28);
1722                                 pstrcpy(finfo->name,p+33);
1723                         }
1724                         return(SVAL(p,4)+4);
1725                         
1726                 case 4:
1727                         if (finfo) {
1728                                 /* these dates are probably like the other ones */
1729                                 finfo->ctime = make_unix_date2(p+8);
1730                                 finfo->atime = make_unix_date2(p+12);
1731                                 finfo->mtime = make_unix_date2(p+16);
1732                                 finfo->size = IVAL(p,20);
1733                                 finfo->mode = CVAL(p,28);
1734                                 pstrcpy(finfo->name,p+37);
1735                         }
1736                         return(SVAL(p,4)+4);
1737                         
1738                 case 260: /* NT uses this, but also accepts 2 */
1739                         if (finfo) {
1740                                 int ret = SVAL(p,0);
1741                                 int namelen;
1742                                 p += 4; /* next entry offset */
1743                                 p += 4; /* fileindex */
1744                                 
1745                                 /* these dates appear to arrive in a
1746                                    weird way. It seems to be localtime
1747                                    plus the serverzone given in the
1748                                    initial connect. This is GMT when
1749                                    DST is not in effect and one hour
1750                                    from GMT otherwise. Can this really
1751                                    be right??
1752
1753                                    I suppose this could be called
1754                                    kludge-GMT. Is is the GMT you get
1755                                    by using the current DST setting on
1756                                    a different localtime. It will be
1757                                    cheap to calculate, I suppose, as
1758                                    no DST tables will be needed */
1759
1760                                 finfo->ctime = interpret_long_date(p); p += 8;
1761                                 finfo->atime = interpret_long_date(p); p += 8;
1762                                 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
1763                                 finfo->size = IVAL(p,0); p += 8;
1764                                 p += 8; /* alloc size */
1765                                 finfo->mode = CVAL(p,0); p += 4;
1766                                 namelen = IVAL(p,0); p += 4;
1767                                 p += 4; /* EA size */
1768                                 p += 2; /* short name len? */
1769                                 p += 24; /* short name? */        
1770                                 StrnCpy(finfo->name,p,namelen);
1771                                 return(ret);
1772                         }
1773                         return(SVAL(p,0));
1774                 }
1775         
1776         DEBUG(1,("Unknown long filename format %d\n",level));
1777         return(SVAL(p,0));
1778 }
1779
1780
1781 /****************************************************************************
1782   do a directory listing, calling fn on each file found
1783   ****************************************************************************/
1784 int cli_list(struct cli_state *cli,char *Mask,int attribute,void (*fn)(file_info *))
1785 {
1786         int max_matches = 512;
1787         /* NT uses 260, OS/2 uses 2. Both accept 1. */
1788         int info_level = cli->protocol<PROTOCOL_NT1?1:260; 
1789         char *p, *p2;
1790         pstring mask;
1791         file_info finfo;
1792         int i;
1793         char *dirlist = NULL;
1794         int dirlist_len = 0;
1795         int total_received = -1;
1796         BOOL First = True;
1797         int ff_resume_key = 0;
1798         int ff_searchcount=0;
1799         int ff_eos=0;
1800         int ff_lastname=0;
1801         int ff_dir_handle=0;
1802         int loop_count = 0;
1803         char *rparam=NULL, *rdata=NULL;
1804         int param_len, data_len;
1805         
1806         uint16 setup;
1807         pstring param;
1808         
1809         pstrcpy(mask,Mask);
1810         
1811         while (ff_eos == 0) {
1812                 loop_count++;
1813                 if (loop_count > 200) {
1814                         DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
1815                         break;
1816                 }
1817
1818                 param_len = 12+strlen(mask)+1;
1819
1820                 if (First) {
1821                         setup = TRANSACT2_FINDFIRST;
1822                         SSVAL(param,0,attribute); /* attribute */
1823                         SSVAL(param,2,max_matches); /* max count */
1824                         SSVAL(param,4,8+4+2);   /* resume required + close on end + continue */
1825                         SSVAL(param,6,info_level); 
1826                         SIVAL(param,8,0);
1827                         pstrcpy(param+12,mask);
1828                 } else {
1829                         setup = TRANSACT2_FINDNEXT;
1830                         SSVAL(param,0,ff_dir_handle);
1831                         SSVAL(param,2,max_matches); /* max count */
1832                         SSVAL(param,4,info_level); 
1833                         SIVAL(param,6,ff_resume_key); /* ff_resume_key */
1834                         SSVAL(param,10,8+4+2);  /* resume required + close on end + continue */
1835                         pstrcpy(param+12,mask);
1836
1837                         DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
1838                                  ff_dir_handle,ff_resume_key,ff_lastname,mask));
1839                 }
1840
1841                 if (!cli_send_trans(cli, SMBtrans2, 
1842                                     NULL, 0,                /* Name, length */
1843                                     -1, 0,                  /* fid, flags */
1844                                     &setup, 1, 0,           /* setup, length, max */
1845                                     param, param_len, 10,   /* param, length, max */
1846                                     NULL, 0, 
1847                                     cli->max_xmit /* data, length, max */
1848                                     )) {
1849                         break;
1850                 }
1851
1852                 if (!cli_receive_trans(cli, SMBtrans2, 
1853                                        &rparam, &param_len,
1854                                        &rdata, &data_len)) {
1855                         /* we need to work around a Win95 bug - sometimes
1856                            it gives ERRSRV/ERRerror temprarily */
1857                         uint8 eclass;
1858                         uint32 ecode;
1859                         cli_error(cli, &eclass, &ecode);
1860                         if (eclass != ERRSRV || ecode != ERRerror) break;
1861                         msleep(100);
1862                         continue;
1863                 }
1864
1865                 if (total_received == -1) total_received = 0;
1866
1867                 /* parse out some important return info */
1868                 p = rparam;
1869                 if (First) {
1870                         ff_dir_handle = SVAL(p,0);
1871                         ff_searchcount = SVAL(p,2);
1872                         ff_eos = SVAL(p,4);
1873                         ff_lastname = SVAL(p,8);
1874                 } else {
1875                         ff_searchcount = SVAL(p,0);
1876                         ff_eos = SVAL(p,2);
1877                         ff_lastname = SVAL(p,6);
1878                 }
1879
1880                 if (ff_searchcount == 0) 
1881                         break;
1882
1883                 /* point to the data bytes */
1884                 p = rdata;
1885
1886                 /* we might need the lastname for continuations */
1887                 if (ff_lastname > 0) {
1888                         switch(info_level)
1889                                 {
1890                                 case 260:
1891                                         ff_resume_key =0;
1892                                         StrnCpy(mask,p+ff_lastname,
1893                                                 data_len-ff_lastname);
1894                                         break;
1895                                 case 1:
1896                                         pstrcpy(mask,p + ff_lastname + 1);
1897                                         ff_resume_key = 0;
1898                                         break;
1899                                 }
1900                 } else {
1901                         pstrcpy(mask,"");
1902                 }
1903   
1904                 /* and add them to the dirlist pool */
1905                 dirlist = Realloc(dirlist,dirlist_len + data_len);
1906
1907                 if (!dirlist) {
1908                         DEBUG(0,("Failed to expand dirlist\n"));
1909                         break;
1910                 }
1911
1912                 /* put in a length for the last entry, to ensure we can chain entries 
1913                    into the next packet */
1914                 for (p2=p,i=0;i<(ff_searchcount-1);i++)
1915                         p2 += interpret_long_filename(info_level,p2,NULL);
1916                 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
1917
1918                 /* grab the data for later use */
1919                 memcpy(dirlist+dirlist_len,p,data_len);
1920                 dirlist_len += data_len;
1921
1922                 total_received += ff_searchcount;
1923
1924                 if (rdata) free(rdata); rdata = NULL;
1925                 if (rparam) free(rparam); rparam = NULL;
1926                 
1927                 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
1928                          ff_searchcount,ff_eos,ff_resume_key));
1929
1930                 First = False;
1931         }
1932
1933         for (p=dirlist,i=0;i<total_received;i++) {
1934                 p += interpret_long_filename(info_level,p,&finfo);
1935                 fn(&finfo);
1936         }
1937
1938         /* free up the dirlist buffer */
1939         if (dirlist) free(dirlist);
1940         return(total_received);
1941 }
1942
1943
1944 /****************************************************************************
1945 Send a SamOEMChangePassword command
1946 ****************************************************************************/
1947
1948 BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password,
1949                              char *old_password)
1950 {
1951   char param[16+sizeof(fstring)];
1952   char data[532];
1953   char *p = param;
1954   fstring upper_case_old_pw;
1955   fstring upper_case_new_pw;
1956   unsigned char old_pw_hash[16];
1957   unsigned char new_pw_hash[16];
1958   int data_len;
1959   int param_len = 0;
1960   int new_pw_len = strlen(new_password);
1961   char *rparam = NULL;
1962   char *rdata = NULL;
1963   int rprcnt, rdrcnt;
1964
1965   if (strlen(user) >= sizeof(fstring)-1) {
1966     DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
1967     return False;
1968   }
1969
1970   if (new_pw_len > 512) {
1971     DEBUG(0,("cli_oem_change_password: new password for user %s is too long.\n", user));
1972     return False;
1973   }
1974
1975   SSVAL(p,0,214); /* SamOEMChangePassword command. */
1976   p += 2;
1977   pstrcpy(p, "zsT");
1978   p = skip_string(p,1);
1979   pstrcpy(p, "B516B16");
1980   p = skip_string(p,1);
1981   pstrcpy(p,user);
1982   p = skip_string(p,1);
1983   SSVAL(p,0,532);
1984   p += 2;
1985
1986   param_len = PTR_DIFF(p,param);
1987
1988   /*
1989    * Now setup the data area.
1990    * We need to generate a random fill
1991    * for this area to make it harder to
1992    * decrypt. JRA.
1993    */
1994   generate_random_buffer((unsigned char *)data, sizeof(data), False);
1995   fstrcpy( &data[512 - new_pw_len], new_password);
1996   SIVAL(data, 512, new_pw_len);
1997
1998   /*
1999    * Get the Lanman hash of the old password, we
2000    * use this as the key to SamOEMHash().
2001    */
2002   memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
2003   fstrcpy(upper_case_old_pw, old_password);
2004   strupper(upper_case_old_pw);
2005   E_P16((uchar *)upper_case_old_pw, old_pw_hash);
2006
2007   SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True);
2008
2009   /* 
2010    * Now place the old password hash in the data.
2011    */
2012   memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
2013   fstrcpy(upper_case_new_pw, new_password);
2014   strupper(upper_case_new_pw);
2015
2016   E_P16((uchar *)upper_case_new_pw, new_pw_hash);
2017
2018   E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
2019
2020   data_len = 532;
2021     
2022   if (cli_send_trans(cli,SMBtrans,
2023                     PIPE_LANMAN,strlen(PIPE_LANMAN),      /* name, length */
2024                     0,0,                                  /* fid, flags */
2025                     NULL,0,0,                             /* setup, length, max */
2026                     param,param_len,2,                    /* param, length, max */
2027                     data,data_len,0                       /* data, length, max */
2028                    ) == False) {
2029     DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
2030               user ));
2031     return False;
2032   }
2033
2034   if (cli_receive_trans(cli,SMBtrans,
2035                        &rparam, &rprcnt,
2036                        &rdata, &rdrcnt)) {
2037     if (rparam)
2038       cli->rap_error = SVAL(rparam,0);
2039   }
2040
2041   if (rparam)
2042     free(rparam);
2043   if (rdata)
2044     free(rdata);
2045
2046   return (cli->rap_error == 0);
2047 }
2048
2049 /****************************************************************************
2050 send a negprot command
2051 ****************************************************************************/
2052 BOOL cli_negprot(struct cli_state *cli)
2053 {
2054         char *p;
2055         int numprots;
2056         int plength;
2057
2058         bzero(cli->outbuf,smb_size);
2059
2060         /* setup the protocol strings */
2061         for (plength=0,numprots=0;
2062              prots[numprots].name && prots[numprots].prot<=cli->protocol;
2063              numprots++)
2064                 plength += strlen(prots[numprots].name)+2;
2065     
2066         set_message(cli->outbuf,0,plength,True);
2067
2068         p = smb_buf(cli->outbuf);
2069         for (numprots=0;
2070              prots[numprots].name && prots[numprots].prot<=cli->protocol;
2071              numprots++) {
2072                 *p++ = 2;
2073                 pstrcpy(p,prots[numprots].name);
2074                 p += strlen(p) + 1;
2075         }
2076
2077         CVAL(cli->outbuf,smb_com) = SMBnegprot;
2078         cli_setup_packet(cli);
2079
2080         CVAL(smb_buf(cli->outbuf),0) = 2;
2081
2082         send_smb(cli->fd,cli->outbuf);
2083         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
2084                 return False;
2085
2086         show_msg(cli->inbuf);
2087
2088         if (CVAL(cli->inbuf,smb_rcls) != 0 || 
2089             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2090                 return(False);
2091         }
2092
2093         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2094
2095
2096         if (cli->protocol >= PROTOCOL_NT1) {    
2097                 /* NT protocol */
2098                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
2099                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
2100                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
2101                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
2102                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
2103                 /* this time arrives in real GMT */
2104                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
2105                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2106                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
2107                 if (cli->capabilities & 1) {
2108                         cli->readbraw_supported = True;
2109                         cli->writebraw_supported = True;      
2110                 }
2111         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2112                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2113                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2114                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2115                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
2116                 /* this time is converted to GMT by make_unix_date */
2117                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2118                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2119                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2120                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2121         } else {
2122                 /* the old core protocol */
2123                 cli->sec_mode = 0;
2124                 cli->serverzone = TimeDiff(time(NULL));
2125         }
2126
2127         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2128
2129         return True;
2130 }
2131
2132
2133 /****************************************************************************
2134   send a session request.  see rfc1002.txt 4.3 and 4.3.2
2135 ****************************************************************************/
2136 BOOL cli_session_request(struct cli_state *cli,
2137                         struct nmb_name *calling, struct nmb_name *called)
2138 {
2139         char *p;
2140         int len = 4;
2141         /* send a session request (RFC 1002) */
2142
2143         memcpy(&(cli->calling), calling, sizeof(*calling));
2144         memcpy(&(cli->called ), called , sizeof(*called ));
2145   
2146         /* put in the destination name */
2147         p = cli->outbuf+len;
2148         name_mangle(cli->called .name, p, cli->called .name_type);
2149         len += name_len(p);
2150
2151         /* and my name */
2152         p = cli->outbuf+len;
2153         name_mangle(cli->calling.name, p, cli->calling.name_type);
2154         len += name_len(p);
2155
2156         /* setup the packet length */
2157         _smb_setlen(cli->outbuf,len);
2158         CVAL(cli->outbuf,0) = 0x81;
2159
2160 #ifdef WITH_SSL
2161 retry:
2162 #endif /* WITH_SSL */
2163
2164         send_smb(cli->fd,cli->outbuf);
2165         DEBUG(5,("Sent session request\n"));
2166
2167         if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
2168                 return False;
2169
2170 #ifdef WITH_SSL
2171     if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2172         if (!sslutil_fd_is_ssl(cli->fd)){
2173             if (sslutil_connect(cli->fd) == 0)
2174                 goto retry;
2175         }
2176     }
2177 #endif /* WITH_SSL */
2178
2179         if (CVAL(cli->inbuf,0) != 0x82) {
2180                 /* This is the wrong place to put the error... JRA. */
2181                 cli->rap_error = CVAL(cli->inbuf,0);
2182                 return False;
2183         }
2184         return(True);
2185 }
2186
2187
2188 /****************************************************************************
2189 open the client sockets
2190 ****************************************************************************/
2191 BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
2192 {
2193         struct in_addr dest_ip;
2194         extern struct in_addr ipzero;
2195
2196         fstrcpy(cli->desthost, host);
2197         
2198         if (!ip || ip_equal(*ip, ipzero)) {
2199                 if (!resolve_name( cli->desthost, &dest_ip)) {
2200                         return False;
2201                 }
2202         } else {
2203                 dest_ip = *ip;
2204         }
2205
2206
2207         cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout);
2208         if (cli->fd == -1)
2209                 return False;
2210
2211         return True;
2212 }
2213
2214
2215 /****************************************************************************
2216 initialise a client structure
2217 ****************************************************************************/
2218 BOOL cli_initialise(struct cli_state *cli)
2219 {
2220         if (cli->initialised)
2221       cli_shutdown(cli);
2222
2223         memset(cli, 0, sizeof(*cli));
2224         cli->fd = -1;
2225         cli->cnum = -1;
2226         cli->pid = (uint16)getpid();
2227         cli->mid = 1;
2228         cli->vuid = UID_FIELD_INVALID;
2229         cli->protocol = PROTOCOL_NT1;
2230         cli->timeout = 20000;
2231         cli->bufsize = CLI_BUFFER_SIZE+4;
2232         cli->max_xmit = cli->bufsize;
2233         cli->outbuf = (char *)malloc(cli->bufsize);
2234         cli->inbuf = (char *)malloc(cli->bufsize);
2235         if (!cli->outbuf || !cli->inbuf)
2236       return False;
2237         cli->initialised = 1;
2238         return True;
2239 }
2240
2241 /****************************************************************************
2242 shutdown a client structure
2243 ****************************************************************************/
2244 void cli_shutdown(struct cli_state *cli)
2245 {
2246         if (cli->outbuf)
2247       free(cli->outbuf);
2248         if (cli->inbuf)
2249       free(cli->inbuf);
2250 #ifdef WITH_SSL
2251     if (cli->fd != -1)
2252       sslutil_disconnect(cli->fd);
2253 #endif /* WITH_SSL */
2254         if (cli->fd != -1) 
2255       close(cli->fd);
2256         memset(cli, 0, sizeof(*cli));
2257 }
2258
2259
2260 /****************************************************************************
2261   return error codes for the last packet
2262   returns 0 if there was no error and the bext approx of a unix errno
2263   otherwise
2264 ****************************************************************************/
2265 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
2266 {
2267         int  flgs2 = SVAL(cli->inbuf,smb_flg2);
2268         char rcls;
2269         int code;
2270
2271         if (eclass) *eclass = 0;
2272         if (num   ) *num = 0;
2273
2274         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
2275                 /* 32 bit error codes detected */
2276                 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2277                 if (num) *num = nt_err;
2278                 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2279                 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2280
2281                 switch (nt_err & 0xFFFFFF) {
2282                 case NT_STATUS_ACCESS_VIOLATION: return EACCES;
2283                 case NT_STATUS_NO_SUCH_FILE: return ENOENT;
2284                 case NT_STATUS_NO_SUCH_DEVICE: return ENODEV;
2285                 case NT_STATUS_INVALID_HANDLE: return EBADF;
2286                 case NT_STATUS_NO_MEMORY: return ENOMEM;
2287                 case NT_STATUS_ACCESS_DENIED: return EACCES;
2288                 case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2289                 case NT_STATUS_SHARING_VIOLATION: return EBUSY;
2290                 }
2291
2292                 /* for all other cases - a default code */
2293                 return EINVAL;
2294         }
2295
2296         rcls  = CVAL(cli->inbuf,smb_rcls);
2297         code  = SVAL(cli->inbuf,smb_err);
2298         if (rcls == 0) return 0;
2299
2300         if (eclass) *eclass = rcls;
2301         if (num   ) *num    = code;
2302
2303         if (rcls == ERRDOS) {
2304                 switch (code) {
2305                 case ERRbadfile: return ENOENT;
2306                 case ERRnoaccess: return EACCES;
2307                 }
2308         }
2309         if (rcls == ERRSRV) {
2310                 switch (code) {
2311                 case ERRbadpw: return EPERM;
2312                 }
2313         }
2314         /* for other cases */
2315         return EINVAL;
2316 }
2317
2318 /****************************************************************************
2319 set socket options on a open connection
2320 ****************************************************************************/
2321 void cli_sockopt(struct cli_state *cli, char *options)
2322 {
2323         set_socket_options(cli->fd, options);
2324 }
2325
2326 /****************************************************************************
2327 set the PID to use for smb messages. Return the old pid.
2328 ****************************************************************************/
2329 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2330 {
2331         uint16 ret = cli->pid;
2332         cli->pid = pid;
2333         return ret;
2334 }
2335
2336 /****************************************************************************
2337 establishes a connection right up to doing tconX, reading in a password.
2338 ****************************************************************************/
2339 BOOL cli_reestablish_connection(struct cli_state *cli)
2340 {
2341         struct nmb_name calling;
2342         struct nmb_name called;
2343         fstring dest_host;
2344         struct in_addr dest_ip;
2345         fstring share;
2346         fstring dev;
2347         BOOL do_tcon = False;
2348
2349         if (!cli->initialised || cli->fd == -1)
2350         {
2351                 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2352                 return False;
2353         }
2354
2355         /* copy the parameters necessary to re-establish the connection */
2356
2357         if (cli->cnum != 0)
2358         {
2359                 fstrcpy(share, cli->share);
2360                 fstrcpy(dev  , cli->dev);
2361                 do_tcon = True;
2362         }
2363
2364         memcpy(&called , &(cli->called ), sizeof(called ));
2365         memcpy(&calling, &(cli->calling), sizeof(calling));
2366         fstrcpy(dest_host, cli->full_dest_host_name);
2367         dest_ip = cli->dest_ip;
2368
2369         DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2370                           namestr(&calling), namestr(&called), inet_ntoa(dest_ip),
2371                       cli->user_name, cli->domain));
2372
2373         return cli_establish_connection(cli,
2374                                         dest_host, &dest_ip,
2375                                         &calling, &called,
2376                                         share, dev, False, do_tcon);
2377 }
2378
2379 /****************************************************************************
2380 establishes a connection right up to doing tconX, reading in a password.
2381 ****************************************************************************/
2382 BOOL cli_establish_connection(struct cli_state *cli, 
2383                                 char *dest_host, struct in_addr *dest_ip,
2384                                 struct nmb_name *calling, struct nmb_name *called,
2385                                 char *service, char *service_type,
2386                                 BOOL do_shutdown, BOOL do_tcon)
2387 {
2388         DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2389                           namestr(calling), namestr(called), inet_ntoa(*dest_ip),
2390                       cli->user_name, cli->domain));
2391
2392         /* establish connection */
2393
2394         if ((!cli->initialised))
2395         {
2396                 return False;
2397         }
2398
2399         if (cli->fd == -1)
2400         {
2401                 if (!cli_connect(cli, dest_host, dest_ip))
2402                 {
2403                         DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2404                                           namestr(calling), inet_ntoa(*dest_ip)));
2405                         return False;
2406                 }
2407         }
2408
2409         if (!cli_session_request(cli, calling, called))
2410         {
2411                 DEBUG(1,("failed session request\n"));
2412                 if (do_shutdown)
2413           cli_shutdown(cli);
2414                 return False;
2415         }
2416
2417         if (!cli_negprot(cli))
2418         {
2419                 DEBUG(1,("failed negprot\n"));
2420                 if (do_shutdown)
2421           cli_shutdown(cli);
2422                 return False;
2423         }
2424
2425         if (cli->pwd.cleartext || cli->pwd.null_pwd)
2426         {
2427                 /* attempt clear-text session */
2428
2429                 fstring passwd;
2430
2431                 pwd_get_cleartext(&(cli->pwd), passwd);
2432
2433                 /* attempt clear-text session */
2434                 if (!cli_session_setup(cli, cli->user_name,
2435                                passwd, strlen(passwd),
2436                                NULL, 0,
2437                                cli->domain))
2438                 {
2439                         DEBUG(1,("failed session setup\n"));
2440                         if (do_shutdown)
2441               cli_shutdown(cli);
2442                         return False;
2443                 }
2444                 if (do_tcon)
2445                 {
2446                         if (!cli_send_tconX(cli, service, service_type,
2447                                             (char*)passwd, strlen(passwd)))
2448                         {
2449                                 DEBUG(1,("failed tcon_X\n"));
2450                                 if (do_shutdown)
2451                   cli_shutdown(cli);
2452                                 return False;
2453                         }
2454                 }
2455         }
2456         else
2457         {
2458                 /* attempt encrypted session */
2459                 unsigned char nt_sess_pwd[24];
2460                 unsigned char lm_sess_pwd[24];
2461
2462                 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2463                 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
2464                 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
2465
2466                 /* attempt encrypted session */
2467                 if (!cli_session_setup(cli, cli->user_name,
2468                                (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
2469                                (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
2470                                cli->domain))
2471                 {
2472                         DEBUG(1,("failed session setup\n"));
2473                         if (do_shutdown)
2474               cli_shutdown(cli);
2475                         return False;
2476                 }
2477
2478                 if (do_tcon)
2479                 {
2480                         if (!cli_send_tconX(cli, service, service_type,
2481                                             (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
2482                         {
2483                                 DEBUG(1,("failed tcon_X\n"));
2484                                 if (do_shutdown)
2485                   cli_shutdown(cli);
2486                                 return False;
2487                         }
2488                 }
2489         }
2490
2491         if (do_shutdown)
2492       cli_shutdown(cli);
2493
2494         return True;
2495 }
2496
2497
2498 /****************************************************************************
2499   cancel a print job
2500   ****************************************************************************/
2501 int cli_printjob_del(struct cli_state *cli, int job)
2502 {
2503         char *rparam = NULL;
2504         char *rdata = NULL;
2505         char *p;
2506         int rdrcnt,rprcnt, ret = -1;
2507         pstring param;
2508
2509         bzero(param,sizeof(param));
2510
2511         p = param;
2512         SSVAL(p,0,81);          /* DosPrintJobDel() */
2513         p += 2;
2514         pstrcpy(p,"W");
2515         p = skip_string(p,1);
2516         pstrcpy(p,"");
2517         p = skip_string(p,1);
2518         SSVAL(p,0,job);     
2519         p += 2;
2520         
2521         if (cli_api(cli, 
2522                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
2523                     NULL, 0, CLI_BUFFER_SIZE,            /* data, length, maxlen */
2524                     &rparam, &rprcnt,                /* return params, length */
2525                     &rdata, &rdrcnt)) {               /* return data, length */
2526                 ret = SVAL(rparam,0);
2527         }
2528
2529         if (rparam) free(rparam);
2530         if (rdata) free(rdata);
2531
2532         return ret;
2533 }
2534
2535
2536 /****************************************************************************
2537 call fn() on each entry in a print queue
2538 ****************************************************************************/
2539 int cli_print_queue(struct cli_state *cli, 
2540                     void (*fn)(struct print_job_info *))
2541 {
2542         char *rparam = NULL;
2543         char *rdata = NULL;
2544         char *p;
2545         int rdrcnt, rprcnt;
2546         pstring param;
2547         int result_code=0;
2548         int i = -1;
2549         
2550         bzero(param,sizeof(param));
2551
2552         p = param;
2553         SSVAL(p,0,76);         /* API function number 76 (DosPrintJobEnum) */
2554         p += 2;
2555         pstrcpy(p,"zWrLeh");   /* parameter description? */
2556         p = skip_string(p,1);
2557         pstrcpy(p,"WWzWWDDzz");  /* returned data format */
2558         p = skip_string(p,1);
2559         pstrcpy(p,cli->share);    /* name of queue */
2560         p = skip_string(p,1);
2561         SSVAL(p,0,2);   /* API function level 2, PRJINFO_2 data structure */
2562         SSVAL(p,2,1000); /* size of bytes of returned data buffer */
2563         p += 4;
2564         pstrcpy(p,"");   /* subformat */
2565         p = skip_string(p,1);
2566
2567         DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
2568
2569         if (cli_api(cli, 
2570                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
2571                     NULL, 0, CLI_BUFFER_SIZE,            /* data, length, maxlen */
2572                     &rparam, &rprcnt,                /* return params, length */
2573                     &rdata, &rdrcnt)) {               /* return data, length */
2574                 int converter;
2575                 result_code = SVAL(rparam,0);
2576                 converter = SVAL(rparam,2);       /* conversion factor */
2577
2578                 if (result_code == 0) {
2579                         struct print_job_info job;
2580                         
2581                         p = rdata; 
2582
2583                         for (i = 0; i < SVAL(rparam,4); ++i) {
2584                                 job.id = SVAL(p,0);
2585                                 job.priority = SVAL(p,2);
2586                                 fstrcpy(job.user,
2587                                         fix_char_ptr(SVAL(p,4), converter, 
2588                                                      rdata, rdrcnt));
2589                                 job.t = make_unix_date3(p + 12);
2590                                 job.size = IVAL(p,16);
2591                                 fstrcpy(job.name,fix_char_ptr(SVAL(p,24), 
2592                                                               converter, 
2593                                                               rdata, rdrcnt));
2594                                 fn(&job);                               
2595                                 p += 28;
2596                         }
2597                 }
2598         }
2599
2600         /* If any parameters or data were returned, free the storage. */
2601         if(rparam) free(rparam);
2602         if(rdata) free(rdata);
2603
2604         return i;
2605 }