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