155f0a249SGordon Ross /*
255f0a249SGordon Ross * This file and its contents are supplied under the terms of the
355f0a249SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0.
455f0a249SGordon Ross * You may only use this file in accordance with the terms of version
555f0a249SGordon Ross * 1.0 of the CDDL.
655f0a249SGordon Ross *
755f0a249SGordon Ross * A full copy of the text of the CDDL should have accompanied this
855f0a249SGordon Ross * source. A copy of the CDDL is also available via the Internet at
955f0a249SGordon Ross * http://www.illumos.org/license/CDDL.
1055f0a249SGordon Ross */
1155f0a249SGordon Ross
1255f0a249SGordon Ross /*
1325a9a7aaSGordon Ross * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
14*08f2ce59SGordon Ross * Copyright 2022 RackTop Systems, Inc.
1555f0a249SGordon Ross */
1655f0a249SGordon Ross
1755f0a249SGordon Ross /*
1855f0a249SGordon Ross * Support functions for smb2_ioctl/fsctl categories:
1955f0a249SGordon Ross * FILE_DEVICE_FILE_SYSTEM (9)
2055f0a249SGordon Ross * FILE_DEVICE_NETWORK_FILE_SYSTEM (20)
2155f0a249SGordon Ross */
2255f0a249SGordon Ross
2355f0a249SGordon Ross #include <smbsrv/smb2_kproto.h>
2455f0a249SGordon Ross #include <smbsrv/smb_fsops.h>
2555f0a249SGordon Ross #include <smb/winioctl.h>
2655f0a249SGordon Ross
2725a9a7aaSGordon Ross static uint32_t
smb2_fsctl_invalid(smb_request_t * sr,smb_fsctl_t * fsctl)2825a9a7aaSGordon Ross smb2_fsctl_invalid(smb_request_t *sr, smb_fsctl_t *fsctl)
2925a9a7aaSGordon Ross {
3025a9a7aaSGordon Ross return (NT_STATUS_INVALID_DEVICE_REQUEST);
3125a9a7aaSGordon Ross }
3225a9a7aaSGordon Ross
3355f0a249SGordon Ross static uint32_t
smb2_fsctl_notsup(smb_request_t * sr,smb_fsctl_t * fsctl)3455f0a249SGordon Ross smb2_fsctl_notsup(smb_request_t *sr, smb_fsctl_t *fsctl)
3555f0a249SGordon Ross {
3655f0a249SGordon Ross return (NT_STATUS_NOT_SUPPORTED);
3755f0a249SGordon Ross }
3855f0a249SGordon Ross
3955f0a249SGordon Ross /*
40*08f2ce59SGordon Ross * Same as smb2_fsctl_invalid, but make some noise (if DEBUG)
4155f0a249SGordon Ross * so we'll learn about new fsctl codes clients start using.
4255f0a249SGordon Ross */
4355f0a249SGordon Ross /* ARGSUSED */
4455f0a249SGordon Ross static uint32_t
smb2_fsctl_unknown(smb_request_t * sr,smb_fsctl_t * fsctl)4555f0a249SGordon Ross smb2_fsctl_unknown(smb_request_t *sr, smb_fsctl_t *fsctl)
4655f0a249SGordon Ross {
4755f0a249SGordon Ross #ifdef DEBUG
4855f0a249SGordon Ross cmn_err(CE_NOTE, "smb2_fsctl_unknown: code 0x%x", fsctl->CtlCode);
4955f0a249SGordon Ross #endif
50*08f2ce59SGordon Ross return (NT_STATUS_INVALID_DEVICE_REQUEST);
5155f0a249SGordon Ross }
5255f0a249SGordon Ross
5355f0a249SGordon Ross /*
5455f0a249SGordon Ross * FSCTL_GET_COMPRESSION
5555f0a249SGordon Ross */
5655f0a249SGordon Ross static uint32_t
smb2_fsctl_get_compression(smb_request_t * sr,smb_fsctl_t * fsctl)5755f0a249SGordon Ross smb2_fsctl_get_compression(smb_request_t *sr, smb_fsctl_t *fsctl)
5855f0a249SGordon Ross {
5955f0a249SGordon Ross _NOTE(ARGUNUSED(sr))
6055f0a249SGordon Ross uint16_t compress_state = 0;
6125a9a7aaSGordon Ross int rc;
6255f0a249SGordon Ross
6325a9a7aaSGordon Ross rc = smb_mbc_encodef(fsctl->in_mbc, "w",
6455f0a249SGordon Ross compress_state);
6525a9a7aaSGordon Ross if (rc != 0)
6625a9a7aaSGordon Ross return (NT_STATUS_BUFFER_OVERFLOW);
6755f0a249SGordon Ross
6855f0a249SGordon Ross return (NT_STATUS_SUCCESS);
6955f0a249SGordon Ross }
7055f0a249SGordon Ross
7155f0a249SGordon Ross /*
7255f0a249SGordon Ross * FSCTL_SET_COMPRESSION
7355f0a249SGordon Ross */
7455f0a249SGordon Ross static uint32_t
smb2_fsctl_set_compression(smb_request_t * sr,smb_fsctl_t * fsctl)7555f0a249SGordon Ross smb2_fsctl_set_compression(smb_request_t *sr, smb_fsctl_t *fsctl)
7655f0a249SGordon Ross {
7755f0a249SGordon Ross _NOTE(ARGUNUSED(sr))
7855f0a249SGordon Ross
7955f0a249SGordon Ross uint16_t compress_state;
8055f0a249SGordon Ross (void) smb_mbc_decodef(fsctl->in_mbc, "w",
8155f0a249SGordon Ross &compress_state);
8255f0a249SGordon Ross
8355f0a249SGordon Ross if (compress_state > 0)
8455f0a249SGordon Ross return (NT_STATUS_COMPRESSION_DISABLED);
8555f0a249SGordon Ross
8655f0a249SGordon Ross return (NT_STATUS_SUCCESS);
8755f0a249SGordon Ross }
8855f0a249SGordon Ross
8955f0a249SGordon Ross /*
9055f0a249SGordon Ross * FSCTL_SRV_REQUEST_RESUME_KEY
9155f0a249SGordon Ross *
9255f0a249SGordon Ross * The returned data is an (opaque to the client) 24-byte blob
9355f0a249SGordon Ross * in which we stash the SMB2 "file ID" (both parts). Later,
9455f0a249SGordon Ross * copychunk may lookup the ofile using that file ID.
9555f0a249SGordon Ross * See: smb2_fsctl_copychunk()
9655f0a249SGordon Ross *
9755f0a249SGordon Ross * Note that Mac clients make this request on a directory
9855f0a249SGordon Ross * (even though this only makes sense on a file) just to
9955f0a249SGordon Ross * find out if the server supports server-side copy.
10055f0a249SGordon Ross * There's no harm letting a client have a resume key
10155f0a249SGordon Ross * for a directory. They'll never be able to DO anything
10255f0a249SGordon Ross * with it because we check for a plain file later.
10355f0a249SGordon Ross */
10455f0a249SGordon Ross static uint32_t
smb2_fsctl_get_resume_key(smb_request_t * sr,smb_fsctl_t * fsctl)10555f0a249SGordon Ross smb2_fsctl_get_resume_key(smb_request_t *sr, smb_fsctl_t *fsctl)
10655f0a249SGordon Ross {
10755f0a249SGordon Ross smb_ofile_t *of = sr->fid_ofile;
10855f0a249SGordon Ross smb2fid_t smb2fid;
10925a9a7aaSGordon Ross int rc;
11055f0a249SGordon Ross
11155f0a249SGordon Ross /* Caller makes sure we have of = sr->fid_ofile */
11255f0a249SGordon Ross /* Don't insist on a plain file (see above). */
11355f0a249SGordon Ross
11455f0a249SGordon Ross smb2fid.persistent = of->f_persistid;
11555f0a249SGordon Ross smb2fid.temporal = of->f_fid;
11655f0a249SGordon Ross
11725a9a7aaSGordon Ross rc = smb_mbc_encodef(
11855f0a249SGordon Ross fsctl->out_mbc, "qq16.",
11955f0a249SGordon Ross smb2fid.persistent,
12055f0a249SGordon Ross smb2fid.temporal);
12125a9a7aaSGordon Ross if (rc != 0)
12225a9a7aaSGordon Ross return (NT_STATUS_BUFFER_OVERFLOW);
12355f0a249SGordon Ross
12455f0a249SGordon Ross return (NT_STATUS_SUCCESS);
12555f0a249SGordon Ross }
12655f0a249SGordon Ross
12755f0a249SGordon Ross /*
12855f0a249SGordon Ross * FILE_DEVICE_FILE_SYSTEM (9)
12955f0a249SGordon Ross */
13055f0a249SGordon Ross uint32_t
smb2_fsctl_fs(smb_request_t * sr,smb_fsctl_t * fsctl)13155f0a249SGordon Ross smb2_fsctl_fs(smb_request_t *sr, smb_fsctl_t *fsctl)
13255f0a249SGordon Ross {
13355f0a249SGordon Ross uint32_t (*func)(smb_request_t *, smb_fsctl_t *);
13455f0a249SGordon Ross uint32_t status;
13555f0a249SGordon Ross
13655f0a249SGordon Ross switch (fsctl->CtlCode) {
13755f0a249SGordon Ross case FSCTL_GET_COMPRESSION: /* 15 */
13855f0a249SGordon Ross func = smb2_fsctl_get_compression;
13955f0a249SGordon Ross break;
14055f0a249SGordon Ross case FSCTL_SET_COMPRESSION: /* 16 */
14155f0a249SGordon Ross func = smb2_fsctl_set_compression;
14255f0a249SGordon Ross break;
14355f0a249SGordon Ross case FSCTL_SET_REPARSE_POINT: /* 41 */
14455f0a249SGordon Ross case FSCTL_GET_REPARSE_POINT: /* 42 */
145*08f2ce59SGordon Ross func = smb2_fsctl_invalid;
14655f0a249SGordon Ross break;
14725a9a7aaSGordon Ross case FSCTL_CREATE_OR_GET_OBJECT_ID: /* 48 */
14825a9a7aaSGordon Ross func = smb2_fsctl_invalid;
14925a9a7aaSGordon Ross break;
15055f0a249SGordon Ross case FSCTL_SET_SPARSE: /* 49 */
15155f0a249SGordon Ross func = smb2_fsctl_set_sparse;
15255f0a249SGordon Ross break;
15355f0a249SGordon Ross case FSCTL_SET_ZERO_DATA: /* 50 */
15455f0a249SGordon Ross func = smb2_fsctl_set_zero_data;
15555f0a249SGordon Ross break;
15655f0a249SGordon Ross case FSCTL_QUERY_ALLOCATED_RANGES: /* 51 */
15755f0a249SGordon Ross func = smb2_fsctl_query_alloc_ranges;
15855f0a249SGordon Ross break;
15955f0a249SGordon Ross case FSCTL_FILE_LEVEL_TRIM: /* 130 */
160*08f2ce59SGordon Ross func = smb2_fsctl_invalid;
16155f0a249SGordon Ross break;
16255f0a249SGordon Ross case FSCTL_OFFLOAD_READ: /* 153 */
1638d499c80SGordon Ross func = smb2_fsctl_odx_read;
1648d499c80SGordon Ross break;
16555f0a249SGordon Ross case FSCTL_OFFLOAD_WRITE: /* 154 */
1668d499c80SGordon Ross func = smb2_fsctl_odx_write;
16755f0a249SGordon Ross break;
168*08f2ce59SGordon Ross case FSCTL_GET_INTEGRITY_INFORMATION: /* 159 */
16955f0a249SGordon Ross case FSCTL_SET_INTEGRITY_INFORMATION: /* 160 */
170*08f2ce59SGordon Ross func = smb2_fsctl_invalid;
17155f0a249SGordon Ross break;
172252bc4b2SGordon Ross case FSCTL_QUERY_FILE_REGIONS: /* 161 */
173252bc4b2SGordon Ross func = smb2_fsctl_query_file_regions;
174252bc4b2SGordon Ross break;
17555f0a249SGordon Ross
176*08f2ce59SGordon Ross case FSCTL_REFS_STREAM_SNAPSHOT_MANAGEMENT:
177*08f2ce59SGordon Ross /* WPTS wants NOT_SUPPORTED here. */
178*08f2ce59SGordon Ross func = smb2_fsctl_notsup;
179*08f2ce59SGordon Ross break;
180*08f2ce59SGordon Ross
18155f0a249SGordon Ross default:
18255f0a249SGordon Ross func = smb2_fsctl_unknown;
18355f0a249SGordon Ross break;
18455f0a249SGordon Ross }
18555f0a249SGordon Ross
18655f0a249SGordon Ross /*
18755f0a249SGordon Ross * All "fs" sub-codes require a disk file.
18855f0a249SGordon Ross */
18955f0a249SGordon Ross if (sr->fid_ofile == NULL ||
19055f0a249SGordon Ross !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype))
19155f0a249SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
19255f0a249SGordon Ross
19355f0a249SGordon Ross status = (*func)(sr, fsctl);
19455f0a249SGordon Ross return (status);
19555f0a249SGordon Ross }
19655f0a249SGordon Ross
19755f0a249SGordon Ross /*
19855f0a249SGordon Ross * FILE_DEVICE_NETWORK_FILE_SYSTEM (20)
19955f0a249SGordon Ross */
20055f0a249SGordon Ross uint32_t
smb2_fsctl_netfs(smb_request_t * sr,smb_fsctl_t * fsctl)20155f0a249SGordon Ross smb2_fsctl_netfs(smb_request_t *sr, smb_fsctl_t *fsctl)
20255f0a249SGordon Ross {
20355f0a249SGordon Ross uint32_t (*func)(smb_request_t *, smb_fsctl_t *);
20455f0a249SGordon Ross uint32_t status;
20555f0a249SGordon Ross boolean_t need_disk_file = B_TRUE;
20655f0a249SGordon Ross
20755f0a249SGordon Ross switch (fsctl->CtlCode) {
20855f0a249SGordon Ross case FSCTL_SRV_ENUMERATE_SNAPSHOTS: /* 0x19 */
20955f0a249SGordon Ross func = smb_vss_enum_snapshots;
21055f0a249SGordon Ross break;
21155f0a249SGordon Ross case FSCTL_SRV_REQUEST_RESUME_KEY: /* 0x1e */
21255f0a249SGordon Ross func = smb2_fsctl_get_resume_key;
21355f0a249SGordon Ross break;
21455f0a249SGordon Ross case FSCTL_SRV_COPYCHUNK: /* 0x3c(r) */
21555f0a249SGordon Ross case FSCTL_SRV_COPYCHUNK_WRITE: /* 0x3c(w) */
21655f0a249SGordon Ross func = smb2_fsctl_copychunk;
21755f0a249SGordon Ross break;
21855f0a249SGordon Ross case FSCTL_SRV_READ_HASH: /* 0x6e */
219*08f2ce59SGordon Ross func = smb2_fsctl_invalid;
22055f0a249SGordon Ross break;
22155f0a249SGordon Ross case FSCTL_LMR_REQUEST_RESILIENCY: /* 0x75 */
22255f0a249SGordon Ross func = smb2_fsctl_set_resilient;
22355f0a249SGordon Ross break;
22455f0a249SGordon Ross case FSCTL_QUERY_NETWORK_INTERFACE_INFO: /* 0x7f */
22555f0a249SGordon Ross need_disk_file = B_FALSE;
226*08f2ce59SGordon Ross func = smb2_fsctl_invalid;
22755f0a249SGordon Ross break;
22855f0a249SGordon Ross case FSCTL_VALIDATE_NEGOTIATE_INFO: /* 0x81 */
22955f0a249SGordon Ross need_disk_file = B_FALSE;
23055f0a249SGordon Ross func = smb2_nego_validate;
23155f0a249SGordon Ross break;
23255f0a249SGordon Ross default:
23355f0a249SGordon Ross func = smb2_fsctl_unknown;
23455f0a249SGordon Ross break;
23555f0a249SGordon Ross }
23655f0a249SGordon Ross
23755f0a249SGordon Ross /*
23855f0a249SGordon Ross * Most "net fs" sub-codes require a disk file,
23955f0a249SGordon Ross * except a couple that clear need_disk_file.
24055f0a249SGordon Ross */
24155f0a249SGordon Ross if (need_disk_file && (sr->fid_ofile == NULL ||
24255f0a249SGordon Ross !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)))
24355f0a249SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
24455f0a249SGordon Ross
24555f0a249SGordon Ross status = (*func)(sr, fsctl);
24655f0a249SGordon Ross return (status);
24755f0a249SGordon Ross }
248