third_party: Update socket_wrapper to version 1.4.2
[Samba.git] / source3 / libsmb / clirap.c
blob50be489d5a5f7cea3bba37bc4bc4b3667334c8d3
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
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.
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.
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/>.
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 "cli_smb2_fnum.h"
32 #include "lib/util/string_wrappers.h"
34 #include <gnutls/gnutls.h>
35 #include <gnutls/crypto.h>
37 #define PIPE_LANMAN "\\PIPE\\LANMAN"
39 /****************************************************************************
40 Call a remote api
41 ****************************************************************************/
43 bool cli_api(struct cli_state *cli,
44 char *param, int prcnt, int mprcnt,
45 char *data, int drcnt, int mdrcnt,
46 char **rparam, unsigned int *rprcnt,
47 char **rdata, unsigned int *rdrcnt)
49 NTSTATUS status;
51 uint8_t *my_rparam, *my_rdata;
52 uint32_t num_my_rparam, num_my_rdata;
54 status = cli_trans(talloc_tos(), cli, SMBtrans,
55 PIPE_LANMAN, 0, /* name, fid */
56 0, 0, /* function, flags */
57 NULL, 0, 0, /* setup */
58 (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
59 (uint8_t *)data, drcnt, mdrcnt, /* Data, length, max */
60 NULL, /* recv_flags2 */
61 NULL, 0, NULL, /* rsetup */
62 &my_rparam, 0, &num_my_rparam,
63 &my_rdata, 0, &num_my_rdata);
64 if (!NT_STATUS_IS_OK(status)) {
65 return false;
69 * I know this memcpy massively hurts, but there are just tons
70 * of callers of cli_api that eventually need changing to
71 * talloc
74 *rparam = (char *)smb_memdup(my_rparam, num_my_rparam);
75 if (*rparam == NULL) {
76 goto fail;
78 *rprcnt = num_my_rparam;
79 TALLOC_FREE(my_rparam);
81 *rdata = (char *)smb_memdup(my_rdata, num_my_rdata);
82 if (*rdata == NULL) {
83 goto fail;
85 *rdrcnt = num_my_rdata;
86 TALLOC_FREE(my_rdata);
88 return true;
89 fail:
90 TALLOC_FREE(my_rdata);
91 TALLOC_FREE(my_rparam);
92 *rparam = NULL;
93 *rprcnt = 0;
94 *rdata = NULL;
95 *rdrcnt = 0;
96 return false;
99 /****************************************************************************
100 Call a NetShareEnum - try and browse available connections on a host.
101 ****************************************************************************/
103 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state)
105 char *rparam = NULL;
106 char *rdata = NULL;
107 char *p;
108 unsigned int rdrcnt,rprcnt;
109 char param[1024];
110 int count = -1;
111 bool ok;
112 int res;
114 /* now send a SMBtrans command with api RNetShareEnum */
115 p = param;
116 SSVAL(p,0,0); /* api number */
117 p += 2;
118 strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
119 p = skip_string(param,sizeof(param),p);
120 strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
121 p = skip_string(param,sizeof(param),p);
122 SSVAL(p,0,1);
124 * Win2k needs a *smaller* buffer than 0xFFFF here -
125 * it returns "out of server memory" with 0xFFFF !!! JRA.
127 SSVAL(p,2,0xFFE0);
128 p += 4;
130 ok = cli_api(
131 cli,
132 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
133 NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
134 &rparam, &rprcnt, /* return params, length */
135 &rdata, &rdrcnt); /* return data, length */
136 if (!ok) {
137 DEBUG(4,("NetShareEnum failed\n"));
138 goto done;
141 if (rprcnt < 6) {
142 DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
143 goto done;
146 res = rparam? SVAL(rparam,0) : -1;
148 if (res == 0 || res == ERRmoredata) {
149 int converter=SVAL(rparam,2);
150 int i;
151 char *rdata_end = rdata + rdrcnt;
153 count=SVAL(rparam,4);
154 p = rdata;
156 for (i=0;i<count;i++,p+=20) {
157 char *sname;
158 int type;
159 int comment_offset;
160 const char *cmnt;
161 const char *p1;
162 char *s1, *s2;
163 size_t len;
164 TALLOC_CTX *frame = talloc_stackframe();
166 if (p + 20 > rdata_end) {
167 TALLOC_FREE(frame);
168 break;
171 sname = p;
172 type = SVAL(p,14);
173 comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
174 if (comment_offset < 0 ||
175 comment_offset > (int)rdrcnt) {
176 TALLOC_FREE(frame);
177 break;
179 cmnt = comment_offset?(rdata+comment_offset):"";
181 /* Work out the comment length. */
182 for (p1 = cmnt, len = 0; *p1 &&
183 p1 < rdata_end; len++)
184 p1++;
185 if (!*p1) {
186 len++;
188 pull_string_talloc(frame,rdata,0,
189 &s1,sname,14,STR_ASCII);
190 pull_string_talloc(frame,rdata,0,
191 &s2,cmnt,len,STR_ASCII);
192 if (!s1 || !s2) {
193 TALLOC_FREE(frame);
194 continue;
197 fn(s1, type, s2, state);
199 TALLOC_FREE(frame);
201 } else {
202 DEBUG(4,("NetShareEnum res=%d\n", res));
205 done:
206 SAFE_FREE(rparam);
207 SAFE_FREE(rdata);
209 return count;
212 /****************************************************************************
213 Call a NetServerEnum for the specified workgroup and servertype mask. This
214 function then calls the specified callback function for each name returned.
216 The callback function takes 4 arguments: the machine name, the server type,
217 the comment and a state pointer.
218 ****************************************************************************/
220 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype,
221 void (*fn)(const char *, uint32_t, const char *, void *),
222 void *state)
224 char *rparam = NULL;
225 char *rdata = NULL;
226 char *rdata_end = NULL;
227 unsigned int rdrcnt,rprcnt;
228 char *p;
229 char param[1024];
230 int uLevel = 1;
231 size_t len;
232 uint32_t func = RAP_NetServerEnum2;
233 char *last_entry = NULL;
234 int total_cnt = 0;
235 int return_cnt = 0;
236 int res;
238 errno = 0; /* reset */
241 * This may take more than one transaction, so we should loop until
242 * we no longer get a more data to process or we have all of the
243 * items.
245 do {
246 /* send a SMBtrans command with api NetServerEnum */
247 p = param;
248 SIVAL(p,0,func); /* api number */
249 p += 2;
251 if (func == RAP_NetServerEnum3) {
252 strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
253 } else {
254 strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
257 p = skip_string(param, sizeof(param), p);
258 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
260 p = skip_string(param, sizeof(param), p);
261 SSVAL(p,0,uLevel);
262 SSVAL(p,2,CLI_BUFFER_SIZE);
263 p += 4;
264 SIVAL(p,0,stype);
265 p += 4;
267 /* If we have more data, tell the server where
268 * to continue from.
270 len = push_ascii(p,
271 workgroup,
272 sizeof(param) - PTR_DIFF(p,param) - 1,
273 STR_TERMINATE|STR_UPPER);
275 if (len == 0) {
276 SAFE_FREE(last_entry);
277 return false;
279 p += len;
281 if (func == RAP_NetServerEnum3) {
282 len = push_ascii(p,
283 last_entry ? last_entry : "",
284 sizeof(param) - PTR_DIFF(p,param) - 1,
285 STR_TERMINATE);
287 if (len == 0) {
288 SAFE_FREE(last_entry);
289 return false;
291 p += len;
294 /* Next time through we need to use the continue api */
295 func = RAP_NetServerEnum3;
297 if (!cli_api(cli,
298 param, PTR_DIFF(p,param), 8, /* params, length, max */
299 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
300 &rparam, &rprcnt, /* return params, return size */
301 &rdata, &rdrcnt)) { /* return data, return size */
303 /* break out of the loop on error */
304 res = -1;
305 break;
308 rdata_end = rdata + rdrcnt;
310 if (rprcnt < 6) {
311 DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
312 res = -1;
313 break;
316 res = rparam ? SVAL(rparam,0) : -1;
318 if (res == 0 || res == ERRmoredata ||
319 (res != -1 && cli_errno(cli) == 0)) {
320 char *sname = NULL;
321 int i, count;
322 int converter=SVAL(rparam,2);
324 /* Get the number of items returned in this buffer */
325 count = SVAL(rparam, 4);
327 /* The next field contains the number of items left,
328 * including those returned in this buffer. So the
329 * first time through this should contain all of the
330 * entries.
332 if (total_cnt == 0) {
333 total_cnt = SVAL(rparam, 6);
336 /* Keep track of how many we have read */
337 return_cnt += count;
338 p = rdata;
340 /* The last name in the previous NetServerEnum reply is
341 * sent back to server in the NetServerEnum3 request
342 * (last_entry). The next reply should repeat this entry
343 * as the first element. We have no proof that this is
344 * always true, but from traces that seems to be the
345 * behavior from Window Servers. So first lets do a lot
346 * of checking, just being paranoid. If the string
347 * matches then we already saw this entry so skip it.
349 * NOTE: sv1_name field must be null terminated and has
350 * a max size of 16 (NetBIOS Name).
352 if (last_entry && count && p &&
353 (strncmp(last_entry, p, 16) == 0)) {
354 count -= 1; /* Skip this entry */
355 return_cnt = -1; /* Not part of total, so don't count. */
356 p = rdata + 26; /* Skip the whole record */
359 for (i = 0; i < count; i++, p += 26) {
360 int comment_offset;
361 const char *cmnt;
362 const char *p1;
363 char *s1, *s2;
364 TALLOC_CTX *frame = talloc_stackframe();
365 uint32_t entry_stype;
367 if (p + 26 > rdata_end) {
368 TALLOC_FREE(frame);
369 break;
372 sname = p;
373 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
374 cmnt = comment_offset?(rdata+comment_offset):"";
376 if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
377 TALLOC_FREE(frame);
378 continue;
381 /* Work out the comment length. */
382 for (p1 = cmnt, len = 0; *p1 &&
383 p1 < rdata_end; len++)
384 p1++;
385 if (!*p1) {
386 len++;
389 entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
391 pull_string_talloc(frame,rdata,0,
392 &s1,sname,16,STR_ASCII);
393 pull_string_talloc(frame,rdata,0,
394 &s2,cmnt,len,STR_ASCII);
396 if (!s1 || !s2) {
397 TALLOC_FREE(frame);
398 continue;
401 fn(s1, entry_stype, s2, state);
402 TALLOC_FREE(frame);
405 /* We are done with the old last entry, so now we can free it */
406 if (last_entry) {
407 SAFE_FREE(last_entry); /* This will set it to null */
410 /* We always make a copy of the last entry if we have one */
411 if (sname) {
412 last_entry = smb_xstrdup(sname);
415 /* If we have more data, but no last entry then error out */
416 if (!last_entry && (res == ERRmoredata)) {
417 errno = EINVAL;
418 res = 0;
423 SAFE_FREE(rparam);
424 SAFE_FREE(rdata);
425 } while ((res == ERRmoredata) && (total_cnt > return_cnt));
427 SAFE_FREE(rparam);
428 SAFE_FREE(rdata);
429 SAFE_FREE(last_entry);
431 if (res == -1) {
432 errno = cli_errno(cli);
433 } else {
434 if (!return_cnt) {
435 /* this is a very special case, when the domain master for the
436 work group isn't part of the work group itself, there is something
437 wild going on */
438 errno = ENOENT;
442 return(return_cnt > 0);
445 /****************************************************************************
446 Send a SamOEMChangePassword command.
447 ****************************************************************************/
449 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
450 const char *old_password)
452 char param[1024];
453 unsigned char data[532];
454 char *p = param;
455 unsigned char old_pw_hash[16];
456 unsigned char new_pw_hash[16];
457 unsigned int data_len;
458 unsigned int param_len = 0;
459 char *rparam = NULL;
460 char *rdata = NULL;
461 unsigned int rprcnt, rdrcnt;
462 gnutls_cipher_hd_t cipher_hnd = NULL;
463 gnutls_datum_t old_pw_key = {
464 .data = old_pw_hash,
465 .size = sizeof(old_pw_hash),
467 int rc;
469 if (strlen(user) >= sizeof(fstring)-1) {
470 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
471 return False;
474 SSVAL(p,0,214); /* SamOEMChangePassword command. */
475 p += 2;
476 strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
477 p = skip_string(param,sizeof(param),p);
478 strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
479 p = skip_string(param,sizeof(param),p);
480 strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
481 p = skip_string(param,sizeof(param),p);
482 SSVAL(p,0,532);
483 p += 2;
485 param_len = PTR_DIFF(p,param);
488 * Get the Lanman hash of the old password, we
489 * use this as the key to make_oem_passwd_hash().
491 E_deshash(old_password, old_pw_hash);
493 encode_pw_buffer(data, new_password, STR_ASCII);
495 #ifdef DEBUG_PASSWORD
496 DEBUG(100,("make_oem_passwd_hash\n"));
497 dump_data(100, data, 516);
498 #endif
499 rc = gnutls_cipher_init(&cipher_hnd,
500 GNUTLS_CIPHER_ARCFOUR_128,
501 &old_pw_key,
502 NULL);
503 if (rc < 0) {
504 DBG_ERR("gnutls_cipher_init failed: %s\n",
505 gnutls_strerror(rc));
506 return false;
508 rc = gnutls_cipher_encrypt(cipher_hnd,
509 data,
510 516);
511 gnutls_cipher_deinit(cipher_hnd);
512 if (rc < 0) {
513 return false;
517 * Now place the old password hash in the data.
519 E_deshash(new_password, new_pw_hash);
521 rc = E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
522 if (rc != 0) {
523 DBG_ERR("E_old_pw_hash failed: %s\n", gnutls_strerror(rc));
524 return false;
527 data_len = 532;
529 if (!cli_api(cli,
530 param, param_len, 4, /* param, length, max */
531 (char *)data, data_len, 0, /* data, length, max */
532 &rparam, &rprcnt,
533 &rdata, &rdrcnt)) {
534 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
535 user ));
536 return False;
539 if (rdrcnt < 2) {
540 cli->rap_error = ERRbadformat;
541 goto done;
544 if (rparam) {
545 cli->rap_error = SVAL(rparam,0);
548 done:
549 SAFE_FREE(rparam);
550 SAFE_FREE(rdata);
552 return (cli->rap_error == 0);
555 /****************************************************************************
556 Send a qpathinfo call.
557 ****************************************************************************/
559 struct cli_qpathinfo1_state {
560 struct cli_state *cli;
561 uint32_t num_data;
562 uint8_t *data;
565 static void cli_qpathinfo1_done(struct tevent_req *subreq);
567 struct tevent_req *cli_qpathinfo1_send(TALLOC_CTX *mem_ctx,
568 struct tevent_context *ev,
569 struct cli_state *cli,
570 const char *fname)
572 struct tevent_req *req = NULL, *subreq = NULL;
573 struct cli_qpathinfo1_state *state = NULL;
575 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo1_state);
576 if (req == NULL) {
577 return NULL;
579 state->cli = cli;
580 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_INFO_STANDARD,
581 22, CLI_BUFFER_SIZE);
582 if (tevent_req_nomem(subreq, req)) {
583 return tevent_req_post(req, ev);
585 tevent_req_set_callback(subreq, cli_qpathinfo1_done, req);
586 return req;
589 static void cli_qpathinfo1_done(struct tevent_req *subreq)
591 struct tevent_req *req = tevent_req_callback_data(
592 subreq, struct tevent_req);
593 struct cli_qpathinfo1_state *state = tevent_req_data(
594 req, struct cli_qpathinfo1_state);
595 NTSTATUS status;
597 status = cli_qpathinfo_recv(subreq, state, &state->data,
598 &state->num_data);
599 TALLOC_FREE(subreq);
600 if (!NT_STATUS_IS_OK(status)) {
601 tevent_req_nterror(req, status);
602 return;
604 tevent_req_done(req);
607 NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
608 time_t *change_time,
609 time_t *access_time,
610 time_t *write_time,
611 off_t *size,
612 uint32_t *pattr)
614 struct cli_qpathinfo1_state *state = tevent_req_data(
615 req, struct cli_qpathinfo1_state);
616 NTSTATUS status;
618 time_t (*date_fn)(const void *buf, int serverzone);
620 if (tevent_req_is_nterror(req, &status)) {
621 return status;
624 if (state->cli->win95) {
625 date_fn = make_unix_date;
626 } else {
627 date_fn = make_unix_date2;
630 if (change_time) {
631 *change_time = date_fn(state->data+0, smb1cli_conn_server_time_zone(state->cli->conn));
633 if (access_time) {
634 *access_time = date_fn(state->data+4, smb1cli_conn_server_time_zone(state->cli->conn));
636 if (write_time) {
637 *write_time = date_fn(state->data+8, smb1cli_conn_server_time_zone(state->cli->conn));
639 if (size) {
640 *size = IVAL(state->data, 12);
642 if (pattr) {
643 *pattr = SVAL(state->data, l1_attrFile);
645 return NT_STATUS_OK;
648 NTSTATUS cli_qpathinfo1(struct cli_state *cli,
649 const char *fname,
650 time_t *change_time,
651 time_t *access_time,
652 time_t *write_time,
653 off_t *size,
654 uint32_t *pattr)
656 TALLOC_CTX *frame = talloc_stackframe();
657 struct tevent_context *ev;
658 struct tevent_req *req;
659 NTSTATUS status = NT_STATUS_NO_MEMORY;
661 if (smbXcli_conn_has_async_calls(cli->conn)) {
663 * Can't use sync call while an async call is in flight
665 status = NT_STATUS_INVALID_PARAMETER;
666 goto fail;
668 ev = samba_tevent_context_init(frame);
669 if (ev == NULL) {
670 goto fail;
672 req = cli_qpathinfo1_send(frame, ev, cli, fname);
673 if (req == NULL) {
674 goto fail;
676 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
677 goto fail;
679 status = cli_qpathinfo1_recv(req, change_time, access_time,
680 write_time, size, pattr);
681 fail:
682 TALLOC_FREE(frame);
683 return status;
686 static void prep_basic_information_buf(
687 uint8_t buf[40],
688 struct timespec create_time,
689 struct timespec access_time,
690 struct timespec write_time,
691 struct timespec change_time,
692 uint32_t attr)
694 char *p = (char *)buf;
696 * Add the create, last access, modification, and status change times
698 put_long_date_full_timespec(
699 TIMESTAMP_SET_NT_OR_BETTER, p, &create_time);
700 p += 8;
702 put_long_date_full_timespec(
703 TIMESTAMP_SET_NT_OR_BETTER, p, &access_time);
704 p += 8;
706 put_long_date_full_timespec(
707 TIMESTAMP_SET_NT_OR_BETTER, p, &write_time);
708 p += 8;
710 put_long_date_full_timespec(
711 TIMESTAMP_SET_NT_OR_BETTER, p, &change_time);
712 p += 8;
714 if (attr == (uint32_t)-1 || attr == FILE_ATTRIBUTE_NORMAL) {
715 /* No change. */
716 attr = 0;
717 } else if (attr == 0) {
718 /* Clear all existing attributes. */
719 attr = FILE_ATTRIBUTE_NORMAL;
722 /* Add attributes */
723 SIVAL(p, 0, attr);
725 p += 4;
727 /* Add padding */
728 SIVAL(p, 0, 0);
729 p += 4;
731 SMB_ASSERT(PTR_DIFF(p, buf) == 40);
734 NTSTATUS cli_setpathinfo_ext(struct cli_state *cli, const char *fname,
735 struct timespec create_time,
736 struct timespec access_time,
737 struct timespec write_time,
738 struct timespec change_time,
739 uint32_t attr)
741 uint8_t buf[40];
743 prep_basic_information_buf(
744 buf,
745 create_time,
746 access_time,
747 write_time,
748 change_time,
749 attr);
751 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
752 DATA_BLOB in_data = data_blob_const(buf, sizeof(buf));
754 * Split out SMB2 here as we need to select
755 * the correct info type and level.
757 return cli_smb2_setpathinfo(cli,
758 fname,
759 1, /* SMB2_SETINFO_FILE */
760 SMB_FILE_BASIC_INFORMATION - 1000,
761 &in_data);
764 return cli_setpathinfo(
765 cli, SMB_FILE_BASIC_INFORMATION, fname, buf, sizeof(buf));
768 struct cli_setfileinfo_ext_state {
769 uint8_t data[40];
770 DATA_BLOB in_data;
773 static void cli_setfileinfo_ext_done(struct tevent_req *subreq);
774 static void cli_setfileinfo_ext_done2(struct tevent_req *subreq);
776 struct tevent_req *cli_setfileinfo_ext_send(
777 TALLOC_CTX *mem_ctx,
778 struct tevent_context *ev,
779 struct cli_state *cli,
780 uint16_t fnum,
781 struct timespec create_time,
782 struct timespec access_time,
783 struct timespec write_time,
784 struct timespec change_time,
785 uint32_t attr)
787 struct tevent_req *req = NULL, *subreq = NULL;
788 struct cli_setfileinfo_ext_state *state = NULL;
790 req = tevent_req_create(
791 mem_ctx, &state, struct cli_setfileinfo_ext_state);
792 if (req == NULL) {
793 return NULL;
795 prep_basic_information_buf(
796 state->data,
797 create_time,
798 access_time,
799 write_time,
800 change_time,
801 attr);
803 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
804 state->in_data = (DATA_BLOB) {
805 .data = state->data, .length = sizeof(state->data),
808 subreq = cli_smb2_set_info_fnum_send(
809 state,
811 cli,
812 fnum,
813 SMB2_0_INFO_FILE,
814 SMB_FILE_BASIC_INFORMATION - 1000,
815 &state->in_data,
816 0); /* in_additional_info */
817 if (tevent_req_nomem(subreq, req)) {
818 return tevent_req_post(req, ev);
820 tevent_req_set_callback(
821 subreq, cli_setfileinfo_ext_done2, req);
822 return req;
825 subreq = cli_setfileinfo_send(
826 state,
828 cli,
829 fnum,
830 SMB_FILE_BASIC_INFORMATION,
831 state->data,
832 sizeof(state->data));
833 if (tevent_req_nomem(subreq, req)) {
834 return tevent_req_post(req, ev);
836 tevent_req_set_callback(subreq, cli_setfileinfo_ext_done, req);
837 return req;
840 static void cli_setfileinfo_ext_done(struct tevent_req *subreq)
842 NTSTATUS status = cli_setfileinfo_recv(subreq);
843 tevent_req_simple_finish_ntstatus(subreq, status);
846 static void cli_setfileinfo_ext_done2(struct tevent_req *subreq)
848 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
849 tevent_req_simple_finish_ntstatus(subreq, status);
852 NTSTATUS cli_setfileinfo_ext_recv(struct tevent_req *req)
854 return tevent_req_simple_recv_ntstatus(req);
857 NTSTATUS cli_setfileinfo_ext(
858 struct cli_state *cli,
859 uint16_t fnum,
860 struct timespec create_time,
861 struct timespec access_time,
862 struct timespec write_time,
863 struct timespec change_time,
864 uint32_t attr)
866 TALLOC_CTX *frame = NULL;
867 struct tevent_context *ev = NULL;
868 struct tevent_req *req = NULL;
869 NTSTATUS status = NT_STATUS_NO_MEMORY;
871 if (smbXcli_conn_has_async_calls(cli->conn)) {
873 * Can't use sync call while an async call is in flight
875 return NT_STATUS_INVALID_PARAMETER;
878 frame = talloc_stackframe();
880 ev = samba_tevent_context_init(frame);
881 if (ev == NULL) {
882 goto fail;
884 req = cli_setfileinfo_ext_send(
887 cli,
888 fnum,
889 create_time,
890 access_time,
891 write_time,
892 change_time,
893 attr);
894 if (req == NULL) {
895 goto fail;
897 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
898 goto fail;
900 status = cli_setfileinfo_ext_recv(req);
901 fail:
902 TALLOC_FREE(frame);
903 return status;
906 /****************************************************************************
907 Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
908 ****************************************************************************/
910 struct cli_qpathinfo2_state {
911 struct timespec create_time;
912 struct timespec access_time;
913 struct timespec write_time;
914 struct timespec change_time;
915 off_t size;
916 uint32_t attr;
917 SMB_INO_T ino;
920 static void cli_qpathinfo2_done2(struct tevent_req *subreq);
921 static void cli_qpathinfo2_done(struct tevent_req *subreq);
923 struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
924 struct tevent_context *ev,
925 struct cli_state *cli,
926 const char *fname)
928 struct tevent_req *req = NULL, *subreq = NULL;
929 struct cli_qpathinfo2_state *state = NULL;
931 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
932 if (req == NULL) {
933 return NULL;
935 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
936 subreq = cli_smb2_qpathinfo2_send(state, ev, cli, fname);
937 if (tevent_req_nomem(subreq, req)) {
938 return tevent_req_post(req, ev);
940 tevent_req_set_callback(subreq, cli_qpathinfo2_done2, req);
941 return req;
943 subreq = cli_qpathinfo_send(state, ev, cli, fname,
944 SMB_QUERY_FILE_ALL_INFO,
945 68, CLI_BUFFER_SIZE);
946 if (tevent_req_nomem(subreq, req)) {
947 return tevent_req_post(req, ev);
949 tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
950 return req;
953 static void cli_qpathinfo2_done2(struct tevent_req *subreq)
955 struct tevent_req *req =
956 tevent_req_callback_data(subreq, struct tevent_req);
957 struct cli_qpathinfo2_state *state =
958 tevent_req_data(req, struct cli_qpathinfo2_state);
959 NTSTATUS status;
961 status = cli_smb2_qpathinfo2_recv(subreq,
962 &state->create_time,
963 &state->access_time,
964 &state->write_time,
965 &state->change_time,
966 &state->size,
967 &state->attr,
968 &state->ino);
969 TALLOC_FREE(subreq);
970 if (tevent_req_nterror(req, status)) {
971 return;
973 tevent_req_done(req);
976 static void cli_qpathinfo2_done(struct tevent_req *subreq)
978 struct tevent_req *req = tevent_req_callback_data(
979 subreq, struct tevent_req);
980 struct cli_qpathinfo2_state *state = tevent_req_data(
981 req, struct cli_qpathinfo2_state);
982 uint8_t *data = NULL;
983 uint32_t num_data;
984 NTSTATUS status;
986 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
987 TALLOC_FREE(subreq);
988 if (!NT_STATUS_IS_OK(status)) {
989 tevent_req_nterror(req, status);
990 return;
993 state->create_time = interpret_long_date((char *)data + 0);
994 state->access_time = interpret_long_date((char *)data + 8);
995 state->write_time = interpret_long_date((char *)data + 16);
996 state->change_time = interpret_long_date((char *)data + 24);
997 state->attr = PULL_LE_U32(data, 32);
998 state->size = PULL_LE_U64(data, 48);
1001 * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO which doesn't
1002 * return an inode number (fileid). We can't change this to
1003 * one of the FILE_ID info levels as only Win2003 and above
1004 * support these [MS-SMB: 2.2.2.3.1] and the SMB1 code needs
1005 * to support older servers.
1007 state->ino = 0;
1009 TALLOC_FREE(data);
1011 tevent_req_done(req);
1014 NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
1015 struct timespec *create_time,
1016 struct timespec *access_time,
1017 struct timespec *write_time,
1018 struct timespec *change_time,
1019 off_t *size, uint32_t *pattr,
1020 SMB_INO_T *ino)
1022 struct cli_qpathinfo2_state *state = tevent_req_data(
1023 req, struct cli_qpathinfo2_state);
1024 NTSTATUS status;
1026 if (tevent_req_is_nterror(req, &status)) {
1027 return status;
1030 if (create_time) {
1031 *create_time = state->create_time;
1033 if (access_time) {
1034 *access_time = state->access_time;
1036 if (write_time) {
1037 *write_time = state->write_time;
1039 if (change_time) {
1040 *change_time = state->change_time;
1042 if (pattr) {
1043 *pattr = state->attr;
1045 if (size) {
1046 *size = state->size;
1048 if (ino) {
1049 *ino = state->ino;
1051 return NT_STATUS_OK;
1054 NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
1055 struct timespec *create_time,
1056 struct timespec *access_time,
1057 struct timespec *write_time,
1058 struct timespec *change_time,
1059 off_t *size, uint32_t *pattr,
1060 SMB_INO_T *ino)
1062 TALLOC_CTX *frame = NULL;
1063 struct tevent_context *ev;
1064 struct tevent_req *req;
1065 NTSTATUS status = NT_STATUS_NO_MEMORY;
1067 frame = talloc_stackframe();
1069 if (smbXcli_conn_has_async_calls(cli->conn)) {
1071 * Can't use sync call while an async call is in flight
1073 status = NT_STATUS_INVALID_PARAMETER;
1074 goto fail;
1076 ev = samba_tevent_context_init(frame);
1077 if (ev == NULL) {
1078 goto fail;
1080 req = cli_qpathinfo2_send(frame, ev, cli, fname);
1081 if (req == NULL) {
1082 goto fail;
1084 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1085 goto fail;
1087 status = cli_qpathinfo2_recv(req, create_time, access_time,
1088 write_time, change_time, size, pattr, ino);
1089 fail:
1090 TALLOC_FREE(frame);
1091 return status;
1094 /****************************************************************************
1095 Get the stream info
1096 ****************************************************************************/
1098 struct cli_qpathinfo_streams_state {
1099 uint32_t num_data;
1100 uint8_t *data;
1103 static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
1105 struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
1106 struct tevent_context *ev,
1107 struct cli_state *cli,
1108 const char *fname)
1110 struct tevent_req *req = NULL, *subreq = NULL;
1111 struct cli_qpathinfo_streams_state *state = NULL;
1113 req = tevent_req_create(mem_ctx, &state,
1114 struct cli_qpathinfo_streams_state);
1115 if (req == NULL) {
1116 return NULL;
1118 subreq = cli_qpathinfo_send(state, ev, cli, fname,
1119 SMB_FILE_STREAM_INFORMATION,
1120 0, CLI_BUFFER_SIZE);
1121 if (tevent_req_nomem(subreq, req)) {
1122 return tevent_req_post(req, ev);
1124 tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
1125 return req;
1128 static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
1130 struct tevent_req *req = tevent_req_callback_data(
1131 subreq, struct tevent_req);
1132 struct cli_qpathinfo_streams_state *state = tevent_req_data(
1133 req, struct cli_qpathinfo_streams_state);
1134 NTSTATUS status;
1136 status = cli_qpathinfo_recv(subreq, state, &state->data,
1137 &state->num_data);
1138 TALLOC_FREE(subreq);
1139 if (!NT_STATUS_IS_OK(status)) {
1140 tevent_req_nterror(req, status);
1141 return;
1143 tevent_req_done(req);
1146 NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
1147 TALLOC_CTX *mem_ctx,
1148 unsigned int *pnum_streams,
1149 struct stream_struct **pstreams)
1151 struct cli_qpathinfo_streams_state *state = tevent_req_data(
1152 req, struct cli_qpathinfo_streams_state);
1153 NTSTATUS status;
1155 if (tevent_req_is_nterror(req, &status)) {
1156 return status;
1158 if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
1159 pnum_streams, pstreams)) {
1160 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1162 return NT_STATUS_OK;
1165 NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
1166 TALLOC_CTX *mem_ctx,
1167 unsigned int *pnum_streams,
1168 struct stream_struct **pstreams)
1170 TALLOC_CTX *frame = NULL;
1171 struct tevent_context *ev;
1172 struct tevent_req *req;
1173 NTSTATUS status = NT_STATUS_NO_MEMORY;
1175 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1176 return cli_smb2_qpathinfo_streams(cli,
1177 fname,
1178 mem_ctx,
1179 pnum_streams,
1180 pstreams);
1183 frame = talloc_stackframe();
1185 if (smbXcli_conn_has_async_calls(cli->conn)) {
1187 * Can't use sync call while an async call is in flight
1189 status = NT_STATUS_INVALID_PARAMETER;
1190 goto fail;
1192 ev = samba_tevent_context_init(frame);
1193 if (ev == NULL) {
1194 goto fail;
1196 req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
1197 if (req == NULL) {
1198 goto fail;
1200 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1201 goto fail;
1203 status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
1204 pstreams);
1205 fail:
1206 TALLOC_FREE(frame);
1207 return status;
1210 bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
1211 size_t data_len,
1212 unsigned int *pnum_streams,
1213 struct stream_struct **pstreams)
1215 unsigned int num_streams;
1216 struct stream_struct *streams;
1217 unsigned int ofs;
1219 num_streams = 0;
1220 streams = NULL;
1221 ofs = 0;
1223 while ((data_len > ofs) && (data_len - ofs >= 24)) {
1224 uint32_t nlen, len;
1225 size_t size;
1226 void *vstr;
1227 struct stream_struct *tmp;
1228 uint8_t *tmp_buf;
1230 tmp = talloc_realloc(mem_ctx, streams,
1231 struct stream_struct,
1232 num_streams+1);
1234 if (tmp == NULL) {
1235 goto fail;
1237 streams = tmp;
1239 nlen = IVAL(rdata, ofs + 0x04);
1241 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1242 rdata, ofs + 0x08);
1243 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1244 rdata, ofs + 0x10);
1246 if (nlen > data_len - (ofs + 24)) {
1247 goto fail;
1251 * We need to null-terminate src, how do I do this with
1252 * convert_string_talloc??
1255 tmp_buf = talloc_array(streams, uint8_t, nlen+2);
1256 if (tmp_buf == NULL) {
1257 goto fail;
1260 memcpy(tmp_buf, rdata+ofs+24, nlen);
1261 tmp_buf[nlen] = 0;
1262 tmp_buf[nlen+1] = 0;
1264 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1265 nlen+2, &vstr, &size))
1267 TALLOC_FREE(tmp_buf);
1268 goto fail;
1271 TALLOC_FREE(tmp_buf);
1272 streams[num_streams].name = (char *)vstr;
1273 num_streams++;
1275 len = IVAL(rdata, ofs);
1276 if (len > data_len - ofs) {
1277 goto fail;
1279 if (len == 0) break;
1280 ofs += len;
1283 *pnum_streams = num_streams;
1284 *pstreams = streams;
1285 return true;
1287 fail:
1288 TALLOC_FREE(streams);
1289 return false;
1292 /****************************************************************************
1293 Send a qfileinfo QUERY_FILE_NAME_INFO call.
1294 ****************************************************************************/
1296 struct cli_qfileinfo_basic_state {
1297 uint32_t attr;
1298 off_t size;
1299 struct timespec create_time;
1300 struct timespec access_time;
1301 struct timespec write_time;
1302 struct timespec change_time;
1303 SMB_INO_T ino;
1306 static void cli_qfileinfo_basic_done(struct tevent_req *subreq);
1307 static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq);
1308 static void cli_qfileinfo_basic_done2(struct tevent_req *subreq);
1310 struct tevent_req *cli_qfileinfo_basic_send(
1311 TALLOC_CTX *mem_ctx,
1312 struct tevent_context *ev,
1313 struct cli_state *cli,
1314 uint16_t fnum)
1316 struct tevent_req *req = NULL, *subreq = NULL;
1317 struct cli_qfileinfo_basic_state *state = NULL;
1319 req = tevent_req_create(
1320 mem_ctx, &state, struct cli_qfileinfo_basic_state);
1321 if (req == NULL) {
1322 return NULL;
1325 if ((smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN2) ||
1326 cli->win95) {
1328 * According to
1329 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/3d9d8f3e-dc70-410d-a3fc-6f4a881e8cab
1330 * SMB_COM_TRANSACTION2 used in cli_qfileinfo_send()
1331 * further down was introduced with the LAN Manager
1332 * 1.2 dialect, which we encode as PROTOCOL_LANMAN2.
1334 * The "win95" check was introduced with commit
1335 * 27e5850fd3e1c8 in 1998. Hard to check these days,
1336 * but leave it in.
1338 * Use a lowerlevel fallback in both cases.
1341 subreq = cli_getattrE_send(state, ev, cli, fnum);
1342 if (tevent_req_nomem(subreq, req)) {
1343 return tevent_req_post(req, ev);
1345 tevent_req_set_callback(
1346 subreq, cli_qfileinfo_basic_doneE, req);
1347 return req;
1350 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1351 subreq = cli_smb2_query_info_fnum_send(
1352 state, /* mem_ctx */
1353 ev, /* ev */
1354 cli, /* cli */
1355 fnum, /* fnum */
1356 1, /* in_info_type */
1357 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1358 0xFFFF, /* in_max_output_length */
1359 NULL, /* in_input_buffer */
1360 0, /* in_additional_info */
1361 0); /* in_flags */
1362 if (tevent_req_nomem(subreq, req)) {
1363 return tevent_req_post(req, ev);
1365 tevent_req_set_callback(
1366 subreq, cli_qfileinfo_basic_done2, req);
1367 return req;
1370 subreq = cli_qfileinfo_send(
1371 state,
1373 cli,
1374 fnum,
1375 SMB_QUERY_FILE_ALL_INFO, /* level */
1376 68, /* min_rdata */
1377 CLI_BUFFER_SIZE); /* max_rdata */
1378 if (tevent_req_nomem(subreq, req)) {
1379 return tevent_req_post(req, ev);
1381 tevent_req_set_callback(subreq, cli_qfileinfo_basic_done, req);
1382 return req;
1385 static void cli_qfileinfo_basic_done(struct tevent_req *subreq)
1387 struct tevent_req *req = tevent_req_callback_data(
1388 subreq, struct tevent_req);
1389 struct cli_qfileinfo_basic_state *state = tevent_req_data(
1390 req, struct cli_qfileinfo_basic_state);
1391 uint8_t *rdata;
1392 uint32_t num_rdata;
1393 NTSTATUS status;
1395 status = cli_qfileinfo_recv(
1396 subreq, state, NULL, &rdata, &num_rdata);
1397 TALLOC_FREE(subreq);
1398 if (tevent_req_nterror(req, status)) {
1399 return;
1402 state->create_time = interpret_long_date((char *)rdata+0);
1403 state->access_time = interpret_long_date((char *)rdata+8);
1404 state->write_time = interpret_long_date((char *)rdata+16);
1405 state->change_time = interpret_long_date((char *)rdata+24);
1406 state->attr = PULL_LE_U32(rdata, 32);
1407 state->size = PULL_LE_U64(rdata,48);
1408 state->ino = PULL_LE_U32(rdata, 64);
1409 TALLOC_FREE(rdata);
1411 tevent_req_done(req);
1414 static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq)
1416 struct tevent_req *req = tevent_req_callback_data(
1417 subreq, struct tevent_req);
1418 struct cli_qfileinfo_basic_state *state = tevent_req_data(
1419 req, struct cli_qfileinfo_basic_state);
1420 NTSTATUS status;
1422 status = cli_getattrE_recv(
1423 subreq,
1424 &state->attr,
1425 &state->size,
1426 &state->change_time.tv_sec,
1427 &state->access_time.tv_sec,
1428 &state->write_time.tv_sec);
1429 TALLOC_FREE(subreq);
1430 if (tevent_req_nterror(req, status)) {
1431 return;
1433 tevent_req_done(req);
1436 static void cli_qfileinfo_basic_done2(struct tevent_req *subreq)
1438 struct tevent_req *req = tevent_req_callback_data(
1439 subreq, struct tevent_req);
1440 struct cli_qfileinfo_basic_state *state = tevent_req_data(
1441 req, struct cli_qfileinfo_basic_state);
1442 DATA_BLOB outbuf = {0};
1443 NTSTATUS status;
1445 status = cli_smb2_query_info_fnum_recv(subreq, state, &outbuf);
1446 TALLOC_FREE(subreq);
1447 if (tevent_req_nterror(req, status)) {
1448 return;
1451 /* Parse the reply. */
1452 if (outbuf.length < 0x60) {
1453 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1454 return;
1457 state->create_time = interpret_long_date(
1458 (const char *)outbuf.data + 0x0);
1459 state->access_time = interpret_long_date(
1460 (const char *)outbuf.data + 0x8);
1461 state->write_time = interpret_long_date(
1462 (const char *)outbuf.data + 0x10);
1463 state->change_time = interpret_long_date(
1464 (const char *)outbuf.data + 0x18);
1465 state->attr = IVAL(outbuf.data, 0x20);
1466 state->size = BVAL(outbuf.data, 0x30);
1467 state->ino = BVAL(outbuf.data, 0x40);
1469 data_blob_free(&outbuf);
1471 tevent_req_done(req);
1474 NTSTATUS cli_qfileinfo_basic_recv(
1475 struct tevent_req *req,
1476 uint32_t *attr,
1477 off_t *size,
1478 struct timespec *create_time,
1479 struct timespec *access_time,
1480 struct timespec *write_time,
1481 struct timespec *change_time,
1482 SMB_INO_T *ino)
1484 struct cli_qfileinfo_basic_state *state = tevent_req_data(
1485 req, struct cli_qfileinfo_basic_state);
1486 NTSTATUS status;
1488 if (tevent_req_is_nterror(req, &status)) {
1489 return status;
1492 if (create_time != NULL) {
1493 *create_time = state->create_time;
1495 if (access_time != NULL) {
1496 *access_time = state->access_time;
1498 if (write_time != NULL) {
1499 *write_time = state->write_time;
1501 if (change_time != NULL) {
1502 *change_time = state->change_time;
1504 if (attr != NULL) {
1505 *attr = state->attr;
1507 if (size != NULL) {
1508 *size = state->size;
1510 if (ino) {
1511 *ino = state->ino;
1514 return NT_STATUS_OK;
1516 /****************************************************************************
1517 Send a qfileinfo call.
1518 ****************************************************************************/
1520 NTSTATUS cli_qfileinfo_basic(
1521 struct cli_state *cli,
1522 uint16_t fnum,
1523 uint32_t *attr,
1524 off_t *size,
1525 struct timespec *create_time,
1526 struct timespec *access_time,
1527 struct timespec *write_time,
1528 struct timespec *change_time,
1529 SMB_INO_T *ino)
1531 TALLOC_CTX *frame = NULL;
1532 struct tevent_context *ev = NULL;
1533 struct tevent_req *req = NULL;
1534 NTSTATUS status = NT_STATUS_NO_MEMORY;
1536 frame = talloc_stackframe();
1538 if (smbXcli_conn_has_async_calls(cli->conn)) {
1540 * Can't use sync call while an async call is in flight
1542 status = NT_STATUS_INVALID_PARAMETER;
1543 goto fail;
1545 ev = samba_tevent_context_init(frame);
1546 if (ev == NULL) {
1547 goto fail;
1549 req = cli_qfileinfo_basic_send(frame, ev, cli, fnum);
1550 if (req == NULL) {
1551 goto fail;
1553 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1554 goto fail;
1557 status = cli_qfileinfo_basic_recv(
1558 req,
1559 attr,
1560 size,
1561 create_time,
1562 access_time,
1563 write_time,
1564 change_time,
1565 ino);
1567 /* cli_smb2_query_info_fnum_recv doesn't set this */
1568 cli->raw_status = status;
1569 fail:
1570 TALLOC_FREE(frame);
1571 return status;
1574 /****************************************************************************
1575 Send a qpathinfo BASIC_INFO call.
1576 ****************************************************************************/
1578 struct cli_qpathinfo_basic_state {
1579 uint32_t num_data;
1580 uint8_t *data;
1583 static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1585 struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1586 struct tevent_context *ev,
1587 struct cli_state *cli,
1588 const char *fname)
1590 struct tevent_req *req = NULL, *subreq = NULL;
1591 struct cli_qpathinfo_basic_state *state = NULL;
1593 req = tevent_req_create(mem_ctx, &state,
1594 struct cli_qpathinfo_basic_state);
1595 if (req == NULL) {
1596 return NULL;
1598 subreq = cli_qpathinfo_send(state, ev, cli, fname,
1599 SMB_QUERY_FILE_BASIC_INFO,
1600 36, CLI_BUFFER_SIZE);
1601 if (tevent_req_nomem(subreq, req)) {
1602 return tevent_req_post(req, ev);
1604 tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1605 return req;
1608 static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1610 struct tevent_req *req = tevent_req_callback_data(
1611 subreq, struct tevent_req);
1612 struct cli_qpathinfo_basic_state *state = tevent_req_data(
1613 req, struct cli_qpathinfo_basic_state);
1614 NTSTATUS status;
1616 status = cli_qpathinfo_recv(subreq, state, &state->data,
1617 &state->num_data);
1618 TALLOC_FREE(subreq);
1619 if (!NT_STATUS_IS_OK(status)) {
1620 tevent_req_nterror(req, status);
1621 return;
1623 tevent_req_done(req);
1626 NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1627 SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1629 struct cli_qpathinfo_basic_state *state = tevent_req_data(
1630 req, struct cli_qpathinfo_basic_state);
1631 NTSTATUS status;
1633 if (tevent_req_is_nterror(req, &status)) {
1634 return status;
1637 sbuf->st_ex_btime = interpret_long_date((char *)state->data);
1638 sbuf->st_ex_atime = interpret_long_date((char *)state->data+8);
1639 sbuf->st_ex_mtime = interpret_long_date((char *)state->data+16);
1640 sbuf->st_ex_ctime = interpret_long_date((char *)state->data+24);
1641 *attributes = IVAL(state->data, 32);
1642 return NT_STATUS_OK;
1645 NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1646 SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1648 TALLOC_CTX *frame = NULL;
1649 struct tevent_context *ev;
1650 struct tevent_req *req;
1651 NTSTATUS status = NT_STATUS_NO_MEMORY;
1653 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1654 return cli_smb2_qpathinfo_basic(cli,
1655 name,
1656 sbuf,
1657 attributes);
1660 frame = talloc_stackframe();
1662 if (smbXcli_conn_has_async_calls(cli->conn)) {
1664 * Can't use sync call while an async call is in flight
1666 status = NT_STATUS_INVALID_PARAMETER;
1667 goto fail;
1669 ev = samba_tevent_context_init(frame);
1670 if (ev == NULL) {
1671 goto fail;
1673 req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1674 if (req == NULL) {
1675 goto fail;
1677 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1678 goto fail;
1680 status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1681 fail:
1682 TALLOC_FREE(frame);
1683 return status;
1686 /****************************************************************************
1687 Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1688 ****************************************************************************/
1690 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1692 uint8_t *rdata;
1693 uint32_t num_rdata;
1694 unsigned int len;
1695 char *converted = NULL;
1696 size_t converted_size = 0;
1697 NTSTATUS status;
1699 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1700 return cli_smb2_qpathinfo_alt_name(cli,
1701 fname,
1702 alt_name);
1705 status = cli_qpathinfo(talloc_tos(), cli, fname,
1706 SMB_QUERY_FILE_ALT_NAME_INFO,
1707 4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1708 if (!NT_STATUS_IS_OK(status)) {
1709 return status;
1712 len = IVAL(rdata, 0);
1714 if (len > num_rdata - 4) {
1715 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1718 /* The returned data is a pushed string, not raw data. */
1719 if (!convert_string_talloc(talloc_tos(),
1720 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
1721 CH_UNIX,
1722 rdata + 4,
1723 len,
1724 &converted,
1725 &converted_size)) {
1726 return NT_STATUS_NO_MEMORY;
1728 fstrcpy(alt_name, converted);
1730 TALLOC_FREE(converted);
1731 TALLOC_FREE(rdata);
1733 return NT_STATUS_OK;
1736 /****************************************************************************
1737 Send a qpathinfo SMB_QUERY_FILE_STANDARD_INFO call.
1738 ****************************************************************************/
1740 NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname,
1741 uint64_t *allocated, uint64_t *size,
1742 uint32_t *nlinks,
1743 bool *is_del_pending, bool *is_dir)
1745 uint8_t *rdata;
1746 uint32_t num_rdata;
1747 NTSTATUS status;
1749 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1750 return NT_STATUS_NOT_IMPLEMENTED;
1753 status = cli_qpathinfo(talloc_tos(), cli, fname,
1754 SMB_QUERY_FILE_STANDARD_INFO,
1755 24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1756 if (!NT_STATUS_IS_OK(status)) {
1757 return status;
1760 if (allocated) {
1761 *allocated = BVAL(rdata, 0);
1764 if (size) {
1765 *size = BVAL(rdata, 8);
1768 if (nlinks) {
1769 *nlinks = IVAL(rdata, 16);
1772 if (is_del_pending) {
1773 *is_del_pending = CVAL(rdata, 20);
1776 if (is_dir) {
1777 *is_dir = CVAL(rdata, 20);
1780 TALLOC_FREE(rdata);
1782 return NT_STATUS_OK;
1786 /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
1787 NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
1788 struct timespec *create_time,
1789 struct timespec *access_time,
1790 struct timespec *write_time,
1791 struct timespec *change_time,
1792 off_t *size, uint32_t *pattr,
1793 SMB_INO_T *ino)
1795 NTSTATUS status = NT_STATUS_OK;
1796 SMB_STRUCT_STAT st = { 0 };
1797 uint32_t attr = 0;
1798 uint64_t pos;
1800 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1802 * NB. cli_qpathinfo2() checks pattr is valid before
1803 * storing a value into it, so we don't need to use
1804 * an intermediate attr variable as below but can
1805 * pass pattr directly.
1807 return cli_qpathinfo2(cli, fname,
1808 create_time, access_time, write_time, change_time,
1809 size, pattr, ino);
1812 if (create_time || access_time || write_time || change_time || pattr) {
1814 * cli_qpathinfo_basic() always indirects the passed
1815 * in pointers so we use intermediate variables to
1816 * collect all of them before assigning any requested
1817 * below.
1819 status = cli_qpathinfo_basic(cli, fname, &st, &attr);
1820 if (!NT_STATUS_IS_OK(status)) {
1821 return status;
1825 if (size) {
1826 status = cli_qpathinfo_standard(cli, fname,
1827 NULL, &pos, NULL, NULL, NULL);
1828 if (!NT_STATUS_IS_OK(status)) {
1829 return status;
1832 *size = pos;
1835 if (create_time) {
1836 *create_time = st.st_ex_btime;
1838 if (access_time) {
1839 *access_time = st.st_ex_atime;
1841 if (write_time) {
1842 *write_time = st.st_ex_mtime;
1844 if (change_time) {
1845 *change_time = st.st_ex_ctime;
1847 if (pattr) {
1848 *pattr = attr;
1850 if (ino) {
1851 *ino = 0;
1854 return NT_STATUS_OK;