ctdb-server: Clean up connection tracking functions
[samba4-gss.git] / source3 / libsmb / clirap.c
blob758d6ccbb1e1c11b6e102d55b53f2accb383e1e9
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 "libcli/smb/reparse.h"
32 #include "cli_smb2_fnum.h"
33 #include "lib/util/string_wrappers.h"
35 #include <gnutls/gnutls.h>
36 #include <gnutls/crypto.h>
38 /****************************************************************************
39 Call a NetShareEnum - try and browse available connections on a host.
40 ****************************************************************************/
42 NTSTATUS cli_RNetShareEnum(
43 struct cli_state *cli,
44 void (*fn)(const char *, uint32_t, const char *, void *),
45 void *state)
47 uint8_t *rparam = NULL;
48 uint8_t *rdata = NULL;
49 char *rdata_end = NULL;
50 char *p = NULL;
51 unsigned int rdrcnt,rprcnt;
52 char param[1024];
53 int count = -1;
54 int i, converter;
55 int res;
56 NTSTATUS status;
58 /* now send a SMBtrans command with api RNetShareEnum */
59 p = param;
60 SSVAL(p,0,0); /* api number */
61 p += 2;
62 strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
63 p = skip_string(param,sizeof(param),p);
64 strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
65 p = skip_string(param,sizeof(param),p);
66 SSVAL(p,0,1);
68 * Win2k needs a *smaller* buffer than 0xFFFF here -
69 * it returns "out of server memory" with 0xFFFF !!! JRA.
71 SSVAL(p,2,0xFFE0);
72 p += 4;
74 status = cli_trans(talloc_tos(), /* mem_ctx */
75 cli, /* cli */
76 SMBtrans, /* cmd */
77 "\\PIPE\\LANMAN", /* name */
78 0, /* fid */
79 0, /* function */
80 0, /* flags */
81 NULL, /* setup */
82 0, /* num_setup */
83 0, /* max_setup */
84 (uint8_t *)param, /* param */
85 PTR_DIFF(p, param), /* num_param */
86 1024, /* max_param */
87 NULL, /* data */
88 0, /* num_data */
89 0xFFE0, /* max_data, for W2K */
90 NULL, /* recv_flags2 */
91 NULL, /* rsetup */
92 0, /* min_rsetup */
93 NULL, /* num_rsetup */
94 &rparam, /* rparam */
95 6, /* min_rparam */
96 &rprcnt, /* num_rparam */
97 &rdata, /* rdata */
98 0, /* min_rdata */
99 &rdrcnt); /* num_rdata */
100 if (!NT_STATUS_IS_OK(status)) {
101 DEBUG(4,("NetShareEnum failed\n"));
102 goto done;
105 res = PULL_LE_U16(rparam, 0);
107 if (!(res == 0 || res == ERRmoredata)) {
108 DEBUG(4,("NetShareEnum res=%d\n", res));
109 status = werror_to_ntstatus(W_ERROR(res));
110 goto done;
113 converter = SVAL(rparam,2);
114 rdata_end = (char *)rdata + rdrcnt;
116 count=SVAL(rparam,4);
117 p = (char *)rdata;
119 for (i=0;i<count;i++,p+=20) {
120 char *sname;
121 int type;
122 int comment_offset;
123 const char *cmnt;
124 const char *p1;
125 char *s1, *s2;
126 size_t len;
127 TALLOC_CTX *frame = talloc_stackframe();
129 if (p + 20 > rdata_end) {
130 TALLOC_FREE(frame);
131 break;
134 sname = p;
135 type = SVAL(p,14);
136 comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
137 if (comment_offset < 0 ||
138 comment_offset > (int)rdrcnt) {
139 TALLOC_FREE(frame);
140 break;
142 cmnt = comment_offset ? ((char *)rdata + comment_offset) : "";
144 /* Work out the comment length. */
145 for (p1 = cmnt, len = 0; *p1 &&
146 p1 < rdata_end; len++)
147 p1++;
148 if (!*p1) {
149 len++;
151 pull_string_talloc(frame,rdata,0,
152 &s1,sname,14,STR_ASCII);
153 pull_string_talloc(frame,rdata,0,
154 &s2,cmnt,len,STR_ASCII);
155 if (!s1 || !s2) {
156 TALLOC_FREE(frame);
157 continue;
160 fn(s1, type, s2, state);
162 TALLOC_FREE(frame);
165 done:
166 TALLOC_FREE(rparam);
167 TALLOC_FREE(rdata);
169 return status;
172 /****************************************************************************
173 Call a NetServerEnum for the specified workgroup and servertype mask. This
174 function then calls the specified callback function for each name returned.
176 The callback function takes 4 arguments: the machine name, the server type,
177 the comment and a state pointer.
178 ****************************************************************************/
180 NTSTATUS cli_NetServerEnum(
181 struct cli_state *cli,
182 char *workgroup,
183 uint32_t stype,
184 void (*fn)(const char *, uint32_t, const char *, void *),
185 void *state)
187 uint8_t *rparam = NULL;
188 uint8_t *rdata = NULL;
189 char *rdata_end = NULL;
190 uint32_t rdrcnt, rprcnt;
191 char *p;
192 char param[1024];
193 int uLevel = 1;
194 size_t len;
195 uint32_t func = RAP_NetServerEnum2;
196 char *last_entry = NULL;
197 int total_cnt = 0;
198 int return_cnt = 0;
199 int res;
200 NTSTATUS status;
203 * This may take more than one transaction, so we should loop until
204 * we no longer get a more data to process or we have all of the
205 * items.
207 do {
208 /* send a SMBtrans command with api NetServerEnum */
209 p = param;
210 SIVAL(p,0,func); /* api number */
211 p += 2;
213 if (func == RAP_NetServerEnum3) {
214 strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
215 } else {
216 strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
219 p = skip_string(param, sizeof(param), p);
220 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
222 p = skip_string(param, sizeof(param), p);
223 SSVAL(p,0,uLevel);
224 SSVAL(p,2,CLI_BUFFER_SIZE);
225 p += 4;
226 SIVAL(p,0,stype);
227 p += 4;
229 /* If we have more data, tell the server where
230 * to continue from.
232 len = push_ascii(p,
233 workgroup,
234 sizeof(param) - PTR_DIFF(p,param) - 1,
235 STR_TERMINATE|STR_UPPER);
237 if (len == 0) {
238 SAFE_FREE(last_entry);
239 return NT_STATUS_INTERNAL_ERROR;
241 p += len;
243 if (func == RAP_NetServerEnum3) {
244 len = push_ascii(p,
245 last_entry ? last_entry : "",
246 sizeof(param) - PTR_DIFF(p,param) - 1,
247 STR_TERMINATE);
249 if (len == 0) {
250 SAFE_FREE(last_entry);
251 return NT_STATUS_INTERNAL_ERROR;
253 p += len;
256 /* Next time through we need to use the continue api */
257 func = RAP_NetServerEnum3;
259 status = cli_trans(talloc_tos(), /* mem_ctx */
260 cli, /* cli */
261 SMBtrans, /* cmd */
262 "\\PIPE\\LANMAN", /* name */
263 0, /* fid */
264 0, /* function */
265 0, /* flags */
266 NULL, /* setup */
267 0, /* num_setup */
268 0, /* max_setup */
269 (uint8_t *)param, /* param */
270 PTR_DIFF(p, param), /* num_param */
271 8, /* max_param */
272 NULL, /* data */
273 0, /* num_data */
274 CLI_BUFFER_SIZE, /* max_data */
275 NULL, /* recv_flags2 */
276 NULL, /* rsetup */
277 0, /* min_rsetup */
278 NULL, /* num_rsetup */
279 &rparam, /* rparam */
280 6, /* min_rparam */
281 &rprcnt, /* num_rparam */
282 &rdata, /* rdata */
283 0, /* min_rdata */
284 &rdrcnt); /* num_rdata */
285 if (!NT_STATUS_IS_OK(status)) {
286 /* break out of the loop on error */
287 res = -1;
288 break;
291 rdata_end = (char *)rdata + rdrcnt;
293 res = PULL_LE_U16(rparam, 0);
295 if (res == 0 || res == ERRmoredata) {
296 char *sname = NULL;
297 int i, count;
298 int converter=SVAL(rparam,2);
300 /* Get the number of items returned in this buffer */
301 count = SVAL(rparam, 4);
303 /* The next field contains the number of items left,
304 * including those returned in this buffer. So the
305 * first time through this should contain all of the
306 * entries.
308 if (total_cnt == 0) {
309 total_cnt = SVAL(rparam, 6);
312 /* Keep track of how many we have read */
313 return_cnt += count;
314 p = (char *)rdata;
316 /* The last name in the previous NetServerEnum reply is
317 * sent back to server in the NetServerEnum3 request
318 * (last_entry). The next reply should repeat this entry
319 * as the first element. We have no proof that this is
320 * always true, but from traces that seems to be the
321 * behavior from Window Servers. So first lets do a lot
322 * of checking, just being paranoid. If the string
323 * matches then we already saw this entry so skip it.
325 * NOTE: sv1_name field must be null terminated and has
326 * a max size of 16 (NetBIOS Name).
328 if (last_entry && count && p &&
329 (strncmp(last_entry, p, 16) == 0)) {
330 count -= 1; /* Skip this entry */
331 return_cnt = -1; /* Not part of total, so don't count. */
332 p = (char *)rdata + 26; /* Skip the whole record */
335 for (i = 0; i < count; i++, p += 26) {
336 int comment_offset;
337 const char *cmnt;
338 const char *p1;
339 char *s1, *s2;
340 TALLOC_CTX *frame = talloc_stackframe();
341 uint32_t entry_stype;
343 if (p + 26 > rdata_end) {
344 TALLOC_FREE(frame);
345 break;
348 sname = p;
349 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
350 cmnt = comment_offset ? ((char *)rdata +
351 comment_offset)
352 : "";
354 if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
355 TALLOC_FREE(frame);
356 continue;
359 /* Work out the comment length. */
360 for (p1 = cmnt, len = 0; *p1 &&
361 p1 < rdata_end; len++)
362 p1++;
363 if (!*p1) {
364 len++;
367 entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
369 pull_string_talloc(frame,rdata,0,
370 &s1,sname,16,STR_ASCII);
371 pull_string_talloc(frame,rdata,0,
372 &s2,cmnt,len,STR_ASCII);
374 if (!s1 || !s2) {
375 TALLOC_FREE(frame);
376 continue;
379 fn(s1, entry_stype, s2, state);
380 TALLOC_FREE(frame);
383 /* We are done with the old last entry, so now we can free it */
384 if (last_entry) {
385 SAFE_FREE(last_entry); /* This will set it to null */
388 /* We always make a copy of the last entry if we have one */
389 if (sname) {
390 last_entry = smb_xstrdup(sname);
393 /* If we have more data, but no last entry then error out */
394 if (!last_entry && (res == ERRmoredata)) {
395 res = 0;
400 TALLOC_FREE(rparam);
401 TALLOC_FREE(rdata);
402 } while ((res == ERRmoredata) && (total_cnt > return_cnt));
404 TALLOC_FREE(rparam);
405 TALLOC_FREE(rdata);
406 SAFE_FREE(last_entry);
408 if (return_cnt == 0) {
409 return NT_STATUS_NO_MORE_ENTRIES;
411 return NT_STATUS_OK;
414 /****************************************************************************
415 Send a SamOEMChangePassword command.
416 ****************************************************************************/
418 NTSTATUS cli_oem_change_password(struct cli_state *cli,
419 const char *user,
420 const char *new_password,
421 const char *old_password)
423 char param[1024];
424 uint8_t data[532];
425 char *p = param;
426 unsigned char old_pw_hash[16];
427 unsigned char new_pw_hash[16];
428 unsigned int param_len = 0;
429 uint8_t *rparam = NULL;
430 uint32_t rprcnt;
431 gnutls_cipher_hd_t cipher_hnd = NULL;
432 gnutls_datum_t old_pw_key = {
433 .data = old_pw_hash,
434 .size = sizeof(old_pw_hash),
436 int rc, res;
437 NTSTATUS status;
439 if (strlen(user) >= sizeof(fstring)-1) {
440 DBG_ERR("user name %s is too long.\n", user);
441 return NT_STATUS_NAME_TOO_LONG;
444 SSVAL(p,0,214); /* SamOEMChangePassword command. */
445 p += 2;
446 strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
447 p = skip_string(param,sizeof(param),p);
448 strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
449 p = skip_string(param,sizeof(param),p);
450 strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
451 p = skip_string(param,sizeof(param),p);
452 SSVAL(p,0,532);
453 p += 2;
455 param_len = PTR_DIFF(p,param);
458 * Get the Lanman hash of the old password, we
459 * use this as the key to make_oem_passwd_hash().
461 E_deshash(old_password, old_pw_hash);
463 encode_pw_buffer(data, new_password, STR_ASCII);
465 #ifdef DEBUG_PASSWORD
466 DEBUG(100,("make_oem_passwd_hash\n"));
467 dump_data(100, data, 516);
468 #endif
469 rc = gnutls_cipher_init(&cipher_hnd,
470 GNUTLS_CIPHER_ARCFOUR_128,
471 &old_pw_key,
472 NULL);
473 if (rc < 0) {
474 DBG_ERR("gnutls_cipher_init failed: %s\n",
475 gnutls_strerror(rc));
476 status = gnutls_error_to_ntstatus(
477 rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
478 return status;
480 rc = gnutls_cipher_encrypt(cipher_hnd,
481 data,
482 516);
483 gnutls_cipher_deinit(cipher_hnd);
484 if (rc < 0) {
485 status = gnutls_error_to_ntstatus(
486 rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
487 return status;
491 * Now place the old password hash in the data.
493 E_deshash(new_password, new_pw_hash);
495 rc = E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
496 if (rc != 0) {
497 DBG_ERR("E_old_pw_hash failed: %s\n", gnutls_strerror(rc));
498 status = gnutls_error_to_ntstatus(
499 rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
500 return status;
503 status = cli_trans(talloc_tos(), /* mem_ctx */
504 cli, /* cli */
505 SMBtrans, /* cmd */
506 "\\PIPE\\LANMAN", /* name */
507 0, /* fid */
508 0, /* function */
509 0, /* flags */
510 NULL, /* setup */
511 0, /* num_setup */
512 0, /* max_setup */
513 (uint8_t *)param, /* param */
514 param_len, /* num_param */
515 4, /* max_param */
516 data, /* data */
517 sizeof(data), /* num_data */
518 0, /* max_data */
519 NULL, /* recv_flags2 */
520 NULL, /* rsetup */
521 0, /* min_rsetup */
522 NULL, /* num_rsetup */
523 &rparam, /* rparam */
524 2, /* min_rparam */
525 &rprcnt, /* num_rparam */
526 NULL, /* rdata */
527 0, /* min_rdata */
528 NULL); /* num_rdata */
529 if (!NT_STATUS_IS_OK(status)) {
530 return status;
532 res = PULL_LE_U16(rparam, 0);
534 status = werror_to_ntstatus(W_ERROR(res));
536 TALLOC_FREE(rparam);
538 return status;
541 static void prep_basic_information_buf(
542 uint8_t buf[40],
543 struct timespec create_time,
544 struct timespec access_time,
545 struct timespec write_time,
546 struct timespec change_time,
547 uint32_t attr)
549 char *p = (char *)buf;
551 * Add the create, last access, modification, and status change times
553 put_long_date_full_timespec(
554 TIMESTAMP_SET_NT_OR_BETTER, p, &create_time);
555 p += 8;
557 put_long_date_full_timespec(
558 TIMESTAMP_SET_NT_OR_BETTER, p, &access_time);
559 p += 8;
561 put_long_date_full_timespec(
562 TIMESTAMP_SET_NT_OR_BETTER, p, &write_time);
563 p += 8;
565 put_long_date_full_timespec(
566 TIMESTAMP_SET_NT_OR_BETTER, p, &change_time);
567 p += 8;
569 if (attr == (uint32_t)-1 || attr == FILE_ATTRIBUTE_NORMAL) {
570 /* No change. */
571 attr = 0;
572 } else if (attr == 0) {
573 /* Clear all existing attributes. */
574 attr = FILE_ATTRIBUTE_NORMAL;
577 /* Add attributes */
578 SIVAL(p, 0, attr);
580 p += 4;
582 /* Add padding */
583 SIVAL(p, 0, 0);
584 p += 4;
586 SMB_ASSERT(PTR_DIFF(p, buf) == 40);
589 NTSTATUS cli_setpathinfo_ext(struct cli_state *cli, const char *fname,
590 struct timespec create_time,
591 struct timespec access_time,
592 struct timespec write_time,
593 struct timespec change_time,
594 uint32_t attr)
596 uint8_t buf[40];
598 prep_basic_information_buf(
599 buf,
600 create_time,
601 access_time,
602 write_time,
603 change_time,
604 attr);
606 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
607 DATA_BLOB in_data = data_blob_const(buf, sizeof(buf));
609 * Split out SMB2 here as we need to select
610 * the correct info type and level.
612 return cli_smb2_setpathinfo(cli,
613 fname,
614 SMB2_0_INFO_FILE,
615 FSCC_FILE_BASIC_INFORMATION,
616 &in_data);
619 return cli_setpathinfo(
620 cli, SMB_FILE_BASIC_INFORMATION, fname, buf, sizeof(buf));
623 struct cli_setfileinfo_ext_state {
624 uint8_t data[40];
625 DATA_BLOB in_data;
628 static void cli_setfileinfo_ext_done(struct tevent_req *subreq);
629 static void cli_setfileinfo_ext_done2(struct tevent_req *subreq);
631 struct tevent_req *cli_setfileinfo_ext_send(
632 TALLOC_CTX *mem_ctx,
633 struct tevent_context *ev,
634 struct cli_state *cli,
635 uint16_t fnum,
636 struct timespec create_time,
637 struct timespec access_time,
638 struct timespec write_time,
639 struct timespec change_time,
640 uint32_t attr)
642 struct tevent_req *req = NULL, *subreq = NULL;
643 struct cli_setfileinfo_ext_state *state = NULL;
645 req = tevent_req_create(
646 mem_ctx, &state, struct cli_setfileinfo_ext_state);
647 if (req == NULL) {
648 return NULL;
650 prep_basic_information_buf(
651 state->data,
652 create_time,
653 access_time,
654 write_time,
655 change_time,
656 attr);
658 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
659 state->in_data = (DATA_BLOB) {
660 .data = state->data, .length = sizeof(state->data),
663 subreq = cli_smb2_set_info_fnum_send(
664 state,
666 cli,
667 fnum,
668 SMB2_0_INFO_FILE,
669 FSCC_FILE_BASIC_INFORMATION,
670 &state->in_data,
671 0); /* in_additional_info */
672 if (tevent_req_nomem(subreq, req)) {
673 return tevent_req_post(req, ev);
675 tevent_req_set_callback(
676 subreq, cli_setfileinfo_ext_done2, req);
677 return req;
680 subreq = cli_setfileinfo_send(
681 state,
683 cli,
684 fnum,
685 SMB_FILE_BASIC_INFORMATION,
686 state->data,
687 sizeof(state->data));
688 if (tevent_req_nomem(subreq, req)) {
689 return tevent_req_post(req, ev);
691 tevent_req_set_callback(subreq, cli_setfileinfo_ext_done, req);
692 return req;
695 static void cli_setfileinfo_ext_done(struct tevent_req *subreq)
697 NTSTATUS status = cli_setfileinfo_recv(subreq);
698 tevent_req_simple_finish_ntstatus(subreq, status);
701 static void cli_setfileinfo_ext_done2(struct tevent_req *subreq)
703 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
704 tevent_req_simple_finish_ntstatus(subreq, status);
707 NTSTATUS cli_setfileinfo_ext_recv(struct tevent_req *req)
709 return tevent_req_simple_recv_ntstatus(req);
712 NTSTATUS cli_setfileinfo_ext(
713 struct cli_state *cli,
714 uint16_t fnum,
715 struct timespec create_time,
716 struct timespec access_time,
717 struct timespec write_time,
718 struct timespec change_time,
719 uint32_t attr)
721 TALLOC_CTX *frame = NULL;
722 struct tevent_context *ev = NULL;
723 struct tevent_req *req = NULL;
724 NTSTATUS status = NT_STATUS_NO_MEMORY;
726 if (smbXcli_conn_has_async_calls(cli->conn)) {
728 * Can't use sync call while an async call is in flight
730 return NT_STATUS_INVALID_PARAMETER;
733 frame = talloc_stackframe();
735 ev = samba_tevent_context_init(frame);
736 if (ev == NULL) {
737 goto fail;
739 req = cli_setfileinfo_ext_send(
742 cli,
743 fnum,
744 create_time,
745 access_time,
746 write_time,
747 change_time,
748 attr);
749 if (req == NULL) {
750 goto fail;
752 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
753 goto fail;
755 status = cli_setfileinfo_ext_recv(req);
756 fail:
757 TALLOC_FREE(frame);
758 return status;
761 /****************************************************************************
762 Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
763 ****************************************************************************/
765 struct cli_qpathinfo2_state {
766 struct tevent_context *ev;
767 struct cli_state *cli;
768 const char *fname;
769 struct timespec create_time;
770 struct timespec access_time;
771 struct timespec write_time;
772 struct timespec change_time;
773 off_t size;
774 uint32_t attr;
775 SMB_INO_T ino;
776 mode_t mode;
779 static void cli_qpathinfo2_done2(struct tevent_req *subreq);
780 static void cli_qpathinfo2_done(struct tevent_req *subreq);
781 static void cli_qpathinfo2_got_reparse(struct tevent_req *subreq);
783 struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
784 struct tevent_context *ev,
785 struct cli_state *cli,
786 const char *fname)
788 struct tevent_req *req = NULL, *subreq = NULL;
789 struct cli_qpathinfo2_state *state = NULL;
791 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
792 if (req == NULL) {
793 return NULL;
795 state->ev = ev;
796 state->cli = cli;
797 state->fname = fname;
799 state->mode = S_IFREG;
801 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
802 subreq = cli_smb2_qpathinfo_send(state,
804 cli,
805 fname,
806 FSCC_FILE_ALL_INFORMATION,
807 0x60,
808 UINT16_MAX);
809 if (tevent_req_nomem(subreq, req)) {
810 return tevent_req_post(req, ev);
812 tevent_req_set_callback(subreq, cli_qpathinfo2_done2, req);
813 return req;
815 subreq = cli_qpathinfo_send(state, ev, cli, fname,
816 SMB_QUERY_FILE_ALL_INFO,
817 68, CLI_BUFFER_SIZE);
818 if (tevent_req_nomem(subreq, req)) {
819 return tevent_req_post(req, ev);
821 tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
822 return req;
825 static void cli_qpathinfo2_done2(struct tevent_req *subreq)
827 struct tevent_req *req =
828 tevent_req_callback_data(subreq, struct tevent_req);
829 struct cli_qpathinfo2_state *state =
830 tevent_req_data(req, struct cli_qpathinfo2_state);
831 uint8_t *rdata = NULL;
832 uint32_t num_rdata;
833 NTSTATUS status;
835 status = cli_smb2_qpathinfo_recv(subreq, state, &rdata, &num_rdata);
836 TALLOC_FREE(subreq);
837 if (tevent_req_nterror(req, status)) {
838 return;
840 state->create_time = interpret_long_date(BVAL(rdata, 0x0));
841 state->access_time = interpret_long_date(BVAL(rdata, 0x8));
842 state->write_time = interpret_long_date(BVAL(rdata, 0x10));
843 state->change_time = interpret_long_date(BVAL(rdata, 0x18));
844 state->attr = PULL_LE_U32(rdata, 0x20);
845 state->size = PULL_LE_U64(rdata, 0x30);
846 state->ino = PULL_LE_U64(rdata, 0x40);
848 if (state->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
849 subreq = cli_get_reparse_data_send(state,
850 state->ev,
851 state->cli,
852 state->fname);
853 if (tevent_req_nomem(subreq, req)) {
854 return;
856 tevent_req_set_callback(subreq,
857 cli_qpathinfo2_got_reparse,
858 req);
859 return;
862 tevent_req_done(req);
865 static void cli_qpathinfo2_done(struct tevent_req *subreq)
867 struct tevent_req *req = tevent_req_callback_data(
868 subreq, struct tevent_req);
869 struct cli_qpathinfo2_state *state = tevent_req_data(
870 req, struct cli_qpathinfo2_state);
871 uint8_t *data = NULL;
872 uint32_t num_data;
873 NTSTATUS status;
875 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
876 TALLOC_FREE(subreq);
877 if (tevent_req_nterror(req, status)) {
878 return;
881 state->create_time = interpret_long_date(BVAL(data, 0));
882 state->access_time = interpret_long_date(BVAL(data, 8));
883 state->write_time = interpret_long_date(BVAL(data, 16));
884 state->change_time = interpret_long_date(BVAL(data, 24));
885 state->attr = PULL_LE_U32(data, 32);
886 state->size = PULL_LE_U64(data, 48);
889 * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO which doesn't
890 * return an inode number (fileid). We can't change this to
891 * one of the FILE_ID info levels as only Win2003 and above
892 * support these [MS-SMB: 2.2.2.3.1] and the SMB1 code needs
893 * to support older servers.
895 state->ino = 0;
897 TALLOC_FREE(data);
899 if (state->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
900 subreq = cli_get_reparse_data_send(state,
901 state->ev,
902 state->cli,
903 state->fname);
904 if (tevent_req_nomem(subreq, req)) {
905 return;
907 tevent_req_set_callback(subreq,
908 cli_qpathinfo2_got_reparse,
909 req);
910 return;
913 tevent_req_done(req);
916 static void cli_qpathinfo2_got_reparse(struct tevent_req *subreq)
918 struct tevent_req *req =
919 tevent_req_callback_data(subreq, struct tevent_req);
920 struct cli_qpathinfo2_state *state =
921 tevent_req_data(req, struct cli_qpathinfo2_state);
922 uint8_t *data = NULL;
923 uint32_t num_data;
924 struct reparse_data_buffer reparse = {
925 .tag = 0,
927 NTSTATUS status;
929 status = cli_get_reparse_data_recv(subreq, state, &data, &num_data);
930 TALLOC_FREE(subreq);
931 if (tevent_req_nterror(req, status)) {
932 return;
935 status = reparse_data_buffer_parse(state, &reparse, data, num_data);
936 if (!NT_STATUS_IS_OK(status)) {
937 DBG_DEBUG("Ignoring unknown reparse data\n");
938 goto done;
941 switch (reparse.tag) {
942 case IO_REPARSE_TAG_SYMLINK:
943 state->mode = S_IFLNK;
944 break;
945 case IO_REPARSE_TAG_NFS:
946 switch (reparse.parsed.nfs.type) {
947 case NFS_SPECFILE_LNK:
948 state->mode = S_IFLNK;
949 break;
950 case NFS_SPECFILE_CHR:
951 state->mode = S_IFCHR;
952 break;
953 case NFS_SPECFILE_BLK:
954 state->mode = S_IFBLK;
955 break;
956 case NFS_SPECFILE_FIFO:
957 state->mode = S_IFIFO;
958 break;
959 case NFS_SPECFILE_SOCK:
960 state->mode = S_IFSOCK;
961 break;
963 break;
965 done:
966 tevent_req_done(req);
969 NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
970 struct timespec *create_time,
971 struct timespec *access_time,
972 struct timespec *write_time,
973 struct timespec *change_time,
974 off_t *size,
975 uint32_t *pattr,
976 SMB_INO_T *ino,
977 mode_t *mode)
979 struct cli_qpathinfo2_state *state = tevent_req_data(
980 req, struct cli_qpathinfo2_state);
981 NTSTATUS status;
983 if (tevent_req_is_nterror(req, &status)) {
984 return status;
987 if (create_time) {
988 *create_time = state->create_time;
990 if (access_time) {
991 *access_time = state->access_time;
993 if (write_time) {
994 *write_time = state->write_time;
996 if (change_time) {
997 *change_time = state->change_time;
999 if (pattr) {
1000 *pattr = state->attr;
1002 if (size) {
1003 *size = state->size;
1005 if (ino) {
1006 *ino = state->ino;
1008 if (mode != NULL) {
1009 *mode = state->mode;
1011 return NT_STATUS_OK;
1014 NTSTATUS cli_qpathinfo2(struct cli_state *cli,
1015 const char *fname,
1016 struct timespec *create_time,
1017 struct timespec *access_time,
1018 struct timespec *write_time,
1019 struct timespec *change_time,
1020 off_t *size,
1021 uint32_t *pattr,
1022 SMB_INO_T *ino,
1023 mode_t *mode)
1025 TALLOC_CTX *frame = talloc_stackframe();
1026 struct tevent_context *ev = NULL;
1027 struct tevent_req *req = NULL;
1028 NTSTATUS status = NT_STATUS_NO_MEMORY;
1030 if (smbXcli_conn_has_async_calls(cli->conn)) {
1032 * Can't use sync call while an async call is in flight
1034 status = NT_STATUS_INVALID_PARAMETER;
1035 goto fail;
1037 ev = samba_tevent_context_init(frame);
1038 if (ev == NULL) {
1039 goto fail;
1041 req = cli_qpathinfo2_send(frame, ev, cli, fname);
1042 if (req == NULL) {
1043 goto fail;
1045 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1046 goto fail;
1048 status = cli_qpathinfo2_recv(req,
1049 create_time,
1050 access_time,
1051 write_time,
1052 change_time,
1053 size,
1054 pattr,
1055 ino,
1056 mode);
1057 fail:
1058 TALLOC_FREE(frame);
1059 return status;
1062 /****************************************************************************
1063 Get the stream info
1064 ****************************************************************************/
1066 struct cli_qpathinfo_streams_state {
1067 uint32_t num_data;
1068 uint8_t *data;
1071 static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
1072 static void cli_qpathinfo_streams_done2(struct tevent_req *subreq);
1074 struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
1075 struct tevent_context *ev,
1076 struct cli_state *cli,
1077 const char *fname)
1079 struct tevent_req *req = NULL, *subreq = NULL;
1080 struct cli_qpathinfo_streams_state *state = NULL;
1082 req = tevent_req_create(mem_ctx, &state,
1083 struct cli_qpathinfo_streams_state);
1084 if (req == NULL) {
1085 return NULL;
1087 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1088 subreq = cli_smb2_qpathinfo_send(state,
1090 cli,
1091 fname,
1092 FSCC_FILE_STREAM_INFORMATION,
1094 CLI_BUFFER_SIZE);
1095 if (tevent_req_nomem(subreq, req)) {
1096 return tevent_req_post(req, ev);
1098 tevent_req_set_callback(subreq,
1099 cli_qpathinfo_streams_done2,
1100 req);
1101 return req;
1103 subreq = cli_qpathinfo_send(state, ev, cli, fname,
1104 SMB_FILE_STREAM_INFORMATION,
1105 0, CLI_BUFFER_SIZE);
1106 if (tevent_req_nomem(subreq, req)) {
1107 return tevent_req_post(req, ev);
1109 tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
1110 return req;
1113 static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
1115 struct tevent_req *req = tevent_req_callback_data(
1116 subreq, struct tevent_req);
1117 struct cli_qpathinfo_streams_state *state = tevent_req_data(
1118 req, struct cli_qpathinfo_streams_state);
1119 NTSTATUS status;
1121 status = cli_qpathinfo_recv(subreq, state, &state->data,
1122 &state->num_data);
1123 tevent_req_simple_finish_ntstatus(subreq, status);
1126 static void cli_qpathinfo_streams_done2(struct tevent_req *subreq)
1128 struct tevent_req *req =
1129 tevent_req_callback_data(subreq, struct tevent_req);
1130 struct cli_qpathinfo_streams_state *state =
1131 tevent_req_data(req, struct cli_qpathinfo_streams_state);
1132 NTSTATUS status;
1134 status = cli_smb2_qpathinfo_recv(subreq,
1135 state,
1136 &state->data,
1137 &state->num_data);
1138 tevent_req_simple_finish_ntstatus(subreq, status);
1141 NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
1142 TALLOC_CTX *mem_ctx,
1143 unsigned int *pnum_streams,
1144 struct stream_struct **pstreams)
1146 struct cli_qpathinfo_streams_state *state = tevent_req_data(
1147 req, struct cli_qpathinfo_streams_state);
1148 NTSTATUS status;
1150 if (tevent_req_is_nterror(req, &status)) {
1151 return status;
1153 if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
1154 pnum_streams, pstreams)) {
1155 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1157 return NT_STATUS_OK;
1160 NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
1161 TALLOC_CTX *mem_ctx,
1162 unsigned int *pnum_streams,
1163 struct stream_struct **pstreams)
1165 TALLOC_CTX *frame = NULL;
1166 struct tevent_context *ev;
1167 struct tevent_req *req;
1168 NTSTATUS status = NT_STATUS_NO_MEMORY;
1170 frame = talloc_stackframe();
1172 if (smbXcli_conn_has_async_calls(cli->conn)) {
1174 * Can't use sync call while an async call is in flight
1176 status = NT_STATUS_INVALID_PARAMETER;
1177 goto fail;
1179 ev = samba_tevent_context_init(frame);
1180 if (ev == NULL) {
1181 goto fail;
1183 req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
1184 if (req == NULL) {
1185 goto fail;
1187 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1188 goto fail;
1190 status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
1191 pstreams);
1192 fail:
1193 TALLOC_FREE(frame);
1194 return status;
1197 bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
1198 size_t data_len,
1199 unsigned int *pnum_streams,
1200 struct stream_struct **pstreams)
1202 unsigned int num_streams;
1203 struct stream_struct *streams;
1204 unsigned int ofs;
1206 num_streams = 0;
1207 streams = NULL;
1208 ofs = 0;
1210 while ((data_len > ofs) && (data_len - ofs >= 24)) {
1211 uint32_t nlen, len;
1212 size_t size;
1213 void *vstr;
1214 struct stream_struct *tmp;
1215 uint8_t *tmp_buf;
1217 tmp = talloc_realloc(mem_ctx, streams,
1218 struct stream_struct,
1219 num_streams+1);
1221 if (tmp == NULL) {
1222 goto fail;
1224 streams = tmp;
1226 nlen = IVAL(rdata, ofs + 0x04);
1228 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1229 rdata, ofs + 0x08);
1230 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1231 rdata, ofs + 0x10);
1233 if (nlen > data_len - (ofs + 24)) {
1234 goto fail;
1238 * We need to null-terminate src, how do I do this with
1239 * convert_string_talloc??
1242 tmp_buf = talloc_array(streams, uint8_t, nlen+2);
1243 if (tmp_buf == NULL) {
1244 goto fail;
1247 memcpy(tmp_buf, rdata+ofs+24, nlen);
1248 tmp_buf[nlen] = 0;
1249 tmp_buf[nlen+1] = 0;
1251 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1252 nlen+2, &vstr, &size))
1254 TALLOC_FREE(tmp_buf);
1255 goto fail;
1258 TALLOC_FREE(tmp_buf);
1259 streams[num_streams].name = (char *)vstr;
1260 num_streams++;
1262 len = IVAL(rdata, ofs);
1263 if (len > data_len - ofs) {
1264 goto fail;
1266 if (len == 0) break;
1267 ofs += len;
1270 *pnum_streams = num_streams;
1271 *pstreams = streams;
1272 return true;
1274 fail:
1275 TALLOC_FREE(streams);
1276 return false;
1279 /****************************************************************************
1280 Send a qfileinfo QUERY_FILE_NAME_INFO call.
1281 ****************************************************************************/
1283 struct cli_qfileinfo_basic_state {
1284 uint32_t attr;
1285 off_t size;
1286 struct timespec create_time;
1287 struct timespec access_time;
1288 struct timespec write_time;
1289 struct timespec change_time;
1290 SMB_INO_T ino;
1293 static void cli_qfileinfo_basic_done(struct tevent_req *subreq);
1294 static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq);
1296 struct tevent_req *cli_qfileinfo_basic_send(
1297 TALLOC_CTX *mem_ctx,
1298 struct tevent_context *ev,
1299 struct cli_state *cli,
1300 uint16_t fnum)
1302 struct tevent_req *req = NULL, *subreq = NULL;
1303 struct cli_qfileinfo_basic_state *state = NULL;
1305 req = tevent_req_create(
1306 mem_ctx, &state, struct cli_qfileinfo_basic_state);
1307 if (req == NULL) {
1308 return NULL;
1311 if ((smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN2) ||
1312 cli->win95) {
1314 * According to
1315 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/3d9d8f3e-dc70-410d-a3fc-6f4a881e8cab
1316 * SMB_COM_TRANSACTION2 used in cli_qfileinfo_send()
1317 * further down was introduced with the LAN Manager
1318 * 1.2 dialect, which we encode as PROTOCOL_LANMAN2.
1320 * The "win95" check was introduced with commit
1321 * 27e5850fd3e1c8 in 1998. Hard to check these days,
1322 * but leave it in.
1324 * Use a lowerlevel fallback in both cases.
1327 subreq = cli_getattrE_send(state, ev, cli, fnum);
1328 if (tevent_req_nomem(subreq, req)) {
1329 return tevent_req_post(req, ev);
1331 tevent_req_set_callback(
1332 subreq, cli_qfileinfo_basic_doneE, req);
1333 return req;
1336 subreq = cli_qfileinfo_send(state,
1338 cli,
1339 fnum,
1340 FSCC_FILE_ALL_INFORMATION, /* level */
1341 68, /* min_rdata */
1342 CLI_BUFFER_SIZE); /* max_rdata */
1343 if (tevent_req_nomem(subreq, req)) {
1344 return tevent_req_post(req, ev);
1346 tevent_req_set_callback(subreq, cli_qfileinfo_basic_done, req);
1347 return req;
1350 static void cli_qfileinfo_basic_done(struct tevent_req *subreq)
1352 struct tevent_req *req = tevent_req_callback_data(
1353 subreq, struct tevent_req);
1354 struct cli_qfileinfo_basic_state *state = tevent_req_data(
1355 req, struct cli_qfileinfo_basic_state);
1356 uint8_t *rdata;
1357 uint32_t num_rdata;
1358 NTSTATUS status;
1360 status = cli_qfileinfo_recv(
1361 subreq, state, NULL, &rdata, &num_rdata);
1362 TALLOC_FREE(subreq);
1363 if (tevent_req_nterror(req, status)) {
1364 return;
1367 state->create_time = interpret_long_date(BVAL(rdata, 0));
1368 state->access_time = interpret_long_date(BVAL(rdata, 8));
1369 state->write_time = interpret_long_date(BVAL(rdata, 16));
1370 state->change_time = interpret_long_date(BVAL(rdata, 24));
1371 state->attr = PULL_LE_U32(rdata, 32);
1372 state->size = PULL_LE_U64(rdata,48);
1373 state->ino = PULL_LE_U32(rdata, 64);
1374 TALLOC_FREE(rdata);
1376 tevent_req_done(req);
1379 static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq)
1381 struct tevent_req *req = tevent_req_callback_data(
1382 subreq, struct tevent_req);
1383 struct cli_qfileinfo_basic_state *state = tevent_req_data(
1384 req, struct cli_qfileinfo_basic_state);
1385 NTSTATUS status;
1387 status = cli_getattrE_recv(
1388 subreq,
1389 &state->attr,
1390 &state->size,
1391 &state->change_time.tv_sec,
1392 &state->access_time.tv_sec,
1393 &state->write_time.tv_sec);
1394 TALLOC_FREE(subreq);
1395 if (tevent_req_nterror(req, status)) {
1396 return;
1398 tevent_req_done(req);
1401 NTSTATUS cli_qfileinfo_basic_recv(
1402 struct tevent_req *req,
1403 uint32_t *attr,
1404 off_t *size,
1405 struct timespec *create_time,
1406 struct timespec *access_time,
1407 struct timespec *write_time,
1408 struct timespec *change_time,
1409 SMB_INO_T *ino)
1411 struct cli_qfileinfo_basic_state *state = tevent_req_data(
1412 req, struct cli_qfileinfo_basic_state);
1413 NTSTATUS status;
1415 if (tevent_req_is_nterror(req, &status)) {
1416 return status;
1419 if (create_time != NULL) {
1420 *create_time = state->create_time;
1422 if (access_time != NULL) {
1423 *access_time = state->access_time;
1425 if (write_time != NULL) {
1426 *write_time = state->write_time;
1428 if (change_time != NULL) {
1429 *change_time = state->change_time;
1431 if (attr != NULL) {
1432 *attr = state->attr;
1434 if (size != NULL) {
1435 *size = state->size;
1437 if (ino) {
1438 *ino = state->ino;
1441 return NT_STATUS_OK;
1443 /****************************************************************************
1444 Send a qfileinfo call.
1445 ****************************************************************************/
1447 NTSTATUS cli_qfileinfo_basic(
1448 struct cli_state *cli,
1449 uint16_t fnum,
1450 uint32_t *attr,
1451 off_t *size,
1452 struct timespec *create_time,
1453 struct timespec *access_time,
1454 struct timespec *write_time,
1455 struct timespec *change_time,
1456 SMB_INO_T *ino)
1458 TALLOC_CTX *frame = NULL;
1459 struct tevent_context *ev = NULL;
1460 struct tevent_req *req = NULL;
1461 NTSTATUS status = NT_STATUS_NO_MEMORY;
1463 frame = talloc_stackframe();
1465 if (smbXcli_conn_has_async_calls(cli->conn)) {
1467 * Can't use sync call while an async call is in flight
1469 status = NT_STATUS_INVALID_PARAMETER;
1470 goto fail;
1472 ev = samba_tevent_context_init(frame);
1473 if (ev == NULL) {
1474 goto fail;
1476 req = cli_qfileinfo_basic_send(frame, ev, cli, fnum);
1477 if (req == NULL) {
1478 goto fail;
1480 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1481 goto fail;
1484 status = cli_qfileinfo_basic_recv(
1485 req,
1486 attr,
1487 size,
1488 create_time,
1489 access_time,
1490 write_time,
1491 change_time,
1492 ino);
1493 fail:
1494 TALLOC_FREE(frame);
1495 return status;
1498 /****************************************************************************
1499 Send a qpathinfo BASIC_INFO call.
1500 ****************************************************************************/
1502 struct cli_qpathinfo_basic_state {
1503 uint32_t num_data;
1504 uint8_t *data;
1507 static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1509 struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1510 struct tevent_context *ev,
1511 struct cli_state *cli,
1512 const char *fname)
1514 struct tevent_req *req = NULL, *subreq = NULL;
1515 struct cli_qpathinfo_basic_state *state = NULL;
1517 req = tevent_req_create(mem_ctx, &state,
1518 struct cli_qpathinfo_basic_state);
1519 if (req == NULL) {
1520 return NULL;
1522 subreq = cli_qpathinfo_send(state, ev, cli, fname,
1523 SMB_QUERY_FILE_BASIC_INFO,
1524 36, CLI_BUFFER_SIZE);
1525 if (tevent_req_nomem(subreq, req)) {
1526 return tevent_req_post(req, ev);
1528 tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1529 return req;
1532 static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1534 struct tevent_req *req = tevent_req_callback_data(
1535 subreq, struct tevent_req);
1536 struct cli_qpathinfo_basic_state *state = tevent_req_data(
1537 req, struct cli_qpathinfo_basic_state);
1538 NTSTATUS status;
1540 status = cli_qpathinfo_recv(subreq, state, &state->data,
1541 &state->num_data);
1542 TALLOC_FREE(subreq);
1543 if (tevent_req_nterror(req, status)) {
1544 return;
1546 tevent_req_done(req);
1549 NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1550 SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1552 struct cli_qpathinfo_basic_state *state = tevent_req_data(
1553 req, struct cli_qpathinfo_basic_state);
1554 NTSTATUS status;
1556 if (tevent_req_is_nterror(req, &status)) {
1557 return status;
1560 sbuf->st_ex_btime = interpret_long_date(BVAL(state->data, 0));
1561 sbuf->st_ex_atime = interpret_long_date(BVAL(state->data, 8));
1562 sbuf->st_ex_mtime = interpret_long_date(BVAL(state->data, 16));
1563 sbuf->st_ex_ctime = interpret_long_date(BVAL(state->data, 24));
1564 *attributes = IVAL(state->data, 32);
1565 return NT_STATUS_OK;
1568 NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1569 SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1571 TALLOC_CTX *frame = NULL;
1572 struct tevent_context *ev;
1573 struct tevent_req *req;
1574 NTSTATUS status = NT_STATUS_NO_MEMORY;
1576 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1577 return cli_smb2_qpathinfo_basic(cli,
1578 name,
1579 sbuf,
1580 attributes);
1583 frame = talloc_stackframe();
1585 if (smbXcli_conn_has_async_calls(cli->conn)) {
1587 * Can't use sync call while an async call is in flight
1589 status = NT_STATUS_INVALID_PARAMETER;
1590 goto fail;
1592 ev = samba_tevent_context_init(frame);
1593 if (ev == NULL) {
1594 goto fail;
1596 req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1597 if (req == NULL) {
1598 goto fail;
1600 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1601 goto fail;
1603 status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1604 fail:
1605 TALLOC_FREE(frame);
1606 return status;
1609 /****************************************************************************
1610 Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1611 ****************************************************************************/
1613 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1615 uint8_t *rdata;
1616 uint32_t num_rdata;
1617 unsigned int len;
1618 char *converted = NULL;
1619 size_t converted_size = 0;
1620 NTSTATUS status;
1622 status = cli_qpathinfo(talloc_tos(), cli, fname,
1623 SMB_QUERY_FILE_ALT_NAME_INFO,
1624 4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1625 if (!NT_STATUS_IS_OK(status)) {
1626 return status;
1629 len = IVAL(rdata, 0);
1631 if (len > num_rdata - 4) {
1632 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1635 /* The returned data is a pushed string, not raw data. */
1636 if (!convert_string_talloc(talloc_tos(),
1637 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
1638 CH_UNIX,
1639 rdata + 4,
1640 len,
1641 &converted,
1642 &converted_size)) {
1643 return NT_STATUS_NO_MEMORY;
1645 fstrcpy(alt_name, converted);
1647 TALLOC_FREE(converted);
1648 TALLOC_FREE(rdata);
1650 return NT_STATUS_OK;
1653 /****************************************************************************
1654 Send a qpathinfo SMB_QUERY_FILE_STANDARD_INFO call.
1655 ****************************************************************************/
1657 static NTSTATUS cli_qpathinfo_standard(struct cli_state *cli,
1658 const char *fname,
1659 uint64_t *allocated,
1660 uint64_t *size,
1661 uint32_t *nlinks,
1662 bool *is_del_pending,
1663 bool *is_dir)
1665 uint8_t *rdata;
1666 uint32_t num_rdata;
1667 NTSTATUS status;
1669 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1670 return NT_STATUS_NOT_IMPLEMENTED;
1673 status = cli_qpathinfo(talloc_tos(), cli, fname,
1674 SMB_QUERY_FILE_STANDARD_INFO,
1675 24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1676 if (!NT_STATUS_IS_OK(status)) {
1677 return status;
1680 if (allocated) {
1681 *allocated = BVAL(rdata, 0);
1684 if (size) {
1685 *size = BVAL(rdata, 8);
1688 if (nlinks) {
1689 *nlinks = IVAL(rdata, 16);
1692 if (is_del_pending) {
1693 *is_del_pending = CVAL(rdata, 20);
1696 if (is_dir) {
1697 *is_dir = CVAL(rdata, 20);
1700 TALLOC_FREE(rdata);
1702 return NT_STATUS_OK;
1706 /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
1707 NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
1708 struct timespec *create_time,
1709 struct timespec *access_time,
1710 struct timespec *write_time,
1711 struct timespec *change_time,
1712 off_t *size, uint32_t *pattr,
1713 SMB_INO_T *ino)
1715 NTSTATUS status = NT_STATUS_OK;
1716 SMB_STRUCT_STAT st = { 0 };
1717 uint32_t attr = 0;
1718 uint64_t pos;
1720 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1722 * NB. cli_qpathinfo2() checks pattr is valid before
1723 * storing a value into it, so we don't need to use
1724 * an intermediate attr variable as below but can
1725 * pass pattr directly.
1727 return cli_qpathinfo2(cli,
1728 fname,
1729 create_time,
1730 access_time,
1731 write_time,
1732 change_time,
1733 size,
1734 pattr,
1735 ino,
1736 NULL);
1739 if (create_time || access_time || write_time || change_time || pattr) {
1741 * cli_qpathinfo_basic() always indirects the passed
1742 * in pointers so we use intermediate variables to
1743 * collect all of them before assigning any requested
1744 * below.
1746 status = cli_qpathinfo_basic(cli, fname, &st, &attr);
1747 if (!NT_STATUS_IS_OK(status)) {
1748 return status;
1752 if (size) {
1753 status = cli_qpathinfo_standard(cli, fname,
1754 NULL, &pos, NULL, NULL, NULL);
1755 if (!NT_STATUS_IS_OK(status)) {
1756 return status;
1759 *size = pos;
1762 if (create_time) {
1763 *create_time = st.st_ex_btime;
1765 if (access_time) {
1766 *access_time = st.st_ex_atime;
1768 if (write_time) {
1769 *write_time = st.st_ex_mtime;
1771 if (change_time) {
1772 *change_time = st.st_ex_ctime;
1774 if (pattr) {
1775 *pattr = attr;
1777 if (ino) {
1778 *ino = 0;
1781 return NT_STATUS_OK;