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 57 : 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 57 : 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 57 : 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 51 : *rparam = (char *)smb_memdup(my_rparam, num_my_rparam);
76 51 : if (*rparam == NULL) {
77 0 : goto fail;
78 : }
79 51 : *rprcnt = num_my_rparam;
80 51 : TALLOC_FREE(my_rparam);
81 :
82 51 : *rdata = (char *)smb_memdup(my_rdata, num_my_rdata);
83 51 : if (*rdata == NULL) {
84 14 : goto fail;
85 : }
86 37 : *rdrcnt = num_my_rdata;
87 37 : TALLOC_FREE(my_rdata);
88 :
89 37 : return true;
90 14 : fail:
91 14 : TALLOC_FREE(my_rdata);
92 14 : TALLOC_FREE(my_rparam);
93 14 : *rparam = NULL;
94 14 : *rprcnt = 0;
95 14 : *rdata = NULL;
96 14 : *rdrcnt = 0;
97 14 : 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 53 : 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 53 : char *rparam = NULL;
226 53 : char *rdata = NULL;
227 53 : char *rdata_end = NULL;
228 0 : unsigned int rdrcnt,rprcnt;
229 0 : char *p;
230 0 : char param[1024];
231 53 : int uLevel = 1;
232 0 : size_t len;
233 53 : uint32_t func = RAP_NetServerEnum2;
234 53 : char *last_entry = NULL;
235 53 : int total_cnt = 0;
236 53 : int return_cnt = 0;
237 0 : int res;
238 :
239 53 : 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 53 : p = param;
249 53 : SIVAL(p,0,func); /* api number */
250 53 : p += 2;
251 :
252 53 : if (func == RAP_NetServerEnum3) {
253 0 : strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
254 : } else {
255 53 : strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
256 : }
257 :
258 53 : p = skip_string(param, sizeof(param), p);
259 53 : strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
260 :
261 53 : p = skip_string(param, sizeof(param), p);
262 53 : SSVAL(p,0,uLevel);
263 53 : SSVAL(p,2,CLI_BUFFER_SIZE);
264 53 : p += 4;
265 53 : SIVAL(p,0,stype);
266 53 : p += 4;
267 :
268 : /* If we have more data, tell the server where
269 : * to continue from.
270 : */
271 53 : len = push_ascii(p,
272 : workgroup,
273 53 : sizeof(param) - PTR_DIFF(p,param) - 1,
274 : STR_TERMINATE|STR_UPPER);
275 :
276 53 : if (len == 0) {
277 0 : SAFE_FREE(last_entry);
278 0 : return false;
279 : }
280 53 : p += len;
281 :
282 53 : 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 53 : func = RAP_NetServerEnum3;
297 :
298 53 : if (!cli_api(cli,
299 53 : 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 16 : res = -1;
306 16 : break;
307 : }
308 :
309 37 : rdata_end = rdata + rdrcnt;
310 :
311 37 : if (rprcnt < 6) {
312 0 : DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
313 0 : res = -1;
314 0 : break;
315 : }
316 :
317 37 : res = rparam ? SVAL(rparam,0) : -1;
318 :
319 37 : if (res == 0 || res == ERRmoredata ||
320 0 : (res != -1 && cli_errno(cli) == 0)) {
321 37 : char *sname = NULL;
322 0 : int i, count;
323 37 : int converter=SVAL(rparam,2);
324 :
325 : /* Get the number of items returned in this buffer */
326 37 : 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 37 : if (total_cnt == 0) {
334 37 : total_cnt = SVAL(rparam, 6);
335 : }
336 :
337 : /* Keep track of how many we have read */
338 37 : return_cnt += count;
339 37 : 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 37 : 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 115 : 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 78 : TALLOC_CTX *frame = talloc_stackframe();
366 0 : uint32_t entry_stype;
367 :
368 78 : if (p + 26 > rdata_end) {
369 0 : TALLOC_FREE(frame);
370 0 : break;
371 : }
372 :
373 78 : sname = p;
374 78 : comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
375 78 : cmnt = comment_offset?(rdata+comment_offset):"";
376 :
377 78 : 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 1291 : for (p1 = cmnt, len = 0; *p1 &&
384 1213 : p1 < rdata_end; len++)
385 1213 : p1++;
386 78 : if (!*p1) {
387 78 : len++;
388 : }
389 :
390 78 : entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
391 :
392 78 : pull_string_talloc(frame,rdata,0,
393 : &s1,sname,16,STR_ASCII);
394 78 : pull_string_talloc(frame,rdata,0,
395 : &s2,cmnt,len,STR_ASCII);
396 :
397 78 : if (!s1 || !s2) {
398 0 : TALLOC_FREE(frame);
399 0 : continue;
400 : }
401 :
402 78 : fn(s1, entry_stype, s2, state);
403 78 : TALLOC_FREE(frame);
404 : }
405 :
406 : /* We are done with the old last entry, so now we can free it */
407 37 : 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 37 : if (sname) {
413 37 : last_entry = smb_xstrdup(sname);
414 : }
415 :
416 : /* If we have more data, but no last entry then error out */
417 37 : if (!last_entry && (res == ERRmoredata)) {
418 0 : errno = EINVAL;
419 0 : res = 0;
420 : }
421 :
422 : }
423 :
424 37 : SAFE_FREE(rparam);
425 37 : SAFE_FREE(rdata);
426 37 : } while ((res == ERRmoredata) && (total_cnt > return_cnt));
427 :
428 53 : SAFE_FREE(rparam);
429 53 : SAFE_FREE(rdata);
430 53 : SAFE_FREE(last_entry);
431 :
432 53 : if (res == -1) {
433 16 : errno = cli_errno(cli);
434 : } else {
435 37 : 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 53 : 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 : 1, /* SMB2_SETINFO_FILE */
630 : SMB_FILE_BASIC_INFORMATION - 1000,
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 : SMB_FILE_BASIC_INFORMATION - 1000,
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 : static void cli_qfileinfo_basic_done2(struct tevent_req *subreq);
1311 :
1312 2262 : struct tevent_req *cli_qfileinfo_basic_send(
1313 : TALLOC_CTX *mem_ctx,
1314 : struct tevent_context *ev,
1315 : struct cli_state *cli,
1316 : uint16_t fnum)
1317 : {
1318 2262 : struct tevent_req *req = NULL, *subreq = NULL;
1319 2262 : struct cli_qfileinfo_basic_state *state = NULL;
1320 :
1321 2262 : req = tevent_req_create(
1322 : mem_ctx, &state, struct cli_qfileinfo_basic_state);
1323 2262 : if (req == NULL) {
1324 0 : return NULL;
1325 : }
1326 :
1327 2262 : if ((smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN2) ||
1328 2262 : cli->win95) {
1329 : /*
1330 : * According to
1331 : * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/3d9d8f3e-dc70-410d-a3fc-6f4a881e8cab
1332 : * SMB_COM_TRANSACTION2 used in cli_qfileinfo_send()
1333 : * further down was introduced with the LAN Manager
1334 : * 1.2 dialect, which we encode as PROTOCOL_LANMAN2.
1335 : *
1336 : * The "win95" check was introduced with commit
1337 : * 27e5850fd3e1c8 in 1998. Hard to check these days,
1338 : * but leave it in.
1339 : *
1340 : * Use a lowerlevel fallback in both cases.
1341 : */
1342 :
1343 0 : subreq = cli_getattrE_send(state, ev, cli, fnum);
1344 0 : if (tevent_req_nomem(subreq, req)) {
1345 0 : return tevent_req_post(req, ev);
1346 : }
1347 0 : tevent_req_set_callback(
1348 : subreq, cli_qfileinfo_basic_doneE, req);
1349 0 : return req;
1350 : }
1351 :
1352 2262 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1353 1829 : subreq = cli_smb2_query_info_fnum_send(
1354 : state, /* mem_ctx */
1355 : ev, /* ev */
1356 : cli, /* cli */
1357 : fnum, /* fnum */
1358 : 1, /* in_info_type */
1359 : (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1360 : 0xFFFF, /* in_max_output_length */
1361 : NULL, /* in_input_buffer */
1362 : 0, /* in_additional_info */
1363 : 0); /* in_flags */
1364 1829 : if (tevent_req_nomem(subreq, req)) {
1365 0 : return tevent_req_post(req, ev);
1366 : }
1367 1829 : tevent_req_set_callback(
1368 : subreq, cli_qfileinfo_basic_done2, req);
1369 1829 : return req;
1370 : }
1371 :
1372 433 : subreq = cli_qfileinfo_send(
1373 : state,
1374 : ev,
1375 : cli,
1376 : fnum,
1377 : SMB_QUERY_FILE_ALL_INFO, /* level */
1378 : 68, /* min_rdata */
1379 : CLI_BUFFER_SIZE); /* max_rdata */
1380 433 : if (tevent_req_nomem(subreq, req)) {
1381 0 : return tevent_req_post(req, ev);
1382 : }
1383 433 : tevent_req_set_callback(subreq, cli_qfileinfo_basic_done, req);
1384 433 : return req;
1385 : }
1386 :
1387 433 : static void cli_qfileinfo_basic_done(struct tevent_req *subreq)
1388 : {
1389 433 : struct tevent_req *req = tevent_req_callback_data(
1390 : subreq, struct tevent_req);
1391 433 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1392 : req, struct cli_qfileinfo_basic_state);
1393 0 : uint8_t *rdata;
1394 0 : uint32_t num_rdata;
1395 0 : NTSTATUS status;
1396 :
1397 433 : status = cli_qfileinfo_recv(
1398 : subreq, state, NULL, &rdata, &num_rdata);
1399 433 : TALLOC_FREE(subreq);
1400 433 : if (tevent_req_nterror(req, status)) {
1401 0 : return;
1402 : }
1403 :
1404 433 : state->create_time = interpret_long_date(BVAL(rdata, 0));
1405 433 : state->access_time = interpret_long_date(BVAL(rdata, 8));
1406 433 : state->write_time = interpret_long_date(BVAL(rdata, 16));
1407 433 : state->change_time = interpret_long_date(BVAL(rdata, 24));
1408 433 : state->attr = PULL_LE_U32(rdata, 32);
1409 433 : state->size = PULL_LE_U64(rdata,48);
1410 433 : state->ino = PULL_LE_U32(rdata, 64);
1411 433 : TALLOC_FREE(rdata);
1412 :
1413 433 : tevent_req_done(req);
1414 : }
1415 :
1416 0 : static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq)
1417 : {
1418 0 : struct tevent_req *req = tevent_req_callback_data(
1419 : subreq, struct tevent_req);
1420 0 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1421 : req, struct cli_qfileinfo_basic_state);
1422 0 : NTSTATUS status;
1423 :
1424 0 : status = cli_getattrE_recv(
1425 : subreq,
1426 : &state->attr,
1427 : &state->size,
1428 0 : &state->change_time.tv_sec,
1429 0 : &state->access_time.tv_sec,
1430 0 : &state->write_time.tv_sec);
1431 0 : TALLOC_FREE(subreq);
1432 0 : if (tevent_req_nterror(req, status)) {
1433 0 : return;
1434 : }
1435 0 : tevent_req_done(req);
1436 : }
1437 :
1438 1829 : static void cli_qfileinfo_basic_done2(struct tevent_req *subreq)
1439 : {
1440 1829 : struct tevent_req *req = tevent_req_callback_data(
1441 : subreq, struct tevent_req);
1442 1829 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1443 : req, struct cli_qfileinfo_basic_state);
1444 1829 : DATA_BLOB outbuf = {0};
1445 0 : NTSTATUS status;
1446 :
1447 1829 : status = cli_smb2_query_info_fnum_recv(subreq, state, &outbuf);
1448 1829 : TALLOC_FREE(subreq);
1449 1829 : if (tevent_req_nterror(req, status)) {
1450 0 : return;
1451 : }
1452 :
1453 : /* Parse the reply. */
1454 1829 : if (outbuf.length < 0x60) {
1455 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1456 0 : return;
1457 : }
1458 :
1459 1829 : state->create_time = interpret_long_date(BVAL(outbuf.data, 0x0));
1460 1829 : state->access_time = interpret_long_date(BVAL(outbuf.data, 0x8));
1461 1829 : state->write_time = interpret_long_date(BVAL(outbuf.data, 0x10));
1462 1829 : state->change_time = interpret_long_date(BVAL(outbuf.data, 0x18));
1463 1829 : state->attr = IVAL(outbuf.data, 0x20);
1464 1829 : state->size = BVAL(outbuf.data, 0x30);
1465 1829 : state->ino = BVAL(outbuf.data, 0x40);
1466 :
1467 1829 : data_blob_free(&outbuf);
1468 :
1469 1829 : tevent_req_done(req);
1470 : }
1471 :
1472 2262 : NTSTATUS cli_qfileinfo_basic_recv(
1473 : struct tevent_req *req,
1474 : uint32_t *attr,
1475 : off_t *size,
1476 : struct timespec *create_time,
1477 : struct timespec *access_time,
1478 : struct timespec *write_time,
1479 : struct timespec *change_time,
1480 : SMB_INO_T *ino)
1481 : {
1482 2262 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1483 : req, struct cli_qfileinfo_basic_state);
1484 0 : NTSTATUS status;
1485 :
1486 2262 : if (tevent_req_is_nterror(req, &status)) {
1487 0 : return status;
1488 : }
1489 :
1490 2262 : if (create_time != NULL) {
1491 39 : *create_time = state->create_time;
1492 : }
1493 2262 : if (access_time != NULL) {
1494 73 : *access_time = state->access_time;
1495 : }
1496 2262 : if (write_time != NULL) {
1497 73 : *write_time = state->write_time;
1498 : }
1499 2262 : if (change_time != NULL) {
1500 73 : *change_time = state->change_time;
1501 : }
1502 2262 : if (attr != NULL) {
1503 814 : *attr = state->attr;
1504 : }
1505 2262 : if (size != NULL) {
1506 2228 : *size = state->size;
1507 : }
1508 2262 : if (ino) {
1509 68 : *ino = state->ino;
1510 : }
1511 :
1512 2262 : return NT_STATUS_OK;
1513 : }
1514 : /****************************************************************************
1515 : Send a qfileinfo call.
1516 : ****************************************************************************/
1517 :
1518 940 : NTSTATUS cli_qfileinfo_basic(
1519 : struct cli_state *cli,
1520 : uint16_t fnum,
1521 : uint32_t *attr,
1522 : off_t *size,
1523 : struct timespec *create_time,
1524 : struct timespec *access_time,
1525 : struct timespec *write_time,
1526 : struct timespec *change_time,
1527 : SMB_INO_T *ino)
1528 : {
1529 940 : TALLOC_CTX *frame = NULL;
1530 940 : struct tevent_context *ev = NULL;
1531 940 : struct tevent_req *req = NULL;
1532 940 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1533 :
1534 940 : frame = talloc_stackframe();
1535 :
1536 940 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1537 : /*
1538 : * Can't use sync call while an async call is in flight
1539 : */
1540 0 : status = NT_STATUS_INVALID_PARAMETER;
1541 0 : goto fail;
1542 : }
1543 940 : ev = samba_tevent_context_init(frame);
1544 940 : if (ev == NULL) {
1545 0 : goto fail;
1546 : }
1547 940 : req = cli_qfileinfo_basic_send(frame, ev, cli, fnum);
1548 940 : if (req == NULL) {
1549 0 : goto fail;
1550 : }
1551 940 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1552 0 : goto fail;
1553 : }
1554 :
1555 940 : status = cli_qfileinfo_basic_recv(
1556 : req,
1557 : attr,
1558 : size,
1559 : create_time,
1560 : access_time,
1561 : write_time,
1562 : change_time,
1563 : ino);
1564 :
1565 : /* cli_smb2_query_info_fnum_recv doesn't set this */
1566 940 : cli->raw_status = status;
1567 940 : fail:
1568 940 : TALLOC_FREE(frame);
1569 940 : return status;
1570 : }
1571 :
1572 : /****************************************************************************
1573 : Send a qpathinfo BASIC_INFO call.
1574 : ****************************************************************************/
1575 :
1576 : struct cli_qpathinfo_basic_state {
1577 : uint32_t num_data;
1578 : uint8_t *data;
1579 : };
1580 :
1581 : static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1582 :
1583 4216 : struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1584 : struct tevent_context *ev,
1585 : struct cli_state *cli,
1586 : const char *fname)
1587 : {
1588 4216 : struct tevent_req *req = NULL, *subreq = NULL;
1589 4216 : struct cli_qpathinfo_basic_state *state = NULL;
1590 :
1591 4216 : req = tevent_req_create(mem_ctx, &state,
1592 : struct cli_qpathinfo_basic_state);
1593 4216 : if (req == NULL) {
1594 0 : return NULL;
1595 : }
1596 4216 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
1597 : SMB_QUERY_FILE_BASIC_INFO,
1598 : 36, CLI_BUFFER_SIZE);
1599 4216 : if (tevent_req_nomem(subreq, req)) {
1600 0 : return tevent_req_post(req, ev);
1601 : }
1602 4216 : tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1603 4216 : return req;
1604 : }
1605 :
1606 4216 : static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1607 : {
1608 4216 : struct tevent_req *req = tevent_req_callback_data(
1609 : subreq, struct tevent_req);
1610 4216 : struct cli_qpathinfo_basic_state *state = tevent_req_data(
1611 : req, struct cli_qpathinfo_basic_state);
1612 0 : NTSTATUS status;
1613 :
1614 4216 : status = cli_qpathinfo_recv(subreq, state, &state->data,
1615 : &state->num_data);
1616 4216 : TALLOC_FREE(subreq);
1617 4216 : if (tevent_req_nterror(req, status)) {
1618 1808 : return;
1619 : }
1620 2408 : tevent_req_done(req);
1621 : }
1622 :
1623 4216 : NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1624 : SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1625 : {
1626 4216 : struct cli_qpathinfo_basic_state *state = tevent_req_data(
1627 : req, struct cli_qpathinfo_basic_state);
1628 0 : NTSTATUS status;
1629 :
1630 4216 : if (tevent_req_is_nterror(req, &status)) {
1631 1808 : return status;
1632 : }
1633 :
1634 2408 : sbuf->st_ex_btime = interpret_long_date(BVAL(state->data, 0));
1635 2408 : sbuf->st_ex_atime = interpret_long_date(BVAL(state->data, 8));
1636 2408 : sbuf->st_ex_mtime = interpret_long_date(BVAL(state->data, 16));
1637 2408 : sbuf->st_ex_ctime = interpret_long_date(BVAL(state->data, 24));
1638 2408 : *attributes = IVAL(state->data, 32);
1639 2408 : return NT_STATUS_OK;
1640 : }
1641 :
1642 10818 : NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1643 : SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1644 : {
1645 10818 : TALLOC_CTX *frame = NULL;
1646 0 : struct tevent_context *ev;
1647 0 : struct tevent_req *req;
1648 10818 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1649 :
1650 10818 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1651 6602 : return cli_smb2_qpathinfo_basic(cli,
1652 : name,
1653 : sbuf,
1654 : attributes);
1655 : }
1656 :
1657 4216 : frame = talloc_stackframe();
1658 :
1659 4216 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1660 : /*
1661 : * Can't use sync call while an async call is in flight
1662 : */
1663 0 : status = NT_STATUS_INVALID_PARAMETER;
1664 0 : goto fail;
1665 : }
1666 4216 : ev = samba_tevent_context_init(frame);
1667 4216 : if (ev == NULL) {
1668 0 : goto fail;
1669 : }
1670 4216 : req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1671 4216 : if (req == NULL) {
1672 0 : goto fail;
1673 : }
1674 4216 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1675 0 : goto fail;
1676 : }
1677 4216 : status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1678 4216 : fail:
1679 4216 : TALLOC_FREE(frame);
1680 4216 : return status;
1681 : }
1682 :
1683 : /****************************************************************************
1684 : Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1685 : ****************************************************************************/
1686 :
1687 1737 : NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1688 : {
1689 0 : uint8_t *rdata;
1690 0 : uint32_t num_rdata;
1691 0 : unsigned int len;
1692 1737 : char *converted = NULL;
1693 1737 : size_t converted_size = 0;
1694 0 : NTSTATUS status;
1695 :
1696 1737 : status = cli_qpathinfo(talloc_tos(), cli, fname,
1697 : SMB_QUERY_FILE_ALT_NAME_INFO,
1698 : 4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1699 1737 : if (!NT_STATUS_IS_OK(status)) {
1700 56 : return status;
1701 : }
1702 :
1703 1681 : len = IVAL(rdata, 0);
1704 :
1705 1681 : if (len > num_rdata - 4) {
1706 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1707 : }
1708 :
1709 : /* The returned data is a pushed string, not raw data. */
1710 1681 : if (!convert_string_talloc(talloc_tos(),
1711 1681 : smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
1712 : CH_UNIX,
1713 1681 : rdata + 4,
1714 : len,
1715 : &converted,
1716 : &converted_size)) {
1717 0 : return NT_STATUS_NO_MEMORY;
1718 : }
1719 1681 : fstrcpy(alt_name, converted);
1720 :
1721 1681 : TALLOC_FREE(converted);
1722 1681 : TALLOC_FREE(rdata);
1723 :
1724 1681 : return NT_STATUS_OK;
1725 : }
1726 :
1727 : /****************************************************************************
1728 : Send a qpathinfo SMB_QUERY_FILE_STANDARD_INFO call.
1729 : ****************************************************************************/
1730 :
1731 2300 : NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname,
1732 : uint64_t *allocated, uint64_t *size,
1733 : uint32_t *nlinks,
1734 : bool *is_del_pending, bool *is_dir)
1735 : {
1736 0 : uint8_t *rdata;
1737 0 : uint32_t num_rdata;
1738 0 : NTSTATUS status;
1739 :
1740 2300 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1741 0 : return NT_STATUS_NOT_IMPLEMENTED;
1742 : }
1743 :
1744 2300 : status = cli_qpathinfo(talloc_tos(), cli, fname,
1745 : SMB_QUERY_FILE_STANDARD_INFO,
1746 : 24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1747 2300 : if (!NT_STATUS_IS_OK(status)) {
1748 0 : return status;
1749 : }
1750 :
1751 2300 : if (allocated) {
1752 0 : *allocated = BVAL(rdata, 0);
1753 : }
1754 :
1755 2300 : if (size) {
1756 2300 : *size = BVAL(rdata, 8);
1757 : }
1758 :
1759 2300 : if (nlinks) {
1760 0 : *nlinks = IVAL(rdata, 16);
1761 : }
1762 :
1763 2300 : if (is_del_pending) {
1764 0 : *is_del_pending = CVAL(rdata, 20);
1765 : }
1766 :
1767 2300 : if (is_dir) {
1768 0 : *is_dir = CVAL(rdata, 20);
1769 : }
1770 :
1771 2300 : TALLOC_FREE(rdata);
1772 :
1773 2300 : return NT_STATUS_OK;
1774 : }
1775 :
1776 :
1777 : /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
1778 5890 : NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
1779 : struct timespec *create_time,
1780 : struct timespec *access_time,
1781 : struct timespec *write_time,
1782 : struct timespec *change_time,
1783 : off_t *size, uint32_t *pattr,
1784 : SMB_INO_T *ino)
1785 : {
1786 5890 : NTSTATUS status = NT_STATUS_OK;
1787 5890 : SMB_STRUCT_STAT st = { 0 };
1788 5890 : uint32_t attr = 0;
1789 0 : uint64_t pos;
1790 :
1791 5890 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1792 : /*
1793 : * NB. cli_qpathinfo2() checks pattr is valid before
1794 : * storing a value into it, so we don't need to use
1795 : * an intermediate attr variable as below but can
1796 : * pass pattr directly.
1797 : */
1798 3014 : return cli_qpathinfo2(cli,
1799 : fname,
1800 : create_time,
1801 : access_time,
1802 : write_time,
1803 : change_time,
1804 : size,
1805 : pattr,
1806 : ino,
1807 : NULL);
1808 : }
1809 :
1810 2876 : if (create_time || access_time || write_time || change_time || pattr) {
1811 : /*
1812 : * cli_qpathinfo_basic() always indirects the passed
1813 : * in pointers so we use intermediate variables to
1814 : * collect all of them before assigning any requested
1815 : * below.
1816 : */
1817 2876 : status = cli_qpathinfo_basic(cli, fname, &st, &attr);
1818 2876 : if (!NT_STATUS_IS_OK(status)) {
1819 576 : return status;
1820 : }
1821 : }
1822 :
1823 2300 : if (size) {
1824 2300 : status = cli_qpathinfo_standard(cli, fname,
1825 : NULL, &pos, NULL, NULL, NULL);
1826 2300 : if (!NT_STATUS_IS_OK(status)) {
1827 0 : return status;
1828 : }
1829 :
1830 2300 : *size = pos;
1831 : }
1832 :
1833 2300 : if (create_time) {
1834 2300 : *create_time = st.st_ex_btime;
1835 : }
1836 2300 : if (access_time) {
1837 2300 : *access_time = st.st_ex_atime;
1838 : }
1839 2300 : if (write_time) {
1840 2300 : *write_time = st.st_ex_mtime;
1841 : }
1842 2300 : if (change_time) {
1843 2300 : *change_time = st.st_ex_ctime;
1844 : }
1845 2300 : if (pattr) {
1846 772 : *pattr = attr;
1847 : }
1848 2300 : if (ino) {
1849 0 : *ino = 0;
1850 : }
1851 :
1852 2300 : return NT_STATUS_OK;
1853 : }
|