xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_fsctl_fs.c (revision 08f2ce59ccfd4e449c92dd87b23e756e439d4daa)
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