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