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