1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 /* 17 * Support functions for smb2_ioctl/fsctl categories: 18 * FILE_DEVICE_FILE_SYSTEM (9) 19 * FILE_DEVICE_NETWORK_FILE_SYSTEM (20) 20 */ 21 22 #include <smbsrv/smb2_kproto.h> 23 #include <smbsrv/smb_fsops.h> 24 #include <smb/winioctl.h> 25 26 /* ARGSUSED */ 27 static uint32_t 28 smb2_fsctl_notsup(smb_request_t *sr, smb_fsctl_t *fsctl) 29 { 30 return (NT_STATUS_NOT_SUPPORTED); 31 } 32 33 /* 34 * Same as smb2_fsctl_notsup, but make some noise (if DEBUG) 35 * so we'll learn about new fsctl codes clients start using. 36 */ 37 /* ARGSUSED */ 38 static uint32_t 39 smb2_fsctl_unknown(smb_request_t *sr, smb_fsctl_t *fsctl) 40 { 41 #ifdef DEBUG 42 cmn_err(CE_NOTE, "smb2_fsctl_unknown: code 0x%x", fsctl->CtlCode); 43 #endif 44 return (NT_STATUS_NOT_SUPPORTED); 45 } 46 47 /* 48 * FSCTL_GET_COMPRESSION 49 */ 50 static uint32_t 51 smb2_fsctl_get_compression(smb_request_t *sr, smb_fsctl_t *fsctl) 52 { 53 _NOTE(ARGUNUSED(sr)) 54 uint16_t compress_state = 0; 55 56 (void) smb_mbc_encodef(fsctl->in_mbc, "w", 57 compress_state); 58 59 return (NT_STATUS_SUCCESS); 60 } 61 62 /* 63 * FSCTL_SET_COMPRESSION 64 */ 65 static uint32_t 66 smb2_fsctl_set_compression(smb_request_t *sr, smb_fsctl_t *fsctl) 67 { 68 _NOTE(ARGUNUSED(sr)) 69 70 uint16_t compress_state; 71 (void) smb_mbc_decodef(fsctl->in_mbc, "w", 72 &compress_state); 73 74 if (compress_state > 0) 75 return (NT_STATUS_COMPRESSION_DISABLED); 76 77 return (NT_STATUS_SUCCESS); 78 } 79 80 /* 81 * FSCTL_SRV_REQUEST_RESUME_KEY 82 * 83 * The returned data is an (opaque to the client) 24-byte blob 84 * in which we stash the SMB2 "file ID" (both parts). Later, 85 * copychunk may lookup the ofile using that file ID. 86 * See: smb2_fsctl_copychunk() 87 * 88 * Note that Mac clients make this request on a directory 89 * (even though this only makes sense on a file) just to 90 * find out if the server supports server-side copy. 91 * There's no harm letting a client have a resume key 92 * for a directory. They'll never be able to DO anything 93 * with it because we check for a plain file later. 94 */ 95 static uint32_t 96 smb2_fsctl_get_resume_key(smb_request_t *sr, smb_fsctl_t *fsctl) 97 { 98 smb_ofile_t *of = sr->fid_ofile; 99 smb2fid_t smb2fid; 100 101 /* Caller makes sure we have of = sr->fid_ofile */ 102 /* Don't insist on a plain file (see above). */ 103 104 smb2fid.persistent = of->f_persistid; 105 smb2fid.temporal = of->f_fid; 106 107 (void) smb_mbc_encodef( 108 fsctl->out_mbc, "qq16.", 109 smb2fid.persistent, 110 smb2fid.temporal); 111 112 return (NT_STATUS_SUCCESS); 113 } 114 115 /* 116 * FILE_DEVICE_FILE_SYSTEM (9) 117 */ 118 uint32_t 119 smb2_fsctl_fs(smb_request_t *sr, smb_fsctl_t *fsctl) 120 { 121 uint32_t (*func)(smb_request_t *, smb_fsctl_t *); 122 uint32_t status; 123 124 switch (fsctl->CtlCode) { 125 case FSCTL_GET_COMPRESSION: /* 15 */ 126 func = smb2_fsctl_get_compression; 127 break; 128 case FSCTL_SET_COMPRESSION: /* 16 */ 129 func = smb2_fsctl_set_compression; 130 break; 131 case FSCTL_SET_REPARSE_POINT: /* 41 */ 132 case FSCTL_GET_REPARSE_POINT: /* 42 */ 133 case FSCTL_CREATE_OR_GET_OBJECT_ID: /* 48 */ 134 func = smb2_fsctl_notsup; 135 break; 136 case FSCTL_SET_SPARSE: /* 49 */ 137 func = smb2_fsctl_set_sparse; 138 break; 139 case FSCTL_SET_ZERO_DATA: /* 50 */ 140 func = smb2_fsctl_set_zero_data; 141 break; 142 case FSCTL_QUERY_ALLOCATED_RANGES: /* 51 */ 143 func = smb2_fsctl_query_alloc_ranges; 144 break; 145 case FSCTL_FILE_LEVEL_TRIM: /* 130 */ 146 func = smb2_fsctl_notsup; 147 break; 148 case FSCTL_OFFLOAD_READ: /* 153 */ 149 case FSCTL_OFFLOAD_WRITE: /* 154 */ 150 func = smb2_fsctl_notsup; 151 break; 152 case FSCTL_SET_INTEGRITY_INFORMATION: /* 160 */ 153 func = smb2_fsctl_notsup; 154 break; 155 case FSCTL_QUERY_FILE_REGIONS: /* 161 */ 156 func = smb2_fsctl_query_file_regions; 157 break; 158 159 default: 160 func = smb2_fsctl_unknown; 161 break; 162 } 163 164 /* 165 * All "fs" sub-codes require a disk file. 166 */ 167 if (sr->fid_ofile == NULL || 168 !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) 169 return (NT_STATUS_INVALID_PARAMETER); 170 171 status = (*func)(sr, fsctl); 172 return (status); 173 } 174 175 /* 176 * FILE_DEVICE_NETWORK_FILE_SYSTEM (20) 177 */ 178 uint32_t 179 smb2_fsctl_netfs(smb_request_t *sr, smb_fsctl_t *fsctl) 180 { 181 uint32_t (*func)(smb_request_t *, smb_fsctl_t *); 182 uint32_t status; 183 boolean_t need_disk_file = B_TRUE; 184 185 switch (fsctl->CtlCode) { 186 case FSCTL_SRV_ENUMERATE_SNAPSHOTS: /* 0x19 */ 187 func = smb_vss_enum_snapshots; 188 break; 189 case FSCTL_SRV_REQUEST_RESUME_KEY: /* 0x1e */ 190 func = smb2_fsctl_get_resume_key; 191 break; 192 case FSCTL_SRV_COPYCHUNK: /* 0x3c(r) */ 193 case FSCTL_SRV_COPYCHUNK_WRITE: /* 0x3c(w) */ 194 func = smb2_fsctl_copychunk; 195 break; 196 case FSCTL_SRV_READ_HASH: /* 0x6e */ 197 func = smb2_fsctl_notsup; 198 break; 199 case FSCTL_LMR_REQUEST_RESILIENCY: /* 0x75 */ 200 func = smb2_fsctl_set_resilient; 201 break; 202 case FSCTL_QUERY_NETWORK_INTERFACE_INFO: /* 0x7f */ 203 need_disk_file = B_FALSE; 204 func = smb2_fsctl_notsup; 205 break; 206 case FSCTL_VALIDATE_NEGOTIATE_INFO: /* 0x81 */ 207 need_disk_file = B_FALSE; 208 func = smb2_nego_validate; 209 break; 210 default: 211 func = smb2_fsctl_unknown; 212 break; 213 } 214 215 /* 216 * Most "net fs" sub-codes require a disk file, 217 * except a couple that clear need_disk_file. 218 */ 219 if (need_disk_file && (sr->fid_ofile == NULL || 220 !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype))) 221 return (NT_STATUS_INVALID_PARAMETER); 222 223 status = (*func)(sr, fsctl); 224 return (status); 225 } 226