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