xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
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
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
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