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