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