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