1*a90cf9f2SGordon Ross /*
2*a90cf9f2SGordon Ross * CDDL HEADER START
3*a90cf9f2SGordon Ross *
4*a90cf9f2SGordon Ross * The contents of this file are subject to the terms of the
5*a90cf9f2SGordon Ross * Common Development and Distribution License (the "License").
6*a90cf9f2SGordon Ross * You may not use this file except in compliance with the License.
7*a90cf9f2SGordon Ross *
8*a90cf9f2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*a90cf9f2SGordon Ross * or http://www.opensolaris.org/os/licensing.
10*a90cf9f2SGordon Ross * See the License for the specific language governing permissions
11*a90cf9f2SGordon Ross * and limitations under the License.
12*a90cf9f2SGordon Ross *
13*a90cf9f2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14*a90cf9f2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*a90cf9f2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16*a90cf9f2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17*a90cf9f2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18*a90cf9f2SGordon Ross *
19*a90cf9f2SGordon Ross * CDDL HEADER END
20*a90cf9f2SGordon Ross */
21*a90cf9f2SGordon Ross /*
22*a90cf9f2SGordon Ross * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23*a90cf9f2SGordon Ross * Use is subject to license terms.
24*a90cf9f2SGordon Ross *
25*a90cf9f2SGordon Ross * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26*a90cf9f2SGordon Ross */
27*a90cf9f2SGordon Ross
28*a90cf9f2SGordon Ross /*
29*a90cf9f2SGordon Ross * Dispatch function for SMB2_IOCTL
30*a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.15
31*a90cf9f2SGordon Ross */
32*a90cf9f2SGordon Ross
33*a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
34*a90cf9f2SGordon Ross #include <smbsrv/winioctl.h>
35*a90cf9f2SGordon Ross
36*a90cf9f2SGordon Ross struct smb2_ioctbl_ent {
37*a90cf9f2SGordon Ross uint32_t te_code;
38*a90cf9f2SGordon Ross uint32_t te_flags;
39*a90cf9f2SGordon Ross uint32_t (*te_func)(smb_request_t *, smb_fsctl_t *);
40*a90cf9f2SGordon Ross };
41*a90cf9f2SGordon Ross static struct smb2_ioctbl_ent smb2_ioc_tbl[];
42*a90cf9f2SGordon Ross
43*a90cf9f2SGordon Ross /* te_flags */
44*a90cf9f2SGordon Ross #define ITF_IPC_ONLY 1
45*a90cf9f2SGordon Ross #define ITF_NO_FID 2
46*a90cf9f2SGordon Ross #define ITF_DISK_FID 4
47*a90cf9f2SGordon Ross
48*a90cf9f2SGordon Ross smb_sdrc_t
smb2_ioctl(smb_request_t * sr)49*a90cf9f2SGordon Ross smb2_ioctl(smb_request_t *sr)
50*a90cf9f2SGordon Ross {
51*a90cf9f2SGordon Ross smb2fid_t smb2fid;
52*a90cf9f2SGordon Ross smb_fsctl_t fsctl;
53*a90cf9f2SGordon Ross mbuf_chain_t in_mbc;
54*a90cf9f2SGordon Ross struct smb2_ioctbl_ent *te;
55*a90cf9f2SGordon Ross uint32_t InputOffset;
56*a90cf9f2SGordon Ross uint32_t MaxInputResp;
57*a90cf9f2SGordon Ross uint32_t OutputOffset;
58*a90cf9f2SGordon Ross uint32_t Flags;
59*a90cf9f2SGordon Ross uint32_t status;
60*a90cf9f2SGordon Ross uint16_t StructSize;
61*a90cf9f2SGordon Ross int rc = 0;
62*a90cf9f2SGordon Ross
63*a90cf9f2SGordon Ross bzero(&in_mbc, sizeof (in_mbc));
64*a90cf9f2SGordon Ross
65*a90cf9f2SGordon Ross /*
66*a90cf9f2SGordon Ross * SMB2 Ioctl request
67*a90cf9f2SGordon Ross */
68*a90cf9f2SGordon Ross rc = smb_mbc_decodef(
69*a90cf9f2SGordon Ross &sr->smb_data, "w..lqqlllllll4.",
70*a90cf9f2SGordon Ross &StructSize, /* w */
71*a90cf9f2SGordon Ross /* reserved .. */
72*a90cf9f2SGordon Ross &fsctl.CtlCode, /* l */
73*a90cf9f2SGordon Ross &smb2fid.persistent, /* q */
74*a90cf9f2SGordon Ross &smb2fid.temporal, /* q */
75*a90cf9f2SGordon Ross &InputOffset, /* l */
76*a90cf9f2SGordon Ross &fsctl.InputCount, /* l */
77*a90cf9f2SGordon Ross &MaxInputResp, /* l */
78*a90cf9f2SGordon Ross &OutputOffset, /* l */
79*a90cf9f2SGordon Ross &fsctl.OutputCount, /* l */
80*a90cf9f2SGordon Ross &fsctl.MaxOutputResp, /* l */
81*a90cf9f2SGordon Ross &Flags); /* l */
82*a90cf9f2SGordon Ross /* reserved2 4. */
83*a90cf9f2SGordon Ross if (rc || StructSize != 57)
84*a90cf9f2SGordon Ross return (SDRC_ERROR);
85*a90cf9f2SGordon Ross
86*a90cf9f2SGordon Ross if (Flags != SMB2_0_IOCTL_IS_FSCTL) {
87*a90cf9f2SGordon Ross status = NT_STATUS_NOT_SUPPORTED;
88*a90cf9f2SGordon Ross goto errout;
89*a90cf9f2SGordon Ross }
90*a90cf9f2SGordon Ross
91*a90cf9f2SGordon Ross for (te = smb2_ioc_tbl; te->te_code; te++) {
92*a90cf9f2SGordon Ross if (te->te_code == fsctl.CtlCode)
93*a90cf9f2SGordon Ross break;
94*a90cf9f2SGordon Ross }
95*a90cf9f2SGordon Ross if (te->te_code == 0) {
96*a90cf9f2SGordon Ross #ifdef DEBUG
97*a90cf9f2SGordon Ross cmn_err(CE_NOTE, "smb2_ioctl: unknown code 0x%x",
98*a90cf9f2SGordon Ross fsctl.CtlCode);
99*a90cf9f2SGordon Ross #endif
100*a90cf9f2SGordon Ross status = NT_STATUS_NOT_SUPPORTED;
101*a90cf9f2SGordon Ross goto errout;
102*a90cf9f2SGordon Ross }
103*a90cf9f2SGordon Ross
104*a90cf9f2SGordon Ross /*
105*a90cf9f2SGordon Ross * Some requests are only valid on IPC$
106*a90cf9f2SGordon Ross */
107*a90cf9f2SGordon Ross if ((te->te_flags & ITF_IPC_ONLY) != 0 &&
108*a90cf9f2SGordon Ross !STYPE_ISIPC(sr->tid_tree->t_res_type)) {
109*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_DEVICE_REQUEST;
110*a90cf9f2SGordon Ross goto errout;
111*a90cf9f2SGordon Ross }
112*a90cf9f2SGordon Ross
113*a90cf9f2SGordon Ross /*
114*a90cf9f2SGordon Ross * Note: some ioctl commands don't need a FID.
115*a90cf9f2SGordon Ross */
116*a90cf9f2SGordon Ross if (te->te_flags & ITF_NO_FID) {
117*a90cf9f2SGordon Ross if (smb2fid.temporal != ~0LL) {
118*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER;
119*a90cf9f2SGordon Ross goto errout;
120*a90cf9f2SGordon Ross }
121*a90cf9f2SGordon Ross } else {
122*a90cf9f2SGordon Ross status = smb2sr_lookup_fid(sr, &smb2fid);
123*a90cf9f2SGordon Ross if (status) {
124*a90cf9f2SGordon Ross status = NT_STATUS_FILE_CLOSED;
125*a90cf9f2SGordon Ross goto errout;
126*a90cf9f2SGordon Ross }
127*a90cf9f2SGordon Ross }
128*a90cf9f2SGordon Ross
129*a90cf9f2SGordon Ross /*
130*a90cf9f2SGordon Ross * Note: some ioctls require a "disk" fid.
131*a90cf9f2SGordon Ross */
132*a90cf9f2SGordon Ross if (te->te_flags & ITF_DISK_FID) {
133*a90cf9f2SGordon Ross if (sr->fid_ofile == NULL ||
134*a90cf9f2SGordon Ross !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
135*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER;
136*a90cf9f2SGordon Ross goto errout;
137*a90cf9f2SGordon Ross }
138*a90cf9f2SGordon Ross }
139*a90cf9f2SGordon Ross
140*a90cf9f2SGordon Ross /*
141*a90cf9f2SGordon Ross * If there's an input buffer, setup a shadow.
142*a90cf9f2SGordon Ross */
143*a90cf9f2SGordon Ross if (fsctl.InputCount) {
144*a90cf9f2SGordon Ross if (InputOffset < (SMB2_HDR_SIZE + 56)) {
145*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER;
146*a90cf9f2SGordon Ross goto errout;
147*a90cf9f2SGordon Ross }
148*a90cf9f2SGordon Ross rc = MBC_SHADOW_CHAIN(&in_mbc, &sr->smb_data,
149*a90cf9f2SGordon Ross sr->smb2_cmd_hdr + InputOffset, fsctl.InputCount);
150*a90cf9f2SGordon Ross if (rc) {
151*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER;
152*a90cf9f2SGordon Ross goto errout;
153*a90cf9f2SGordon Ross }
154*a90cf9f2SGordon Ross }
155*a90cf9f2SGordon Ross fsctl.in_mbc = &in_mbc;
156*a90cf9f2SGordon Ross
157*a90cf9f2SGordon Ross /*
158*a90cf9f2SGordon Ross * If output is possible, setup the output mbuf_chain
159*a90cf9f2SGordon Ross */
160*a90cf9f2SGordon Ross if (fsctl.MaxOutputResp > smb2_max_trans)
161*a90cf9f2SGordon Ross fsctl.MaxOutputResp = smb2_max_trans;
162*a90cf9f2SGordon Ross sr->raw_data.max_bytes = fsctl.MaxOutputResp;
163*a90cf9f2SGordon Ross fsctl.out_mbc = &sr->raw_data;
164*a90cf9f2SGordon Ross
165*a90cf9f2SGordon Ross /*
166*a90cf9f2SGordon Ross * Dispatch to the handler for CtlCode
167*a90cf9f2SGordon Ross */
168*a90cf9f2SGordon Ross status = (te->te_func)(sr, &fsctl);
169*a90cf9f2SGordon Ross if (status != 0) {
170*a90cf9f2SGordon Ross sr->smb2_status = status;
171*a90cf9f2SGordon Ross if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR)
172*a90cf9f2SGordon Ross goto errout;
173*a90cf9f2SGordon Ross /* Warnings like NT_STATUS_BUFFER_OVERFLOW are OK. */
174*a90cf9f2SGordon Ross }
175*a90cf9f2SGordon Ross
176*a90cf9f2SGordon Ross fsctl.InputCount = 0;
177*a90cf9f2SGordon Ross InputOffset = SMB2_HDR_SIZE + 48;
178*a90cf9f2SGordon Ross
179*a90cf9f2SGordon Ross fsctl.OutputCount = MBC_LENGTH(&sr->raw_data);
180*a90cf9f2SGordon Ross OutputOffset = (fsctl.OutputCount) ? InputOffset : 0;
181*a90cf9f2SGordon Ross
182*a90cf9f2SGordon Ross /*
183*a90cf9f2SGordon Ross * SMB2 Ioctl reply
184*a90cf9f2SGordon Ross */
185*a90cf9f2SGordon Ross StructSize = 49;
186*a90cf9f2SGordon Ross rc = smb_mbc_encodef(
187*a90cf9f2SGordon Ross &sr->reply, "w..lqqlllll4.#C",
188*a90cf9f2SGordon Ross StructSize, /* w */
189*a90cf9f2SGordon Ross /* reserved .. */
190*a90cf9f2SGordon Ross fsctl.CtlCode, /* l */
191*a90cf9f2SGordon Ross smb2fid.persistent, /* q */
192*a90cf9f2SGordon Ross smb2fid.temporal, /* q */
193*a90cf9f2SGordon Ross InputOffset, /* l */
194*a90cf9f2SGordon Ross fsctl.InputCount, /* l */
195*a90cf9f2SGordon Ross OutputOffset, /* l */
196*a90cf9f2SGordon Ross fsctl.OutputCount, /* l */
197*a90cf9f2SGordon Ross Flags, /* l */
198*a90cf9f2SGordon Ross /* reserved2 4. */
199*a90cf9f2SGordon Ross fsctl.OutputCount, /* # */
200*a90cf9f2SGordon Ross &sr->raw_data); /* C */
201*a90cf9f2SGordon Ross return ((rc) ? SDRC_ERROR : SDRC_SUCCESS);
202*a90cf9f2SGordon Ross
203*a90cf9f2SGordon Ross errout:
204*a90cf9f2SGordon Ross smb2sr_put_error(sr, status);
205*a90cf9f2SGordon Ross return (SDRC_SUCCESS);
206*a90cf9f2SGordon Ross }
207*a90cf9f2SGordon Ross
208*a90cf9f2SGordon Ross /* ARGSUSED */
209*a90cf9f2SGordon Ross static uint32_t
smb2_fsctl_notsup(smb_request_t * sr,smb_fsctl_t * fsctl)210*a90cf9f2SGordon Ross smb2_fsctl_notsup(smb_request_t *sr, smb_fsctl_t *fsctl)
211*a90cf9f2SGordon Ross {
212*a90cf9f2SGordon Ross return (NT_STATUS_NOT_SUPPORTED);
213*a90cf9f2SGordon Ross }
214*a90cf9f2SGordon Ross
215*a90cf9f2SGordon Ross static struct smb2_ioctbl_ent
216*a90cf9f2SGordon Ross smb2_ioc_tbl[] = {
217*a90cf9f2SGordon Ross
218*a90cf9f2SGordon Ross /*
219*a90cf9f2SGordon Ross * FILE_DEVICE_DFS (6)
220*a90cf9f2SGordon Ross */
221*a90cf9f2SGordon Ross { FSCTL_DFS_GET_REFERRALS,
222*a90cf9f2SGordon Ross ITF_IPC_ONLY | ITF_NO_FID, smb_dfs_get_referrals },
223*a90cf9f2SGordon Ross { FSCTL_DFS_GET_REFERRALS_EX,
224*a90cf9f2SGordon Ross ITF_IPC_ONLY | ITF_NO_FID, smb_dfs_get_referrals },
225*a90cf9f2SGordon Ross
226*a90cf9f2SGordon Ross /*
227*a90cf9f2SGordon Ross * FILE_DEVICE_FILE_SYSTEM (9)
228*a90cf9f2SGordon Ross */
229*a90cf9f2SGordon Ross { FSCTL_SET_REPARSE_POINT, 0, smb2_fsctl_notsup },
230*a90cf9f2SGordon Ross { FSCTL_CREATE_OR_GET_OBJECT_ID, 0, smb2_fsctl_notsup },
231*a90cf9f2SGordon Ross { FSCTL_FILE_LEVEL_TRIM, 0, smb2_fsctl_notsup },
232*a90cf9f2SGordon Ross
233*a90cf9f2SGordon Ross /*
234*a90cf9f2SGordon Ross * FILE_DEVICE_NAMED_PIPE (17)
235*a90cf9f2SGordon Ross */
236*a90cf9f2SGordon Ross { FSCTL_PIPE_PEEK,
237*a90cf9f2SGordon Ross ITF_IPC_ONLY, smb_opipe_fsctl },
238*a90cf9f2SGordon Ross { FSCTL_PIPE_TRANSCEIVE,
239*a90cf9f2SGordon Ross ITF_IPC_ONLY, smb_opipe_fsctl },
240*a90cf9f2SGordon Ross { FSCTL_PIPE_WAIT,
241*a90cf9f2SGordon Ross ITF_IPC_ONLY | ITF_NO_FID, smb_opipe_fsctl },
242*a90cf9f2SGordon Ross
243*a90cf9f2SGordon Ross /*
244*a90cf9f2SGordon Ross * FILE_DEVICE_NETWORK_FILE_SYSTEM (20)
245*a90cf9f2SGordon Ross */
246*a90cf9f2SGordon Ross { FSCTL_SRV_ENUMERATE_SNAPSHOTS,
247*a90cf9f2SGordon Ross ITF_DISK_FID, smb_vss_enum_snapshots },
248*a90cf9f2SGordon Ross { FSCTL_SRV_REQUEST_RESUME_KEY, 0, smb2_fsctl_notsup },
249*a90cf9f2SGordon Ross { FSCTL_SRV_COPYCHUNK, 0, smb2_fsctl_notsup },
250*a90cf9f2SGordon Ross { FSCTL_SRV_COPYCHUNK_WRITE, 0, smb2_fsctl_notsup },
251*a90cf9f2SGordon Ross { FSCTL_SRV_READ_HASH, 0, smb2_fsctl_notsup },
252*a90cf9f2SGordon Ross
253*a90cf9f2SGordon Ross { FSCTL_LMR_REQUEST_RESILIENCY,
254*a90cf9f2SGordon Ross ITF_NO_FID, smb2_fsctl_notsup },
255*a90cf9f2SGordon Ross { FSCTL_QUERY_NETWORK_INTERFACE_INFO,
256*a90cf9f2SGordon Ross ITF_NO_FID, smb2_fsctl_notsup },
257*a90cf9f2SGordon Ross { FSCTL_VALIDATE_NEGOTIATE_INFO,
258*a90cf9f2SGordon Ross ITF_NO_FID, smb2_fsctl_vneginfo },
259*a90cf9f2SGordon Ross
260*a90cf9f2SGordon Ross /*
261*a90cf9f2SGordon Ross * End marker
262*a90cf9f2SGordon Ross */
263*a90cf9f2SGordon Ross { 0, 0, 0 }
264*a90cf9f2SGordon Ross };
265