s3:libsmb: don't reuse the callers stype variable in cli_NetServerEnum()
[ira/wip.git] / source3 / libsmb / clirap.c
1 /*
2    Unix SMB/CIFS implementation.
3    client RAP calls
4    Copyright (C) Andrew Tridgell         1994-1998
5    Copyright (C) Gerald (Jerry) Carter   2004
6    Copyright (C) James Peach             2007
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "../libcli/auth/libcli_auth.h"
24
25 /****************************************************************************
26  Call a remote api
27 ****************************************************************************/
28
29 bool cli_api(struct cli_state *cli,
30              char *param, int prcnt, int mprcnt,
31              char *data, int drcnt, int mdrcnt,
32              char **rparam, unsigned int *rprcnt,
33              char **rdata, unsigned int *rdrcnt)
34 {
35         cli_send_trans(cli,SMBtrans,
36                  PIPE_LANMAN,             /* Name */
37                  0,0,                     /* fid, flags */
38                  NULL,0,0,                /* Setup, length, max */
39                  param, prcnt, mprcnt,    /* Params, length, max */
40                  data, drcnt, mdrcnt      /* Data, length, max */
41                 );
42
43         return (cli_receive_trans(cli,SMBtrans,
44                             rparam, rprcnt,
45                             rdata, rdrcnt));
46 }
47
48 /****************************************************************************
49  Perform a NetWkstaUserLogon.
50 ****************************************************************************/
51
52 bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
53 {
54         char *rparam = NULL;
55         char *rdata = NULL;
56         char *p;
57         unsigned int rdrcnt,rprcnt;
58         char param[1024];
59
60         memset(param, 0, sizeof(param));
61
62         /* send a SMBtrans command with api NetWkstaUserLogon */
63         p = param;
64         SSVAL(p,0,132); /* api number */
65         p += 2;
66         strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
67         p = skip_string(param,sizeof(param),p);
68         strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
69         p = skip_string(param,sizeof(param),p);
70         SSVAL(p,0,1);
71         p += 2;
72         strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
73         strupper_m(p);
74         p += 21;
75         p++;
76         p += 15;
77         p++;
78         strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
79         strupper_m(p);
80         p += 16;
81         SSVAL(p, 0, CLI_BUFFER_SIZE);
82         p += 2;
83         SSVAL(p, 0, CLI_BUFFER_SIZE);
84         p += 2;
85
86         if (cli_api(cli,
87                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
88                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
89                     &rparam, &rprcnt,               /* return params, return size */
90                     &rdata, &rdrcnt                 /* return data, return size */
91                    )) {
92                 cli->rap_error = rparam? SVAL(rparam,0) : -1;
93                 p = rdata;
94
95                 if (cli->rap_error == 0) {
96                         DEBUG(4,("NetWkstaUserLogon success\n"));
97                         cli->privileges = SVAL(p, 24);
98                         /* The cli->eff_name field used to be set here
99                            but it wasn't used anywhere else. */
100                 } else {
101                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
102                 }
103         }
104
105         SAFE_FREE(rparam);
106         SAFE_FREE(rdata);
107         return (cli->rap_error == 0);
108 }
109
110 /****************************************************************************
111  Call a NetShareEnum - try and browse available connections on a host.
112 ****************************************************************************/
113
114 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
115 {
116         char *rparam = NULL;
117         char *rdata = NULL;
118         char *p;
119         unsigned int rdrcnt,rprcnt;
120         char param[1024];
121         int count = -1;
122
123         /* now send a SMBtrans command with api RNetShareEnum */
124         p = param;
125         SSVAL(p,0,0); /* api number */
126         p += 2;
127         strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
128         p = skip_string(param,sizeof(param),p);
129         strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
130         p = skip_string(param,sizeof(param),p);
131         SSVAL(p,0,1);
132         /*
133          * Win2k needs a *smaller* buffer than 0xFFFF here -
134          * it returns "out of server memory" with 0xFFFF !!! JRA.
135          */
136         SSVAL(p,2,0xFFE0);
137         p += 4;
138
139         if (cli_api(cli,
140                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
141                     NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
142                     &rparam, &rprcnt,                /* return params, length */
143                     &rdata, &rdrcnt))                /* return data, length */
144                 {
145                         int res = rparam? SVAL(rparam,0) : -1;
146
147                         if (res == 0 || res == ERRmoredata) {
148                                 int converter=SVAL(rparam,2);
149                                 int i;
150                                 char *rdata_end = rdata + rdrcnt;
151
152                                 count=SVAL(rparam,4);
153                                 p = rdata;
154
155                                 for (i=0;i<count;i++,p+=20) {
156                                         char *sname;
157                                         int type;
158                                         int comment_offset;
159                                         const char *cmnt;
160                                         const char *p1;
161                                         char *s1, *s2;
162                                         size_t len;
163                                         TALLOC_CTX *frame = talloc_stackframe();
164
165                                         if (p + 20 > rdata_end) {
166                                                 TALLOC_FREE(frame);
167                                                 break;
168                                         }
169
170                                         sname = p;
171                                         type = SVAL(p,14);
172                                         comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
173                                         if (comment_offset < 0 ||
174                                                         comment_offset > (int)rdrcnt) {
175                                                 TALLOC_FREE(frame);
176                                                 break;
177                                         }
178                                         cmnt = comment_offset?(rdata+comment_offset):"";
179
180                                         /* Work out the comment length. */
181                                         for (p1 = cmnt, len = 0; *p1 &&
182                                                         p1 < rdata_end; len++)
183                                                 p1++;
184                                         if (!*p1) {
185                                                 len++;
186                                         }
187                                         pull_string_talloc(frame,rdata,0,
188                                                 &s1,sname,14,STR_ASCII);
189                                         pull_string_talloc(frame,rdata,0,
190                                                 &s2,cmnt,len,STR_ASCII);
191                                         if (!s1 || !s2) {
192                                                 TALLOC_FREE(frame);
193                                                 continue;
194                                         }
195
196                                         fn(s1, type, s2, state);
197
198                                         TALLOC_FREE(frame);
199                                 }
200                         } else {
201                                 DEBUG(4,("NetShareEnum res=%d\n", res));
202                         }
203                 } else {
204                         DEBUG(4,("NetShareEnum failed\n"));
205                 }
206
207         SAFE_FREE(rparam);
208         SAFE_FREE(rdata);
209
210         return count;
211 }
212
213 /****************************************************************************
214  Call a NetServerEnum for the specified workgroup and servertype mask.  This
215  function then calls the specified callback function for each name returned.
216
217  The callback function takes 4 arguments: the machine name, the server type,
218  the comment and a state pointer.
219 ****************************************************************************/
220
221 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
222                        void (*fn)(const char *, uint32, const char *, void *),
223                        void *state)
224 {
225         char *rparam = NULL;
226         char *rdata = NULL;
227         char *rdata_end = NULL;
228         unsigned int rdrcnt,rprcnt;
229         char *p;
230         char param[1024];
231         int uLevel = 1;
232         size_t len;
233         uint32 func = RAP_NetServerEnum2;
234         char *last_entry = NULL;
235         int total_cnt = 0;
236         int return_cnt = 0;
237         int res;
238
239         errno = 0; /* reset */
240
241         /*
242          * This may take more than one transaction, so we should loop until
243          * we no longer get a more data to process or we have all of the
244          * items.
245          */
246         do {
247                 /* send a SMBtrans command with api NetServerEnum */
248                 p = param;
249                 SIVAL(p,0,func); /* api number */
250                 p += 2;
251                 /* Next time through we need to use the continue api */
252                 func = RAP_NetServerEnum3;
253
254                 if (last_entry) {
255                         strlcpy(p,"WrLehDOz", sizeof(param)-PTR_DIFF(p,param));
256                 } else {
257                         strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
258                 }
259
260                 p = skip_string(param, sizeof(param), p);
261                 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
262
263                 p = skip_string(param, sizeof(param), p);
264                 SSVAL(p,0,uLevel);
265                 SSVAL(p,2,CLI_BUFFER_SIZE);
266                 p += 4;
267                 SIVAL(p,0,stype);
268                 p += 4;
269
270                 /* If we have more data, tell the server where
271                  * to continue from.
272                  */
273                 len = push_ascii(p,
274                                 last_entry ? last_entry : workgroup,
275                                 sizeof(param) - PTR_DIFF(p,param) - 1,
276                                 STR_TERMINATE|STR_UPPER);
277
278                 if (len == (size_t)-1) {
279                         SAFE_FREE(last_entry);
280                         return false;
281                 }
282                 p += len;
283
284                 if (!cli_api(cli,
285                         param, PTR_DIFF(p,param), 8, /* params, length, max */
286                         NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
287                             &rparam, &rprcnt, /* return params, return size */
288                             &rdata, &rdrcnt)) { /* return data, return size */
289
290                         /* break out of the loop on error */
291                         res = -1;
292                         break;
293                 }
294
295                 rdata_end = rdata + rdrcnt;
296                 res = rparam ? SVAL(rparam,0) : -1;
297
298                 if (res == 0 || res == ERRmoredata ||
299                     (res != -1 && cli_errno(cli) == 0)) {
300                         char *sname = NULL;
301                         int i, count;
302                         int converter=SVAL(rparam,2);
303
304                         /* Get the number of items returned in this buffer */
305                         count = SVAL(rparam, 4);
306
307                         /* The next field contains the number of items left,
308                          * including those returned in this buffer. So the
309                          * first time through this should contain all of the
310                          * entries.
311                          */
312                         if (total_cnt == 0) {
313                                 total_cnt = SVAL(rparam, 6);
314                         }
315
316                         /* Keep track of how many we have read */
317                         return_cnt += count;
318                         p = rdata;
319
320                         /* The last name in the previous NetServerEnum reply is
321                          * sent back to server in the NetServerEnum3 request
322                          * (last_entry). The next reply should repeat this entry
323                          * as the first element. We have no proof that this is
324                          * always true, but from traces that seems to be the
325                          * behavior from Window Servers. So first lets do a lot
326                          * of checking, just being paranoid. If the string
327                          * matches then we already saw this entry so skip it.
328                          *
329                          * NOTE: sv1_name field must be null terminated and has
330                          * a max size of 16 (NetBIOS Name).
331                          */
332                         if (last_entry && count && p &&
333                                 (strncmp(last_entry, p, 16) == 0)) {
334                             count -= 1; /* Skip this entry */
335                             return_cnt = -1; /* Not part of total, so don't count. */
336                             p = rdata + 26; /* Skip the whole record */
337                         }
338
339                         for (i = 0; i < count; i++, p += 26) {
340                                 int comment_offset;
341                                 const char *cmnt;
342                                 const char *p1;
343                                 char *s1, *s2;
344                                 TALLOC_CTX *frame = talloc_stackframe();
345                                 uint32_t entry_stype;
346
347                                 if (p + 26 > rdata_end) {
348                                         TALLOC_FREE(frame);
349                                         break;
350                                 }
351
352                                 sname = p;
353                                 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
354                                 cmnt = comment_offset?(rdata+comment_offset):"";
355
356                                 if (comment_offset < 0 || comment_offset > (int)rdrcnt) {
357                                         TALLOC_FREE(frame);
358                                         continue;
359                                 }
360
361                                 /* Work out the comment length. */
362                                 for (p1 = cmnt, len = 0; *p1 &&
363                                                 p1 < rdata_end; len++)
364                                         p1++;
365                                 if (!*p1) {
366                                         len++;
367                                 }
368
369                                 entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
370
371                                 pull_string_talloc(frame,rdata,0,
372                                         &s1,sname,16,STR_ASCII);
373                                 pull_string_talloc(frame,rdata,0,
374                                         &s2,cmnt,len,STR_ASCII);
375
376                                 if (!s1 || !s2) {
377                                         TALLOC_FREE(frame);
378                                         continue;
379                                 }
380
381                                 fn(s1, entry_stype, s2, state);
382                                 TALLOC_FREE(frame);
383                         }
384
385                         /* We are done with the old last entry, so now we can free it */
386                         if (last_entry) {
387                                 SAFE_FREE(last_entry); /* This will set it to null */
388                         }
389
390                         /* We always make a copy of  the last entry if we have one */
391                         if (sname) {
392                                 last_entry = smb_xstrdup(sname);
393                         }
394
395                         /* If we have more data, but no last entry then error out */
396                         if (!last_entry && (res == ERRmoredata)) {
397                                 errno = EINVAL;
398                                 res = 0;
399                         }
400
401                 }
402
403                 SAFE_FREE(rparam);
404                 SAFE_FREE(rdata);
405         } while ((res == ERRmoredata) && (total_cnt > return_cnt));
406
407         SAFE_FREE(rparam);
408         SAFE_FREE(rdata);
409         SAFE_FREE(last_entry);
410
411         if (res == -1) {
412                 errno = cli_errno(cli);
413         } else {
414                 if (!return_cnt) {
415                         /* this is a very special case, when the domain master for the
416                            work group isn't part of the work group itself, there is something
417                            wild going on */
418                         errno = ENOENT;
419                 }
420             }
421
422         return(return_cnt > 0);
423 }
424
425 /****************************************************************************
426  Send a SamOEMChangePassword command.
427 ****************************************************************************/
428
429 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
430                              const char *old_password)
431 {
432         char param[1024];
433         unsigned char data[532];
434         char *p = param;
435         unsigned char old_pw_hash[16];
436         unsigned char new_pw_hash[16];
437         unsigned int data_len;
438         unsigned int param_len = 0;
439         char *rparam = NULL;
440         char *rdata = NULL;
441         unsigned int rprcnt, rdrcnt;
442
443         if (strlen(user) >= sizeof(fstring)-1) {
444                 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
445                 return False;
446         }
447
448         SSVAL(p,0,214); /* SamOEMChangePassword command. */
449         p += 2;
450         strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
451         p = skip_string(param,sizeof(param),p);
452         strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
453         p = skip_string(param,sizeof(param),p);
454         strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
455         p = skip_string(param,sizeof(param),p);
456         SSVAL(p,0,532);
457         p += 2;
458
459         param_len = PTR_DIFF(p,param);
460
461         /*
462          * Get the Lanman hash of the old password, we
463          * use this as the key to make_oem_passwd_hash().
464          */
465         E_deshash(old_password, old_pw_hash);
466
467         encode_pw_buffer(data, new_password, STR_ASCII);
468
469 #ifdef DEBUG_PASSWORD
470         DEBUG(100,("make_oem_passwd_hash\n"));
471         dump_data(100, data, 516);
472 #endif
473         arcfour_crypt( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
474
475         /*
476          * Now place the old password hash in the data.
477          */
478         E_deshash(new_password, new_pw_hash);
479
480         E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
481
482         data_len = 532;
483
484         if (cli_send_trans(cli,SMBtrans,
485                     PIPE_LANMAN,                          /* name */
486                     0,0,                                  /* fid, flags */
487                     NULL,0,0,                             /* setup, length, max */
488                     param,param_len,2,                    /* param, length, max */
489                     (char *)data,data_len,0                       /* data, length, max */
490                    ) == False) {
491                 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
492                         user ));
493                 return False;
494         }
495
496         if (!cli_receive_trans(cli,SMBtrans,
497                        &rparam, &rprcnt,
498                        &rdata, &rdrcnt)) {
499                 DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
500                         user ));
501                 return False;
502         }
503
504         if (rparam) {
505                 cli->rap_error = SVAL(rparam,0);
506         }
507
508         SAFE_FREE(rparam);
509         SAFE_FREE(rdata);
510
511         return (cli->rap_error == 0);
512 }
513
514 /****************************************************************************
515  Send a qpathinfo call.
516 ****************************************************************************/
517
518 bool cli_qpathinfo(struct cli_state *cli,
519                         const char *fname,
520                         time_t *change_time,
521                         time_t *access_time,
522                         time_t *write_time,
523                         SMB_OFF_T *size,
524                         uint16 *mode)
525 {
526         unsigned int data_len = 0;
527         unsigned int param_len = 0;
528         unsigned int rparam_len, rdata_len;
529         uint16 setup = TRANSACT2_QPATHINFO;
530         char *param;
531         char *rparam=NULL, *rdata=NULL;
532         int count=8;
533         bool ret;
534         time_t (*date_fn)(struct cli_state *, const void *);
535         char *p;
536         size_t nlen = 2*(strlen(fname)+1);
537
538         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
539         if (!param) {
540                 return false;
541         }
542         p = param;
543         memset(p, '\0', 6);
544         SSVAL(p, 0, SMB_INFO_STANDARD);
545         p += 6;
546         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
547         param_len = PTR_DIFF(p, param);
548
549         do {
550                 ret = (cli_send_trans(cli, SMBtrans2,
551                                       NULL,           /* Name */
552                                       -1, 0,          /* fid, flags */
553                                       &setup, 1, 0,   /* setup, length, max */
554                                       param, param_len, 10, /* param, length, max */
555                                       NULL, data_len, cli->max_xmit /* data, length, max */
556                                       ) &&
557                        cli_receive_trans(cli, SMBtrans2,
558                                          &rparam, &rparam_len,
559                                          &rdata, &rdata_len));
560                 if (!cli_is_dos_error(cli)) break;
561                 if (!ret) {
562                         /* we need to work around a Win95 bug - sometimes
563                            it gives ERRSRV/ERRerror temprarily */
564                         uint8 eclass;
565                         uint32 ecode;
566                         cli_dos_error(cli, &eclass, &ecode);
567                         if (eclass != ERRSRV || ecode != ERRerror) break;
568                         smb_msleep(100);
569                 }
570         } while (count-- && ret==False);
571
572         SAFE_FREE(param);
573         if (!ret || !rdata || rdata_len < 22) {
574                 return False;
575         }
576
577         if (cli->win95) {
578                 date_fn = cli_make_unix_date;
579         } else {
580                 date_fn = cli_make_unix_date2;
581         }
582
583         if (change_time) {
584                 *change_time = date_fn(cli, rdata+0);
585         }
586         if (access_time) {
587                 *access_time = date_fn(cli, rdata+4);
588         }
589         if (write_time) {
590                 *write_time = date_fn(cli, rdata+8);
591         }
592         if (size) {
593                 *size = IVAL(rdata, 12);
594         }
595         if (mode) {
596                 *mode = SVAL(rdata,l1_attrFile);
597         }
598
599         SAFE_FREE(rdata);
600         SAFE_FREE(rparam);
601         return True;
602 }
603
604 /****************************************************************************
605  Send a setpathinfo call.
606 ****************************************************************************/
607
608 bool cli_setpathinfo(struct cli_state *cli, const char *fname,
609                      time_t create_time,
610                      time_t access_time,
611                      time_t write_time,
612                      time_t change_time,
613                      uint16 mode)
614 {
615         unsigned int data_len = 0;
616         unsigned int param_len = 0;
617         unsigned int rparam_len, rdata_len;
618         uint16 setup = TRANSACT2_SETPATHINFO;
619         char *param;
620         char data[40];
621         char *rparam=NULL, *rdata=NULL;
622         int count=8;
623         bool ret;
624         char *p;
625         size_t nlen = 2*(strlen(fname)+1);
626
627         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
628         if (!param) {
629                 return false;
630         }
631         memset(param, '\0', 6);
632         memset(data, 0, sizeof(data));
633
634         p = param;
635
636         /* Add the information level */
637         SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
638
639         /* Skip reserved */
640         p += 6;
641
642         /* Add the file name */
643         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
644
645         param_len = PTR_DIFF(p, param);
646
647         p = data;
648
649         /*
650          * Add the create, last access, modification, and status change times
651          */
652         put_long_date(p, create_time);
653         p += 8;
654
655         put_long_date(p, access_time);
656         p += 8;
657
658         put_long_date(p, write_time);
659         p += 8;
660
661         put_long_date(p, change_time);
662         p += 8;
663
664         /* Add attributes */
665         SIVAL(p, 0, mode);
666         p += 4;
667
668         /* Add padding */
669         SIVAL(p, 0, 0);
670         p += 4;
671
672         data_len = PTR_DIFF(p, data);
673
674         do {
675                 ret = (cli_send_trans(cli, SMBtrans2,
676                                       NULL,           /* Name */
677                                       -1, 0,          /* fid, flags */
678                                       &setup, 1, 0,   /* setup, length, max */
679                                       param, param_len, 10, /* param, length, max */
680                                       data, data_len, cli->max_xmit /* data, length, max */
681                                       ) &&
682                        cli_receive_trans(cli, SMBtrans2,
683                                          &rparam, &rparam_len,
684                                          &rdata, &rdata_len));
685                 if (!cli_is_dos_error(cli)) break;
686                 if (!ret) {
687                         /* we need to work around a Win95 bug - sometimes
688                            it gives ERRSRV/ERRerror temprarily */
689                         uint8 eclass;
690                         uint32 ecode;
691                         cli_dos_error(cli, &eclass, &ecode);
692                         if (eclass != ERRSRV || ecode != ERRerror) break;
693                         smb_msleep(100);
694                 }
695         } while (count-- && ret==False);
696
697         SAFE_FREE(param);
698         if (!ret) {
699                 return False;
700         }
701
702         SAFE_FREE(rdata);
703         SAFE_FREE(rparam);
704         return True;
705 }
706
707 /****************************************************************************
708  Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
709 ****************************************************************************/
710
711 bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
712                     struct timespec *create_time,
713                     struct timespec *access_time,
714                     struct timespec *write_time,
715                     struct timespec *change_time,
716                     SMB_OFF_T *size, uint16 *mode,
717                     SMB_INO_T *ino)
718 {
719         unsigned int data_len = 0;
720         unsigned int param_len = 0;
721         uint16 setup = TRANSACT2_QPATHINFO;
722         char *param;
723         char *rparam=NULL, *rdata=NULL;
724         char *p;
725         size_t nlen = 2*(strlen(fname)+1);
726
727         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
728         if (!param) {
729                 return false;
730         }
731         p = param;
732         memset(param, '\0', 6);
733         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
734         p += 6;
735         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
736
737         param_len = PTR_DIFF(p, param);
738
739         if (!cli_send_trans(cli, SMBtrans2,
740                             NULL,                         /* name */
741                             -1, 0,                        /* fid, flags */
742                             &setup, 1, 0,                 /* setup, length, max */
743                             param, param_len, 10,         /* param, length, max */
744                             NULL, data_len, cli->max_xmit /* data, length, max */
745                            )) {
746                 SAFE_FREE(param);
747                 return False;
748         }
749
750         SAFE_FREE(param);
751         if (!cli_receive_trans(cli, SMBtrans2,
752                                &rparam, &param_len,
753                                &rdata, &data_len)) {
754                 return False;
755         }
756
757         if (!rdata || data_len < 22) {
758                 return False;
759         }
760
761         if (create_time) {
762                 *create_time = interpret_long_date(rdata+0);
763         }
764         if (access_time) {
765                 *access_time = interpret_long_date(rdata+8);
766         }
767         if (write_time) {
768                 *write_time = interpret_long_date(rdata+16);
769         }
770         if (change_time) {
771                 *change_time = interpret_long_date(rdata+24);
772         }
773         if (mode) {
774                 *mode = SVAL(rdata, 32);
775         }
776         if (size) {
777                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
778         }
779         if (ino) {
780                 *ino = IVAL(rdata, 64);
781         }
782
783         SAFE_FREE(rdata);
784         SAFE_FREE(rparam);
785         return True;
786 }
787
788 /****************************************************************************
789  Get the stream info
790 ****************************************************************************/
791
792 bool cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
793                            TALLOC_CTX *mem_ctx,
794                            unsigned int *pnum_streams,
795                            struct stream_struct **pstreams)
796 {
797         unsigned int data_len = 0;
798         unsigned int param_len = 0;
799         uint16 setup = TRANSACT2_QPATHINFO;
800         char *param;
801         char *rparam=NULL, *rdata=NULL;
802         char *p;
803         unsigned int num_streams;
804         struct stream_struct *streams;
805         unsigned int ofs;
806         size_t namelen = 2*(strlen(fname)+1);
807
808         param = SMB_MALLOC_ARRAY(char, 6+namelen+2);
809         if (param == NULL) {
810                 return false;
811         }
812         p = param;
813         memset(p, 0, 6);
814         SSVAL(p, 0, SMB_FILE_STREAM_INFORMATION);
815         p += 6;
816         p += clistr_push(cli, p, fname, namelen, STR_TERMINATE);
817
818         param_len = PTR_DIFF(p, param);
819
820         if (!cli_send_trans(cli, SMBtrans2,
821                             NULL,                     /* name */
822                             -1, 0,                    /* fid, flags */
823                             &setup, 1, 0,             /* setup, len, max */
824                             param, param_len, 10,     /* param, len, max */
825                             NULL, data_len, cli->max_xmit /* data, len, max */
826                            )) {
827                 return false;
828         }
829
830         if (!cli_receive_trans(cli, SMBtrans2,
831                                &rparam, &param_len,
832                                &rdata, &data_len)) {
833                 return false;
834         }
835
836         if (!rdata) {
837                 SAFE_FREE(rparam);
838                 return false;
839         }
840
841         num_streams = 0;
842         streams = NULL;
843         ofs = 0;
844
845         while ((data_len > ofs) && (data_len - ofs >= 24)) {
846                 uint32_t nlen, len;
847                 size_t size;
848                 void *vstr;
849                 struct stream_struct *tmp;
850                 uint8_t *tmp_buf;
851
852                 tmp = TALLOC_REALLOC_ARRAY(mem_ctx, streams,
853                                            struct stream_struct,
854                                            num_streams+1);
855
856                 if (tmp == NULL) {
857                         goto fail;
858                 }
859                 streams = tmp;
860
861                 nlen                      = IVAL(rdata, ofs + 0x04);
862
863                 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
864                         rdata, ofs + 0x08);
865                 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
866                         rdata, ofs + 0x10);
867
868                 if (nlen > data_len - (ofs + 24)) {
869                         goto fail;
870                 }
871
872                 /*
873                  * We need to null-terminate src, how do I do this with
874                  * convert_string_talloc??
875                  */
876
877                 tmp_buf = TALLOC_ARRAY(streams, uint8_t, nlen+2);
878                 if (tmp_buf == NULL) {
879                         goto fail;
880                 }
881
882                 memcpy(tmp_buf, rdata+ofs+24, nlen);
883                 tmp_buf[nlen] = 0;
884                 tmp_buf[nlen+1] = 0;
885
886                 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
887                                            nlen+2, &vstr, &size, false))
888                 {
889                         TALLOC_FREE(tmp_buf);
890                         goto fail;
891                 }
892
893                 TALLOC_FREE(tmp_buf);
894                 streams[num_streams].name = (char *)vstr;
895                 num_streams++;
896
897                 len = IVAL(rdata, ofs);
898                 if (len > data_len - ofs) {
899                         goto fail;
900                 }
901                 if (len == 0) break;
902                 ofs += len;
903         }
904
905         SAFE_FREE(rdata);
906         SAFE_FREE(rparam);
907
908         *pnum_streams = num_streams;
909         *pstreams = streams;
910         return true;
911
912  fail:
913         TALLOC_FREE(streams);
914         SAFE_FREE(rdata);
915         SAFE_FREE(rparam);
916         return false;
917 }
918
919 /****************************************************************************
920  Send a qfileinfo QUERY_FILE_NAME_INFO call.
921 ****************************************************************************/
922
923 bool cli_qfilename(struct cli_state *cli, uint16_t fnum, char *name, size_t namelen)
924 {
925         unsigned int data_len = 0;
926         unsigned int param_len = 0;
927         uint16 setup = TRANSACT2_QFILEINFO;
928         char param[4];
929         char *rparam=NULL, *rdata=NULL;
930
931         param_len = 4;
932         SSVAL(param, 0, fnum);
933         SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
934
935         if (!cli_send_trans(cli, SMBtrans2,
936                             NULL,                         /* name */
937                             -1, 0,                        /* fid, flags */
938                             &setup, 1, 0,                 /* setup, length, max */
939                             param, param_len, 2,          /* param, length, max */
940                             NULL, data_len, cli->max_xmit /* data, length, max */
941                            )) {
942                 return False;
943         }
944
945         if (!cli_receive_trans(cli, SMBtrans2,
946                                &rparam, &param_len,
947                                &rdata, &data_len)) {
948                 return False;
949         }
950
951         if (!rdata || data_len < 4) {
952                 SAFE_FREE(rparam);
953                 SAFE_FREE(rdata);
954                 return False;
955         }
956
957         clistr_pull(cli->inbuf, name, rdata+4, namelen, IVAL(rdata, 0),
958                     STR_UNICODE);
959
960         SAFE_FREE(rparam);
961         SAFE_FREE(rdata);
962
963         return True;
964 }
965
966 /****************************************************************************
967  Send a qfileinfo call.
968 ****************************************************************************/
969
970 bool cli_qfileinfo(struct cli_state *cli, uint16_t fnum,
971                    uint16 *mode, SMB_OFF_T *size,
972                    struct timespec *create_time,
973                    struct timespec *access_time,
974                    struct timespec *write_time,
975                    struct timespec *change_time,
976                    SMB_INO_T *ino)
977 {
978         uint32_t data_len = 0;
979         uint16 setup;
980         uint8_t param[4];
981         uint8_t *rdata=NULL;
982         NTSTATUS status;
983
984         /* if its a win95 server then fail this - win95 totally screws it
985            up */
986         if (cli->win95) return False;
987
988         SSVAL(param, 0, fnum);
989         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
990
991         SSVAL(&setup, 0, TRANSACT2_QFILEINFO);
992
993         status = cli_trans(talloc_tos(), cli, SMBtrans2,
994                            NULL, -1, 0, 0, /* name, fid, function, flags */
995                            &setup, 1, 0,          /* setup, length, max */
996                            param, 4, 2,   /* param, length, max */
997                            NULL, 0, MIN(cli->max_xmit, 0xffff), /* data, length, max */
998                            NULL, 0, NULL, /* rsetup, length */
999                            NULL, 0, NULL,       /* rparam, length */
1000                            &rdata, 68, &data_len);
1001
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 return false;
1004         }
1005
1006         if (create_time) {
1007                 *create_time = interpret_long_date((char *)rdata+0);
1008         }
1009         if (access_time) {
1010                 *access_time = interpret_long_date((char *)rdata+8);
1011         }
1012         if (write_time) {
1013                 *write_time = interpret_long_date((char *)rdata+16);
1014         }
1015         if (change_time) {
1016                 *change_time = interpret_long_date((char *)rdata+24);
1017         }
1018         if (mode) {
1019                 *mode = SVAL(rdata, 32);
1020         }
1021         if (size) {
1022                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
1023         }
1024         if (ino) {
1025                 *ino = IVAL(rdata, 64);
1026         }
1027
1028         TALLOC_FREE(rdata);
1029         return True;
1030 }
1031
1032 /****************************************************************************
1033  Send a qpathinfo BASIC_INFO call.
1034 ****************************************************************************/
1035
1036 bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
1037                           SMB_STRUCT_STAT *sbuf, uint32 *attributes )
1038 {
1039         unsigned int param_len = 0;
1040         unsigned int data_len = 0;
1041         uint16 setup = TRANSACT2_QPATHINFO;
1042         char *param;
1043         char *rparam=NULL, *rdata=NULL;
1044         char *p;
1045         char *path;
1046         int len;
1047         size_t nlen;
1048         TALLOC_CTX *frame = talloc_stackframe();
1049
1050         path = talloc_strdup(frame, name);
1051         if (!path) {
1052                 TALLOC_FREE(frame);
1053                 return false;
1054         }
1055         /* cleanup */
1056
1057         len = strlen(path);
1058         if ( path[len-1] == '\\' || path[len-1] == '/') {
1059                 path[len-1] = '\0';
1060         }
1061         nlen = 2*(strlen(path)+1);
1062
1063         param = TALLOC_ARRAY(frame,char,6+nlen+2);
1064         if (!param) {
1065                 return false;
1066         }
1067         p = param;
1068         memset(param, '\0', 6);
1069
1070         SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
1071         p += 6;
1072         p += clistr_push(cli, p, path, nlen, STR_TERMINATE);
1073         param_len = PTR_DIFF(p, param);
1074
1075
1076         if (!cli_send_trans(cli, SMBtrans2,
1077                         NULL,                        /* name */
1078                         -1, 0,                       /* fid, flags */
1079                         &setup, 1, 0,                /* setup, length, max */
1080                         param, param_len, 2,         /* param, length, max */
1081                         NULL,  0, cli->max_xmit      /* data, length, max */
1082                         )) {
1083                 TALLOC_FREE(frame);
1084                 return False;
1085         }
1086
1087         TALLOC_FREE(frame);
1088
1089         if (!cli_receive_trans(cli, SMBtrans2,
1090                 &rparam, &param_len,
1091                 &rdata, &data_len)) {
1092                         return False;
1093         }
1094
1095         if (data_len < 36) {
1096                 SAFE_FREE(rdata);
1097                 SAFE_FREE(rparam);
1098                 return False;
1099         }
1100
1101         sbuf->st_ex_atime = interpret_long_date( rdata+8 ); /* Access time. */
1102         sbuf->st_ex_mtime = interpret_long_date( rdata+16 ); /* Write time. */
1103         sbuf->st_ex_ctime = interpret_long_date( rdata+24 ); /* Change time. */
1104
1105         *attributes = IVAL( rdata, 32 );
1106
1107         SAFE_FREE(rparam);
1108         SAFE_FREE(rdata);
1109
1110         return True;
1111 }
1112
1113 /****************************************************************************
1114  Send a qfileinfo call.
1115 ****************************************************************************/
1116
1117 bool cli_qfileinfo_test(struct cli_state *cli, uint16_t fnum, int level, char **poutdata, uint32 *poutlen)
1118 {
1119         unsigned int data_len = 0;
1120         unsigned int param_len = 0;
1121         uint16 setup = TRANSACT2_QFILEINFO;
1122         char param[4];
1123         char *rparam=NULL, *rdata=NULL;
1124
1125         *poutdata = NULL;
1126         *poutlen = 0;
1127
1128         /* if its a win95 server then fail this - win95 totally screws it
1129            up */
1130         if (cli->win95)
1131                 return False;
1132
1133         param_len = 4;
1134
1135         SSVAL(param, 0, fnum);
1136         SSVAL(param, 2, level);
1137
1138         if (!cli_send_trans(cli, SMBtrans2,
1139                             NULL,                           /* name */
1140                             -1, 0,                          /* fid, flags */
1141                             &setup, 1, 0,                   /* setup, length, max */
1142                             param, param_len, 2,            /* param, length, max */
1143                             NULL, data_len, cli->max_xmit   /* data, length, max */
1144                            )) {
1145                 return False;
1146         }
1147
1148         if (!cli_receive_trans(cli, SMBtrans2,
1149                                &rparam, &param_len,
1150                                &rdata, &data_len)) {
1151                 return False;
1152         }
1153
1154         *poutdata = (char *)memdup(rdata, data_len);
1155         if (!*poutdata) {
1156                 SAFE_FREE(rdata);
1157                 SAFE_FREE(rparam);
1158                 return False;
1159         }
1160
1161         *poutlen = data_len;
1162
1163         SAFE_FREE(rdata);
1164         SAFE_FREE(rparam);
1165         return True;
1166 }
1167
1168 /****************************************************************************
1169  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1170 ****************************************************************************/
1171
1172 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1173 {
1174         unsigned int data_len = 0;
1175         unsigned int param_len = 0;
1176         uint16 setup = TRANSACT2_QPATHINFO;
1177         char *param;
1178         char *rparam=NULL, *rdata=NULL;
1179         int count=8;
1180         char *p;
1181         bool ret;
1182         unsigned int len;
1183         size_t nlen = 2*(strlen(fname)+1);
1184
1185         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
1186         if (!param) {
1187                 return NT_STATUS_NO_MEMORY;
1188         }
1189         p = param;
1190         memset(param, '\0', 6);
1191         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
1192         p += 6;
1193         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
1194         param_len = PTR_DIFF(p, param);
1195
1196         do {
1197                 ret = (cli_send_trans(cli, SMBtrans2,
1198                                       NULL,           /* Name */
1199                                       -1, 0,          /* fid, flags */
1200                                       &setup, 1, 0,   /* setup, length, max */
1201                                       param, param_len, 10, /* param, length, max */
1202                                       NULL, data_len, cli->max_xmit /* data, length, max */
1203                                       ) &&
1204                        cli_receive_trans(cli, SMBtrans2,
1205                                          &rparam, &param_len,
1206                                          &rdata, &data_len));
1207                 if (!ret && cli_is_dos_error(cli)) {
1208                         /* we need to work around a Win95 bug - sometimes
1209                            it gives ERRSRV/ERRerror temprarily */
1210                         uint8 eclass;
1211                         uint32 ecode;
1212                         cli_dos_error(cli, &eclass, &ecode);
1213                         if (eclass != ERRSRV || ecode != ERRerror) break;
1214                         smb_msleep(100);
1215                 }
1216         } while (count-- && ret==False);
1217
1218         SAFE_FREE(param);
1219
1220         if (!ret || !rdata || data_len < 4) {
1221                 return NT_STATUS_UNSUCCESSFUL;
1222         }
1223
1224         len = IVAL(rdata, 0);
1225
1226         if (len > data_len - 4) {
1227                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1228         }
1229
1230         clistr_pull(cli->inbuf, alt_name, rdata+4, sizeof(fstring), len,
1231                     STR_UNICODE);
1232
1233         SAFE_FREE(rdata);
1234         SAFE_FREE(rparam);
1235
1236         return NT_STATUS_OK;
1237 }