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