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 2018 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 <smb/winioctl.h> 35 36 smb_sdrc_t 37 smb2_ioctl(smb_request_t *sr) 38 { 39 smb2fid_t smb2fid; 40 smb_fsctl_t fsctl; 41 mbuf_chain_t in_mbc; 42 uint32_t InputOffset; 43 uint32_t MaxInputResp; 44 uint32_t OutputOffset; 45 uint32_t Flags; 46 uint32_t status = 0; 47 uint16_t StructSize; 48 uint16_t DeviceType; 49 int rc = 0; 50 51 /* Todo: put fsctl in sr->arg.ioctl (visible in dtrace probes) */ 52 bzero(&in_mbc, sizeof (in_mbc)); 53 54 /* 55 * Decode SMB2 Ioctl request 56 */ 57 rc = smb_mbc_decodef( 58 &sr->smb_data, "w..lqqlllllll4.", 59 &StructSize, /* w */ 60 /* reserved .. */ 61 &fsctl.CtlCode, /* l */ 62 &smb2fid.persistent, /* q */ 63 &smb2fid.temporal, /* q */ 64 &InputOffset, /* l */ 65 &fsctl.InputCount, /* l */ 66 &MaxInputResp, /* l */ 67 &OutputOffset, /* l */ 68 &fsctl.OutputCount, /* l */ 69 &fsctl.MaxOutputResp, /* l */ 70 &Flags); /* l */ 71 /* reserved2 4. */ 72 if (rc || StructSize != 57) 73 return (SDRC_ERROR); 74 75 /* 76 * If there's an input buffer, setup a shadow. 77 */ 78 if (fsctl.InputCount) { 79 if (InputOffset < (SMB2_HDR_SIZE + 56)) 80 return (SDRC_ERROR); 81 if (fsctl.InputCount > smb2_max_trans) 82 return (SDRC_ERROR); 83 rc = MBC_SHADOW_CHAIN(&in_mbc, &sr->smb_data, 84 sr->smb2_cmd_hdr + InputOffset, fsctl.InputCount); 85 if (rc) { 86 return (SDRC_ERROR); 87 } 88 } 89 fsctl.in_mbc = &in_mbc; 90 91 /* 92 * If output is possible, setup the output mbuf_chain 93 */ 94 if (fsctl.MaxOutputResp > smb2_max_trans) 95 fsctl.MaxOutputResp = smb2_max_trans; 96 sr->raw_data.max_bytes = fsctl.MaxOutputResp; 97 fsctl.out_mbc = &sr->raw_data; 98 99 /* 100 * [MS-SMB2] 3.3.5.15 101 * 102 * If the Flags field of the request is not SMB2_0_IOCTL_IS_FSCTL 103 * the server MUST fail the request with STATUS_NOT_SUPPORTED. 104 * 105 * If the CtlCode is any of (... see switch below...) and the 106 * value of FileId in the SMB2 Header of the request is not 107 * 0xFFFFFFFFFFFFFFFF, then the server MUST fail the request 108 * with STATUS_INVALID_PARAMETER. (Otherwise lookup the FID.) 109 */ 110 if (Flags != SMB2_0_IOCTL_IS_FSCTL) { 111 status = NT_STATUS_NOT_SUPPORTED; 112 } else switch (fsctl.CtlCode) { 113 case FSCTL_DFS_GET_REFERRALS: 114 case FSCTL_DFS_GET_REFERRALS_EX: 115 case FSCTL_QUERY_NETWORK_INTERFACE_INFO: 116 case FSCTL_VALIDATE_NEGOTIATE_INFO: 117 case FSCTL_PIPE_WAIT: 118 if (smb2fid.temporal != ~0LL || 119 smb2fid.persistent != ~0LL) { 120 status = NT_STATUS_INVALID_PARAMETER; 121 } 122 break; 123 default: 124 status = smb2sr_lookup_fid(sr, &smb2fid); 125 if (status != 0) { 126 status = NT_STATUS_FILE_CLOSED; 127 } 128 break; 129 } 130 131 /* 132 * Keep FID lookup before the start probe. 133 */ 134 DTRACE_SMB2_START(op__Ioctl, smb_request_t *, sr); 135 136 if (status) 137 goto errout; 138 139 /* 140 * Dispatch to the handler for CtlCode 141 * See CTL_CODE() in winioctl.h 142 */ 143 DeviceType = fsctl.CtlCode >> 16; 144 switch (DeviceType) { 145 case FILE_DEVICE_DFS: /* 6 */ 146 status = smb_dfs_fsctl(sr, &fsctl); 147 break; 148 case FILE_DEVICE_FILE_SYSTEM: /* 9 */ 149 status = smb2_fsctl_fs(sr, &fsctl); 150 break; 151 case FILE_DEVICE_NAMED_PIPE: /* 17 */ 152 status = smb_opipe_fsctl(sr, &fsctl); 153 break; 154 case FILE_DEVICE_NETWORK_FILE_SYSTEM: /* 20 */ 155 status = smb2_fsctl_netfs(sr, &fsctl); 156 break; 157 default: 158 status = NT_STATUS_NOT_SUPPORTED; 159 break; 160 } 161 162 errout: 163 sr->smb2_status = status; 164 DTRACE_SMB2_DONE(op__Ioctl, smb_request_t *, sr); 165 166 if (status != 0) { 167 /* 168 * NT status codes with severity "error" normally cause 169 * an error response with no data. However, there are 170 * exceptions like smb2_fsctl_copychunk that may return 171 * severity==error _with_ a data part. 172 */ 173 if ((NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR) && 174 (fsctl.CtlCode != FSCTL_SRV_COPYCHUNK) && 175 (fsctl.CtlCode != FSCTL_SRV_COPYCHUNK_WRITE)) { 176 /* no error data */ 177 smb2sr_put_error(sr, status); 178 return (SDRC_SUCCESS); 179 } 180 /* Else, error response _with_ data. */ 181 } 182 183 fsctl.InputCount = 0; 184 InputOffset = SMB2_HDR_SIZE + 48; 185 186 fsctl.OutputCount = MBC_LENGTH(&sr->raw_data); 187 OutputOffset = (fsctl.OutputCount) ? InputOffset : 0; 188 189 /* 190 * Encode SMB2 Ioctl reply 191 */ 192 StructSize = 49; 193 rc = smb_mbc_encodef( 194 &sr->reply, "w..lqqlllll4.#C", 195 StructSize, /* w */ 196 /* reserved .. */ 197 fsctl.CtlCode, /* l */ 198 smb2fid.persistent, /* q */ 199 smb2fid.temporal, /* q */ 200 InputOffset, /* l */ 201 fsctl.InputCount, /* l */ 202 OutputOffset, /* l */ 203 fsctl.OutputCount, /* l */ 204 0, /* Flags l */ 205 /* reserved2 4. */ 206 fsctl.OutputCount, /* # */ 207 &sr->raw_data); /* C */ 208 if (rc) 209 sr->smb2_status = NT_STATUS_INTERNAL_ERROR; 210 211 return (SDRC_SUCCESS); 212 } 213