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