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