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