90ea3d12bfbff1f02ec96cc63a6e2c96f5f45208
[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         {
1601                 int size2;
1602
1603                 while (issued - received < mpx && issued < blocks) {
1604                         int size1 = MIN(block, size-issued*block);
1605                         cli_issue_read(cli, fnum, offset+issued*block, size1, issued);
1606                         issued++;
1607                 }
1608
1609                 if (!cli_receive_smb(cli)) {
1610                         return total;
1611                 }
1612
1613                 received++;
1614                 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1615                 size2 = SVAL(cli->inbuf, smb_vwv5);
1616
1617                 if (cli_error(cli, NULL, NULL))
1618                 {
1619                         blocks = MIN(blocks, mid-1);
1620                         continue;
1621                 }
1622
1623                 if (size2 <= 0) {
1624                         blocks = MIN(blocks, mid-1);
1625                         /* this distinguishes EOF from an error */
1626                         total = MAX(total, 0);
1627                         continue;
1628                 }
1629
1630                 if (size2 > block) {
1631                         DEBUG(0,("server returned more than we wanted!\n"));
1632                         exit(1);
1633                 }
1634                 if (mid >= issued) {
1635                         DEBUG(0,("invalid mid from server!\n"));
1636                         exit(1);
1637                 }
1638                 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1639
1640                 memcpy(buf+mid*block, p, size2);
1641
1642                 total = MAX(total, mid*block + size2);
1643         }
1644
1645         while (received < issued) {
1646                 cli_receive_smb(cli);
1647                 received++;
1648         }
1649         
1650         return total;
1651 }
1652
1653
1654 /****************************************************************************
1655 issue a single SMBwrite and don't wait for a reply
1656 ****************************************************************************/
1657 static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
1658                             size_t size, int i)
1659 {
1660         char *p;
1661
1662         bzero(cli->outbuf,smb_size);
1663         bzero(cli->inbuf,smb_size);
1664
1665         set_message(cli->outbuf,12,size,True);
1666         
1667         CVAL(cli->outbuf,smb_com) = SMBwriteX;
1668         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1669         cli_setup_packet(cli);
1670         
1671         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1672         SSVAL(cli->outbuf,smb_vwv2,fnum);
1673
1674         SIVAL(cli->outbuf,smb_vwv3,offset);
1675         SIVAL(cli->outbuf,smb_vwv5,IS_BITS_SET_ALL(mode, 0x0008) ? 0xFFFFFFFF : 0);
1676         SSVAL(cli->outbuf,smb_vwv7,mode);
1677
1678         SSVAL(cli->outbuf,smb_vwv8,IS_BITS_SET_ALL(mode, 0x0008) ? size : 0);
1679         SSVAL(cli->outbuf,smb_vwv10,size);
1680         SSVAL(cli->outbuf,smb_vwv11,
1681               smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1682         
1683         p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1684         memcpy(p, buf, size);
1685
1686         SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1687         
1688         cli_send_smb(cli, True);
1689 }
1690
1691 /****************************************************************************
1692   write to a file
1693   write_mode: 0x0001 disallow write cacheing
1694               0x0002 return bytes remaining
1695               0x0004 use raw named pipe protocol
1696               0x0008 start of message mode named pipe protocol
1697 ****************************************************************************/
1698 ssize_t cli_write(struct cli_state *cli,
1699                   int fnum, uint16 write_mode,
1700                   char *buf, off_t offset, size_t size)
1701 {
1702         int total = -1;
1703         int issued=0;
1704         int received=0;
1705         int mpx = MAX(cli->max_mux-1, 1);
1706         int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1707         int mid;
1708         int blocks = (size + (block-1)) / block;
1709
1710         if (size == 0) return 0;
1711
1712         while (received < blocks) {
1713                 int size2;
1714
1715                 while (issued - received < mpx && issued < blocks) {
1716                         int size1 = MIN(block, size-issued*block);
1717                         cli_issue_write(cli, fnum, offset+issued*block,
1718                                         write_mode,
1719                                         buf + issued*block,
1720                                         size1, issued);
1721                         issued++;
1722                 }
1723
1724                 if (!cli_receive_smb(cli)) {
1725                         return total;
1726                 }
1727
1728                 received++;
1729                 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1730                 size2 = SVAL(cli->inbuf, smb_vwv2);
1731
1732                 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1733                         blocks = MIN(blocks, mid-1);
1734                         continue;
1735                 }
1736
1737                 if (size2 <= 0) {
1738                         blocks = MIN(blocks, mid-1);
1739                         /* this distinguishes EOF from an error */
1740                         total = MAX(total, 0);
1741                         continue;
1742                 }
1743
1744                 total += size2;
1745
1746                 total = MAX(total, mid*block + size2);
1747         }
1748
1749         while (received < issued) {
1750                 cli_receive_smb(cli);
1751                 received++;
1752         }
1753         
1754         return total;
1755 }
1756
1757
1758 /****************************************************************************
1759 do a SMBgetattrE call
1760 ****************************************************************************/
1761 BOOL cli_getattrE(struct cli_state *cli, int fd, 
1762                   uint16 *attr, size_t *size, 
1763                   time_t *c_time, time_t *a_time, time_t *m_time)
1764 {
1765         bzero(cli->outbuf,smb_size);
1766         bzero(cli->inbuf,smb_size);
1767
1768         set_message(cli->outbuf,2,0,True);
1769
1770         CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1771         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1772         cli_setup_packet(cli);
1773
1774         SSVAL(cli->outbuf,smb_vwv0,fd);
1775
1776         cli_send_smb(cli, True);
1777         if (!cli_receive_smb(cli)) {
1778                 return False;
1779         }
1780         
1781         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1782                 return False;
1783         }
1784
1785         if (size) {
1786                 *size = IVAL(cli->inbuf, smb_vwv6);
1787         }
1788
1789         if (attr) {
1790                 *attr = SVAL(cli->inbuf,smb_vwv10);
1791         }
1792
1793         if (c_time) {
1794                 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1795         }
1796
1797         if (a_time) {
1798                 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1799         }
1800
1801         if (m_time) {
1802                 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1803         }
1804
1805         return True;
1806 }
1807
1808
1809 /****************************************************************************
1810 do a SMBgetatr call
1811 ****************************************************************************/
1812 BOOL cli_getatr(struct cli_state *cli, char *fname, 
1813                 uint16 *attr, size_t *size, time_t *t)
1814 {
1815         char *p;
1816
1817         bzero(cli->outbuf,smb_size);
1818         bzero(cli->inbuf,smb_size);
1819
1820         set_message(cli->outbuf,0,strlen(fname)+2,True);
1821
1822         CVAL(cli->outbuf,smb_com) = SMBgetatr;
1823         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1824         cli_setup_packet(cli);
1825
1826         p = smb_buf(cli->outbuf);
1827         *p = 4;
1828         pstrcpy(p+1, fname);
1829
1830         cli_send_smb(cli, True);
1831         if (!cli_receive_smb(cli)) {
1832                 return False;
1833         }
1834         
1835         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1836                 return False;
1837         }
1838
1839         if (size) {
1840                 *size = IVAL(cli->inbuf, smb_vwv3);
1841         }
1842
1843         if (t) {
1844                 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1845         }
1846
1847         if (attr) {
1848                 *attr = SVAL(cli->inbuf,smb_vwv0);
1849         }
1850
1851
1852         return True;
1853 }
1854
1855
1856 /****************************************************************************
1857 do a SMBsetatr call
1858 ****************************************************************************/
1859 BOOL cli_setatr(struct cli_state *cli, char *fname, uint16 attr, time_t t)
1860 {
1861         char *p;
1862
1863         bzero(cli->outbuf,smb_size);
1864         bzero(cli->inbuf,smb_size);
1865
1866         set_message(cli->outbuf,8,strlen(fname)+4,True);
1867
1868         CVAL(cli->outbuf,smb_com) = SMBsetatr;
1869         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1870         cli_setup_packet(cli);
1871
1872         SSVAL(cli->outbuf,smb_vwv0, attr);
1873         put_dos_date3(cli->outbuf,smb_vwv1, t);
1874
1875         p = smb_buf(cli->outbuf);
1876         *p = 4;
1877         pstrcpy(p+1, fname);
1878         p = skip_string(p,1);
1879         *p = 4;
1880
1881         cli_send_smb(cli, True);
1882         if (!cli_receive_smb(cli)) {
1883                 return False;
1884         }
1885         
1886         if (CVAL(cli->inbuf,smb_rcls) != 0) {
1887                 return False;
1888         }
1889
1890         return True;
1891 }
1892
1893 /****************************************************************************
1894 send a qpathinfo call
1895 ****************************************************************************/
1896 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
1897                    time_t *c_time, time_t *a_time, time_t *m_time, 
1898                    size_t *size, uint16 *mode)
1899 {
1900         int data_len = 0;
1901         int param_len = 0;
1902         uint16 setup = TRANSACT2_QPATHINFO;
1903         pstring param;
1904         char *rparam=NULL, *rdata=NULL;
1905         int count=8;
1906         BOOL ret;
1907         time_t (*date_fn)(void *);
1908
1909         param_len = strlen(fname) + 7;
1910
1911         memset(param, 0, param_len);
1912         SSVAL(param, 0, SMB_INFO_STANDARD);
1913         pstrcpy(&param[6], fname);
1914
1915         do {
1916                 ret = (cli_send_trans(cli, SMBtrans2, 
1917                                       NULL, 0,        /* Name, length */
1918                                       -1, 0,          /* fid, flags */
1919                                       &setup, 1, 0,   /* setup, length, max */
1920                                       param, param_len, 10, /* param, length, max */
1921                                       NULL, data_len, cli->max_xmit /* data, length, max */
1922                                       ) &&
1923                        cli_receive_trans(cli, SMBtrans2, 
1924                                          &rparam, &param_len,
1925                                          &rdata, &data_len));
1926                 if (!ret) {
1927                         /* we need to work around a Win95 bug - sometimes
1928                            it gives ERRSRV/ERRerror temprarily */
1929                         uint8 eclass;
1930                         uint32 ecode;
1931                         cli_error(cli, &eclass, &ecode);
1932                         if (eclass != ERRSRV || ecode != ERRerror) break;
1933                         msleep(100);
1934                 }
1935         } while (count-- && ret==False);
1936
1937         if (!ret || !rdata || data_len < 22) {
1938                 return False;
1939         }
1940
1941         if (cli->win95) {
1942                 date_fn = make_unix_date;
1943         } else {
1944                 date_fn = make_unix_date2;
1945         }
1946
1947         if (c_time) {
1948                 *c_time = date_fn(rdata+0);
1949         }
1950         if (a_time) {
1951                 *a_time = date_fn(rdata+4);
1952         }
1953         if (m_time) {
1954                 *m_time = date_fn(rdata+8);
1955         }
1956         if (size) {
1957                 *size = IVAL(rdata, 12);
1958         }
1959         if (mode) {
1960                 *mode = SVAL(rdata,l1_attrFile);
1961         }
1962
1963         if (rdata) free(rdata);
1964         if (rparam) free(rparam);
1965         return True;
1966 }
1967
1968 /****************************************************************************
1969 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1970 ****************************************************************************/
1971 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, 
1972                     time_t *c_time, time_t *a_time, time_t *m_time, 
1973                     time_t *w_time, size_t *size, uint16 *mode,
1974                     SMB_INO_T *ino)
1975 {
1976         int data_len = 0;
1977         int param_len = 0;
1978         uint16 setup = TRANSACT2_QPATHINFO;
1979         pstring param;
1980         char *rparam=NULL, *rdata=NULL;
1981
1982         param_len = strlen(fname) + 7;
1983
1984         memset(param, 0, param_len);
1985         SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1986         pstrcpy(&param[6], fname);
1987
1988         if (!cli_send_trans(cli, SMBtrans2, 
1989                             NULL, 0,                      /* name, length */
1990                             -1, 0,                        /* fid, flags */
1991                             &setup, 1, 0,                 /* setup, length, max */
1992                             param, param_len, 10,         /* param, length, max */
1993                             NULL, data_len, cli->max_xmit /* data, length, max */
1994                            )) {
1995                 return False;
1996         }
1997
1998         if (!cli_receive_trans(cli, SMBtrans2,
1999                                &rparam, &param_len,
2000                                &rdata, &data_len)) {
2001                 return False;
2002         }
2003
2004         if (!rdata || data_len < 22) {
2005                 return False;
2006         }
2007
2008         if (c_time) {
2009                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
2010         }
2011         if (a_time) {
2012                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
2013         }
2014         if (m_time) {
2015                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
2016         }
2017         if (w_time) {
2018                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
2019         }
2020         if (mode) {
2021                 *mode = SVAL(rdata, 32);
2022         }
2023         if (size) {
2024                 *size = IVAL(rdata, 40);
2025         }
2026         if (ino) {
2027                 *ino = IVAL(rdata, 64);
2028         }
2029
2030         if (rdata) free(rdata);
2031         if (rparam) free(rparam);
2032         return True;
2033 }
2034
2035
2036 /****************************************************************************
2037 send a qfileinfo call
2038 ****************************************************************************/
2039 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
2040                    uint16 *mode, size_t *size,
2041                    time_t *c_time, time_t *a_time, time_t *m_time, 
2042                    time_t *w_time, SMB_INO_T *ino)
2043 {
2044         int data_len = 0;
2045         int param_len = 0;
2046         uint16 setup = TRANSACT2_QFILEINFO;
2047         pstring param;
2048         char *rparam=NULL, *rdata=NULL;
2049
2050         /* if its a win95 server then fail this - win95 totally screws it
2051            up */
2052         if (cli->win95) return False;
2053
2054         param_len = 4;
2055
2056         memset(param, 0, param_len);
2057         SSVAL(param, 0, fnum);
2058         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
2059
2060         if (!cli_send_trans(cli, SMBtrans2, 
2061                             NULL, 0,                        /* name, length */
2062                             -1, 0,                          /* fid, flags */
2063                             &setup, 1, 0,                   /* setup, length, max */
2064                             param, param_len, 2,            /* param, length, max */
2065                             NULL, data_len, cli->max_xmit   /* data, length, max */
2066                            )) {
2067                 return False;
2068         }
2069
2070         if (!cli_receive_trans(cli, SMBtrans2,
2071                                &rparam, &param_len,
2072                                &rdata, &data_len)) {
2073                 return False;
2074         }
2075
2076         if (!rdata || data_len < 68) {
2077                 return False;
2078         }
2079
2080         if (c_time) {
2081                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
2082         }
2083         if (a_time) {
2084                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
2085         }
2086         if (m_time) {
2087                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
2088         }
2089         if (w_time) {
2090                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
2091         }
2092         if (mode) {
2093                 *mode = SVAL(rdata, 32);
2094         }
2095         if (size) {
2096                 *size = IVAL(rdata, 40);
2097         }
2098         if (ino) {
2099                 *ino = IVAL(rdata, 64);
2100         }
2101
2102         if (rdata) free(rdata);
2103         if (rparam) free(rparam);
2104         return True;
2105 }
2106
2107
2108 /****************************************************************************
2109 interpret a long filename structure - this is mostly guesses at the moment
2110 The length of the structure is returned
2111 The structure of a long filename depends on the info level. 260 is used
2112 by NT and 2 is used by OS/2
2113 ****************************************************************************/
2114 static int interpret_long_filename(int level,char *p,file_info *finfo)
2115 {
2116         extern file_info def_finfo;
2117
2118         if (finfo)
2119                 memcpy(finfo,&def_finfo,sizeof(*finfo));
2120
2121         switch (level)
2122                 {
2123                 case 1: /* OS/2 understands this */
2124                         if (finfo) {
2125                                 /* these dates are converted to GMT by make_unix_date */
2126                                 finfo->ctime = make_unix_date2(p+4);
2127                                 finfo->atime = make_unix_date2(p+8);
2128                                 finfo->mtime = make_unix_date2(p+12);
2129                                 finfo->size = IVAL(p,16);
2130                                 finfo->mode = CVAL(p,24);
2131                                 pstrcpy(finfo->name,p+27);
2132                         }
2133                         return(28 + CVAL(p,26));
2134
2135                 case 2: /* this is what OS/2 uses mostly */
2136                         if (finfo) {
2137                                 /* these dates are converted to GMT by make_unix_date */
2138                                 finfo->ctime = make_unix_date2(p+4);
2139                                 finfo->atime = make_unix_date2(p+8);
2140                                 finfo->mtime = make_unix_date2(p+12);
2141                                 finfo->size = IVAL(p,16);
2142                                 finfo->mode = CVAL(p,24);
2143                                 pstrcpy(finfo->name,p+31);
2144                         }
2145                         return(32 + CVAL(p,30));
2146
2147                         /* levels 3 and 4 are untested */
2148                 case 3:
2149                         if (finfo) {
2150                                 /* these dates are probably like the other ones */
2151                                 finfo->ctime = make_unix_date2(p+8);
2152                                 finfo->atime = make_unix_date2(p+12);
2153                                 finfo->mtime = make_unix_date2(p+16);
2154                                 finfo->size = IVAL(p,20);
2155                                 finfo->mode = CVAL(p,28);
2156                                 pstrcpy(finfo->name,p+33);
2157                         }
2158                         return(SVAL(p,4)+4);
2159                         
2160                 case 4:
2161                         if (finfo) {
2162                                 /* these dates are probably like the other ones */
2163                                 finfo->ctime = make_unix_date2(p+8);
2164                                 finfo->atime = make_unix_date2(p+12);
2165                                 finfo->mtime = make_unix_date2(p+16);
2166                                 finfo->size = IVAL(p,20);
2167                                 finfo->mode = CVAL(p,28);
2168                                 pstrcpy(finfo->name,p+37);
2169                         }
2170                         return(SVAL(p,4)+4);
2171                         
2172                 case 260: /* NT uses this, but also accepts 2 */
2173                         if (finfo) {
2174                                 int ret = SVAL(p,0);
2175                                 int namelen;
2176                                 p += 4; /* next entry offset */
2177                                 p += 4; /* fileindex */
2178                                 
2179                                 /* these dates appear to arrive in a
2180                                    weird way. It seems to be localtime
2181                                    plus the serverzone given in the
2182                                    initial connect. This is GMT when
2183                                    DST is not in effect and one hour
2184                                    from GMT otherwise. Can this really
2185                                    be right??
2186
2187                                    I suppose this could be called
2188                                    kludge-GMT. Is is the GMT you get
2189                                    by using the current DST setting on
2190                                    a different localtime. It will be
2191                                    cheap to calculate, I suppose, as
2192                                    no DST tables will be needed */
2193
2194                                 finfo->ctime = interpret_long_date(p); p += 8;
2195                                 finfo->atime = interpret_long_date(p); p += 8;
2196                                 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
2197                                 finfo->size = IVAL(p,0); p += 8;
2198                                 p += 8; /* alloc size */
2199                                 finfo->mode = CVAL(p,0); p += 4;
2200                                 namelen = IVAL(p,0); p += 4;
2201                                 p += 4; /* EA size */
2202                                 p += 2; /* short name len? */
2203                                 p += 24; /* short name? */        
2204                                 StrnCpy(finfo->name,p,namelen);
2205                                 return(ret);
2206                         }
2207                         return(SVAL(p,0));
2208                 }
2209         
2210         DEBUG(1,("Unknown long filename format %d\n",level));
2211         return(SVAL(p,0));
2212 }
2213
2214
2215 /****************************************************************************
2216   do a directory listing, calling fn on each file found
2217   ****************************************************************************/
2218 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute, 
2219              void (*fn)(file_info *, const char *))
2220 {
2221         int max_matches = 512;
2222         /* NT uses 260, OS/2 uses 2. Both accept 1. */
2223         int info_level = cli->protocol<PROTOCOL_NT1?1:260; 
2224         char *p, *p2;
2225         pstring mask;
2226         file_info finfo;
2227         int i;
2228         char *dirlist = NULL;
2229         int dirlist_len = 0;
2230         int total_received = -1;
2231         BOOL First = True;
2232         int ff_resume_key = 0;
2233         int ff_searchcount=0;
2234         int ff_eos=0;
2235         int ff_lastname=0;
2236         int ff_dir_handle=0;
2237         int loop_count = 0;
2238         char *rparam=NULL, *rdata=NULL;
2239         int param_len, data_len;
2240         
2241         uint16 setup;
2242         pstring param;
2243         
2244         pstrcpy(mask,Mask);
2245         
2246         while (ff_eos == 0) {
2247                 loop_count++;
2248                 if (loop_count > 200) {
2249                         DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
2250                         break;
2251                 }
2252
2253                 param_len = 12+strlen(mask)+1;
2254
2255                 if (First) {
2256                         setup = TRANSACT2_FINDFIRST;
2257                         SSVAL(param,0,attribute); /* attribute */
2258                         SSVAL(param,2,max_matches); /* max count */
2259                         SSVAL(param,4,8+4+2);   /* resume required + close on end + continue */
2260                         SSVAL(param,6,info_level); 
2261                         SIVAL(param,8,0);
2262                         pstrcpy(param+12,mask);
2263                 } else {
2264                         setup = TRANSACT2_FINDNEXT;
2265                         SSVAL(param,0,ff_dir_handle);
2266                         SSVAL(param,2,max_matches); /* max count */
2267                         SSVAL(param,4,info_level); 
2268                         SIVAL(param,6,ff_resume_key); /* ff_resume_key */
2269                         SSVAL(param,10,8+4+2);  /* resume required + close on end + continue */
2270                         pstrcpy(param+12,mask);
2271
2272                         DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
2273                                  ff_dir_handle,ff_resume_key,ff_lastname,mask));
2274                 }
2275
2276                 if (!cli_send_trans(cli, SMBtrans2, 
2277                                     NULL, 0,                /* Name, length */
2278                                     -1, 0,                  /* fid, flags */
2279                                     &setup, 1, 0,           /* setup, length, max */
2280                                     param, param_len, 10,   /* param, length, max */
2281                                     NULL, 0, 
2282                                     cli->max_xmit /* data, length, max */
2283                                     )) {
2284                         break;
2285                 }
2286
2287                 if (!cli_receive_trans(cli, SMBtrans2, 
2288                                        &rparam, &param_len,
2289                                        &rdata, &data_len)) {
2290                         /* we need to work around a Win95 bug - sometimes
2291                            it gives ERRSRV/ERRerror temprarily */
2292                         uint8 eclass;
2293                         uint32 ecode;
2294                         cli_error(cli, &eclass, &ecode);
2295                         if (eclass != ERRSRV || ecode != ERRerror) break;
2296                         msleep(100);
2297                         continue;
2298                 }
2299
2300                 if (total_received == -1) total_received = 0;
2301
2302                 /* parse out some important return info */
2303                 p = rparam;
2304                 if (First) {
2305                         ff_dir_handle = SVAL(p,0);
2306                         ff_searchcount = SVAL(p,2);
2307                         ff_eos = SVAL(p,4);
2308                         ff_lastname = SVAL(p,8);
2309                 } else {
2310                         ff_searchcount = SVAL(p,0);
2311                         ff_eos = SVAL(p,2);
2312                         ff_lastname = SVAL(p,6);
2313                 }
2314
2315                 if (ff_searchcount == 0) 
2316                         break;
2317
2318                 /* point to the data bytes */
2319                 p = rdata;
2320
2321                 /* we might need the lastname for continuations */
2322                 if (ff_lastname > 0) {
2323                         switch(info_level)
2324                                 {
2325                                 case 260:
2326                                         ff_resume_key =0;
2327                                         StrnCpy(mask,p+ff_lastname,
2328                                                 data_len-ff_lastname);
2329                                         break;
2330                                 case 1:
2331                                         pstrcpy(mask,p + ff_lastname + 1);
2332                                         ff_resume_key = 0;
2333                                         break;
2334                                 }
2335                 } else {
2336                         pstrcpy(mask,"");
2337                 }
2338   
2339                 /* and add them to the dirlist pool */
2340                 dirlist = Realloc(dirlist,dirlist_len + data_len);
2341
2342                 if (!dirlist) {
2343                         DEBUG(0,("Failed to expand dirlist\n"));
2344                         break;
2345                 }
2346
2347                 /* put in a length for the last entry, to ensure we can chain entries 
2348                    into the next packet */
2349                 for (p2=p,i=0;i<(ff_searchcount-1);i++)
2350                         p2 += interpret_long_filename(info_level,p2,NULL);
2351                 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
2352
2353                 /* grab the data for later use */
2354                 memcpy(dirlist+dirlist_len,p,data_len);
2355                 dirlist_len += data_len;
2356
2357                 total_received += ff_searchcount;
2358
2359                 if (rdata) free(rdata); rdata = NULL;
2360                 if (rparam) free(rparam); rparam = NULL;
2361                 
2362                 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
2363                          ff_searchcount,ff_eos,ff_resume_key));
2364
2365                 First = False;
2366         }
2367
2368         for (p=dirlist,i=0;i<total_received;i++) {
2369                 p += interpret_long_filename(info_level,p,&finfo);
2370                 fn(&finfo, Mask);
2371         }
2372
2373         /* free up the dirlist buffer */
2374         if (dirlist) free(dirlist);
2375         return(total_received);
2376 }
2377
2378
2379 /****************************************************************************
2380 Send a SamOEMChangePassword command
2381 ****************************************************************************/
2382
2383 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
2384                              const char *old_password)
2385 {
2386   char param[16+sizeof(fstring)];
2387   char data[532];
2388   char *p = param;
2389   fstring upper_case_old_pw;
2390   fstring upper_case_new_pw;
2391   unsigned char old_pw_hash[16];
2392   unsigned char new_pw_hash[16];
2393   int data_len;
2394   int param_len = 0;
2395   char *rparam = NULL;
2396   char *rdata = NULL;
2397   int rprcnt, rdrcnt;
2398
2399   if (strlen(user) >= sizeof(fstring)-1) {
2400     DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
2401     return False;
2402   }
2403
2404   SSVAL(p,0,214); /* SamOEMChangePassword command. */
2405   p += 2;
2406   pstrcpy(p, "zsT");
2407   p = skip_string(p,1);
2408   pstrcpy(p, "B516B16");
2409   p = skip_string(p,1);
2410   pstrcpy(p,user);
2411   p = skip_string(p,1);
2412   SSVAL(p,0,532);
2413   p += 2;
2414
2415   param_len = PTR_DIFF(p,param);
2416
2417   /*
2418    * Get the Lanman hash of the old password, we
2419    * use this as the key to make_oem_passwd_hash().
2420    */
2421   memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
2422   fstrcpy(upper_case_old_pw, old_password);
2423   strupper(upper_case_old_pw);
2424   E_P16((uchar *)upper_case_old_pw, old_pw_hash);
2425
2426         if (!make_oem_passwd_hash( data, new_password, old_pw_hash, False))
2427         {
2428                 return False;
2429         }
2430
2431   /* 
2432    * Now place the old password hash in the data.
2433    */
2434   memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
2435   fstrcpy(upper_case_new_pw, new_password);
2436   strupper(upper_case_new_pw);
2437
2438   E_P16((uchar *)upper_case_new_pw, new_pw_hash);
2439
2440   E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
2441
2442   data_len = 532;
2443     
2444   if (!cli_send_trans(cli,SMBtrans,
2445                     PIPE_LANMAN,strlen(PIPE_LANMAN),      /* name, length */
2446                     0,0,                                  /* fid, flags */
2447                     NULL,0,0,                             /* setup, length, max */
2448                     param,param_len,2,                    /* param, length, max */
2449                     data,data_len,0                       /* data, length, max */
2450                    ))
2451   {
2452     DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
2453               user ));
2454     return False;
2455   }
2456
2457   if (cli_receive_trans(cli,SMBtrans,
2458                        &rparam, &rprcnt,
2459                        &rdata, &rdrcnt)) {
2460     if (rparam)
2461       cli->rap_error = SVAL(rparam,0);
2462   }
2463
2464   if (rparam)
2465     free(rparam);
2466   if (rdata)
2467     free(rdata);
2468
2469   return (cli->rap_error == 0);
2470 }
2471
2472 /****************************************************************************
2473 send a negprot command
2474 ****************************************************************************/
2475 BOOL cli_negprot(struct cli_state *cli)
2476 {
2477         char *p;
2478         int numprots;
2479         int plength;
2480
2481         bzero(cli->outbuf,smb_size);
2482
2483         /* setup the protocol strings */
2484         for (plength=0,numprots=0;
2485              prots[numprots].name && prots[numprots].prot<=cli->protocol;
2486              numprots++)
2487                 plength += strlen(prots[numprots].name)+2;
2488     
2489         set_message(cli->outbuf,0,plength,True);
2490
2491         p = smb_buf(cli->outbuf);
2492         for (numprots=0;
2493              prots[numprots].name && prots[numprots].prot<=cli->protocol;
2494              numprots++) {
2495                 *p++ = 2;
2496                 pstrcpy(p,prots[numprots].name);
2497                 p += strlen(p) + 1;
2498         }
2499
2500         CVAL(cli->outbuf,smb_com) = SMBnegprot;
2501         cli_setup_packet(cli);
2502
2503         CVAL(smb_buf(cli->outbuf),0) = 2;
2504
2505         cli_send_smb(cli, True);
2506         if (!cli_receive_smb(cli))
2507         {
2508                 return False;
2509         }
2510
2511         if (CVAL(cli->inbuf,smb_rcls) != 0 || 
2512             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2513                 return(False);
2514         }
2515
2516         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2517
2518
2519         if (cli->protocol >= PROTOCOL_NT1)
2520         {    
2521                 char *buf = smb_buf(cli->inbuf);
2522                 int bcc = SVAL(cli->inbuf,smb_vwv+2*(CVAL(cli->inbuf,smb_wct)));
2523                 /* NT protocol */
2524                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
2525                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
2526                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
2527                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
2528                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
2529                 /* this time arrives in real GMT */
2530                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
2531
2532                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
2533                 if (IS_BITS_SET_ALL(cli->capabilities, CAP_RAW_MODE))
2534                 {
2535                         cli->readbraw_supported = True;
2536                         cli->writebraw_supported = True;      
2537                 }
2538
2539                 if (IS_BITS_SET_ALL(cli->capabilities, CAP_EXTENDED_SECURITY))
2540                 {
2541                         /* oops, some kerberos-related nonsense. */
2542                         /* expect to have to use NTLMSSP-over-SMB */
2543                         DEBUG(10,("unknown kerberos-related (?) blob\n"));
2544                         memset(cli->cryptkey, 0, 8);
2545                         cli->server_domain[0] = 0;
2546                 }
2547                 else
2548                 {
2549                         memcpy(cli->cryptkey, buf,8);
2550                         if (bcc > 8)
2551                         {
2552                                 unibuf_to_ascii(cli->server_domain,  buf+8,
2553                                                 sizeof(cli->server_domain));
2554                         }
2555                         else
2556                         {
2557                                 cli->server_domain[0] = 0;
2558                         }
2559                         DEBUG(5,("server's domain: %s bcc: %d\n",
2560                                 cli->server_domain, bcc));
2561                 }
2562         }
2563         else if (cli->protocol >= PROTOCOL_LANMAN1)
2564         {
2565                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2566                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2567                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2568                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
2569                 /* this time is converted to GMT by make_unix_date */
2570                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2571                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2572                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2573                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2574         } else {
2575                 /* the old core protocol */
2576                 cli->sec_mode = 0;
2577                 cli->serverzone = TimeDiff(time(NULL));
2578         }
2579
2580         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2581
2582         return True;
2583 }
2584
2585
2586 /****************************************************************************
2587   send a session request.  see rfc1002.txt 4.3 and 4.3.2
2588 ****************************************************************************/
2589 BOOL cli_session_request(struct cli_state *cli,
2590                          struct nmb_name *calling, struct nmb_name *called)
2591 {
2592         char *p;
2593         int len = 4;
2594         /* send a session request (RFC 1002) */
2595
2596         memcpy(&(cli->calling), calling, sizeof(*calling));
2597         memcpy(&(cli->called ), called , sizeof(*called ));
2598   
2599         if (cli->port == 445)
2600         {
2601                 return True;
2602         }
2603
2604         /* put in the destination name */
2605         p = cli->outbuf+len;
2606         name_mangle(cli->called .name, p, cli->called .name_type);
2607         len += name_len(p);
2608
2609         /* and my name */
2610         p = cli->outbuf+len;
2611         name_mangle(cli->calling.name, p, cli->calling.name_type);
2612         len += name_len(p);
2613
2614         /* setup the packet length */
2615         _smb_setlen(cli->outbuf,len);
2616         CVAL(cli->outbuf,0) = 0x81;
2617
2618 #ifdef WITH_SSL
2619 retry:
2620 #endif /* WITH_SSL */
2621
2622         cli_send_smb(cli, True);
2623         DEBUG(5,("Sent session request\n"));
2624
2625         if (!cli_receive_smb(cli))
2626                 return False;
2627
2628 #ifdef WITH_SSL
2629     if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2630         if (!sslutil_fd_is_ssl(cli->fd)){
2631             if (sslutil_connect(cli->fd) == 0)
2632                 goto retry;
2633         }
2634     }
2635 #endif /* WITH_SSL */
2636
2637         if (CVAL(cli->inbuf,0) != 0x82) {
2638                 /* This is the wrong place to put the error... JRA. */
2639                 cli->rap_error = CVAL(cli->inbuf,0);
2640                 return False;
2641         }
2642         return(True);
2643 }
2644
2645
2646 /****************************************************************************
2647 open the client sockets
2648 ****************************************************************************/
2649 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
2650 {
2651         extern struct in_addr ipzero;
2652         int port = cli->port;
2653
2654         fstrcpy(cli->desthost, host);
2655         
2656         if (!ip || ip_equal(*ip, ipzero)) {
2657                 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
2658                         return False;
2659                 }
2660                 if (ip) *ip = cli->dest_ip;
2661         } else {
2662                 cli->dest_ip = *ip;
2663         }
2664
2665
2666         if (port == 0) port = SMB_PORT2;
2667
2668         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
2669                                   port, cli->timeout);
2670         if (cli->fd == -1)
2671         {
2672                 if (cli->port != 0)
2673                 {
2674                         return False;
2675                 }
2676                 port = SMB_PORT;
2677
2678                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
2679                                           port, cli->timeout);
2680                 if (cli->fd == -1) return False;
2681         }
2682
2683         cli->port = port;
2684
2685         return True;
2686 }
2687
2688
2689 /****************************************************************************
2690 initialise a client structure
2691 ****************************************************************************/
2692 struct cli_state *cli_initialise(struct cli_state *cli)
2693 {
2694         if (!cli) {
2695                 cli = (struct cli_state *)malloc(sizeof(*cli));
2696                 if (!cli)
2697                         return NULL;
2698                 ZERO_STRUCTP(cli);
2699         }
2700
2701         if (cli->initialised) {
2702                 cli_shutdown(cli);
2703         }
2704
2705         ZERO_STRUCTP(cli);
2706
2707         cli->port = 0;
2708         cli->fd = -1;
2709         cli->cnum = -1;
2710         cli->pid = (uint16)getpid();
2711         cli->mid = 1;
2712         cli->vuid = UID_FIELD_INVALID;
2713         cli->protocol = PROTOCOL_NT1;
2714         cli->timeout = 20000;
2715         cli->bufsize = CLI_BUFFER_SIZE+4;
2716         cli->max_xmit = cli->bufsize;
2717         cli->outbuf = (char *)malloc(cli->bufsize);
2718         cli->inbuf = (char *)malloc(cli->bufsize);
2719         if (!cli->outbuf || !cli->inbuf)
2720         {
2721                 return False;
2722         }
2723
2724         cli->initialised = 1;
2725         cli->capabilities = CAP_DFS;
2726
2727         return cli;
2728 }
2729
2730 /****************************************************************************
2731 close the socket descriptor
2732 ****************************************************************************/
2733 void cli_close_socket(struct cli_state *cli)
2734 {
2735 #ifdef WITH_SSL
2736         if (cli->fd != -1)
2737         {
2738                 sslutil_disconnect(cli->fd);
2739         }
2740 #endif /* WITH_SSL */
2741         if (cli->fd != -1) 
2742         {
2743                 close(cli->fd);
2744         }
2745         cli->fd = -1;
2746 }
2747
2748 /****************************************************************************
2749 shutdown a client structure
2750 ****************************************************************************/
2751 void cli_shutdown(struct cli_state *cli)
2752 {
2753         DEBUG(10,("cli_shutdown\n"));
2754         if (cli->outbuf)
2755         {
2756                 free(cli->outbuf);
2757         }
2758         if (cli->inbuf)
2759         {
2760                 free(cli->inbuf);
2761         }
2762         cli_close_socket(cli);
2763         memset(cli, 0, sizeof(*cli));
2764 }
2765
2766
2767 /****************************************************************************
2768   return error codes for the last packet
2769   returns 0 if there was no error and the best approx of a unix errno
2770   otherwise
2771
2772   for 32 bit "warnings", a return code of 0 is expected.
2773
2774 ****************************************************************************/
2775 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
2776 {
2777         int  flgs2;
2778         char rcls;
2779         int code;
2780
2781         if (!cli->initialised)
2782         {
2783                 DEBUG(0,("cli_error: client state uninitialised!\n"));
2784                 return EINVAL;
2785         }
2786
2787         flgs2 = SVAL(cli->inbuf,smb_flg2);
2788
2789         if (eclass) *eclass = 0;
2790         if (num   ) *num = 0;
2791
2792         if (flgs2 & FLAGS2_32_BIT_ERROR_CODES)
2793         {
2794                 /* 32 bit error codes detected */
2795                 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2796                 if (num) *num = nt_err;
2797                 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2798                 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2799
2800                 switch (nt_err & 0xFFFFFF)
2801                 {
2802                         case NT_STATUS_ACCESS_VIOLATION     : return EACCES;
2803                         case NT_STATUS_NO_SUCH_FILE         : return ENOENT;
2804                         case NT_STATUS_NO_SUCH_DEVICE       : return ENODEV;
2805                         case NT_STATUS_INVALID_HANDLE       : return EBADF;
2806                         case NT_STATUS_NO_MEMORY            : return ENOMEM;
2807                         case NT_STATUS_ACCESS_DENIED        : return EACCES;
2808                         case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2809                         case NT_STATUS_SHARING_VIOLATION    : return EBUSY;
2810                         case NT_STATUS_OBJECT_PATH_INVALID  : return ENOTDIR;
2811                         case NT_STATUS_OBJECT_NAME_COLLISION: return EEXIST;
2812                 }
2813
2814                 /* for all other cases - a default code */
2815                 return EINVAL;
2816         }
2817
2818         rcls  = CVAL(cli->inbuf,smb_rcls);
2819         code  = SVAL(cli->inbuf,smb_err);
2820         if (rcls == 0) return 0;
2821
2822         if (eclass) *eclass = rcls;
2823         if (num   ) *num    = code;
2824
2825         if (rcls == ERRDOS) {
2826                 switch (code) {
2827                 case ERRbadfile: return ENOENT;
2828                 case ERRbadpath: return ENOTDIR;
2829                 case ERRnoaccess: return EACCES;
2830                 case ERRfilexists: return EEXIST;
2831                 case ERRrename: return EEXIST;
2832                 case ERRbadshare: return EBUSY;
2833                 case ERRlock: return EBUSY;
2834                 case ERRmoredata: return 0; /* Informational only */
2835                 }
2836         }
2837         if (rcls == ERRSRV) {
2838                 switch (code) {
2839                 case ERRbadpw: return EPERM;
2840                 case ERRaccess: return EACCES;
2841                 case ERRnoresource: return ENOMEM;
2842                 case ERRinvdevice: return ENODEV;
2843                 case ERRinvnetname: return ENODEV;
2844                 }
2845         }
2846         /* for other cases */
2847         return EINVAL;
2848 }
2849
2850 /****************************************************************************
2851 set socket options on a open connection
2852 ****************************************************************************/
2853 void cli_sockopt(struct cli_state *cli, char *options)
2854 {
2855         set_socket_options(cli->fd, options);
2856 }
2857
2858 /****************************************************************************
2859 set the PID to use for smb messages. Return the old pid.
2860 ****************************************************************************/
2861 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2862 {
2863         uint16 ret = cli->pid;
2864         cli->pid = pid;
2865         return ret;
2866 }
2867
2868 /****************************************************************************
2869 re-establishes a connection
2870 ****************************************************************************/
2871 BOOL cli_reestablish_connection(struct cli_state *cli)
2872 {
2873         struct nmb_name calling;
2874         struct nmb_name called;
2875         fstring dest_host;
2876         fstring share;
2877         fstring dev;
2878         BOOL do_tcon = False;
2879         int oldfd = cli->fd;
2880
2881         if (!cli->initialised || cli->fd == -1)
2882         {
2883                 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2884                 return False;
2885         }
2886
2887         /* copy the parameters necessary to re-establish the connection */
2888
2889         if (cli->cnum != 0)
2890         {
2891                 do_tcon = True;
2892         }
2893
2894         if (do_tcon)
2895         {
2896                 fstrcpy(share, cli->share);
2897                 fstrcpy(dev  , cli->dev);
2898         }
2899
2900         memcpy(&called , &(cli->called ), sizeof(called ));
2901         memcpy(&calling, &(cli->calling), sizeof(calling));
2902         fstrcpy(dest_host, cli->desthost);
2903
2904         DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2905                  nmb_namestr(&calling), nmb_namestr(&called), 
2906                  inet_ntoa(cli->dest_ip),
2907                  cli->user_name, cli->domain));
2908
2909         cli->fd = -1;
2910
2911         if (cli_establish_connection(cli,
2912                                      dest_host, &cli->dest_ip,
2913                                      &calling, &called,
2914                                      share, dev, False, do_tcon))
2915         {
2916                 if (cli->fd != oldfd)
2917                 {
2918                         if (dup2(cli->fd, oldfd) == oldfd)
2919                         {
2920                                 cli_close_socket(cli);
2921                         }
2922                 }
2923                 return True;
2924         }
2925         return False;
2926 }
2927
2928 /****************************************************************************
2929 establishes a connection right up to doing tconX, reading in a password.
2930 ****************************************************************************/
2931 BOOL cli_establish_connection(struct cli_state *cli, 
2932                                 char *dest_host, struct in_addr *dest_ip,
2933                                 struct nmb_name *calling, struct nmb_name *called,
2934                                 char *service, char *service_type,
2935                                 BOOL do_shutdown, BOOL do_tcon)
2936 {
2937         fstring callingstr;
2938         fstring calledstr;
2939
2940         nmb_safe_namestr(calling, callingstr, sizeof(callingstr));
2941         nmb_safe_namestr(called , calledstr , sizeof(calledstr ));
2942
2943         DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s] with NTLM%s\n",
2944                           callingstr, calledstr, inet_ntoa(*dest_ip),
2945                       cli->user_name, cli->domain,
2946                         cli->use_ntlmv2 ? "v2" : "v1"));
2947
2948         /* establish connection */
2949
2950         if ((!cli->initialised))
2951         {
2952                 return False;
2953         }
2954
2955         if (cli->fd == -1)
2956         {
2957                 if (!cli_connect(cli, dest_host, dest_ip))
2958                 {
2959                         DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2960                                           callingstr, inet_ntoa(*dest_ip)));
2961                         return False;
2962                 }
2963         }
2964
2965         if (!cli_session_request(cli, calling, called))
2966         {
2967                 DEBUG(1,("failed session request\n"));
2968                 if (do_shutdown)
2969                 {
2970                         cli_shutdown(cli);
2971                 }
2972                 return False;
2973         }
2974
2975         if (!cli_negprot(cli))
2976         {
2977                 DEBUG(1,("failed negprot\n"));
2978                 if (do_shutdown)
2979                 {
2980                         cli_shutdown(cli);
2981                 }
2982                 return False;
2983         }
2984
2985         if (cli->domain[0] == 0)
2986         {
2987                 safe_strcpy(cli->domain, cli->server_domain,
2988                             sizeof(cli->domain));
2989         }
2990
2991         if (IS_BITS_SET_ALL(cli->capabilities, CAP_EXTENDED_SECURITY))
2992         {
2993                 /* common to both session setups */
2994                 char pwd_buf[128];
2995                 int buf_len;
2996                 char *p;
2997                 char *e = pwd_buf + sizeof(pwd_buf);
2998
2999                 /* 1st session setup */
3000                 char pwd_data[34] =
3001                 {
3002                         0x60, 0x40, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05,
3003                         0x05, 0x02, 0xa0, 0x36, 0x30, 0x34, 0xa0, 0x0e,
3004                         0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
3005                         0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa2, 0x22,
3006                         0x04, 0x20
3007                 };
3008                 /* 2nd session setup */
3009 #if 0
3010                 char pwd_data_2[8] =
3011                 {
3012                         0xa1, 0x51, 0x30, 0x4f, 0xa2, 0x4d, 0x04, 0x4b
3013                 };
3014 #endif
3015                 char pwd_data_2[8] =
3016                 {
3017                         0xa1, 0x51, 0x30, 0x4f, 0xa2, 0x4d, 0x04, 0x4b
3018                 };
3019                 prs_struct auth_resp;
3020                 int resp_len;
3021                 char *p_gssapi;
3022                 char *p_oem;
3023                 char *p_gssapi_end;
3024                 uint16 gssapi_len;
3025
3026                 memset(pwd_buf, 0, sizeof(pwd_buf));
3027                 memcpy(pwd_buf, pwd_data, sizeof(pwd_data));
3028                 p = pwd_buf + sizeof(pwd_data);
3029
3030                 safe_strcpy(p, "NTLMSSP", PTR_DIFF(e, p) - 1);
3031                 p = skip_string(p, 1);
3032                 CVAL(p, 0) = 0x1;
3033                 p += 4;
3034                 if (cli->ntlmssp_cli_flgs == 0)
3035                 {
3036                         cli->ntlmssp_cli_flgs =
3037                                 NTLMSSP_NEGOTIATE_UNICODE |
3038                                 NTLMSSP_NEGOTIATE_OEM |
3039                                 NTLMSSP_NEGOTIATE_SIGN |
3040                                 NTLMSSP_NEGOTIATE_SEAL |
3041                                 NTLMSSP_NEGOTIATE_LM_KEY |
3042                                 NTLMSSP_NEGOTIATE_NTLM |
3043                                 NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
3044                                 NTLMSSP_NEGOTIATE_00001000 |
3045                                 NTLMSSP_NEGOTIATE_00002000;
3046 #if 0
3047                         cli->ntlmssp_cli_flgs = 0x80008207;
3048 #endif
3049                 }
3050                 SIVAL(p, 0, cli->ntlmssp_cli_flgs);
3051                 p += 4;
3052                 p += 16; /* skip some NULL space */
3053                 CVAL(p, 0) = 0; p++; /* alignment */
3054
3055                 buf_len = PTR_DIFF(p, pwd_buf);
3056
3057                 /* first session negotiation stage */
3058                 if (!cli_session_setup_x(cli, cli->user_name,
3059                                pwd_buf, buf_len,
3060                                NULL, 0,
3061                                cli->domain))
3062                 {
3063                         DEBUG(1,("failed session setup\n"));
3064                         if (do_shutdown)
3065                         {
3066                                 cli_shutdown(cli);
3067                         }
3068                         return False;
3069                 }
3070
3071                 DEBUG(1,("1st session setup ok\n"));
3072
3073                 if (*cli->server_domain || *cli->server_os || *cli->server_type)
3074                 {
3075                         DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
3076                              cli->server_domain,
3077                              cli->server_os,
3078                              cli->server_type));
3079                 }
3080         
3081                 p = smb_buf(cli->inbuf) + 0x2f;
3082                 cli->ntlmssp_cli_flgs = IVAL(p, 0); /* 0x80808a05; */
3083                 p += 4;
3084                 memcpy(cli->cryptkey, p, 8);
3085 #ifdef DEBUG_PASSWORD
3086                 DEBUG(100,("cli_session_setup_x: ntlmssp %8x\n",
3087                             cli->ntlmssp_cli_flgs));
3088                            
3089                 DEBUG(100,("cli_session_setup_x: crypt key\n"));
3090                 dump_data(100, cli->cryptkey, 8);
3091 #endif
3092                 prs_init(&auth_resp, 1024, 4, SAFETY_MARGIN, False);
3093
3094                 pwd_make_lm_nt_owf(&cli->pwd, cli->cryptkey);
3095
3096                 create_ntlmssp_resp(&cli->pwd, cli->domain,
3097                                      cli->user_name, cli->calling.name,
3098                                      cli->ntlmssp_cli_flgs,
3099                                      &auth_resp);
3100                 prs_link(NULL, &auth_resp, NULL);
3101
3102                 memset(pwd_buf, 0, sizeof(pwd_buf));
3103                 p = pwd_buf;
3104
3105                 CVAL(p, 0) = 0xa1; p++;
3106                 CVAL(p, 0) = 0x82; p++;
3107                 p_gssapi = p; p+= 2;
3108                 CVAL(p, 0) = 0x30; p++;
3109                 CVAL(p, 0) = 0x82; p++;
3110                 p += 2;
3111                 
3112                 CVAL(p, 0) = 0xa2; p++;
3113                 CVAL(p, 0) = 0x82; p++;
3114                 p_oem = p; p+= 2;
3115                 CVAL(p, 0) = 0x04; p++;
3116                 CVAL(p, 0) = 0x82; p++;
3117                 p += 2;
3118
3119                 p_gssapi_end = p;
3120                 
3121                 safe_strcpy(p, "NTLMSSP", PTR_DIFF(e, p) - 1);
3122                 p = skip_string(p, 1);
3123                 CVAL(p, 0) = 0x3;
3124                 p += 4;
3125
3126                 resp_len = mem_buf_len(auth_resp.data);
3127                 mem_buf_copy(p, auth_resp.data, 0, resp_len);
3128                 prs_mem_free(&auth_resp);
3129
3130                 p += resp_len;
3131
3132                 buf_len = PTR_DIFF(p, pwd_buf);
3133                 gssapi_len = PTR_DIFF(p, p_gssapi_end) + 12;
3134
3135                 *p_gssapi++ = (gssapi_len >> 8) & 0xff;
3136                 *p_gssapi++ = gssapi_len & 0xff;
3137
3138                 p_gssapi += 2;
3139                 gssapi_len -= 4;
3140
3141                 *p_gssapi++ = (gssapi_len >> 8) & 0xff;
3142                 *p_gssapi++ = gssapi_len & 0xff;
3143
3144                 gssapi_len -= 4;
3145
3146                 *p_oem++ = (gssapi_len >> 8) & 0xff;
3147                 *p_oem++ = gssapi_len & 0xff;
3148
3149                 p_oem += 2;
3150                 gssapi_len -= 4;
3151
3152                 *p_oem++ = (gssapi_len >> 8) & 0xff;
3153                 *p_oem++ = gssapi_len & 0xff;
3154
3155                 /* second session negotiation stage */
3156                 if (!cli_session_setup_x(cli, cli->user_name,
3157                                pwd_buf, buf_len,
3158                                NULL, 0,
3159                                cli->domain))
3160                 {
3161                         DEBUG(1,("failed session setup\n"));
3162                         if (do_shutdown)
3163                         {
3164                                 cli_shutdown(cli);
3165                         }
3166                         return False;
3167                 }
3168
3169                 DEBUG(1,("2nd session setup ok\n"));
3170
3171                 if (do_tcon)
3172                 {
3173                         if (!cli_send_tconX(cli, service, service_type,
3174                                             NULL, 0))
3175                                             
3176                         {
3177                                 DEBUG(1,("failed tcon_X\n"));
3178                                 if (do_shutdown)
3179                                 {
3180                                         cli_shutdown(cli);
3181                                 }
3182                                 return False;
3183                         }
3184                 }
3185         }
3186         else if (cli->pwd.cleartext || cli->pwd.null_pwd)
3187         {
3188                 fstring passwd, ntpasswd;
3189                 int pass_len = 0, ntpass_len = 0;
3190
3191                 if (cli->pwd.null_pwd)
3192                 {
3193                         /* attempt null session */
3194                         passwd[0] = ntpasswd[0] = 0;
3195                         pass_len = ntpass_len = 1;
3196                 }
3197                 else
3198                 {
3199                         /* attempt clear-text session */
3200                         pwd_get_cleartext(&(cli->pwd), passwd);
3201                         pass_len = strlen(passwd);
3202                 }
3203
3204                 /* attempt clear-text session */
3205                 if (!cli_session_setup(cli, cli->user_name,
3206                                passwd, pass_len,
3207                                ntpasswd, ntpass_len,
3208                                cli->domain))
3209                 {
3210                         DEBUG(1,("failed session setup\n"));
3211                         if (do_shutdown)
3212                         {
3213                                 cli_shutdown(cli);
3214                         }
3215                         return False;
3216                 }
3217                 if (do_tcon)
3218                 {
3219                         if (!cli_send_tconX(cli, service, service_type,
3220                                             (char*)passwd, strlen(passwd)))
3221                         {
3222                                 DEBUG(1,("failed tcon_X\n"));
3223                                 if (do_shutdown)
3224                                 {
3225                                         cli_shutdown(cli);
3226                                 }
3227                                 return False;
3228                         }
3229                 }
3230         }
3231         else
3232         {
3233                 /* attempt encrypted session */
3234                 unsigned char lm_sess_pwd[24];
3235                 unsigned char nt_sess_pwd[128];
3236                 size_t nt_sess_pwd_len;
3237
3238                 if (cli->use_ntlmv2 != False)
3239                 {
3240                         DEBUG(10,("cli_establish_connection: NTLMv2\n"));
3241                         pwd_make_lm_nt_owf2(&(cli->pwd), cli->cryptkey,
3242                                    cli->user_name, calling->name, cli->domain);
3243                 }
3244                 else
3245                 {
3246                         DEBUG(10,("cli_establish_connection: NTLMv1\n"));
3247                         pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
3248                 }
3249
3250                 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd,
3251                                   &nt_sess_pwd_len);
3252
3253                 /* attempt encrypted session */
3254                 if (!cli_session_setup_x(cli, cli->user_name,
3255                                        (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
3256                                        (char*)nt_sess_pwd, nt_sess_pwd_len,
3257                                        cli->domain))
3258                 {
3259                         DEBUG(1,("failed session setup\n"));
3260
3261                         if (cli->use_ntlmv2 == Auto)
3262                         {
3263                                 DEBUG(10,("NTLMv2 failed.  Using NTLMv1\n"));
3264                                 cli->use_ntlmv2 = False;
3265                                 if (do_tcon)
3266                                 {
3267                                         fstrcpy(cli->share, service);
3268                                         fstrcpy(cli->dev, service_type);
3269                                 }
3270                                 fstrcpy(cli->desthost, dest_host);
3271                                 cli_close_socket(cli);
3272                                 return cli_establish_connection(cli, 
3273                                         dest_host, dest_ip,
3274                                         calling, called,
3275                                         service, service_type,
3276                                         do_shutdown, do_tcon);
3277                         }
3278                         
3279                         if (do_shutdown)
3280                         {
3281                                 cli_shutdown(cli);
3282                         }
3283                         return False;
3284                 }
3285
3286                 DEBUG(1,("session setup ok\n"));
3287
3288                 if (*cli->server_domain || *cli->server_os || *cli->server_type)
3289                 {
3290                         DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
3291                              cli->server_domain,
3292                              cli->server_os,
3293                              cli->server_type));
3294                 }
3295         
3296                 if (do_tcon)
3297                 {
3298                         if (!cli_send_tconX(cli, service, service_type,
3299                                             (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
3300                         {
3301                                 DEBUG(1,("failed tcon_X\n"));
3302                                 if (do_shutdown)
3303                                 {
3304                                         cli_shutdown(cli);
3305                                 }
3306                                 return False;
3307                         }
3308                 }
3309         }
3310
3311         if (do_shutdown)
3312         {
3313                 cli_shutdown(cli);
3314         }
3315
3316         return True;
3317 }
3318
3319 /****************************************************************************
3320  connect to one of multiple servers: don't care which
3321 ****************************************************************************/
3322 BOOL cli_connect_serverlist(struct cli_state *cli, char *p)
3323 {
3324         extern pstring global_myname;
3325         extern pstring scope;
3326         fstring remote_machine;
3327         struct in_addr dest_ip;
3328         struct nmb_name calling, called, stupid_smbserver_called;
3329         BOOL connected_ok = False;
3330
3331         /*
3332         * Treat each name in the 'password server =' line as a potential
3333         * PDC/BDC. Contact each in turn and try and authenticate.
3334         */
3335
3336         while(p && next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine)))
3337         {
3338                 ZERO_STRUCTP(cli);
3339
3340                 if (!cli_initialise(cli))
3341                 {
3342                         DEBUG(0,("cli_connect_serverlist: unable to initialize client connection.\n"));
3343                         return False;
3344                 }
3345
3346                 standard_sub_basic(remote_machine);
3347                 strupper(remote_machine);
3348
3349                 if (!resolve_name( remote_machine, &dest_ip, 0x20))
3350                 {
3351                         DEBUG(1,("cli_connect_serverlist: Can't resolve address for %s\n", remote_machine));
3352                         continue;
3353                 }   
3354
3355                 if ((lp_security() != SEC_USER) && (ismyip(dest_ip)))
3356                 {
3357                         DEBUG(1,("cli_connect_serverlist: Password server loop - not using password server %s\n", remote_machine));
3358                         continue;
3359                 }
3360
3361                 make_nmb_name(&calling, global_myname , 0x0 , scope);
3362                 make_nmb_name(&called , remote_machine, 0x20, scope);
3363                 /* stupid microsoft destruction of the ability of netbios
3364                  * to provide multiple netbios servers on one host.
3365                  */
3366                 make_nmb_name(&stupid_smbserver_called , "*SMBSERVER", 0x20, scope);
3367
3368                 pwd_set_nullpwd(&cli->pwd);
3369
3370                 if (!cli_establish_connection(cli, remote_machine, &dest_ip,
3371                                               &calling, &called,
3372                                               "IPC$", "IPC", 
3373                                               False, True) &&
3374                     !cli_establish_connection(cli, remote_machine, &dest_ip,
3375                                               &calling, &stupid_smbserver_called,
3376                                               "IPC$", "IPC", 
3377                                               False, True))
3378                 {
3379                         cli_shutdown(cli);
3380                         continue;
3381                 }      
3382
3383                 if (cli->protocol < PROTOCOL_LANMAN2 ||
3384                     !IS_BITS_SET_ALL(cli->sec_mode, 1))
3385                 {
3386                         DEBUG(1,("cli_connect_serverlist: machine %s isn't in user level security mode\n",
3387                                   remote_machine));
3388                         cli_shutdown(cli);
3389                         continue;
3390                 }
3391
3392                 /*
3393                  * We have an anonymous connection to IPC$.
3394                  */
3395
3396                 connected_ok = True;
3397                 break;
3398         }
3399
3400         if (!connected_ok)
3401         {
3402                 DEBUG(0,("cli_connect_serverlist: Domain password server not available.\n"));
3403                 cli_shutdown(cli);
3404         }
3405
3406         return connected_ok;
3407 }
3408
3409 /****************************************************************************
3410   cancel a print job
3411   ****************************************************************************/
3412 int cli_printjob_del(struct cli_state *cli, int job)
3413 {
3414         char *rparam = NULL;
3415         char *rdata = NULL;
3416         char *p;
3417         int rdrcnt,rprcnt, ret = -1;
3418         pstring param;
3419
3420         bzero(param,sizeof(param));
3421
3422         p = param;
3423         SSVAL(p,0,81);          /* DosPrintJobDel() */
3424         p += 2;
3425         pstrcpy(p,"W");
3426         p = skip_string(p,1);
3427         pstrcpy(p,"");
3428         p = skip_string(p,1);
3429         SSVAL(p,0,job);     
3430         p += 2;
3431         
3432         if (cli_api(cli, 
3433                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
3434                     NULL, 0, CLI_BUFFER_SIZE,            /* data, length, maxlen */
3435                     &rparam, &rprcnt,                /* return params, length */
3436                     &rdata, &rdrcnt)) {               /* return data, length */
3437                 ret = SVAL(rparam,0);
3438         }
3439
3440         if (rparam) free(rparam);
3441         if (rdata) free(rdata);
3442
3443         return ret;
3444 }
3445
3446
3447 /****************************************************************************
3448 call fn() on each entry in a print queue
3449 ****************************************************************************/
3450 int cli_print_queue(struct cli_state *cli, 
3451                     void (*fn)(struct print_job_info *))
3452 {
3453         char *rparam = NULL;
3454         char *rdata = NULL;
3455         char *p;
3456         int rdrcnt, rprcnt;
3457         pstring param;
3458         int result_code=0;
3459         int i = -1;
3460         
3461         bzero(param,sizeof(param));
3462
3463         p = param;
3464         SSVAL(p,0,76);         /* API function number 76 (DosPrintJobEnum) */
3465         p += 2;
3466         pstrcpy(p,"zWrLeh");   /* parameter description? */
3467         p = skip_string(p,1);
3468         pstrcpy(p,"WWzWWDDzz");  /* returned data format */
3469         p = skip_string(p,1);
3470         pstrcpy(p,cli->share);    /* name of queue */
3471         p = skip_string(p,1);
3472         SSVAL(p,0,2);   /* API function level 2, PRJINFO_2 data structure */
3473         SSVAL(p,2,1000); /* size of bytes of returned data buffer */
3474         p += 4;
3475         pstrcpy(p,"");   /* subformat */
3476         p = skip_string(p,1);
3477
3478         DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
3479
3480         if (cli_api(cli, 
3481                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
3482                     NULL, 0, CLI_BUFFER_SIZE,            /* data, length, maxlen */
3483                     &rparam, &rprcnt,                /* return params, length */
3484                     &rdata, &rdrcnt)) {               /* return data, length */
3485                 int converter;
3486                 result_code = SVAL(rparam,0);
3487                 converter = SVAL(rparam,2);       /* conversion factor */
3488
3489                 if (result_code == 0) {
3490                         struct print_job_info job;
3491                         
3492                         p = rdata; 
3493
3494                         for (i = 0; i < SVAL(rparam,4); ++i) {
3495                                 job.id = SVAL(p,0);
3496                                 job.priority = SVAL(p,2);
3497                                 fstrcpy(job.user,
3498                                         fix_char_ptr(SVAL(p,4), converter, 
3499                                                      rdata, rdrcnt));
3500                                 job.t = make_unix_date3(p + 12);
3501                                 job.size = IVAL(p,16);
3502                                 fstrcpy(job.name,fix_char_ptr(SVAL(p,24), 
3503                                                               converter, 
3504                                                               rdata, rdrcnt));
3505                                 fn(&job);                               
3506                                 p += 28;
3507                         }
3508                 }
3509         }
3510
3511         /* If any parameters or data were returned, free the storage. */
3512         if(rparam) free(rparam);
3513         if(rdata) free(rdata);
3514
3515         return i;
3516 }
3517
3518 /****************************************************************************
3519 check for existance of a dir
3520 ****************************************************************************/
3521 BOOL cli_chkpath(struct cli_state *cli, char *path)
3522 {
3523         fstring path2;
3524         char *p;
3525         
3526         fstrcpy(path2,path);
3527         trim_string(path2,NULL,"\\");
3528         if (!*path2) *path2 = '\\';
3529         
3530         bzero(cli->outbuf,smb_size);
3531         set_message(cli->outbuf,0,4 + strlen(path2),True);
3532         SCVAL(cli->outbuf,smb_com,SMBchkpth);
3533         SSVAL(cli->outbuf,smb_tid,cli->cnum);
3534         cli_setup_packet(cli);
3535         
3536         p = smb_buf(cli->outbuf);
3537         *p++ = 4;
3538         fstrcpy(p,path2);
3539
3540         cli_send_smb(cli, True);
3541         if (!cli_receive_smb(cli)) {
3542                 return False;
3543         }
3544
3545         if (cli_error(cli, NULL, NULL)) return False;
3546
3547         return True;
3548 }
3549
3550
3551 /****************************************************************************
3552 start a message sequence
3553 ****************************************************************************/
3554 BOOL cli_message_start(struct cli_state *cli, char *host, char *username, 
3555                               int *grp)
3556 {
3557         char *p;
3558
3559         /* send a SMBsendstrt command */
3560         bzero(cli->outbuf,smb_size);
3561         set_message(cli->outbuf,0,0,True);
3562         CVAL(cli->outbuf,smb_com) = SMBsendstrt;
3563         SSVAL(cli->outbuf,smb_tid,cli->cnum);
3564         cli_setup_packet(cli);
3565         
3566         p = smb_buf(cli->outbuf);
3567         *p++ = 4;
3568         pstrcpy(p,username);
3569         p = skip_string(p,1);
3570         *p++ = 4;
3571         pstrcpy(p,host);
3572         p = skip_string(p,1);
3573         
3574         set_message(cli->outbuf,0,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
3575         
3576         cli_send_smb(cli, True);        
3577         
3578         if (!cli_receive_smb(cli)) {
3579                 return False;
3580         }
3581
3582         if (cli_error(cli, NULL, NULL)) return False;
3583
3584         *grp = SVAL(cli->inbuf,smb_vwv0);
3585
3586         return True;
3587 }
3588
3589
3590 /****************************************************************************
3591 send a message 
3592 ****************************************************************************/
3593 BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
3594 {
3595         char *p;
3596
3597         bzero(cli->outbuf,smb_size);
3598         set_message(cli->outbuf,1,len+3,True);
3599         CVAL(cli->outbuf,smb_com) = SMBsendtxt;
3600         SSVAL(cli->outbuf,smb_tid,cli->cnum);
3601         cli_setup_packet(cli);
3602
3603         SSVAL(cli->outbuf,smb_vwv0,grp);
3604         
3605         p = smb_buf(cli->outbuf);
3606         *p = 1;
3607         SSVAL(p,1,len);
3608         memcpy(p+3,msg,len);
3609         cli_send_smb(cli, True);
3610
3611         if (!cli_receive_smb(cli)) {
3612                 return False;
3613         }
3614
3615         if (cli_error(cli, NULL, NULL)) return False;
3616
3617         return True;
3618 }      
3619
3620 /****************************************************************************
3621 end a message 
3622 ****************************************************************************/
3623 BOOL cli_message_end(struct cli_state *cli, int grp)
3624 {
3625         bzero(cli->outbuf,smb_size);
3626         set_message(cli->outbuf,1,0,True);
3627         CVAL(cli->outbuf,smb_com) = SMBsendend;
3628         SSVAL(cli->outbuf,smb_tid,cli->cnum);
3629
3630         SSVAL(cli->outbuf,smb_vwv0,grp);
3631
3632         cli_setup_packet(cli);
3633         
3634         cli_send_smb(cli, True);
3635
3636         if (!cli_receive_smb(cli)) {
3637                 return False;
3638         }
3639
3640         if (cli_error(cli, NULL, NULL)) return False;
3641
3642         return True;
3643 }      
3644
3645
3646 /****************************************************************************
3647 query disk space
3648 ****************************************************************************/
3649 BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3650 {
3651         bzero(cli->outbuf,smb_size);
3652         set_message(cli->outbuf,0,0,True);
3653         CVAL(cli->outbuf,smb_com) = SMBdskattr;
3654         SSVAL(cli->outbuf,smb_tid,cli->cnum);
3655         cli_setup_packet(cli);
3656
3657         cli_send_smb(cli, True);
3658         if (!cli_receive_smb(cli)) {
3659                 return False;
3660         }
3661
3662         *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
3663         *total = SVAL(cli->inbuf,smb_vwv0);
3664         *avail = SVAL(cli->inbuf,smb_vwv3);
3665         
3666         return True;
3667 }