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