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