xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_fsctl_fs.c (revision 55f0a249fd3511728b02627190771a4ce4ddf20e)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 /*
17  * Support functions for smb2_ioctl/fsctl categories:
18  * FILE_DEVICE_FILE_SYSTEM (9)
19  * FILE_DEVICE_NETWORK_FILE_SYSTEM (20)
20  */
21 
22 #include <smbsrv/smb2_kproto.h>
23 #include <smbsrv/smb_fsops.h>
24 #include <smb/winioctl.h>
25 
26 /* ARGSUSED */
27 static uint32_t
28 smb2_fsctl_notsup(smb_request_t *sr, smb_fsctl_t *fsctl)
29 {
30 	return (NT_STATUS_NOT_SUPPORTED);
31 }
32 
33 /*
34  * Same as smb2_fsctl_notsup, but make some noise (if DEBUG)
35  * so we'll learn about new fsctl codes clients start using.
36  */
37 /* ARGSUSED */
38 static uint32_t
39 smb2_fsctl_unknown(smb_request_t *sr, smb_fsctl_t *fsctl)
40 {
41 #ifdef	DEBUG
42 	cmn_err(CE_NOTE, "smb2_fsctl_unknown: code 0x%x", fsctl->CtlCode);
43 #endif
44 	return (NT_STATUS_NOT_SUPPORTED);
45 }
46 
47 /*
48  * FSCTL_GET_COMPRESSION
49  */
50 static uint32_t
51 smb2_fsctl_get_compression(smb_request_t *sr, smb_fsctl_t *fsctl)
52 {
53 	_NOTE(ARGUNUSED(sr))
54 	uint16_t compress_state = 0;
55 
56 	(void) smb_mbc_encodef(fsctl->in_mbc, "w",
57 	    compress_state);
58 
59 	return (NT_STATUS_SUCCESS);
60 }
61 
62 /*
63  * FSCTL_SET_COMPRESSION
64  */
65 static uint32_t
66 smb2_fsctl_set_compression(smb_request_t *sr, smb_fsctl_t *fsctl)
67 {
68 	_NOTE(ARGUNUSED(sr))
69 
70 	uint16_t compress_state;
71 	(void) smb_mbc_decodef(fsctl->in_mbc, "w",
72 	    &compress_state);
73 
74 	if (compress_state > 0)
75 		return (NT_STATUS_COMPRESSION_DISABLED);
76 
77 	return (NT_STATUS_SUCCESS);
78 }
79 
80 /*
81  * FSCTL_SRV_REQUEST_RESUME_KEY
82  *
83  * The returned data is an (opaque to the client) 24-byte blob
84  * in which we stash the SMB2 "file ID" (both parts). Later,
85  * copychunk may lookup the ofile using that file ID.
86  * See: smb2_fsctl_copychunk()
87  *
88  * Note that Mac clients make this request on a directory
89  * (even though this only makes sense on a file) just to
90  * find out if the server supports server-side copy.
91  * There's no harm letting a client have a resume key
92  * for a directory.  They'll never be able to DO anything
93  * with it because we check for a plain file later.
94  */
95 static uint32_t
96 smb2_fsctl_get_resume_key(smb_request_t *sr, smb_fsctl_t *fsctl)
97 {
98 	smb_ofile_t *of = sr->fid_ofile;
99 	smb2fid_t smb2fid;
100 
101 	/* Caller makes sure we have of = sr->fid_ofile */
102 	/* Don't insist on a plain file (see above). */
103 
104 	smb2fid.persistent = of->f_persistid;
105 	smb2fid.temporal = of->f_fid;
106 
107 	(void) smb_mbc_encodef(
108 	    fsctl->out_mbc, "qq16.",
109 	    smb2fid.persistent,
110 	    smb2fid.temporal);
111 
112 	return (NT_STATUS_SUCCESS);
113 }
114 
115 /*
116  * FILE_DEVICE_FILE_SYSTEM (9)
117  */
118 uint32_t
119 smb2_fsctl_fs(smb_request_t *sr, smb_fsctl_t *fsctl)
120 {
121 	uint32_t (*func)(smb_request_t *, smb_fsctl_t *);
122 	uint32_t status;
123 
124 	switch (fsctl->CtlCode) {
125 	case FSCTL_GET_COMPRESSION:		/* 15 */
126 		func = smb2_fsctl_get_compression;
127 		break;
128 	case FSCTL_SET_COMPRESSION:		/* 16 */
129 		func = smb2_fsctl_set_compression;
130 		break;
131 	case FSCTL_SET_REPARSE_POINT:		/* 41 */
132 	case FSCTL_GET_REPARSE_POINT:		/* 42 */
133 	case FSCTL_CREATE_OR_GET_OBJECT_ID:	/* 48 */
134 		func = smb2_fsctl_notsup;
135 		break;
136 	case FSCTL_SET_SPARSE:			/* 49 */
137 		func = smb2_fsctl_set_sparse;
138 		break;
139 	case FSCTL_SET_ZERO_DATA:		/* 50 */
140 		func = smb2_fsctl_set_zero_data;
141 		break;
142 	case FSCTL_QUERY_ALLOCATED_RANGES:	/* 51 */
143 		func = smb2_fsctl_query_alloc_ranges;
144 		break;
145 	case FSCTL_FILE_LEVEL_TRIM:		/* 130 */
146 		func = smb2_fsctl_notsup;
147 		break;
148 	case FSCTL_OFFLOAD_READ:		/* 153 */
149 	case FSCTL_OFFLOAD_WRITE:		/* 154 */
150 		func = smb2_fsctl_notsup;
151 		break;
152 	case FSCTL_SET_INTEGRITY_INFORMATION:	/* 160 */
153 	case FSCTL_QUERY_FILE_REGIONS:		/* 161 */
154 		func = smb2_fsctl_notsup;
155 		break;
156 
157 	default:
158 		func = smb2_fsctl_unknown;
159 		break;
160 	}
161 
162 	/*
163 	 * All "fs" sub-codes require a disk file.
164 	 */
165 	if (sr->fid_ofile == NULL ||
166 	    !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype))
167 		return (NT_STATUS_INVALID_PARAMETER);
168 
169 	status = (*func)(sr, fsctl);
170 	return (status);
171 }
172 
173 /*
174  * FILE_DEVICE_NETWORK_FILE_SYSTEM (20)
175  */
176 uint32_t
177 smb2_fsctl_netfs(smb_request_t *sr, smb_fsctl_t *fsctl)
178 {
179 	uint32_t (*func)(smb_request_t *, smb_fsctl_t *);
180 	uint32_t status;
181 	boolean_t need_disk_file = B_TRUE;
182 
183 	switch (fsctl->CtlCode) {
184 	case FSCTL_SRV_ENUMERATE_SNAPSHOTS:	/* 0x19 */
185 		func = smb_vss_enum_snapshots;
186 		break;
187 	case FSCTL_SRV_REQUEST_RESUME_KEY:	/* 0x1e */
188 		func = smb2_fsctl_get_resume_key;
189 		break;
190 	case FSCTL_SRV_COPYCHUNK:		/* 0x3c(r) */
191 	case FSCTL_SRV_COPYCHUNK_WRITE:		/* 0x3c(w) */
192 		func = smb2_fsctl_copychunk;
193 		break;
194 	case FSCTL_SRV_READ_HASH:		/* 0x6e */
195 		func = smb2_fsctl_notsup;
196 		break;
197 	case FSCTL_LMR_REQUEST_RESILIENCY:	/* 0x75 */
198 		func = smb2_fsctl_set_resilient;
199 		break;
200 	case FSCTL_QUERY_NETWORK_INTERFACE_INFO: /* 0x7f */
201 		need_disk_file = B_FALSE;
202 		func = smb2_fsctl_notsup;
203 		break;
204 	case FSCTL_VALIDATE_NEGOTIATE_INFO:	/* 0x81 */
205 		need_disk_file = B_FALSE;
206 		func = smb2_nego_validate;
207 		break;
208 	default:
209 		func = smb2_fsctl_unknown;
210 		break;
211 	}
212 
213 	/*
214 	 * Most "net fs" sub-codes require a disk file,
215 	 * except a couple that clear need_disk_file.
216 	 */
217 	if (need_disk_file && (sr->fid_ofile == NULL ||
218 	    !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)))
219 		return (NT_STATUS_INVALID_PARAMETER);
220 
221 	status = (*func)(sr, fsctl);
222 	return (status);
223 }
224