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