Line data Source code
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 : #include "../librpc/gen_ndr/rap.h"
25 : #include "../lib/util/tevent_ntstatus.h"
26 : #include "async_smb.h"
27 : #include "libsmb/libsmb.h"
28 : #include "libsmb/clirap.h"
29 : #include "trans2.h"
30 : #include "../libcli/smb/smbXcli_base.h"
31 : #include "libcli/smb/reparse.h"
32 : #include "cli_smb2_fnum.h"
33 : #include "lib/util/string_wrappers.h"
34 :
35 : #include <gnutls/gnutls.h>
36 : #include <gnutls/crypto.h>
37 :
38 : #define PIPE_LANMAN "\\PIPE\\LANMAN"
39 :
40 : /****************************************************************************
41 : Call a remote api
42 : ****************************************************************************/
43 :
44 56 : bool cli_api(struct cli_state *cli,
45 : char *param, int prcnt, int mprcnt,
46 : char *data, int drcnt, int mdrcnt,
47 : char **rparam, unsigned int *rprcnt,
48 : char **rdata, unsigned int *rdrcnt)
49 : {
50 0 : NTSTATUS status;
51 :
52 0 : uint8_t *my_rparam, *my_rdata;
53 0 : uint32_t num_my_rparam, num_my_rdata;
54 :
55 56 : status = cli_trans(talloc_tos(), cli, SMBtrans,
56 : PIPE_LANMAN, 0, /* name, fid */
57 : 0, 0, /* function, flags */
58 : NULL, 0, 0, /* setup */
59 : (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
60 : (uint8_t *)data, drcnt, mdrcnt, /* Data, length, max */
61 : NULL, /* recv_flags2 */
62 : NULL, 0, NULL, /* rsetup */
63 : &my_rparam, 0, &num_my_rparam,
64 : &my_rdata, 0, &num_my_rdata);
65 56 : if (!NT_STATUS_IS_OK(status)) {
66 6 : return false;
67 : }
68 :
69 : /*
70 : * I know this memcpy massively hurts, but there are just tons
71 : * of callers of cli_api that eventually need changing to
72 : * talloc
73 : */
74 :
75 50 : *rparam = (char *)smb_memdup(my_rparam, num_my_rparam);
76 50 : if (*rparam == NULL) {
77 0 : goto fail;
78 : }
79 50 : *rprcnt = num_my_rparam;
80 50 : TALLOC_FREE(my_rparam);
81 :
82 50 : *rdata = (char *)smb_memdup(my_rdata, num_my_rdata);
83 50 : if (*rdata == NULL) {
84 9 : goto fail;
85 : }
86 41 : *rdrcnt = num_my_rdata;
87 41 : TALLOC_FREE(my_rdata);
88 :
89 41 : return true;
90 9 : fail:
91 9 : TALLOC_FREE(my_rdata);
92 9 : TALLOC_FREE(my_rparam);
93 9 : *rparam = NULL;
94 9 : *rprcnt = 0;
95 9 : *rdata = NULL;
96 9 : *rdrcnt = 0;
97 9 : return false;
98 : }
99 :
100 : /****************************************************************************
101 : Call a NetShareEnum - try and browse available connections on a host.
102 : ****************************************************************************/
103 :
104 0 : int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state)
105 : {
106 0 : char *rparam = NULL;
107 0 : char *rdata = NULL;
108 0 : char *p;
109 0 : unsigned int rdrcnt,rprcnt;
110 0 : char param[1024];
111 0 : int count = -1;
112 0 : bool ok;
113 0 : int res;
114 :
115 : /* now send a SMBtrans command with api RNetShareEnum */
116 0 : p = param;
117 0 : SSVAL(p,0,0); /* api number */
118 0 : p += 2;
119 0 : strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
120 0 : p = skip_string(param,sizeof(param),p);
121 0 : strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
122 0 : p = skip_string(param,sizeof(param),p);
123 0 : SSVAL(p,0,1);
124 : /*
125 : * Win2k needs a *smaller* buffer than 0xFFFF here -
126 : * it returns "out of server memory" with 0xFFFF !!! JRA.
127 : */
128 0 : SSVAL(p,2,0xFFE0);
129 0 : p += 4;
130 :
131 0 : ok = cli_api(
132 : cli,
133 0 : param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
134 : NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
135 : &rparam, &rprcnt, /* return params, length */
136 : &rdata, &rdrcnt); /* return data, length */
137 0 : if (!ok) {
138 0 : DEBUG(4,("NetShareEnum failed\n"));
139 0 : goto done;
140 : }
141 :
142 0 : if (rprcnt < 6) {
143 0 : DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
144 0 : goto done;
145 : }
146 :
147 0 : res = rparam? SVAL(rparam,0) : -1;
148 :
149 0 : if (res == 0 || res == ERRmoredata) {
150 0 : int converter=SVAL(rparam,2);
151 0 : int i;
152 0 : char *rdata_end = rdata + rdrcnt;
153 :
154 0 : count=SVAL(rparam,4);
155 0 : p = rdata;
156 :
157 0 : for (i=0;i<count;i++,p+=20) {
158 0 : char *sname;
159 0 : int type;
160 0 : int comment_offset;
161 0 : const char *cmnt;
162 0 : const char *p1;
163 0 : char *s1, *s2;
164 0 : size_t len;
165 0 : TALLOC_CTX *frame = talloc_stackframe();
166 :
167 0 : if (p + 20 > rdata_end) {
168 0 : TALLOC_FREE(frame);
169 0 : break;
170 : }
171 :
172 0 : sname = p;
173 0 : type = SVAL(p,14);
174 0 : comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
175 0 : if (comment_offset < 0 ||
176 0 : comment_offset > (int)rdrcnt) {
177 0 : TALLOC_FREE(frame);
178 0 : break;
179 : }
180 0 : cmnt = comment_offset?(rdata+comment_offset):"";
181 :
182 : /* Work out the comment length. */
183 0 : for (p1 = cmnt, len = 0; *p1 &&
184 0 : p1 < rdata_end; len++)
185 0 : p1++;
186 0 : if (!*p1) {
187 0 : len++;
188 : }
189 0 : pull_string_talloc(frame,rdata,0,
190 : &s1,sname,14,STR_ASCII);
191 0 : pull_string_talloc(frame,rdata,0,
192 : &s2,cmnt,len,STR_ASCII);
193 0 : if (!s1 || !s2) {
194 0 : TALLOC_FREE(frame);
195 0 : continue;
196 : }
197 :
198 0 : fn(s1, type, s2, state);
199 :
200 0 : TALLOC_FREE(frame);
201 : }
202 : } else {
203 0 : DEBUG(4,("NetShareEnum res=%d\n", res));
204 : }
205 :
206 0 : done:
207 0 : SAFE_FREE(rparam);
208 0 : SAFE_FREE(rdata);
209 :
210 0 : 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 52 : bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype,
222 : void (*fn)(const char *, uint32_t, const char *, void *),
223 : void *state)
224 : {
225 52 : char *rparam = NULL;
226 52 : char *rdata = NULL;
227 52 : char *rdata_end = NULL;
228 0 : unsigned int rdrcnt,rprcnt;
229 0 : char *p;
230 0 : char param[1024];
231 52 : int uLevel = 1;
232 0 : size_t len;
233 52 : uint32_t func = RAP_NetServerEnum2;
234 52 : char *last_entry = NULL;
235 52 : int total_cnt = 0;
236 52 : int return_cnt = 0;
237 0 : int res;
238 :
239 52 : 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 0 : do {
247 : /* send a SMBtrans command with api NetServerEnum */
248 52 : p = param;
249 52 : SIVAL(p,0,func); /* api number */
250 52 : p += 2;
251 :
252 52 : if (func == RAP_NetServerEnum3) {
253 0 : strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
254 : } else {
255 52 : strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
256 : }
257 :
258 52 : p = skip_string(param, sizeof(param), p);
259 52 : strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
260 :
261 52 : p = skip_string(param, sizeof(param), p);
262 52 : SSVAL(p,0,uLevel);
263 52 : SSVAL(p,2,CLI_BUFFER_SIZE);
264 52 : p += 4;
265 52 : SIVAL(p,0,stype);
266 52 : p += 4;
267 :
268 : /* If we have more data, tell the server where
269 : * to continue from.
270 : */
271 52 : len = push_ascii(p,
272 : workgroup,
273 52 : sizeof(param) - PTR_DIFF(p,param) - 1,
274 : STR_TERMINATE|STR_UPPER);
275 :
276 52 : if (len == 0) {
277 0 : SAFE_FREE(last_entry);
278 0 : return false;
279 : }
280 52 : p += len;
281 :
282 52 : if (func == RAP_NetServerEnum3) {
283 0 : len = push_ascii(p,
284 : last_entry ? last_entry : "",
285 0 : sizeof(param) - PTR_DIFF(p,param) - 1,
286 : STR_TERMINATE);
287 :
288 0 : if (len == 0) {
289 0 : SAFE_FREE(last_entry);
290 0 : return false;
291 : }
292 0 : p += len;
293 : }
294 :
295 : /* Next time through we need to use the continue api */
296 52 : func = RAP_NetServerEnum3;
297 :
298 52 : if (!cli_api(cli,
299 52 : param, PTR_DIFF(p,param), 8, /* params, length, max */
300 : NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
301 : &rparam, &rprcnt, /* return params, return size */
302 : &rdata, &rdrcnt)) { /* return data, return size */
303 :
304 : /* break out of the loop on error */
305 11 : res = -1;
306 11 : break;
307 : }
308 :
309 41 : rdata_end = rdata + rdrcnt;
310 :
311 41 : if (rprcnt < 6) {
312 0 : DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
313 0 : res = -1;
314 0 : break;
315 : }
316 :
317 41 : res = rparam ? SVAL(rparam,0) : -1;
318 :
319 41 : if (res == 0 || res == ERRmoredata ||
320 0 : (res != -1 && cli_errno(cli) == 0)) {
321 41 : char *sname = NULL;
322 0 : int i, count;
323 41 : int converter=SVAL(rparam,2);
324 :
325 : /* Get the number of items returned in this buffer */
326 41 : count = SVAL(rparam, 4);
327 :
328 : /* The next field contains the number of items left,
329 : * including those returned in this buffer. So the
330 : * first time through this should contain all of the
331 : * entries.
332 : */
333 41 : if (total_cnt == 0) {
334 41 : total_cnt = SVAL(rparam, 6);
335 : }
336 :
337 : /* Keep track of how many we have read */
338 41 : return_cnt += count;
339 41 : p = rdata;
340 :
341 : /* The last name in the previous NetServerEnum reply is
342 : * sent back to server in the NetServerEnum3 request
343 : * (last_entry). The next reply should repeat this entry
344 : * as the first element. We have no proof that this is
345 : * always true, but from traces that seems to be the
346 : * behavior from Window Servers. So first lets do a lot
347 : * of checking, just being paranoid. If the string
348 : * matches then we already saw this entry so skip it.
349 : *
350 : * NOTE: sv1_name field must be null terminated and has
351 : * a max size of 16 (NetBIOS Name).
352 : */
353 41 : if (last_entry && count && p &&
354 0 : (strncmp(last_entry, p, 16) == 0)) {
355 0 : count -= 1; /* Skip this entry */
356 0 : return_cnt = -1; /* Not part of total, so don't count. */
357 0 : p = rdata + 26; /* Skip the whole record */
358 : }
359 :
360 120 : for (i = 0; i < count; i++, p += 26) {
361 0 : int comment_offset;
362 0 : const char *cmnt;
363 0 : const char *p1;
364 0 : char *s1, *s2;
365 79 : TALLOC_CTX *frame = talloc_stackframe();
366 0 : uint32_t entry_stype;
367 :
368 79 : if (p + 26 > rdata_end) {
369 0 : TALLOC_FREE(frame);
370 0 : break;
371 : }
372 :
373 79 : sname = p;
374 79 : comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
375 79 : cmnt = comment_offset?(rdata+comment_offset):"";
376 :
377 79 : if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
378 0 : TALLOC_FREE(frame);
379 0 : continue;
380 : }
381 :
382 : /* Work out the comment length. */
383 1308 : for (p1 = cmnt, len = 0; *p1 &&
384 1229 : p1 < rdata_end; len++)
385 1229 : p1++;
386 79 : if (!*p1) {
387 79 : len++;
388 : }
389 :
390 79 : entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
391 :
392 79 : pull_string_talloc(frame,rdata,0,
393 : &s1,sname,16,STR_ASCII);
394 79 : pull_string_talloc(frame,rdata,0,
395 : &s2,cmnt,len,STR_ASCII);
396 :
397 79 : if (!s1 || !s2) {
398 0 : TALLOC_FREE(frame);
399 0 : continue;
400 : }
401 :
402 79 : fn(s1, entry_stype, s2, state);
403 79 : TALLOC_FREE(frame);
404 : }
405 :
406 : /* We are done with the old last entry, so now we can free it */
407 41 : if (last_entry) {
408 0 : SAFE_FREE(last_entry); /* This will set it to null */
409 : }
410 :
411 : /* We always make a copy of the last entry if we have one */
412 41 : if (sname) {
413 41 : last_entry = smb_xstrdup(sname);
414 : }
415 :
416 : /* If we have more data, but no last entry then error out */
417 41 : if (!last_entry && (res == ERRmoredata)) {
418 0 : errno = EINVAL;
419 0 : res = 0;
420 : }
421 :
422 : }
423 :
424 41 : SAFE_FREE(rparam);
425 41 : SAFE_FREE(rdata);
426 41 : } while ((res == ERRmoredata) && (total_cnt > return_cnt));
427 :
428 52 : SAFE_FREE(rparam);
429 52 : SAFE_FREE(rdata);
430 52 : SAFE_FREE(last_entry);
431 :
432 52 : if (res == -1) {
433 11 : errno = cli_errno(cli);
434 : } else {
435 41 : if (!return_cnt) {
436 : /* this is a very special case, when the domain master for the
437 : work group isn't part of the work group itself, there is something
438 : wild going on */
439 0 : errno = ENOENT;
440 : }
441 : }
442 :
443 52 : return(return_cnt > 0);
444 : }
445 :
446 : /****************************************************************************
447 : Send a SamOEMChangePassword command.
448 : ****************************************************************************/
449 :
450 0 : bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
451 : const char *old_password)
452 : {
453 0 : char param[1024];
454 0 : unsigned char data[532];
455 0 : char *p = param;
456 0 : unsigned char old_pw_hash[16];
457 0 : unsigned char new_pw_hash[16];
458 0 : unsigned int data_len;
459 0 : unsigned int param_len = 0;
460 0 : char *rparam = NULL;
461 0 : char *rdata = NULL;
462 0 : unsigned int rprcnt, rdrcnt;
463 0 : gnutls_cipher_hd_t cipher_hnd = NULL;
464 0 : gnutls_datum_t old_pw_key = {
465 : .data = old_pw_hash,
466 : .size = sizeof(old_pw_hash),
467 : };
468 0 : int rc;
469 :
470 0 : if (strlen(user) >= sizeof(fstring)-1) {
471 0 : DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
472 0 : return False;
473 : }
474 :
475 0 : SSVAL(p,0,214); /* SamOEMChangePassword command. */
476 0 : p += 2;
477 0 : strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
478 0 : p = skip_string(param,sizeof(param),p);
479 0 : strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
480 0 : p = skip_string(param,sizeof(param),p);
481 0 : strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
482 0 : p = skip_string(param,sizeof(param),p);
483 0 : SSVAL(p,0,532);
484 0 : p += 2;
485 :
486 0 : param_len = PTR_DIFF(p,param);
487 :
488 : /*
489 : * Get the Lanman hash of the old password, we
490 : * use this as the key to make_oem_passwd_hash().
491 : */
492 0 : E_deshash(old_password, old_pw_hash);
493 :
494 0 : encode_pw_buffer(data, new_password, STR_ASCII);
495 :
496 : #ifdef DEBUG_PASSWORD
497 0 : DEBUG(100,("make_oem_passwd_hash\n"));
498 0 : dump_data(100, data, 516);
499 : #endif
500 0 : rc = gnutls_cipher_init(&cipher_hnd,
501 : GNUTLS_CIPHER_ARCFOUR_128,
502 : &old_pw_key,
503 : NULL);
504 0 : if (rc < 0) {
505 0 : DBG_ERR("gnutls_cipher_init failed: %s\n",
506 : gnutls_strerror(rc));
507 0 : return false;
508 : }
509 0 : rc = gnutls_cipher_encrypt(cipher_hnd,
510 : data,
511 : 516);
512 0 : gnutls_cipher_deinit(cipher_hnd);
513 0 : if (rc < 0) {
514 0 : return false;
515 : }
516 :
517 : /*
518 : * Now place the old password hash in the data.
519 : */
520 0 : E_deshash(new_password, new_pw_hash);
521 :
522 0 : rc = E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
523 0 : if (rc != 0) {
524 0 : DBG_ERR("E_old_pw_hash failed: %s\n", gnutls_strerror(rc));
525 0 : return false;
526 : }
527 :
528 0 : data_len = 532;
529 :
530 0 : if (!cli_api(cli,
531 : param, param_len, 4, /* param, length, max */
532 : (char *)data, data_len, 0, /* data, length, max */
533 : &rparam, &rprcnt,
534 : &rdata, &rdrcnt)) {
535 0 : DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
536 : user ));
537 0 : return False;
538 : }
539 :
540 0 : if (rdrcnt < 2) {
541 0 : cli->rap_error = ERRbadformat;
542 0 : goto done;
543 : }
544 :
545 0 : if (rparam) {
546 0 : cli->rap_error = SVAL(rparam,0);
547 : }
548 :
549 0 : done:
550 0 : SAFE_FREE(rparam);
551 0 : SAFE_FREE(rdata);
552 :
553 0 : return (cli->rap_error == 0);
554 : }
555 :
556 44 : static void prep_basic_information_buf(
557 : uint8_t buf[40],
558 : struct timespec create_time,
559 : struct timespec access_time,
560 : struct timespec write_time,
561 : struct timespec change_time,
562 : uint32_t attr)
563 : {
564 44 : char *p = (char *)buf;
565 : /*
566 : * Add the create, last access, modification, and status change times
567 : */
568 44 : put_long_date_full_timespec(
569 : TIMESTAMP_SET_NT_OR_BETTER, p, &create_time);
570 44 : p += 8;
571 :
572 44 : put_long_date_full_timespec(
573 : TIMESTAMP_SET_NT_OR_BETTER, p, &access_time);
574 44 : p += 8;
575 :
576 44 : put_long_date_full_timespec(
577 : TIMESTAMP_SET_NT_OR_BETTER, p, &write_time);
578 44 : p += 8;
579 :
580 44 : put_long_date_full_timespec(
581 : TIMESTAMP_SET_NT_OR_BETTER, p, &change_time);
582 44 : p += 8;
583 :
584 44 : if (attr == (uint32_t)-1 || attr == FILE_ATTRIBUTE_NORMAL) {
585 : /* No change. */
586 30 : attr = 0;
587 14 : } else if (attr == 0) {
588 : /* Clear all existing attributes. */
589 9 : attr = FILE_ATTRIBUTE_NORMAL;
590 : }
591 :
592 : /* Add attributes */
593 44 : SIVAL(p, 0, attr);
594 :
595 44 : p += 4;
596 :
597 : /* Add padding */
598 44 : SIVAL(p, 0, 0);
599 44 : p += 4;
600 :
601 44 : SMB_ASSERT(PTR_DIFF(p, buf) == 40);
602 44 : }
603 :
604 44 : NTSTATUS cli_setpathinfo_ext(struct cli_state *cli, const char *fname,
605 : struct timespec create_time,
606 : struct timespec access_time,
607 : struct timespec write_time,
608 : struct timespec change_time,
609 : uint32_t attr)
610 : {
611 0 : uint8_t buf[40];
612 :
613 44 : prep_basic_information_buf(
614 : buf,
615 : create_time,
616 : access_time,
617 : write_time,
618 : change_time,
619 : attr);
620 :
621 44 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
622 16 : DATA_BLOB in_data = data_blob_const(buf, sizeof(buf));
623 : /*
624 : * Split out SMB2 here as we need to select
625 : * the correct info type and level.
626 : */
627 16 : return cli_smb2_setpathinfo(cli,
628 : fname,
629 : SMB2_0_INFO_FILE,
630 : FSCC_FILE_BASIC_INFORMATION,
631 : &in_data);
632 : }
633 :
634 28 : return cli_setpathinfo(
635 : cli, SMB_FILE_BASIC_INFORMATION, fname, buf, sizeof(buf));
636 : }
637 :
638 : struct cli_setfileinfo_ext_state {
639 : uint8_t data[40];
640 : DATA_BLOB in_data;
641 : };
642 :
643 : static void cli_setfileinfo_ext_done(struct tevent_req *subreq);
644 : static void cli_setfileinfo_ext_done2(struct tevent_req *subreq);
645 :
646 0 : struct tevent_req *cli_setfileinfo_ext_send(
647 : TALLOC_CTX *mem_ctx,
648 : struct tevent_context *ev,
649 : struct cli_state *cli,
650 : uint16_t fnum,
651 : struct timespec create_time,
652 : struct timespec access_time,
653 : struct timespec write_time,
654 : struct timespec change_time,
655 : uint32_t attr)
656 : {
657 0 : struct tevent_req *req = NULL, *subreq = NULL;
658 0 : struct cli_setfileinfo_ext_state *state = NULL;
659 :
660 0 : req = tevent_req_create(
661 : mem_ctx, &state, struct cli_setfileinfo_ext_state);
662 0 : if (req == NULL) {
663 0 : return NULL;
664 : }
665 0 : prep_basic_information_buf(
666 0 : state->data,
667 : create_time,
668 : access_time,
669 : write_time,
670 : change_time,
671 : attr);
672 :
673 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
674 0 : state->in_data = (DATA_BLOB) {
675 0 : .data = state->data, .length = sizeof(state->data),
676 : };
677 :
678 0 : subreq = cli_smb2_set_info_fnum_send(
679 : state,
680 : ev,
681 : cli,
682 : fnum,
683 : SMB2_0_INFO_FILE,
684 : FSCC_FILE_BASIC_INFORMATION,
685 0 : &state->in_data,
686 : 0); /* in_additional_info */
687 0 : if (tevent_req_nomem(subreq, req)) {
688 0 : return tevent_req_post(req, ev);
689 : }
690 0 : tevent_req_set_callback(
691 : subreq, cli_setfileinfo_ext_done2, req);
692 0 : return req;
693 : }
694 :
695 0 : subreq = cli_setfileinfo_send(
696 : state,
697 : ev,
698 : cli,
699 : fnum,
700 : SMB_FILE_BASIC_INFORMATION,
701 0 : state->data,
702 : sizeof(state->data));
703 0 : if (tevent_req_nomem(subreq, req)) {
704 0 : return tevent_req_post(req, ev);
705 : }
706 0 : tevent_req_set_callback(subreq, cli_setfileinfo_ext_done, req);
707 0 : return req;
708 : }
709 :
710 0 : static void cli_setfileinfo_ext_done(struct tevent_req *subreq)
711 : {
712 0 : NTSTATUS status = cli_setfileinfo_recv(subreq);
713 0 : tevent_req_simple_finish_ntstatus(subreq, status);
714 0 : }
715 :
716 0 : static void cli_setfileinfo_ext_done2(struct tevent_req *subreq)
717 : {
718 0 : NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
719 0 : tevent_req_simple_finish_ntstatus(subreq, status);
720 0 : }
721 :
722 0 : NTSTATUS cli_setfileinfo_ext_recv(struct tevent_req *req)
723 : {
724 0 : return tevent_req_simple_recv_ntstatus(req);
725 : }
726 :
727 0 : NTSTATUS cli_setfileinfo_ext(
728 : struct cli_state *cli,
729 : uint16_t fnum,
730 : struct timespec create_time,
731 : struct timespec access_time,
732 : struct timespec write_time,
733 : struct timespec change_time,
734 : uint32_t attr)
735 : {
736 0 : TALLOC_CTX *frame = NULL;
737 0 : struct tevent_context *ev = NULL;
738 0 : struct tevent_req *req = NULL;
739 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
740 :
741 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
742 : /*
743 : * Can't use sync call while an async call is in flight
744 : */
745 0 : return NT_STATUS_INVALID_PARAMETER;
746 : }
747 :
748 0 : frame = talloc_stackframe();
749 :
750 0 : ev = samba_tevent_context_init(frame);
751 0 : if (ev == NULL) {
752 0 : goto fail;
753 : }
754 0 : req = cli_setfileinfo_ext_send(
755 : ev,
756 : ev,
757 : cli,
758 : fnum,
759 : create_time,
760 : access_time,
761 : write_time,
762 : change_time,
763 : attr);
764 0 : if (req == NULL) {
765 0 : goto fail;
766 : }
767 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
768 0 : goto fail;
769 : }
770 0 : status = cli_setfileinfo_ext_recv(req);
771 0 : fail:
772 0 : TALLOC_FREE(frame);
773 0 : return status;
774 : }
775 :
776 : /****************************************************************************
777 : Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
778 : ****************************************************************************/
779 :
780 : struct cli_qpathinfo2_state {
781 : struct tevent_context *ev;
782 : struct cli_state *cli;
783 : const char *fname;
784 : struct timespec create_time;
785 : struct timespec access_time;
786 : struct timespec write_time;
787 : struct timespec change_time;
788 : off_t size;
789 : uint32_t attr;
790 : SMB_INO_T ino;
791 : mode_t mode;
792 : };
793 :
794 : static void cli_qpathinfo2_done2(struct tevent_req *subreq);
795 : static void cli_qpathinfo2_done(struct tevent_req *subreq);
796 : static void cli_qpathinfo2_got_reparse(struct tevent_req *subreq);
797 :
798 3057 : struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
799 : struct tevent_context *ev,
800 : struct cli_state *cli,
801 : const char *fname)
802 : {
803 3057 : struct tevent_req *req = NULL, *subreq = NULL;
804 3057 : struct cli_qpathinfo2_state *state = NULL;
805 :
806 3057 : req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
807 3057 : if (req == NULL) {
808 0 : return NULL;
809 : }
810 3057 : state->ev = ev;
811 3057 : state->cli = cli;
812 3057 : state->fname = fname;
813 :
814 3057 : state->mode = S_IFREG;
815 :
816 3057 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
817 3024 : subreq = cli_smb2_qpathinfo_send(state,
818 : ev,
819 : cli,
820 : fname,
821 : FSCC_FILE_ALL_INFORMATION,
822 : 0x60,
823 : UINT16_MAX);
824 3024 : if (tevent_req_nomem(subreq, req)) {
825 0 : return tevent_req_post(req, ev);
826 : }
827 3024 : tevent_req_set_callback(subreq, cli_qpathinfo2_done2, req);
828 3024 : return req;
829 : }
830 33 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
831 : SMB_QUERY_FILE_ALL_INFO,
832 : 68, CLI_BUFFER_SIZE);
833 33 : if (tevent_req_nomem(subreq, req)) {
834 0 : return tevent_req_post(req, ev);
835 : }
836 33 : tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
837 33 : return req;
838 : }
839 :
840 3024 : static void cli_qpathinfo2_done2(struct tevent_req *subreq)
841 : {
842 0 : struct tevent_req *req =
843 3024 : tevent_req_callback_data(subreq, struct tevent_req);
844 0 : struct cli_qpathinfo2_state *state =
845 3024 : tevent_req_data(req, struct cli_qpathinfo2_state);
846 3024 : uint8_t *rdata = NULL;
847 0 : uint32_t num_rdata;
848 0 : NTSTATUS status;
849 :
850 3024 : status = cli_smb2_qpathinfo_recv(subreq, state, &rdata, &num_rdata);
851 3024 : TALLOC_FREE(subreq);
852 3024 : if (tevent_req_nterror(req, status)) {
853 579 : return;
854 : }
855 2445 : state->create_time = interpret_long_date(BVAL(rdata, 0x0));
856 2445 : state->access_time = interpret_long_date(BVAL(rdata, 0x8));
857 2445 : state->write_time = interpret_long_date(BVAL(rdata, 0x10));
858 2445 : state->change_time = interpret_long_date(BVAL(rdata, 0x18));
859 2445 : state->attr = PULL_LE_U32(rdata, 0x20);
860 2445 : state->size = PULL_LE_U64(rdata, 0x30);
861 2445 : state->ino = PULL_LE_U64(rdata, 0x40);
862 :
863 2445 : if (state->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
864 0 : subreq = cli_get_reparse_data_send(state,
865 : state->ev,
866 : state->cli,
867 : state->fname);
868 0 : if (tevent_req_nomem(subreq, req)) {
869 0 : return;
870 : }
871 0 : tevent_req_set_callback(subreq,
872 : cli_qpathinfo2_got_reparse,
873 : req);
874 0 : return;
875 : }
876 :
877 2445 : tevent_req_done(req);
878 : }
879 :
880 33 : static void cli_qpathinfo2_done(struct tevent_req *subreq)
881 : {
882 33 : struct tevent_req *req = tevent_req_callback_data(
883 : subreq, struct tevent_req);
884 33 : struct cli_qpathinfo2_state *state = tevent_req_data(
885 : req, struct cli_qpathinfo2_state);
886 33 : uint8_t *data = NULL;
887 0 : uint32_t num_data;
888 0 : NTSTATUS status;
889 :
890 33 : status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
891 33 : TALLOC_FREE(subreq);
892 33 : if (tevent_req_nterror(req, status)) {
893 2 : return;
894 : }
895 :
896 31 : state->create_time = interpret_long_date(BVAL(data, 0));
897 31 : state->access_time = interpret_long_date(BVAL(data, 8));
898 31 : state->write_time = interpret_long_date(BVAL(data, 16));
899 31 : state->change_time = interpret_long_date(BVAL(data, 24));
900 31 : state->attr = PULL_LE_U32(data, 32);
901 31 : state->size = PULL_LE_U64(data, 48);
902 :
903 : /*
904 : * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO which doesn't
905 : * return an inode number (fileid). We can't change this to
906 : * one of the FILE_ID info levels as only Win2003 and above
907 : * support these [MS-SMB: 2.2.2.3.1] and the SMB1 code needs
908 : * to support older servers.
909 : */
910 31 : state->ino = 0;
911 :
912 31 : TALLOC_FREE(data);
913 :
914 31 : if (state->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
915 0 : subreq = cli_get_reparse_data_send(state,
916 : state->ev,
917 : state->cli,
918 : state->fname);
919 0 : if (tevent_req_nomem(subreq, req)) {
920 0 : return;
921 : }
922 0 : tevent_req_set_callback(subreq,
923 : cli_qpathinfo2_got_reparse,
924 : req);
925 0 : return;
926 : }
927 :
928 31 : tevent_req_done(req);
929 : }
930 :
931 0 : static void cli_qpathinfo2_got_reparse(struct tevent_req *subreq)
932 : {
933 0 : struct tevent_req *req =
934 0 : tevent_req_callback_data(subreq, struct tevent_req);
935 0 : struct cli_qpathinfo2_state *state =
936 0 : tevent_req_data(req, struct cli_qpathinfo2_state);
937 0 : uint8_t *data = NULL;
938 0 : uint32_t num_data;
939 0 : struct reparse_data_buffer reparse = {
940 : .tag = 0,
941 : };
942 0 : NTSTATUS status;
943 :
944 0 : status = cli_get_reparse_data_recv(subreq, state, &data, &num_data);
945 0 : TALLOC_FREE(subreq);
946 0 : if (tevent_req_nterror(req, status)) {
947 0 : return;
948 : }
949 :
950 0 : status = reparse_data_buffer_parse(state, &reparse, data, num_data);
951 0 : if (!NT_STATUS_IS_OK(status)) {
952 0 : DBG_DEBUG("Ignoring unknown reparse data\n");
953 0 : goto done;
954 : }
955 :
956 0 : switch (reparse.tag) {
957 0 : case IO_REPARSE_TAG_SYMLINK:
958 0 : state->mode = S_IFLNK;
959 0 : break;
960 0 : case IO_REPARSE_TAG_NFS:
961 0 : switch (reparse.parsed.nfs.type) {
962 0 : case NFS_SPECFILE_LNK:
963 0 : state->mode = S_IFLNK;
964 0 : break;
965 0 : case NFS_SPECFILE_CHR:
966 0 : state->mode = S_IFCHR;
967 0 : break;
968 0 : case NFS_SPECFILE_BLK:
969 0 : state->mode = S_IFBLK;
970 0 : break;
971 0 : case NFS_SPECFILE_FIFO:
972 0 : state->mode = S_IFIFO;
973 0 : break;
974 0 : case NFS_SPECFILE_SOCK:
975 0 : state->mode = S_IFSOCK;
976 0 : break;
977 : }
978 0 : break;
979 : }
980 0 : done:
981 0 : tevent_req_done(req);
982 : }
983 :
984 3057 : NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
985 : struct timespec *create_time,
986 : struct timespec *access_time,
987 : struct timespec *write_time,
988 : struct timespec *change_time,
989 : off_t *size,
990 : uint32_t *pattr,
991 : SMB_INO_T *ino,
992 : mode_t *mode)
993 : {
994 3057 : struct cli_qpathinfo2_state *state = tevent_req_data(
995 : req, struct cli_qpathinfo2_state);
996 0 : NTSTATUS status;
997 :
998 3057 : if (tevent_req_is_nterror(req, &status)) {
999 581 : return status;
1000 : }
1001 :
1002 2476 : if (create_time) {
1003 2476 : *create_time = state->create_time;
1004 : }
1005 2476 : if (access_time) {
1006 2468 : *access_time = state->access_time;
1007 : }
1008 2476 : if (write_time) {
1009 2468 : *write_time = state->write_time;
1010 : }
1011 2476 : if (change_time) {
1012 2468 : *change_time = state->change_time;
1013 : }
1014 2476 : if (pattr) {
1015 925 : *pattr = state->attr;
1016 : }
1017 2476 : if (size) {
1018 2468 : *size = state->size;
1019 : }
1020 2476 : if (ino) {
1021 25 : *ino = state->ino;
1022 : }
1023 2476 : if (mode != NULL) {
1024 16 : *mode = state->mode;
1025 : }
1026 2476 : return NT_STATUS_OK;
1027 : }
1028 :
1029 3057 : NTSTATUS cli_qpathinfo2(struct cli_state *cli,
1030 : const char *fname,
1031 : struct timespec *create_time,
1032 : struct timespec *access_time,
1033 : struct timespec *write_time,
1034 : struct timespec *change_time,
1035 : off_t *size,
1036 : uint32_t *pattr,
1037 : SMB_INO_T *ino,
1038 : mode_t *mode)
1039 : {
1040 3057 : TALLOC_CTX *frame = talloc_stackframe();
1041 3057 : struct tevent_context *ev = NULL;
1042 3057 : struct tevent_req *req = NULL;
1043 3057 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1044 :
1045 3057 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1046 : /*
1047 : * Can't use sync call while an async call is in flight
1048 : */
1049 0 : status = NT_STATUS_INVALID_PARAMETER;
1050 0 : goto fail;
1051 : }
1052 3057 : ev = samba_tevent_context_init(frame);
1053 3057 : if (ev == NULL) {
1054 0 : goto fail;
1055 : }
1056 3057 : req = cli_qpathinfo2_send(frame, ev, cli, fname);
1057 3057 : if (req == NULL) {
1058 0 : goto fail;
1059 : }
1060 3057 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1061 0 : goto fail;
1062 : }
1063 3057 : status = cli_qpathinfo2_recv(req,
1064 : create_time,
1065 : access_time,
1066 : write_time,
1067 : change_time,
1068 : size,
1069 : pattr,
1070 : ino,
1071 : mode);
1072 3057 : fail:
1073 3057 : TALLOC_FREE(frame);
1074 3057 : return status;
1075 : }
1076 :
1077 : /****************************************************************************
1078 : Get the stream info
1079 : ****************************************************************************/
1080 :
1081 : struct cli_qpathinfo_streams_state {
1082 : uint32_t num_data;
1083 : uint8_t *data;
1084 : };
1085 :
1086 : static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
1087 : static void cli_qpathinfo_streams_done2(struct tevent_req *subreq);
1088 :
1089 1681 : struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
1090 : struct tevent_context *ev,
1091 : struct cli_state *cli,
1092 : const char *fname)
1093 : {
1094 1681 : struct tevent_req *req = NULL, *subreq = NULL;
1095 1681 : struct cli_qpathinfo_streams_state *state = NULL;
1096 :
1097 1681 : req = tevent_req_create(mem_ctx, &state,
1098 : struct cli_qpathinfo_streams_state);
1099 1681 : if (req == NULL) {
1100 0 : return NULL;
1101 : }
1102 1681 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1103 909 : subreq = cli_smb2_qpathinfo_send(state,
1104 : ev,
1105 : cli,
1106 : fname,
1107 : FSCC_FILE_STREAM_INFORMATION,
1108 : 0,
1109 : CLI_BUFFER_SIZE);
1110 909 : if (tevent_req_nomem(subreq, req)) {
1111 0 : return tevent_req_post(req, ev);
1112 : }
1113 909 : tevent_req_set_callback(subreq,
1114 : cli_qpathinfo_streams_done2,
1115 : req);
1116 909 : return req;
1117 : }
1118 772 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
1119 : SMB_FILE_STREAM_INFORMATION,
1120 : 0, CLI_BUFFER_SIZE);
1121 772 : if (tevent_req_nomem(subreq, req)) {
1122 0 : return tevent_req_post(req, ev);
1123 : }
1124 772 : tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
1125 772 : return req;
1126 : }
1127 :
1128 772 : static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
1129 : {
1130 772 : struct tevent_req *req = tevent_req_callback_data(
1131 : subreq, struct tevent_req);
1132 772 : struct cli_qpathinfo_streams_state *state = tevent_req_data(
1133 : req, struct cli_qpathinfo_streams_state);
1134 0 : NTSTATUS status;
1135 :
1136 772 : status = cli_qpathinfo_recv(subreq, state, &state->data,
1137 : &state->num_data);
1138 772 : tevent_req_simple_finish_ntstatus(subreq, status);
1139 772 : }
1140 :
1141 909 : static void cli_qpathinfo_streams_done2(struct tevent_req *subreq)
1142 : {
1143 0 : struct tevent_req *req =
1144 909 : tevent_req_callback_data(subreq, struct tevent_req);
1145 0 : struct cli_qpathinfo_streams_state *state =
1146 909 : tevent_req_data(req, struct cli_qpathinfo_streams_state);
1147 0 : NTSTATUS status;
1148 :
1149 909 : status = cli_smb2_qpathinfo_recv(subreq,
1150 : state,
1151 : &state->data,
1152 : &state->num_data);
1153 909 : tevent_req_simple_finish_ntstatus(subreq, status);
1154 909 : }
1155 :
1156 1681 : NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
1157 : TALLOC_CTX *mem_ctx,
1158 : unsigned int *pnum_streams,
1159 : struct stream_struct **pstreams)
1160 : {
1161 1681 : struct cli_qpathinfo_streams_state *state = tevent_req_data(
1162 : req, struct cli_qpathinfo_streams_state);
1163 0 : NTSTATUS status;
1164 :
1165 1681 : if (tevent_req_is_nterror(req, &status)) {
1166 40 : return status;
1167 : }
1168 1641 : if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
1169 : pnum_streams, pstreams)) {
1170 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1171 : }
1172 1641 : return NT_STATUS_OK;
1173 : }
1174 :
1175 1681 : NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
1176 : TALLOC_CTX *mem_ctx,
1177 : unsigned int *pnum_streams,
1178 : struct stream_struct **pstreams)
1179 : {
1180 1681 : TALLOC_CTX *frame = NULL;
1181 0 : struct tevent_context *ev;
1182 0 : struct tevent_req *req;
1183 1681 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1184 :
1185 1681 : frame = talloc_stackframe();
1186 :
1187 1681 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1188 : /*
1189 : * Can't use sync call while an async call is in flight
1190 : */
1191 0 : status = NT_STATUS_INVALID_PARAMETER;
1192 0 : goto fail;
1193 : }
1194 1681 : ev = samba_tevent_context_init(frame);
1195 1681 : if (ev == NULL) {
1196 0 : goto fail;
1197 : }
1198 1681 : req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
1199 1681 : if (req == NULL) {
1200 0 : goto fail;
1201 : }
1202 1681 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1203 0 : goto fail;
1204 : }
1205 1681 : status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
1206 : pstreams);
1207 1681 : fail:
1208 1681 : TALLOC_FREE(frame);
1209 1681 : return status;
1210 : }
1211 :
1212 1641 : bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
1213 : size_t data_len,
1214 : unsigned int *pnum_streams,
1215 : struct stream_struct **pstreams)
1216 : {
1217 0 : unsigned int num_streams;
1218 0 : struct stream_struct *streams;
1219 0 : unsigned int ofs;
1220 :
1221 1641 : num_streams = 0;
1222 1641 : streams = NULL;
1223 1641 : ofs = 0;
1224 :
1225 1641 : while ((data_len > ofs) && (data_len - ofs >= 24)) {
1226 0 : uint32_t nlen, len;
1227 0 : size_t size;
1228 0 : void *vstr;
1229 0 : struct stream_struct *tmp;
1230 0 : uint8_t *tmp_buf;
1231 :
1232 1419 : tmp = talloc_realloc(mem_ctx, streams,
1233 : struct stream_struct,
1234 : num_streams+1);
1235 :
1236 1419 : if (tmp == NULL) {
1237 0 : goto fail;
1238 : }
1239 1419 : streams = tmp;
1240 :
1241 1419 : nlen = IVAL(rdata, ofs + 0x04);
1242 :
1243 1419 : streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1244 : rdata, ofs + 0x08);
1245 1419 : streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1246 : rdata, ofs + 0x10);
1247 :
1248 1419 : if (nlen > data_len - (ofs + 24)) {
1249 0 : goto fail;
1250 : }
1251 :
1252 : /*
1253 : * We need to null-terminate src, how do I do this with
1254 : * convert_string_talloc??
1255 : */
1256 :
1257 1419 : tmp_buf = talloc_array(streams, uint8_t, nlen+2);
1258 1419 : if (tmp_buf == NULL) {
1259 0 : goto fail;
1260 : }
1261 :
1262 1419 : memcpy(tmp_buf, rdata+ofs+24, nlen);
1263 1419 : tmp_buf[nlen] = 0;
1264 1419 : tmp_buf[nlen+1] = 0;
1265 :
1266 1419 : if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1267 1419 : nlen+2, &vstr, &size))
1268 : {
1269 0 : TALLOC_FREE(tmp_buf);
1270 0 : goto fail;
1271 : }
1272 :
1273 1419 : TALLOC_FREE(tmp_buf);
1274 1419 : streams[num_streams].name = (char *)vstr;
1275 1419 : num_streams++;
1276 :
1277 1419 : len = IVAL(rdata, ofs);
1278 1419 : if (len > data_len - ofs) {
1279 0 : goto fail;
1280 : }
1281 1419 : if (len == 0) break;
1282 0 : ofs += len;
1283 : }
1284 :
1285 1641 : *pnum_streams = num_streams;
1286 1641 : *pstreams = streams;
1287 1641 : return true;
1288 :
1289 0 : fail:
1290 0 : TALLOC_FREE(streams);
1291 0 : return false;
1292 : }
1293 :
1294 : /****************************************************************************
1295 : Send a qfileinfo QUERY_FILE_NAME_INFO call.
1296 : ****************************************************************************/
1297 :
1298 : struct cli_qfileinfo_basic_state {
1299 : uint32_t attr;
1300 : off_t size;
1301 : struct timespec create_time;
1302 : struct timespec access_time;
1303 : struct timespec write_time;
1304 : struct timespec change_time;
1305 : SMB_INO_T ino;
1306 : };
1307 :
1308 : static void cli_qfileinfo_basic_done(struct tevent_req *subreq);
1309 : static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq);
1310 :
1311 2262 : struct tevent_req *cli_qfileinfo_basic_send(
1312 : TALLOC_CTX *mem_ctx,
1313 : struct tevent_context *ev,
1314 : struct cli_state *cli,
1315 : uint16_t fnum)
1316 : {
1317 2262 : struct tevent_req *req = NULL, *subreq = NULL;
1318 2262 : struct cli_qfileinfo_basic_state *state = NULL;
1319 :
1320 2262 : req = tevent_req_create(
1321 : mem_ctx, &state, struct cli_qfileinfo_basic_state);
1322 2262 : if (req == NULL) {
1323 0 : return NULL;
1324 : }
1325 :
1326 2262 : if ((smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN2) ||
1327 2262 : cli->win95) {
1328 : /*
1329 : * According to
1330 : * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/3d9d8f3e-dc70-410d-a3fc-6f4a881e8cab
1331 : * SMB_COM_TRANSACTION2 used in cli_qfileinfo_send()
1332 : * further down was introduced with the LAN Manager
1333 : * 1.2 dialect, which we encode as PROTOCOL_LANMAN2.
1334 : *
1335 : * The "win95" check was introduced with commit
1336 : * 27e5850fd3e1c8 in 1998. Hard to check these days,
1337 : * but leave it in.
1338 : *
1339 : * Use a lowerlevel fallback in both cases.
1340 : */
1341 :
1342 0 : subreq = cli_getattrE_send(state, ev, cli, fnum);
1343 0 : if (tevent_req_nomem(subreq, req)) {
1344 0 : return tevent_req_post(req, ev);
1345 : }
1346 0 : tevent_req_set_callback(
1347 : subreq, cli_qfileinfo_basic_doneE, req);
1348 0 : return req;
1349 : }
1350 :
1351 2262 : subreq = cli_qfileinfo_send(state,
1352 : ev,
1353 : cli,
1354 : fnum,
1355 : FSCC_FILE_ALL_INFORMATION, /* level */
1356 : 68, /* min_rdata */
1357 : CLI_BUFFER_SIZE); /* max_rdata */
1358 2262 : if (tevent_req_nomem(subreq, req)) {
1359 0 : return tevent_req_post(req, ev);
1360 : }
1361 2262 : tevent_req_set_callback(subreq, cli_qfileinfo_basic_done, req);
1362 2262 : return req;
1363 : }
1364 :
1365 2262 : static void cli_qfileinfo_basic_done(struct tevent_req *subreq)
1366 : {
1367 2262 : struct tevent_req *req = tevent_req_callback_data(
1368 : subreq, struct tevent_req);
1369 2262 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1370 : req, struct cli_qfileinfo_basic_state);
1371 0 : uint8_t *rdata;
1372 0 : uint32_t num_rdata;
1373 0 : NTSTATUS status;
1374 :
1375 2262 : status = cli_qfileinfo_recv(
1376 : subreq, state, NULL, &rdata, &num_rdata);
1377 2262 : TALLOC_FREE(subreq);
1378 2262 : if (tevent_req_nterror(req, status)) {
1379 0 : return;
1380 : }
1381 :
1382 2262 : state->create_time = interpret_long_date(BVAL(rdata, 0));
1383 2262 : state->access_time = interpret_long_date(BVAL(rdata, 8));
1384 2262 : state->write_time = interpret_long_date(BVAL(rdata, 16));
1385 2262 : state->change_time = interpret_long_date(BVAL(rdata, 24));
1386 2262 : state->attr = PULL_LE_U32(rdata, 32);
1387 2262 : state->size = PULL_LE_U64(rdata,48);
1388 2262 : state->ino = PULL_LE_U32(rdata, 64);
1389 2262 : TALLOC_FREE(rdata);
1390 :
1391 2262 : tevent_req_done(req);
1392 : }
1393 :
1394 0 : static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq)
1395 : {
1396 0 : struct tevent_req *req = tevent_req_callback_data(
1397 : subreq, struct tevent_req);
1398 0 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1399 : req, struct cli_qfileinfo_basic_state);
1400 0 : NTSTATUS status;
1401 :
1402 0 : status = cli_getattrE_recv(
1403 : subreq,
1404 : &state->attr,
1405 : &state->size,
1406 0 : &state->change_time.tv_sec,
1407 0 : &state->access_time.tv_sec,
1408 0 : &state->write_time.tv_sec);
1409 0 : TALLOC_FREE(subreq);
1410 0 : if (tevent_req_nterror(req, status)) {
1411 0 : return;
1412 : }
1413 0 : tevent_req_done(req);
1414 : }
1415 :
1416 2262 : NTSTATUS cli_qfileinfo_basic_recv(
1417 : struct tevent_req *req,
1418 : uint32_t *attr,
1419 : off_t *size,
1420 : struct timespec *create_time,
1421 : struct timespec *access_time,
1422 : struct timespec *write_time,
1423 : struct timespec *change_time,
1424 : SMB_INO_T *ino)
1425 : {
1426 2262 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1427 : req, struct cli_qfileinfo_basic_state);
1428 0 : NTSTATUS status;
1429 :
1430 2262 : if (tevent_req_is_nterror(req, &status)) {
1431 0 : return status;
1432 : }
1433 :
1434 2262 : if (create_time != NULL) {
1435 39 : *create_time = state->create_time;
1436 : }
1437 2262 : if (access_time != NULL) {
1438 73 : *access_time = state->access_time;
1439 : }
1440 2262 : if (write_time != NULL) {
1441 73 : *write_time = state->write_time;
1442 : }
1443 2262 : if (change_time != NULL) {
1444 73 : *change_time = state->change_time;
1445 : }
1446 2262 : if (attr != NULL) {
1447 814 : *attr = state->attr;
1448 : }
1449 2262 : if (size != NULL) {
1450 2228 : *size = state->size;
1451 : }
1452 2262 : if (ino) {
1453 68 : *ino = state->ino;
1454 : }
1455 :
1456 2262 : return NT_STATUS_OK;
1457 : }
1458 : /****************************************************************************
1459 : Send a qfileinfo call.
1460 : ****************************************************************************/
1461 :
1462 940 : NTSTATUS cli_qfileinfo_basic(
1463 : struct cli_state *cli,
1464 : uint16_t fnum,
1465 : uint32_t *attr,
1466 : off_t *size,
1467 : struct timespec *create_time,
1468 : struct timespec *access_time,
1469 : struct timespec *write_time,
1470 : struct timespec *change_time,
1471 : SMB_INO_T *ino)
1472 : {
1473 940 : TALLOC_CTX *frame = NULL;
1474 940 : struct tevent_context *ev = NULL;
1475 940 : struct tevent_req *req = NULL;
1476 940 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1477 :
1478 940 : frame = talloc_stackframe();
1479 :
1480 940 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1481 : /*
1482 : * Can't use sync call while an async call is in flight
1483 : */
1484 0 : status = NT_STATUS_INVALID_PARAMETER;
1485 0 : goto fail;
1486 : }
1487 940 : ev = samba_tevent_context_init(frame);
1488 940 : if (ev == NULL) {
1489 0 : goto fail;
1490 : }
1491 940 : req = cli_qfileinfo_basic_send(frame, ev, cli, fnum);
1492 940 : if (req == NULL) {
1493 0 : goto fail;
1494 : }
1495 940 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1496 0 : goto fail;
1497 : }
1498 :
1499 940 : status = cli_qfileinfo_basic_recv(
1500 : req,
1501 : attr,
1502 : size,
1503 : create_time,
1504 : access_time,
1505 : write_time,
1506 : change_time,
1507 : ino);
1508 :
1509 : /* cli_smb2_query_info_fnum_recv doesn't set this */
1510 940 : cli->raw_status = status;
1511 940 : fail:
1512 940 : TALLOC_FREE(frame);
1513 940 : return status;
1514 : }
1515 :
1516 : /****************************************************************************
1517 : Send a qpathinfo BASIC_INFO call.
1518 : ****************************************************************************/
1519 :
1520 : struct cli_qpathinfo_basic_state {
1521 : uint32_t num_data;
1522 : uint8_t *data;
1523 : };
1524 :
1525 : static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1526 :
1527 4224 : struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1528 : struct tevent_context *ev,
1529 : struct cli_state *cli,
1530 : const char *fname)
1531 : {
1532 4224 : struct tevent_req *req = NULL, *subreq = NULL;
1533 4224 : struct cli_qpathinfo_basic_state *state = NULL;
1534 :
1535 4224 : req = tevent_req_create(mem_ctx, &state,
1536 : struct cli_qpathinfo_basic_state);
1537 4224 : if (req == NULL) {
1538 0 : return NULL;
1539 : }
1540 4224 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
1541 : SMB_QUERY_FILE_BASIC_INFO,
1542 : 36, CLI_BUFFER_SIZE);
1543 4224 : if (tevent_req_nomem(subreq, req)) {
1544 0 : return tevent_req_post(req, ev);
1545 : }
1546 4224 : tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1547 4224 : return req;
1548 : }
1549 :
1550 4224 : static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1551 : {
1552 4224 : struct tevent_req *req = tevent_req_callback_data(
1553 : subreq, struct tevent_req);
1554 4224 : struct cli_qpathinfo_basic_state *state = tevent_req_data(
1555 : req, struct cli_qpathinfo_basic_state);
1556 0 : NTSTATUS status;
1557 :
1558 4224 : status = cli_qpathinfo_recv(subreq, state, &state->data,
1559 : &state->num_data);
1560 4224 : TALLOC_FREE(subreq);
1561 4224 : if (tevent_req_nterror(req, status)) {
1562 1816 : return;
1563 : }
1564 2408 : tevent_req_done(req);
1565 : }
1566 :
1567 4224 : NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1568 : SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1569 : {
1570 4224 : struct cli_qpathinfo_basic_state *state = tevent_req_data(
1571 : req, struct cli_qpathinfo_basic_state);
1572 0 : NTSTATUS status;
1573 :
1574 4224 : if (tevent_req_is_nterror(req, &status)) {
1575 1816 : return status;
1576 : }
1577 :
1578 2408 : sbuf->st_ex_btime = interpret_long_date(BVAL(state->data, 0));
1579 2408 : sbuf->st_ex_atime = interpret_long_date(BVAL(state->data, 8));
1580 2408 : sbuf->st_ex_mtime = interpret_long_date(BVAL(state->data, 16));
1581 2408 : sbuf->st_ex_ctime = interpret_long_date(BVAL(state->data, 24));
1582 2408 : *attributes = IVAL(state->data, 32);
1583 2408 : return NT_STATUS_OK;
1584 : }
1585 :
1586 11172 : NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1587 : SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1588 : {
1589 11172 : TALLOC_CTX *frame = NULL;
1590 0 : struct tevent_context *ev;
1591 0 : struct tevent_req *req;
1592 11172 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1593 :
1594 11172 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1595 6948 : return cli_smb2_qpathinfo_basic(cli,
1596 : name,
1597 : sbuf,
1598 : attributes);
1599 : }
1600 :
1601 4224 : frame = talloc_stackframe();
1602 :
1603 4224 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1604 : /*
1605 : * Can't use sync call while an async call is in flight
1606 : */
1607 0 : status = NT_STATUS_INVALID_PARAMETER;
1608 0 : goto fail;
1609 : }
1610 4224 : ev = samba_tevent_context_init(frame);
1611 4224 : if (ev == NULL) {
1612 0 : goto fail;
1613 : }
1614 4224 : req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1615 4224 : if (req == NULL) {
1616 0 : goto fail;
1617 : }
1618 4224 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1619 0 : goto fail;
1620 : }
1621 4224 : status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1622 4224 : fail:
1623 4224 : TALLOC_FREE(frame);
1624 4224 : return status;
1625 : }
1626 :
1627 : /****************************************************************************
1628 : Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1629 : ****************************************************************************/
1630 :
1631 1737 : NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1632 : {
1633 0 : uint8_t *rdata;
1634 0 : uint32_t num_rdata;
1635 0 : unsigned int len;
1636 1737 : char *converted = NULL;
1637 1737 : size_t converted_size = 0;
1638 0 : NTSTATUS status;
1639 :
1640 1737 : status = cli_qpathinfo(talloc_tos(), cli, fname,
1641 : SMB_QUERY_FILE_ALT_NAME_INFO,
1642 : 4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1643 1737 : if (!NT_STATUS_IS_OK(status)) {
1644 56 : return status;
1645 : }
1646 :
1647 1681 : len = IVAL(rdata, 0);
1648 :
1649 1681 : if (len > num_rdata - 4) {
1650 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1651 : }
1652 :
1653 : /* The returned data is a pushed string, not raw data. */
1654 1681 : if (!convert_string_talloc(talloc_tos(),
1655 1681 : smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
1656 : CH_UNIX,
1657 1681 : rdata + 4,
1658 : len,
1659 : &converted,
1660 : &converted_size)) {
1661 0 : return NT_STATUS_NO_MEMORY;
1662 : }
1663 1681 : fstrcpy(alt_name, converted);
1664 :
1665 1681 : TALLOC_FREE(converted);
1666 1681 : TALLOC_FREE(rdata);
1667 :
1668 1681 : return NT_STATUS_OK;
1669 : }
1670 :
1671 : /****************************************************************************
1672 : Send a qpathinfo SMB_QUERY_FILE_STANDARD_INFO call.
1673 : ****************************************************************************/
1674 :
1675 2300 : NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname,
1676 : uint64_t *allocated, uint64_t *size,
1677 : uint32_t *nlinks,
1678 : bool *is_del_pending, bool *is_dir)
1679 : {
1680 0 : uint8_t *rdata;
1681 0 : uint32_t num_rdata;
1682 0 : NTSTATUS status;
1683 :
1684 2300 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1685 0 : return NT_STATUS_NOT_IMPLEMENTED;
1686 : }
1687 :
1688 2300 : status = cli_qpathinfo(talloc_tos(), cli, fname,
1689 : SMB_QUERY_FILE_STANDARD_INFO,
1690 : 24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1691 2300 : if (!NT_STATUS_IS_OK(status)) {
1692 0 : return status;
1693 : }
1694 :
1695 2300 : if (allocated) {
1696 0 : *allocated = BVAL(rdata, 0);
1697 : }
1698 :
1699 2300 : if (size) {
1700 2300 : *size = BVAL(rdata, 8);
1701 : }
1702 :
1703 2300 : if (nlinks) {
1704 0 : *nlinks = IVAL(rdata, 16);
1705 : }
1706 :
1707 2300 : if (is_del_pending) {
1708 0 : *is_del_pending = CVAL(rdata, 20);
1709 : }
1710 :
1711 2300 : if (is_dir) {
1712 0 : *is_dir = CVAL(rdata, 20);
1713 : }
1714 :
1715 2300 : TALLOC_FREE(rdata);
1716 :
1717 2300 : return NT_STATUS_OK;
1718 : }
1719 :
1720 :
1721 : /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
1722 5890 : NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
1723 : struct timespec *create_time,
1724 : struct timespec *access_time,
1725 : struct timespec *write_time,
1726 : struct timespec *change_time,
1727 : off_t *size, uint32_t *pattr,
1728 : SMB_INO_T *ino)
1729 : {
1730 5890 : NTSTATUS status = NT_STATUS_OK;
1731 5890 : SMB_STRUCT_STAT st = { 0 };
1732 5890 : uint32_t attr = 0;
1733 0 : uint64_t pos;
1734 :
1735 5890 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1736 : /*
1737 : * NB. cli_qpathinfo2() checks pattr is valid before
1738 : * storing a value into it, so we don't need to use
1739 : * an intermediate attr variable as below but can
1740 : * pass pattr directly.
1741 : */
1742 3014 : return cli_qpathinfo2(cli,
1743 : fname,
1744 : create_time,
1745 : access_time,
1746 : write_time,
1747 : change_time,
1748 : size,
1749 : pattr,
1750 : ino,
1751 : NULL);
1752 : }
1753 :
1754 2876 : if (create_time || access_time || write_time || change_time || pattr) {
1755 : /*
1756 : * cli_qpathinfo_basic() always indirects the passed
1757 : * in pointers so we use intermediate variables to
1758 : * collect all of them before assigning any requested
1759 : * below.
1760 : */
1761 2876 : status = cli_qpathinfo_basic(cli, fname, &st, &attr);
1762 2876 : if (!NT_STATUS_IS_OK(status)) {
1763 576 : return status;
1764 : }
1765 : }
1766 :
1767 2300 : if (size) {
1768 2300 : status = cli_qpathinfo_standard(cli, fname,
1769 : NULL, &pos, NULL, NULL, NULL);
1770 2300 : if (!NT_STATUS_IS_OK(status)) {
1771 0 : return status;
1772 : }
1773 :
1774 2300 : *size = pos;
1775 : }
1776 :
1777 2300 : if (create_time) {
1778 2300 : *create_time = st.st_ex_btime;
1779 : }
1780 2300 : if (access_time) {
1781 2300 : *access_time = st.st_ex_atime;
1782 : }
1783 2300 : if (write_time) {
1784 2300 : *write_time = st.st_ex_mtime;
1785 : }
1786 2300 : if (change_time) {
1787 2300 : *change_time = st.st_ex_ctime;
1788 : }
1789 2300 : if (pattr) {
1790 772 : *pattr = attr;
1791 : }
1792 2300 : if (ino) {
1793 0 : *ino = 0;
1794 : }
1795 :
1796 2300 : return NT_STATUS_OK;
1797 : }
|