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