2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
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/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "lib/util_ea.h"
43 uint64_t fid_persistent;
44 uint64_t fid_volatile;
48 * Handle mapping code.
51 /***************************************************************
52 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
53 Ensures handle is owned by cli struct.
54 ***************************************************************/
56 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
57 const struct smb2_hnd *ph, /* In */
58 uint16_t *pfnum) /* Out */
61 struct idr_context *idp = cli->smb2.open_handles;
62 struct smb2_hnd *owned_h = talloc_memdup(cli,
64 sizeof(struct smb2_hnd));
66 if (owned_h == NULL) {
67 return NT_STATUS_NO_MEMORY;
72 cli->smb2.open_handles = idr_init(cli);
73 if (cli->smb2.open_handles == NULL) {
75 return NT_STATUS_NO_MEMORY;
77 idp = cli->smb2.open_handles;
80 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
83 return NT_STATUS_NO_MEMORY;
86 *pfnum = (uint16_t)ret;
90 /***************************************************************
91 Return the smb2_hnd pointer associated with the given fnum.
92 ***************************************************************/
94 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
95 uint16_t fnum, /* In */
96 struct smb2_hnd **pph) /* Out */
98 struct idr_context *idp = cli->smb2.open_handles;
101 return NT_STATUS_INVALID_PARAMETER;
103 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
105 return NT_STATUS_INVALID_HANDLE;
110 /***************************************************************
111 Delete the fnum to smb2_hnd mapping. Zeros out handle on
113 ***************************************************************/
115 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
116 struct smb2_hnd **pph, /* In */
117 uint16_t fnum) /* In */
119 struct idr_context *idp = cli->smb2.open_handles;
123 return NT_STATUS_INVALID_PARAMETER;
126 ph = (struct smb2_hnd *)idr_find(idp, fnum);
128 return NT_STATUS_INVALID_PARAMETER;
130 idr_remove(idp, fnum);
135 /***************************************************************
137 ***************************************************************/
139 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
141 if (create_flags & REQUEST_BATCH_OPLOCK) {
142 return SMB2_OPLOCK_LEVEL_BATCH;
143 } else if (create_flags & REQUEST_OPLOCK) {
144 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
147 /* create_flags doesn't do a level2 request. */
148 return SMB2_OPLOCK_LEVEL_NONE;
151 /***************************************************************
152 Small wrapper that allows SMB2 create to return a uint16_t fnum.
153 ***************************************************************/
155 struct cli_smb2_create_fnum_state {
156 struct cli_state *cli;
157 struct smb_create_returns cr;
159 struct tevent_req *subreq;
162 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
163 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
165 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
166 struct tevent_context *ev,
167 struct cli_state *cli,
169 uint32_t create_flags,
170 uint32_t desired_access,
171 uint32_t file_attributes,
172 uint32_t share_access,
173 uint32_t create_disposition,
174 uint32_t create_options)
176 struct tevent_req *req, *subreq;
177 struct cli_smb2_create_fnum_state *state;
179 req = tevent_req_create(mem_ctx, &state,
180 struct cli_smb2_create_fnum_state);
186 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
187 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
188 return tevent_req_post(req, ev);
191 if (cli->backup_intent) {
192 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
195 /* SMB2 is pickier about pathnames. Ensure it doesn't
197 if (*fname == '\\') {
201 subreq = smb2cli_create_send(state, ev,
207 flags_to_smb2_oplock(create_flags),
208 SMB2_IMPERSONATION_IMPERSONATION,
215 if (tevent_req_nomem(subreq, req)) {
216 return tevent_req_post(req, ev);
218 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
220 state->subreq = subreq;
221 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
226 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
228 struct tevent_req *req = tevent_req_callback_data(
229 subreq, struct tevent_req);
230 struct cli_smb2_create_fnum_state *state = tevent_req_data(
231 req, struct cli_smb2_create_fnum_state);
235 status = smb2cli_create_recv(subreq, &h.fid_persistent,
236 &h.fid_volatile, &state->cr, NULL, NULL);
238 if (tevent_req_nterror(req, status)) {
242 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
243 if (tevent_req_nterror(req, status)) {
246 tevent_req_done(req);
249 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
251 struct cli_smb2_create_fnum_state *state = tevent_req_data(
252 req, struct cli_smb2_create_fnum_state);
253 return tevent_req_cancel(state->subreq);
256 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
257 struct smb_create_returns *cr)
259 struct cli_smb2_create_fnum_state *state = tevent_req_data(
260 req, struct cli_smb2_create_fnum_state);
263 if (tevent_req_is_nterror(req, &status)) {
267 *pfnum = state->fnum;
275 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
277 uint32_t create_flags,
278 uint32_t desired_access,
279 uint32_t file_attributes,
280 uint32_t share_access,
281 uint32_t create_disposition,
282 uint32_t create_options,
284 struct smb_create_returns *cr)
286 TALLOC_CTX *frame = talloc_stackframe();
287 struct tevent_context *ev;
288 struct tevent_req *req;
289 NTSTATUS status = NT_STATUS_NO_MEMORY;
291 if (smbXcli_conn_has_async_calls(cli->conn)) {
293 * Can't use sync call while an async call is in flight
295 status = NT_STATUS_INVALID_PARAMETER;
298 ev = samba_tevent_context_init(frame);
302 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
303 desired_access, file_attributes,
304 share_access, create_disposition,
309 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
312 status = cli_smb2_create_fnum_recv(req, pfid, cr);
318 /***************************************************************
319 Small wrapper that allows SMB2 close to use a uint16_t fnum.
320 ***************************************************************/
322 struct cli_smb2_close_fnum_state {
323 struct cli_state *cli;
328 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
330 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
331 struct tevent_context *ev,
332 struct cli_state *cli,
335 struct tevent_req *req, *subreq;
336 struct cli_smb2_close_fnum_state *state;
339 req = tevent_req_create(mem_ctx, &state,
340 struct cli_smb2_close_fnum_state);
347 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
348 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
349 return tevent_req_post(req, ev);
352 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
353 if (tevent_req_nterror(req, status)) {
354 return tevent_req_post(req, ev);
357 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
358 cli->smb2.session, cli->smb2.tcon,
359 0, state->ph->fid_persistent,
360 state->ph->fid_volatile);
361 if (tevent_req_nomem(subreq, req)) {
362 return tevent_req_post(req, ev);
364 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
368 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
370 struct tevent_req *req = tevent_req_callback_data(
371 subreq, struct tevent_req);
372 struct cli_smb2_close_fnum_state *state = tevent_req_data(
373 req, struct cli_smb2_close_fnum_state);
376 status = smb2cli_close_recv(subreq);
377 if (tevent_req_nterror(req, status)) {
381 /* Delete the fnum -> handle mapping. */
382 status = delete_smb2_handle_mapping(state->cli, &state->ph,
384 if (tevent_req_nterror(req, status)) {
387 tevent_req_done(req);
390 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
392 return tevent_req_simple_recv_ntstatus(req);
395 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
397 TALLOC_CTX *frame = talloc_stackframe();
398 struct tevent_context *ev;
399 struct tevent_req *req;
400 NTSTATUS status = NT_STATUS_NO_MEMORY;
402 if (smbXcli_conn_has_async_calls(cli->conn)) {
404 * Can't use sync call while an async call is in flight
406 status = NT_STATUS_INVALID_PARAMETER;
409 ev = samba_tevent_context_init(frame);
413 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
417 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
420 status = cli_smb2_close_fnum_recv(req);
426 /***************************************************************
427 Small wrapper that allows SMB2 to create a directory
429 ***************************************************************/
431 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
436 if (smbXcli_conn_has_async_calls(cli->conn)) {
438 * Can't use sync call while an async call is in flight
440 return NT_STATUS_INVALID_PARAMETER;
443 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
444 return NT_STATUS_INVALID_PARAMETER;
447 status = cli_smb2_create_fnum(cli,
449 0, /* create_flags */
450 FILE_READ_ATTRIBUTES, /* desired_access */
451 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
452 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
453 FILE_CREATE, /* create_disposition */
454 FILE_DIRECTORY_FILE, /* create_options */
458 if (!NT_STATUS_IS_OK(status)) {
461 return cli_smb2_close_fnum(cli, fnum);
464 /***************************************************************
465 Small wrapper that allows SMB2 to delete a directory
467 ***************************************************************/
469 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
474 if (smbXcli_conn_has_async_calls(cli->conn)) {
476 * Can't use sync call while an async call is in flight
478 return NT_STATUS_INVALID_PARAMETER;
481 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
482 return NT_STATUS_INVALID_PARAMETER;
485 status = cli_smb2_create_fnum(cli,
487 0, /* create_flags */
488 DELETE_ACCESS, /* desired_access */
489 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
490 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
491 FILE_OPEN, /* create_disposition */
492 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
496 if (!NT_STATUS_IS_OK(status)) {
499 return cli_smb2_close_fnum(cli, fnum);
502 /***************************************************************
503 Small wrapper that allows SMB2 to unlink a pathname.
505 ***************************************************************/
507 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
512 if (smbXcli_conn_has_async_calls(cli->conn)) {
514 * Can't use sync call while an async call is in flight
516 return NT_STATUS_INVALID_PARAMETER;
519 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
520 return NT_STATUS_INVALID_PARAMETER;
523 status = cli_smb2_create_fnum(cli,
525 0, /* create_flags */
526 DELETE_ACCESS, /* desired_access */
527 FILE_ATTRIBUTE_NORMAL, /* file attributes */
528 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
529 FILE_OPEN, /* create_disposition */
530 FILE_DELETE_ON_CLOSE, /* create_options */
534 if (!NT_STATUS_IS_OK(status)) {
537 return cli_smb2_close_fnum(cli, fnum);
540 /***************************************************************
541 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
542 ***************************************************************/
544 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
545 uint32_t dir_data_length,
546 struct file_info *finfo,
547 uint32_t *next_offset)
553 if (dir_data_length < 4) {
554 return NT_STATUS_INFO_LENGTH_MISMATCH;
557 *next_offset = IVAL(dir_data, 0);
559 if (*next_offset > dir_data_length) {
560 return NT_STATUS_INFO_LENGTH_MISMATCH;
563 if (*next_offset != 0) {
564 /* Ensure we only read what in this record. */
565 dir_data_length = *next_offset;
568 if (dir_data_length < 105) {
569 return NT_STATUS_INFO_LENGTH_MISMATCH;
572 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
573 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
574 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
575 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
576 finfo->mode = CVAL(dir_data + 56, 0);
577 namelen = IVAL(dir_data + 60,0);
578 if (namelen > (dir_data_length - 104)) {
579 return NT_STATUS_INFO_LENGTH_MISMATCH;
581 slen = CVAL(dir_data + 68, 0);
583 return NT_STATUS_INFO_LENGTH_MISMATCH;
585 ret = pull_string_talloc(finfo,
587 FLAGS2_UNICODE_STRINGS,
592 if (ret == (size_t)-1) {
593 /* Bad conversion. */
594 return NT_STATUS_INVALID_NETWORK_RESPONSE;
597 ret = pull_string_talloc(finfo,
599 FLAGS2_UNICODE_STRINGS,
604 if (ret == (size_t)-1) {
605 /* Bad conversion. */
606 return NT_STATUS_INVALID_NETWORK_RESPONSE;
611 /*******************************************************************
612 Given a filename - get its directory name
613 ********************************************************************/
615 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
623 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
626 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
637 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
640 (*parent)[len] = '\0';
648 /***************************************************************
649 Wrapper that allows SMB2 to list a directory.
651 ***************************************************************/
653 NTSTATUS cli_smb2_list(struct cli_state *cli,
654 const char *pathname,
656 NTSTATUS (*fn)(const char *,
663 uint16_t fnum = 0xffff;
664 char *parent_dir = NULL;
665 const char *mask = NULL;
666 struct smb2_hnd *ph = NULL;
667 bool processed_file = false;
668 TALLOC_CTX *frame = talloc_stackframe();
669 TALLOC_CTX *subframe = NULL;
672 if (smbXcli_conn_has_async_calls(cli->conn)) {
674 * Can't use sync call while an async call is in flight
676 status = NT_STATUS_INVALID_PARAMETER;
680 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
681 status = NT_STATUS_INVALID_PARAMETER;
685 /* Get the directory name. */
686 if (!windows_parent_dirname(frame,
690 status = NT_STATUS_NO_MEMORY;
694 mask_has_wild = ms_has_wild(mask);
696 status = cli_smb2_create_fnum(cli,
698 0, /* create_flags */
699 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
700 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
701 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
702 FILE_OPEN, /* create_disposition */
703 FILE_DIRECTORY_FILE, /* create_options */
707 if (!NT_STATUS_IS_OK(status)) {
711 status = map_fnum_to_smb2_handle(cli,
714 if (!NT_STATUS_IS_OK(status)) {
719 uint8_t *dir_data = NULL;
720 uint32_t dir_data_length = 0;
721 uint32_t next_offset = 0;
722 subframe = talloc_stackframe();
724 status = smb2cli_query_directory(cli->conn,
728 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
739 if (!NT_STATUS_IS_OK(status)) {
740 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
747 struct file_info *finfo = talloc_zero(subframe,
751 status = NT_STATUS_NO_MEMORY;
755 status = parse_finfo_id_both_directory_info(dir_data,
760 if (!NT_STATUS_IS_OK(status)) {
764 if (dir_check_ftype((uint32_t)finfo->mode,
765 (uint32_t)attribute)) {
767 * Only process if attributes match.
768 * On SMB1 server does this, so on
769 * SMB2 we need to emulate in the
772 * https://bugzilla.samba.org/show_bug.cgi?id=10260
774 processed_file = true;
776 status = fn(cli->dfs_mountpoint,
781 if (!NT_STATUS_IS_OK(status)) {
788 /* Move to next entry. */
790 dir_data += next_offset;
791 dir_data_length -= next_offset;
793 } while (next_offset != 0);
795 TALLOC_FREE(subframe);
797 if (!mask_has_wild) {
799 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
800 * when handed a non-wildcard path. Do it
801 * for the server (with a non-wildcard path
802 * there should only ever be one file returned.
804 status = STATUS_NO_MORE_FILES;
808 } while (NT_STATUS_IS_OK(status));
810 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
811 status = NT_STATUS_OK;
814 if (NT_STATUS_IS_OK(status) && !processed_file) {
816 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
817 * if no files match. Emulate this in the client.
819 status = NT_STATUS_NO_SUCH_FILE;
824 if (fnum != 0xffff) {
825 cli_smb2_close_fnum(cli, fnum);
827 TALLOC_FREE(subframe);
832 /***************************************************************
833 Wrapper that allows SMB2 to query a path info (basic level).
835 ***************************************************************/
837 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
839 SMB_STRUCT_STAT *sbuf,
840 uint32_t *attributes)
843 struct smb_create_returns cr;
844 uint16_t fnum = 0xffff;
845 size_t namelen = strlen(name);
847 if (smbXcli_conn_has_async_calls(cli->conn)) {
849 * Can't use sync call while an async call is in flight
851 return NT_STATUS_INVALID_PARAMETER;
854 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
855 return NT_STATUS_INVALID_PARAMETER;
858 /* SMB2 is pickier about pathnames. Ensure it doesn't
860 if (namelen > 0 && name[namelen-1] == '\\') {
861 char *modname = talloc_strdup(talloc_tos(), name);
862 modname[namelen-1] = '\0';
866 /* This is commonly used as a 'cd'. Try qpathinfo on
867 a directory handle first. */
869 status = cli_smb2_create_fnum(cli,
871 0, /* create_flags */
872 FILE_READ_ATTRIBUTES, /* desired_access */
873 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
874 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
875 FILE_OPEN, /* create_disposition */
876 FILE_DIRECTORY_FILE, /* create_options */
880 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
882 status = cli_smb2_create_fnum(cli,
884 0, /* create_flags */
885 FILE_READ_ATTRIBUTES, /* desired_access */
886 0, /* file attributes */
887 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
888 FILE_OPEN, /* create_disposition */
889 0, /* create_options */
894 if (!NT_STATUS_IS_OK(status)) {
898 cli_smb2_close_fnum(cli, fnum);
902 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
903 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
904 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
905 sbuf->st_ex_size = cr.end_of_file;
906 *attributes = cr.file_attributes;
911 /***************************************************************
912 Helper function for pathname operations.
913 ***************************************************************/
915 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
917 uint32_t desired_access,
921 size_t namelen = strlen(name);
922 TALLOC_CTX *frame = talloc_stackframe();
924 /* SMB2 is pickier about pathnames. Ensure it doesn't
926 if (namelen > 0 && name[namelen-1] == '\\') {
927 char *modname = talloc_strdup(frame, name);
928 if (modname == NULL) {
929 status = NT_STATUS_NO_MEMORY;
932 modname[namelen-1] = '\0';
936 /* Try to open a file handle first. */
937 status = cli_smb2_create_fnum(cli,
939 0, /* create_flags */
941 0, /* file attributes */
942 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
943 FILE_OPEN, /* create_disposition */
944 0, /* create_options */
948 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
949 status = cli_smb2_create_fnum(cli,
951 0, /* create_flags */
953 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
954 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
955 FILE_OPEN, /* create_disposition */
956 FILE_DIRECTORY_FILE, /* create_options */
967 /***************************************************************
968 Wrapper that allows SMB2 to query a path info (ALTNAME level).
970 ***************************************************************/
972 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
977 DATA_BLOB outbuf = data_blob_null;
978 uint16_t fnum = 0xffff;
979 struct smb2_hnd *ph = NULL;
980 uint32_t altnamelen = 0;
981 TALLOC_CTX *frame = talloc_stackframe();
983 if (smbXcli_conn_has_async_calls(cli->conn)) {
985 * Can't use sync call while an async call is in flight
987 status = NT_STATUS_INVALID_PARAMETER;
991 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
992 status = NT_STATUS_INVALID_PARAMETER;
996 status = get_fnum_from_path(cli,
998 FILE_READ_ATTRIBUTES,
1001 if (!NT_STATUS_IS_OK(status)) {
1005 status = map_fnum_to_smb2_handle(cli,
1008 if (!NT_STATUS_IS_OK(status)) {
1012 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1013 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1015 status = smb2cli_query_info(cli->conn,
1019 1, /* in_info_type */
1020 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1021 0xFFFF, /* in_max_output_length */
1022 NULL, /* in_input_buffer */
1023 0, /* in_additional_info */
1030 if (!NT_STATUS_IS_OK(status)) {
1034 /* Parse the reply. */
1035 if (outbuf.length < 4) {
1036 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1040 altnamelen = IVAL(outbuf.data, 0);
1041 if (altnamelen > outbuf.length - 4) {
1042 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1046 if (altnamelen > 0) {
1048 char *short_name = NULL;
1049 ret = pull_string_talloc(frame,
1051 FLAGS2_UNICODE_STRINGS,
1056 if (ret == (size_t)-1) {
1057 /* Bad conversion. */
1058 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1062 fstrcpy(alt_name, short_name);
1067 status = NT_STATUS_OK;
1071 if (fnum != 0xffff) {
1072 cli_smb2_close_fnum(cli, fnum);
1079 /***************************************************************
1080 Wrapper that allows SMB2 to query a fnum info (basic level).
1082 ***************************************************************/
1084 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1088 struct timespec *create_time,
1089 struct timespec *access_time,
1090 struct timespec *write_time,
1091 struct timespec *change_time,
1095 DATA_BLOB outbuf = data_blob_null;
1096 struct smb2_hnd *ph = NULL;
1097 TALLOC_CTX *frame = talloc_stackframe();
1099 if (smbXcli_conn_has_async_calls(cli->conn)) {
1101 * Can't use sync call while an async call is in flight
1103 status = NT_STATUS_INVALID_PARAMETER;
1107 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1108 status = NT_STATUS_INVALID_PARAMETER;
1112 status = map_fnum_to_smb2_handle(cli,
1115 if (!NT_STATUS_IS_OK(status)) {
1119 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1120 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1122 status = smb2cli_query_info(cli->conn,
1126 1, /* in_info_type */
1127 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1128 0xFFFF, /* in_max_output_length */
1129 NULL, /* in_input_buffer */
1130 0, /* in_additional_info */
1136 if (!NT_STATUS_IS_OK(status)) {
1140 /* Parse the reply. */
1141 if (outbuf.length < 0x60) {
1142 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1147 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1150 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1153 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1156 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1159 uint32_t attr = IVAL(outbuf.data, 0x20);
1160 *mode = (uint16_t)attr;
1163 uint64_t file_size = BVAL(outbuf.data, 0x30);
1164 *size = (off_t)file_size;
1167 uint64_t file_index = BVAL(outbuf.data, 0x40);
1168 *ino = (SMB_INO_T)file_index;
1177 /***************************************************************
1178 Wrapper that allows SMB2 to query an fnum.
1179 Implement on top of cli_smb2_qfileinfo_basic().
1181 ***************************************************************/
1183 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1187 time_t *change_time,
1188 time_t *access_time,
1191 struct timespec access_time_ts;
1192 struct timespec write_time_ts;
1193 struct timespec change_time_ts;
1194 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1204 if (!NT_STATUS_IS_OK(status)) {
1209 *change_time = change_time_ts.tv_sec;
1212 *access_time = access_time_ts.tv_sec;
1215 *write_time = write_time_ts.tv_sec;
1217 return NT_STATUS_OK;
1220 /***************************************************************
1221 Wrapper that allows SMB2 to get pathname attributes.
1223 ***************************************************************/
1225 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1232 uint16_t fnum = 0xffff;
1233 struct smb2_hnd *ph = NULL;
1234 TALLOC_CTX *frame = talloc_stackframe();
1236 if (smbXcli_conn_has_async_calls(cli->conn)) {
1238 * Can't use sync call while an async call is in flight
1240 status = NT_STATUS_INVALID_PARAMETER;
1244 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1245 status = NT_STATUS_INVALID_PARAMETER;
1249 status = get_fnum_from_path(cli,
1251 FILE_READ_ATTRIBUTES,
1254 if (!NT_STATUS_IS_OK(status)) {
1258 status = map_fnum_to_smb2_handle(cli,
1261 if (!NT_STATUS_IS_OK(status)) {
1264 status = cli_smb2_getattrE(cli,
1271 if (!NT_STATUS_IS_OK(status)) {
1277 if (fnum != 0xffff) {
1278 cli_smb2_close_fnum(cli, fnum);
1285 /***************************************************************
1286 Wrapper that allows SMB2 to query a pathname info (basic level).
1287 Implement on top of cli_smb2_qfileinfo_basic().
1289 ***************************************************************/
1291 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1293 struct timespec *create_time,
1294 struct timespec *access_time,
1295 struct timespec *write_time,
1296 struct timespec *change_time,
1302 struct smb2_hnd *ph = NULL;
1303 uint16_t fnum = 0xffff;
1304 TALLOC_CTX *frame = talloc_stackframe();
1306 if (smbXcli_conn_has_async_calls(cli->conn)) {
1308 * Can't use sync call while an async call is in flight
1310 status = NT_STATUS_INVALID_PARAMETER;
1314 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1315 status = NT_STATUS_INVALID_PARAMETER;
1319 status = get_fnum_from_path(cli,
1321 FILE_READ_ATTRIBUTES,
1324 if (!NT_STATUS_IS_OK(status)) {
1328 status = map_fnum_to_smb2_handle(cli,
1331 if (!NT_STATUS_IS_OK(status)) {
1335 status = cli_smb2_qfileinfo_basic(cli,
1347 if (fnum != 0xffff) {
1348 cli_smb2_close_fnum(cli, fnum);
1355 /***************************************************************
1356 Wrapper that allows SMB2 to query pathname streams.
1358 ***************************************************************/
1360 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1362 TALLOC_CTX *mem_ctx,
1363 unsigned int *pnum_streams,
1364 struct stream_struct **pstreams)
1367 struct smb2_hnd *ph = NULL;
1368 uint16_t fnum = 0xffff;
1369 DATA_BLOB outbuf = data_blob_null;
1370 TALLOC_CTX *frame = talloc_stackframe();
1372 if (smbXcli_conn_has_async_calls(cli->conn)) {
1374 * Can't use sync call while an async call is in flight
1376 status = NT_STATUS_INVALID_PARAMETER;
1380 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1381 status = NT_STATUS_INVALID_PARAMETER;
1385 status = get_fnum_from_path(cli,
1387 FILE_READ_ATTRIBUTES,
1390 if (!NT_STATUS_IS_OK(status)) {
1394 status = map_fnum_to_smb2_handle(cli,
1397 if (!NT_STATUS_IS_OK(status)) {
1401 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1402 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1404 status = smb2cli_query_info(cli->conn,
1408 1, /* in_info_type */
1409 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1410 0xFFFF, /* in_max_output_length */
1411 NULL, /* in_input_buffer */
1412 0, /* in_additional_info */
1419 if (!NT_STATUS_IS_OK(status)) {
1423 /* Parse the reply. */
1424 if (!parse_streams_blob(mem_ctx,
1429 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1435 if (fnum != 0xffff) {
1436 cli_smb2_close_fnum(cli, fnum);
1443 /***************************************************************
1444 Wrapper that allows SMB2 to set pathname attributes.
1446 ***************************************************************/
1448 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1454 uint16_t fnum = 0xffff;
1455 struct smb2_hnd *ph = NULL;
1456 uint8_t inbuf_store[40];
1457 DATA_BLOB inbuf = data_blob_null;
1458 TALLOC_CTX *frame = talloc_stackframe();
1460 if (smbXcli_conn_has_async_calls(cli->conn)) {
1462 * Can't use sync call while an async call is in flight
1464 status = NT_STATUS_INVALID_PARAMETER;
1468 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1469 status = NT_STATUS_INVALID_PARAMETER;
1473 status = get_fnum_from_path(cli,
1475 FILE_WRITE_ATTRIBUTES,
1478 if (!NT_STATUS_IS_OK(status)) {
1482 status = map_fnum_to_smb2_handle(cli,
1485 if (!NT_STATUS_IS_OK(status)) {
1489 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1490 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1492 inbuf.data = inbuf_store;
1493 inbuf.length = sizeof(inbuf_store);
1494 data_blob_clear(&inbuf);
1496 SSVAL(inbuf.data, 32, attr);
1498 put_long_date((char *)inbuf.data + 16,mtime);
1500 /* Set all the other times to -1. */
1501 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1502 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1503 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1505 status = smb2cli_set_info(cli->conn,
1509 1, /* in_info_type */
1510 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1511 &inbuf, /* in_input_buffer */
1512 0, /* in_additional_info */
1517 if (fnum != 0xffff) {
1518 cli_smb2_close_fnum(cli, fnum);
1525 /***************************************************************
1526 Wrapper that allows SMB2 to set file handle times.
1528 ***************************************************************/
1530 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1537 struct smb2_hnd *ph = NULL;
1538 uint8_t inbuf_store[40];
1539 DATA_BLOB inbuf = data_blob_null;
1541 if (smbXcli_conn_has_async_calls(cli->conn)) {
1543 * Can't use sync call while an async call is in flight
1545 return NT_STATUS_INVALID_PARAMETER;
1548 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1549 return NT_STATUS_INVALID_PARAMETER;
1552 status = map_fnum_to_smb2_handle(cli,
1555 if (!NT_STATUS_IS_OK(status)) {
1559 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1560 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1562 inbuf.data = inbuf_store;
1563 inbuf.length = sizeof(inbuf_store);
1564 data_blob_clear(&inbuf);
1566 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1567 if (change_time != 0) {
1568 put_long_date((char *)inbuf.data + 24, change_time);
1570 if (access_time != 0) {
1571 put_long_date((char *)inbuf.data + 8, access_time);
1573 if (write_time != 0) {
1574 put_long_date((char *)inbuf.data + 16, write_time);
1577 return smb2cli_set_info(cli->conn,
1581 1, /* in_info_type */
1582 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1583 &inbuf, /* in_input_buffer */
1584 0, /* in_additional_info */
1589 /***************************************************************
1590 Wrapper that allows SMB2 to query disk attributes (size).
1592 ***************************************************************/
1594 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, uint64_t *bsize, uint64_t *total, uint64_t *avail)
1597 uint16_t fnum = 0xffff;
1598 DATA_BLOB outbuf = data_blob_null;
1599 struct smb2_hnd *ph = NULL;
1600 uint32_t sectors_per_unit = 0;
1601 uint32_t bytes_per_sector = 0;
1602 uint64_t total_size = 0;
1603 uint64_t size_free = 0;
1604 TALLOC_CTX *frame = talloc_stackframe();
1606 if (smbXcli_conn_has_async_calls(cli->conn)) {
1608 * Can't use sync call while an async call is in flight
1610 status = NT_STATUS_INVALID_PARAMETER;
1614 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1615 status = NT_STATUS_INVALID_PARAMETER;
1619 /* First open the top level directory. */
1620 status = cli_smb2_create_fnum(cli,
1622 0, /* create_flags */
1623 FILE_READ_ATTRIBUTES, /* desired_access */
1624 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1625 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1626 FILE_OPEN, /* create_disposition */
1627 FILE_DIRECTORY_FILE, /* create_options */
1631 if (!NT_STATUS_IS_OK(status)) {
1635 status = map_fnum_to_smb2_handle(cli,
1638 if (!NT_STATUS_IS_OK(status)) {
1642 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1643 level 3 (SMB_FS_SIZE_INFORMATION). */
1645 status = smb2cli_query_info(cli->conn,
1649 2, /* in_info_type */
1650 3, /* in_file_info_class */
1651 0xFFFF, /* in_max_output_length */
1652 NULL, /* in_input_buffer */
1653 0, /* in_additional_info */
1659 if (!NT_STATUS_IS_OK(status)) {
1663 /* Parse the reply. */
1664 if (outbuf.length != 24) {
1665 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1669 total_size = BVAL(outbuf.data, 0);
1670 size_free = BVAL(outbuf.data, 8);
1671 sectors_per_unit = IVAL(outbuf.data, 16);
1672 bytes_per_sector = IVAL(outbuf.data, 20);
1675 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1678 *total = total_size;
1684 status = NT_STATUS_OK;
1688 if (fnum != 0xffff) {
1689 cli_smb2_close_fnum(cli, fnum);
1696 /***************************************************************
1697 Wrapper that allows SMB2 to query a security descriptor.
1699 ***************************************************************/
1701 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1704 TALLOC_CTX *mem_ctx,
1705 struct security_descriptor **ppsd)
1708 DATA_BLOB outbuf = data_blob_null;
1709 struct smb2_hnd *ph = NULL;
1710 struct security_descriptor *lsd = NULL;
1711 TALLOC_CTX *frame = talloc_stackframe();
1713 if (smbXcli_conn_has_async_calls(cli->conn)) {
1715 * Can't use sync call while an async call is in flight
1717 status = NT_STATUS_INVALID_PARAMETER;
1721 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1722 status = NT_STATUS_INVALID_PARAMETER;
1726 status = map_fnum_to_smb2_handle(cli,
1729 if (!NT_STATUS_IS_OK(status)) {
1733 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1735 status = smb2cli_query_info(cli->conn,
1739 3, /* in_info_type */
1740 0, /* in_file_info_class */
1741 0xFFFF, /* in_max_output_length */
1742 NULL, /* in_input_buffer */
1743 sec_info, /* in_additional_info */
1750 if (!NT_STATUS_IS_OK(status)) {
1754 /* Parse the reply. */
1755 status = unmarshall_sec_desc(mem_ctx,
1760 if (!NT_STATUS_IS_OK(status)) {
1776 /***************************************************************
1777 Wrapper that allows SMB2 to set a security descriptor.
1779 ***************************************************************/
1781 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1784 const struct security_descriptor *sd)
1787 DATA_BLOB inbuf = data_blob_null;
1788 struct smb2_hnd *ph = NULL;
1789 TALLOC_CTX *frame = talloc_stackframe();
1791 if (smbXcli_conn_has_async_calls(cli->conn)) {
1793 * Can't use sync call while an async call is in flight
1795 status = NT_STATUS_INVALID_PARAMETER;
1799 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1800 status = NT_STATUS_INVALID_PARAMETER;
1804 status = map_fnum_to_smb2_handle(cli,
1807 if (!NT_STATUS_IS_OK(status)) {
1811 status = marshall_sec_desc(frame,
1816 if (!NT_STATUS_IS_OK(status)) {
1820 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1822 status = smb2cli_set_info(cli->conn,
1826 3, /* in_info_type */
1827 0, /* in_file_info_class */
1828 &inbuf, /* in_input_buffer */
1829 sec_info, /* in_additional_info */
1839 /***************************************************************
1840 Wrapper that allows SMB2 to rename a file.
1842 ***************************************************************/
1844 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1845 const char *fname_src,
1846 const char *fname_dst)
1849 DATA_BLOB inbuf = data_blob_null;
1850 uint16_t fnum = 0xffff;
1851 struct smb2_hnd *ph = NULL;
1852 smb_ucs2_t *converted_str = NULL;
1853 size_t converted_size_bytes = 0;
1855 TALLOC_CTX *frame = talloc_stackframe();
1857 if (smbXcli_conn_has_async_calls(cli->conn)) {
1859 * Can't use sync call while an async call is in flight
1861 status = NT_STATUS_INVALID_PARAMETER;
1865 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1866 status = NT_STATUS_INVALID_PARAMETER;
1870 status = get_fnum_from_path(cli,
1875 if (!NT_STATUS_IS_OK(status)) {
1879 status = map_fnum_to_smb2_handle(cli,
1882 if (!NT_STATUS_IS_OK(status)) {
1886 /* SMB2 is pickier about pathnames. Ensure it doesn't
1888 if (*fname_dst == '\\') {
1892 /* SMB2 is pickier about pathnames. Ensure it doesn't
1894 namelen = strlen(fname_dst);
1895 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1896 char *modname = talloc_strdup(frame, fname_dst);
1897 modname[namelen-1] = '\0';
1898 fname_dst = modname;
1901 if (!push_ucs2_talloc(frame,
1904 &converted_size_bytes)) {
1905 status = NT_STATUS_INVALID_PARAMETER;
1909 /* W2K8 insists the dest name is not null
1910 terminated. Remove the last 2 zero bytes
1911 and reduce the name length. */
1913 if (converted_size_bytes < 2) {
1914 status = NT_STATUS_INVALID_PARAMETER;
1917 converted_size_bytes -= 2;
1919 inbuf = data_blob_talloc_zero(frame,
1920 20 + converted_size_bytes);
1921 if (inbuf.data == NULL) {
1922 status = NT_STATUS_NO_MEMORY;
1926 SIVAL(inbuf.data, 16, converted_size_bytes);
1927 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1929 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1930 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1932 status = smb2cli_set_info(cli->conn,
1936 1, /* in_info_type */
1937 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1938 &inbuf, /* in_input_buffer */
1939 0, /* in_additional_info */
1945 if (fnum != 0xffff) {
1946 cli_smb2_close_fnum(cli, fnum);
1953 /***************************************************************
1954 Wrapper that allows SMB2 to set an EA on a fnum.
1956 ***************************************************************/
1958 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1960 const char *ea_name,
1965 DATA_BLOB inbuf = data_blob_null;
1967 char *ea_name_ascii = NULL;
1969 struct smb2_hnd *ph = NULL;
1970 TALLOC_CTX *frame = talloc_stackframe();
1972 if (smbXcli_conn_has_async_calls(cli->conn)) {
1974 * Can't use sync call while an async call is in flight
1976 status = NT_STATUS_INVALID_PARAMETER;
1980 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1981 status = NT_STATUS_INVALID_PARAMETER;
1985 status = map_fnum_to_smb2_handle(cli,
1988 if (!NT_STATUS_IS_OK(status)) {
1992 /* Marshall the SMB2 EA data. */
1993 if (ea_len > 0xFFFF) {
1994 status = NT_STATUS_INVALID_PARAMETER;
1998 if (!push_ascii_talloc(frame,
2002 status = NT_STATUS_INVALID_PARAMETER;
2006 if (namelen < 2 || namelen > 0xFF) {
2007 status = NT_STATUS_INVALID_PARAMETER;
2011 bloblen = 8 + ea_len + namelen;
2012 /* Round up to a 4 byte boundary. */
2013 bloblen = ((bloblen + 3)&~3);
2015 inbuf = data_blob_talloc_zero(frame, bloblen);
2016 if (inbuf.data == NULL) {
2017 status = NT_STATUS_NO_MEMORY;
2020 /* namelen doesn't include the NULL byte. */
2021 SCVAL(inbuf.data, 5, namelen - 1);
2022 SSVAL(inbuf.data, 6, ea_len);
2023 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2024 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2026 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2027 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2029 status = smb2cli_set_info(cli->conn,
2033 1, /* in_info_type */
2034 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2035 &inbuf, /* in_input_buffer */
2036 0, /* in_additional_info */
2046 /***************************************************************
2047 Wrapper that allows SMB2 to set an EA on a pathname.
2049 ***************************************************************/
2051 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2053 const char *ea_name,
2058 uint16_t fnum = 0xffff;
2060 if (smbXcli_conn_has_async_calls(cli->conn)) {
2062 * Can't use sync call while an async call is in flight
2064 status = NT_STATUS_INVALID_PARAMETER;
2068 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2069 status = NT_STATUS_INVALID_PARAMETER;
2073 status = get_fnum_from_path(cli,
2078 if (!NT_STATUS_IS_OK(status)) {
2082 status = cli_set_ea_fnum(cli,
2087 if (!NT_STATUS_IS_OK(status)) {
2093 if (fnum != 0xffff) {
2094 cli_smb2_close_fnum(cli, fnum);
2100 /***************************************************************
2101 Wrapper that allows SMB2 to get an EA list on a pathname.
2103 ***************************************************************/
2105 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2109 struct ea_struct **pea_array)
2112 uint16_t fnum = 0xffff;
2113 DATA_BLOB outbuf = data_blob_null;
2114 struct smb2_hnd *ph = NULL;
2115 struct ea_list *ea_list = NULL;
2116 struct ea_list *eal = NULL;
2117 size_t ea_count = 0;
2118 TALLOC_CTX *frame = talloc_stackframe();
2123 if (smbXcli_conn_has_async_calls(cli->conn)) {
2125 * Can't use sync call while an async call is in flight
2127 status = NT_STATUS_INVALID_PARAMETER;
2131 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2132 status = NT_STATUS_INVALID_PARAMETER;
2136 status = get_fnum_from_path(cli,
2141 if (!NT_STATUS_IS_OK(status)) {
2145 status = map_fnum_to_smb2_handle(cli,
2148 if (!NT_STATUS_IS_OK(status)) {
2152 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2153 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2155 status = smb2cli_query_info(cli->conn,
2159 1, /* in_info_type */
2160 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2161 0xFFFF, /* in_max_output_length */
2162 NULL, /* in_input_buffer */
2163 0, /* in_additional_info */
2170 if (!NT_STATUS_IS_OK(status)) {
2174 /* Parse the reply. */
2175 ea_list = read_nttrans_ea_list(ctx,
2176 (const char *)outbuf.data,
2178 if (ea_list == NULL) {
2179 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2183 /* Convert to an array. */
2184 for (eal = ea_list; eal; eal = eal->next) {
2189 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2190 if (*pea_array == NULL) {
2191 status = NT_STATUS_NO_MEMORY;
2195 for (eal = ea_list; eal; eal = eal->next) {
2196 (*pea_array)[ea_count++] = ea_list->ea;
2198 *pnum_eas = ea_count;
2203 if (fnum != 0xffff) {
2204 cli_smb2_close_fnum(cli, fnum);
2211 struct cli_smb2_read_state {
2212 struct tevent_context *ev;
2213 struct cli_state *cli;
2214 struct smb2_hnd *ph;
2215 uint64_t start_offset;
2221 static void cli_smb2_read_done(struct tevent_req *subreq);
2223 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2224 struct tevent_context *ev,
2225 struct cli_state *cli,
2231 struct tevent_req *req, *subreq;
2232 struct cli_smb2_read_state *state;
2234 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2240 state->start_offset = (uint64_t)offset;
2241 state->size = (uint32_t)size;
2242 state->received = 0;
2245 status = map_fnum_to_smb2_handle(cli,
2248 if (tevent_req_nterror(req, status)) {
2249 return tevent_req_post(req, ev);
2252 subreq = smb2cli_read_send(state,
2255 state->cli->timeout,
2256 state->cli->smb2.session,
2257 state->cli->smb2.tcon,
2259 state->start_offset,
2260 state->ph->fid_persistent,
2261 state->ph->fid_volatile,
2262 0, /* minimum_count */
2263 0); /* remaining_bytes */
2265 if (tevent_req_nomem(subreq, req)) {
2266 return tevent_req_post(req, ev);
2268 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2272 static void cli_smb2_read_done(struct tevent_req *subreq)
2274 struct tevent_req *req = tevent_req_callback_data(
2275 subreq, struct tevent_req);
2276 struct cli_smb2_read_state *state = tevent_req_data(
2277 req, struct cli_smb2_read_state);
2280 status = smb2cli_read_recv(subreq, state,
2281 &state->buf, &state->received);
2282 if (tevent_req_nterror(req, status)) {
2286 if (state->received > state->size) {
2287 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2291 tevent_req_done(req);
2294 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2299 struct cli_smb2_read_state *state = tevent_req_data(
2300 req, struct cli_smb2_read_state);
2302 if (tevent_req_is_nterror(req, &status)) {
2306 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2307 * better make sure that you copy it away before you talloc_free(req).
2308 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2310 *received = (ssize_t)state->received;
2311 *rcvbuf = state->buf;
2312 return NT_STATUS_OK;
2315 struct cli_smb2_write_state {
2316 struct tevent_context *ev;
2317 struct cli_state *cli;
2318 struct smb2_hnd *ph;
2326 static void cli_smb2_write_written(struct tevent_req *req);
2328 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2329 struct tevent_context *ev,
2330 struct cli_state *cli,
2338 struct tevent_req *req, *subreq = NULL;
2339 struct cli_smb2_write_state *state = NULL;
2341 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2347 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2348 state->flags = (uint32_t)mode;
2350 state->offset = (uint64_t)offset;
2351 state->size = (uint32_t)size;
2354 status = map_fnum_to_smb2_handle(cli,
2357 if (tevent_req_nterror(req, status)) {
2358 return tevent_req_post(req, ev);
2361 subreq = smb2cli_write_send(state,
2364 state->cli->timeout,
2365 state->cli->smb2.session,
2366 state->cli->smb2.tcon,
2369 state->ph->fid_persistent,
2370 state->ph->fid_volatile,
2371 0, /* remaining_bytes */
2372 state->flags, /* flags */
2375 if (tevent_req_nomem(subreq, req)) {
2376 return tevent_req_post(req, ev);
2378 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2382 static void cli_smb2_write_written(struct tevent_req *subreq)
2384 struct tevent_req *req = tevent_req_callback_data(
2385 subreq, struct tevent_req);
2386 struct cli_smb2_write_state *state = tevent_req_data(
2387 req, struct cli_smb2_write_state);
2391 status = smb2cli_write_recv(subreq, &written);
2392 TALLOC_FREE(subreq);
2393 if (tevent_req_nterror(req, status)) {
2397 state->written = written;
2399 tevent_req_done(req);
2402 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2405 struct cli_smb2_write_state *state = tevent_req_data(
2406 req, struct cli_smb2_write_state);
2409 if (tevent_req_is_nterror(req, &status)) {
2410 tevent_req_received(req);
2414 if (pwritten != NULL) {
2415 *pwritten = (size_t)state->written;
2417 tevent_req_received(req);
2418 return NT_STATUS_OK;
2421 /***************************************************************
2422 Wrapper that allows SMB2 async write using an fnum.
2423 This is mostly cut-and-paste from Volker's code inside
2424 source3/libsmb/clireadwrite.c, adapted for SMB2.
2426 Done this way so I can reuse all the logic inside cli_push()
2428 ***************************************************************/
2430 struct cli_smb2_writeall_state {
2431 struct tevent_context *ev;
2432 struct cli_state *cli;
2433 struct smb2_hnd *ph;
2441 static void cli_smb2_writeall_written(struct tevent_req *req);
2443 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2444 struct tevent_context *ev,
2445 struct cli_state *cli,
2453 struct tevent_req *req, *subreq = NULL;
2454 struct cli_smb2_writeall_state *state = NULL;
2459 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2465 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2466 state->flags = (uint32_t)mode;
2468 state->offset = (uint64_t)offset;
2469 state->size = (uint32_t)size;
2472 status = map_fnum_to_smb2_handle(cli,
2475 if (tevent_req_nterror(req, status)) {
2476 return tevent_req_post(req, ev);
2479 to_write = state->size;
2480 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2481 to_write = MIN(max_size, to_write);
2482 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2484 to_write = MIN(max_size, to_write);
2487 subreq = smb2cli_write_send(state,
2490 state->cli->timeout,
2491 state->cli->smb2.session,
2492 state->cli->smb2.tcon,
2495 state->ph->fid_persistent,
2496 state->ph->fid_volatile,
2497 0, /* remaining_bytes */
2498 state->flags, /* flags */
2499 state->buf + state->written);
2501 if (tevent_req_nomem(subreq, req)) {
2502 return tevent_req_post(req, ev);
2504 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2508 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2510 struct tevent_req *req = tevent_req_callback_data(
2511 subreq, struct tevent_req);
2512 struct cli_smb2_writeall_state *state = tevent_req_data(
2513 req, struct cli_smb2_writeall_state);
2515 uint32_t written, to_write;
2519 status = smb2cli_write_recv(subreq, &written);
2520 TALLOC_FREE(subreq);
2521 if (tevent_req_nterror(req, status)) {
2525 state->written += written;
2527 if (state->written > state->size) {
2528 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2532 to_write = state->size - state->written;
2534 if (to_write == 0) {
2535 tevent_req_done(req);
2539 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2540 to_write = MIN(max_size, to_write);
2541 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2543 to_write = MIN(max_size, to_write);
2546 subreq = smb2cli_write_send(state,
2549 state->cli->timeout,
2550 state->cli->smb2.session,
2551 state->cli->smb2.tcon,
2553 state->offset + state->written,
2554 state->ph->fid_persistent,
2555 state->ph->fid_volatile,
2556 0, /* remaining_bytes */
2557 state->flags, /* flags */
2558 state->buf + state->written);
2560 if (tevent_req_nomem(subreq, req)) {
2563 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2566 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2569 struct cli_smb2_writeall_state *state = tevent_req_data(
2570 req, struct cli_smb2_writeall_state);
2573 if (tevent_req_is_nterror(req, &status)) {
2576 if (pwritten != NULL) {
2577 *pwritten = (size_t)state->written;
2579 return NT_STATUS_OK;