1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross * CDDL HEADER START
3a90cf9f2SGordon Ross *
4a90cf9f2SGordon Ross * The contents of this file are subject to the terms of the
5a90cf9f2SGordon Ross * Common Development and Distribution License (the "License").
6a90cf9f2SGordon Ross * You may not use this file except in compliance with the License.
7a90cf9f2SGordon Ross *
8a90cf9f2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a90cf9f2SGordon Ross * or http://www.opensolaris.org/os/licensing.
10a90cf9f2SGordon Ross * See the License for the specific language governing permissions
11a90cf9f2SGordon Ross * and limitations under the License.
12a90cf9f2SGordon Ross *
13a90cf9f2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14a90cf9f2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a90cf9f2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16a90cf9f2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17a90cf9f2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18a90cf9f2SGordon Ross *
19a90cf9f2SGordon Ross * CDDL HEADER END
20a90cf9f2SGordon Ross */
21a90cf9f2SGordon Ross /*
22a90cf9f2SGordon Ross * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23a90cf9f2SGordon Ross * Use is subject to license terms.
24a90cf9f2SGordon Ross *
25adee6784SGordon Ross * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
26a90cf9f2SGordon Ross */
27a90cf9f2SGordon Ross
28a90cf9f2SGordon Ross /*
29a90cf9f2SGordon Ross * Dispatch function for SMB2_IOCTL
30a90cf9f2SGordon Ross * [MS-SMB2] 3.3.5.15
31a90cf9f2SGordon Ross */
32a90cf9f2SGordon Ross
33a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
34adee6784SGordon Ross #include <smb/winioctl.h>
35a90cf9f2SGordon Ross
36a90cf9f2SGordon Ross smb_sdrc_t
smb2_ioctl(smb_request_t * sr)37a90cf9f2SGordon Ross smb2_ioctl(smb_request_t *sr)
38a90cf9f2SGordon Ross {
39a90cf9f2SGordon Ross smb2fid_t smb2fid;
40a90cf9f2SGordon Ross smb_fsctl_t fsctl;
41a90cf9f2SGordon Ross mbuf_chain_t in_mbc;
42a90cf9f2SGordon Ross uint32_t InputOffset;
43a90cf9f2SGordon Ross uint32_t MaxInputResp;
44a90cf9f2SGordon Ross uint32_t OutputOffset;
45a90cf9f2SGordon Ross uint32_t Flags;
4693bc28dbSGordon Ross uint32_t status = 0;
47a90cf9f2SGordon Ross uint16_t StructSize;
48*55f0a249SGordon Ross uint16_t DeviceType;
49a90cf9f2SGordon Ross int rc = 0;
50a90cf9f2SGordon Ross
5193bc28dbSGordon Ross /* Todo: put fsctl in sr->arg.ioctl (visible in dtrace probes) */
52a90cf9f2SGordon Ross bzero(&in_mbc, sizeof (in_mbc));
53a90cf9f2SGordon Ross
54a90cf9f2SGordon Ross /*
5593bc28dbSGordon Ross * Decode SMB2 Ioctl request
56a90cf9f2SGordon Ross */
57a90cf9f2SGordon Ross rc = smb_mbc_decodef(
58a90cf9f2SGordon Ross &sr->smb_data, "w..lqqlllllll4.",
59a90cf9f2SGordon Ross &StructSize, /* w */
60a90cf9f2SGordon Ross /* reserved .. */
61a90cf9f2SGordon Ross &fsctl.CtlCode, /* l */
62a90cf9f2SGordon Ross &smb2fid.persistent, /* q */
63a90cf9f2SGordon Ross &smb2fid.temporal, /* q */
64a90cf9f2SGordon Ross &InputOffset, /* l */
65a90cf9f2SGordon Ross &fsctl.InputCount, /* l */
66a90cf9f2SGordon Ross &MaxInputResp, /* l */
67a90cf9f2SGordon Ross &OutputOffset, /* l */
68a90cf9f2SGordon Ross &fsctl.OutputCount, /* l */
69a90cf9f2SGordon Ross &fsctl.MaxOutputResp, /* l */
70a90cf9f2SGordon Ross &Flags); /* l */
71a90cf9f2SGordon Ross /* reserved2 4. */
72a90cf9f2SGordon Ross if (rc || StructSize != 57)
73a90cf9f2SGordon Ross return (SDRC_ERROR);
74a90cf9f2SGordon Ross
7593bc28dbSGordon Ross /*
7693bc28dbSGordon Ross * If there's an input buffer, setup a shadow.
7793bc28dbSGordon Ross */
7893bc28dbSGordon Ross if (fsctl.InputCount) {
7993bc28dbSGordon Ross if (InputOffset < (SMB2_HDR_SIZE + 56))
8093bc28dbSGordon Ross return (SDRC_ERROR);
8193bc28dbSGordon Ross if (fsctl.InputCount > smb2_max_trans)
8293bc28dbSGordon Ross return (SDRC_ERROR);
8393bc28dbSGordon Ross rc = MBC_SHADOW_CHAIN(&in_mbc, &sr->smb_data,
8493bc28dbSGordon Ross sr->smb2_cmd_hdr + InputOffset, fsctl.InputCount);
8593bc28dbSGordon Ross if (rc) {
8693bc28dbSGordon Ross return (SDRC_ERROR);
8793bc28dbSGordon Ross }
8893bc28dbSGordon Ross }
8993bc28dbSGordon Ross fsctl.in_mbc = &in_mbc;
9093bc28dbSGordon Ross
9193bc28dbSGordon Ross /*
9293bc28dbSGordon Ross * If output is possible, setup the output mbuf_chain
9393bc28dbSGordon Ross */
9493bc28dbSGordon Ross if (fsctl.MaxOutputResp > smb2_max_trans)
9593bc28dbSGordon Ross fsctl.MaxOutputResp = smb2_max_trans;
9693bc28dbSGordon Ross sr->raw_data.max_bytes = fsctl.MaxOutputResp;
9793bc28dbSGordon Ross fsctl.out_mbc = &sr->raw_data;
9893bc28dbSGordon Ross
9993bc28dbSGordon Ross /*
10093bc28dbSGordon Ross * [MS-SMB2] 3.3.5.15
10193bc28dbSGordon Ross *
10293bc28dbSGordon Ross * If the Flags field of the request is not SMB2_0_IOCTL_IS_FSCTL
10393bc28dbSGordon Ross * the server MUST fail the request with STATUS_NOT_SUPPORTED.
10493bc28dbSGordon Ross *
10593bc28dbSGordon Ross * If the CtlCode is any of (... see switch below...) and the
10693bc28dbSGordon Ross * value of FileId in the SMB2 Header of the request is not
10793bc28dbSGordon Ross * 0xFFFFFFFFFFFFFFFF, then the server MUST fail the request
10893bc28dbSGordon Ross * with STATUS_INVALID_PARAMETER. (Otherwise lookup the FID.)
10993bc28dbSGordon Ross */
110a90cf9f2SGordon Ross if (Flags != SMB2_0_IOCTL_IS_FSCTL) {
111a90cf9f2SGordon Ross status = NT_STATUS_NOT_SUPPORTED;
11293bc28dbSGordon Ross } else switch (fsctl.CtlCode) {
11393bc28dbSGordon Ross case FSCTL_DFS_GET_REFERRALS:
11493bc28dbSGordon Ross case FSCTL_DFS_GET_REFERRALS_EX:
11593bc28dbSGordon Ross case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
11693bc28dbSGordon Ross case FSCTL_VALIDATE_NEGOTIATE_INFO:
11793bc28dbSGordon Ross case FSCTL_PIPE_WAIT:
11893bc28dbSGordon Ross if (smb2fid.temporal != ~0LL ||
11993bc28dbSGordon Ross smb2fid.persistent != ~0LL) {
12093bc28dbSGordon Ross status = NT_STATUS_INVALID_PARAMETER;
12193bc28dbSGordon Ross }
12293bc28dbSGordon Ross break;
12393bc28dbSGordon Ross default:
12493bc28dbSGordon Ross status = smb2sr_lookup_fid(sr, &smb2fid);
12593bc28dbSGordon Ross if (status != 0) {
12693bc28dbSGordon Ross status = NT_STATUS_FILE_CLOSED;
12793bc28dbSGordon Ross }
12893bc28dbSGordon Ross break;
129a90cf9f2SGordon Ross }
130a90cf9f2SGordon Ross
13193bc28dbSGordon Ross /*
13293bc28dbSGordon Ross * Keep FID lookup before the start probe.
13393bc28dbSGordon Ross */
13493bc28dbSGordon Ross DTRACE_SMB2_START(op__Ioctl, smb_request_t *, sr);
13593bc28dbSGordon Ross
13693bc28dbSGordon Ross if (status)
13793bc28dbSGordon Ross goto errout;
13893bc28dbSGordon Ross
139a90cf9f2SGordon Ross /*
140a90cf9f2SGordon Ross * Dispatch to the handler for CtlCode
141*55f0a249SGordon Ross * See CTL_CODE() in winioctl.h
142a90cf9f2SGordon Ross */
143*55f0a249SGordon Ross DeviceType = fsctl.CtlCode >> 16;
144*55f0a249SGordon Ross switch (DeviceType) {
145*55f0a249SGordon Ross case FILE_DEVICE_DFS: /* 6 */
146*55f0a249SGordon Ross status = smb_dfs_fsctl(sr, &fsctl);
147*55f0a249SGordon Ross break;
148*55f0a249SGordon Ross case FILE_DEVICE_FILE_SYSTEM: /* 9 */
149*55f0a249SGordon Ross status = smb2_fsctl_fs(sr, &fsctl);
150*55f0a249SGordon Ross break;
151*55f0a249SGordon Ross case FILE_DEVICE_NAMED_PIPE: /* 17 */
152*55f0a249SGordon Ross status = smb_opipe_fsctl(sr, &fsctl);
153*55f0a249SGordon Ross break;
154*55f0a249SGordon Ross case FILE_DEVICE_NETWORK_FILE_SYSTEM: /* 20 */
155*55f0a249SGordon Ross status = smb2_fsctl_netfs(sr, &fsctl);
156*55f0a249SGordon Ross break;
157*55f0a249SGordon Ross default:
158*55f0a249SGordon Ross status = NT_STATUS_NOT_SUPPORTED;
159*55f0a249SGordon Ross break;
160*55f0a249SGordon Ross }
16193bc28dbSGordon Ross
16293bc28dbSGordon Ross errout:
16393bc28dbSGordon Ross sr->smb2_status = status;
16493bc28dbSGordon Ross DTRACE_SMB2_DONE(op__Ioctl, smb_request_t *, sr);
16593bc28dbSGordon Ross
166a90cf9f2SGordon Ross if (status != 0) {
167*55f0a249SGordon Ross /*
168*55f0a249SGordon Ross * NT status codes with severity "error" normally cause
169*55f0a249SGordon Ross * an error response with no data. However, there are
170*55f0a249SGordon Ross * exceptions like smb2_fsctl_copychunk that may return
171*55f0a249SGordon Ross * severity==error _with_ a data part.
172*55f0a249SGordon Ross */
173*55f0a249SGordon Ross if ((NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR) &&
174*55f0a249SGordon Ross (fsctl.CtlCode != FSCTL_SRV_COPYCHUNK) &&
175*55f0a249SGordon Ross (fsctl.CtlCode != FSCTL_SRV_COPYCHUNK_WRITE)) {
17693bc28dbSGordon Ross /* no error data */
17793bc28dbSGordon Ross smb2sr_put_error(sr, status);
17893bc28dbSGordon Ross return (SDRC_SUCCESS);
17993bc28dbSGordon Ross }
180*55f0a249SGordon Ross /* Else, error response _with_ data. */
181a90cf9f2SGordon Ross }
182a90cf9f2SGordon Ross
183a90cf9f2SGordon Ross fsctl.InputCount = 0;
184a90cf9f2SGordon Ross InputOffset = SMB2_HDR_SIZE + 48;
185a90cf9f2SGordon Ross
186a90cf9f2SGordon Ross fsctl.OutputCount = MBC_LENGTH(&sr->raw_data);
187a90cf9f2SGordon Ross OutputOffset = (fsctl.OutputCount) ? InputOffset : 0;
188a90cf9f2SGordon Ross
189a90cf9f2SGordon Ross /*
19093bc28dbSGordon Ross * Encode SMB2 Ioctl reply
191a90cf9f2SGordon Ross */
192a90cf9f2SGordon Ross StructSize = 49;
193a90cf9f2SGordon Ross rc = smb_mbc_encodef(
194a90cf9f2SGordon Ross &sr->reply, "w..lqqlllll4.#C",
195a90cf9f2SGordon Ross StructSize, /* w */
196a90cf9f2SGordon Ross /* reserved .. */
197a90cf9f2SGordon Ross fsctl.CtlCode, /* l */
198a90cf9f2SGordon Ross smb2fid.persistent, /* q */
199a90cf9f2SGordon Ross smb2fid.temporal, /* q */
200a90cf9f2SGordon Ross InputOffset, /* l */
201a90cf9f2SGordon Ross fsctl.InputCount, /* l */
202a90cf9f2SGordon Ross OutputOffset, /* l */
203a90cf9f2SGordon Ross fsctl.OutputCount, /* l */
204*55f0a249SGordon Ross 0, /* Flags l */
205a90cf9f2SGordon Ross /* reserved2 4. */
206a90cf9f2SGordon Ross fsctl.OutputCount, /* # */
207a90cf9f2SGordon Ross &sr->raw_data); /* C */
20893bc28dbSGordon Ross if (rc)
20993bc28dbSGordon Ross sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
210a90cf9f2SGordon Ross
211a90cf9f2SGordon Ross return (SDRC_SUCCESS);
212a90cf9f2SGordon Ross }
213