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