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 func = smb2_fsctl_odx_read;
150 break;
151 case FSCTL_OFFLOAD_WRITE: /* 154 */
152 func = smb2_fsctl_odx_write;
153 break;
154 case FSCTL_SET_INTEGRITY_INFORMATION: /* 160 */
155 func = smb2_fsctl_notsup;
156 break;
157 case FSCTL_QUERY_FILE_REGIONS: /* 161 */
158 func = smb2_fsctl_query_file_regions;
159 break;
160
161 default:
162 func = smb2_fsctl_unknown;
163 break;
164 }
165
166 /*
167 * All "fs" sub-codes require a disk file.
168 */
169 if (sr->fid_ofile == NULL ||
170 !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype))
171 return (NT_STATUS_INVALID_PARAMETER);
172
173 status = (*func)(sr, fsctl);
174 return (status);
175 }
176
177 /*
178 * FILE_DEVICE_NETWORK_FILE_SYSTEM (20)
179 */
180 uint32_t
181 smb2_fsctl_netfs(smb_request_t *sr, smb_fsctl_t *fsctl)
182 {
183 uint32_t (*func)(smb_request_t *, smb_fsctl_t *);
184 uint32_t status;
185 boolean_t need_disk_file = B_TRUE;
186
187 switch (fsctl->CtlCode) {
188 case FSCTL_SRV_ENUMERATE_SNAPSHOTS: /* 0x19 */
189 func = smb_vss_enum_snapshots;
190 break;
191 case FSCTL_SRV_REQUEST_RESUME_KEY: /* 0x1e */
192 func = smb2_fsctl_get_resume_key;
193 break;
194 case FSCTL_SRV_COPYCHUNK: /* 0x3c(r) */
195 case FSCTL_SRV_COPYCHUNK_WRITE: /* 0x3c(w) */
196 func = smb2_fsctl_copychunk;
197 break;
198 case FSCTL_SRV_READ_HASH: /* 0x6e */
199 func = smb2_fsctl_notsup;
200 break;
201 case FSCTL_LMR_REQUEST_RESILIENCY: /* 0x75 */
202 func = smb2_fsctl_set_resilient;
203 break;
204 case FSCTL_QUERY_NETWORK_INTERFACE_INFO: /* 0x7f */
205 need_disk_file = B_FALSE;
206 func = smb2_fsctl_notsup;
207 break;
208 case FSCTL_VALIDATE_NEGOTIATE_INFO: /* 0x81 */
209 need_disk_file = B_FALSE;
210 func = smb2_nego_validate;
211 break;
212 default:
213 func = smb2_fsctl_unknown;
214 break;
215 }
216
217 /*
218 * Most "net fs" sub-codes require a disk file,
219 * except a couple that clear need_disk_file.
220 */
221 if (need_disk_file && (sr->fid_ofile == NULL ||
222 !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)))
223 return (NT_STATUS_INVALID_PARAMETER);
224
225 status = (*func)(sr, fsctl);
226 return (status);
227 }