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