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