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 func = smb2_fsctl_odx_read; 150 break; 151 case FSCTL_OFFLOAD_WRITE: /* 154 */ 152 func = smb2_fsctl_odx_write; 153 break; 154 case FSCTL_SET_INTEGRITY_INFORMATION: /* 160 */ 155 func = smb2_fsctl_notsup; 156 break; 157 case FSCTL_QUERY_FILE_REGIONS: /* 161 */ 158 func = smb2_fsctl_query_file_regions; 159 break; 160 161 default: 162 func = smb2_fsctl_unknown; 163 break; 164 } 165 166 /* 167 * All "fs" sub-codes require a disk file. 168 */ 169 if (sr->fid_ofile == NULL || 170 !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) 171 return (NT_STATUS_INVALID_PARAMETER); 172 173 status = (*func)(sr, fsctl); 174 return (status); 175 } 176 177 /* 178 * FILE_DEVICE_NETWORK_FILE_SYSTEM (20) 179 */ 180 uint32_t 181 smb2_fsctl_netfs(smb_request_t *sr, smb_fsctl_t *fsctl) 182 { 183 uint32_t (*func)(smb_request_t *, smb_fsctl_t *); 184 uint32_t status; 185 boolean_t need_disk_file = B_TRUE; 186 187 switch (fsctl->CtlCode) { 188 case FSCTL_SRV_ENUMERATE_SNAPSHOTS: /* 0x19 */ 189 func = smb_vss_enum_snapshots; 190 break; 191 case FSCTL_SRV_REQUEST_RESUME_KEY: /* 0x1e */ 192 func = smb2_fsctl_get_resume_key; 193 break; 194 case FSCTL_SRV_COPYCHUNK: /* 0x3c(r) */ 195 case FSCTL_SRV_COPYCHUNK_WRITE: /* 0x3c(w) */ 196 func = smb2_fsctl_copychunk; 197 break; 198 case FSCTL_SRV_READ_HASH: /* 0x6e */ 199 func = smb2_fsctl_notsup; 200 break; 201 case FSCTL_LMR_REQUEST_RESILIENCY: /* 0x75 */ 202 func = smb2_fsctl_set_resilient; 203 break; 204 case FSCTL_QUERY_NETWORK_INTERFACE_INFO: /* 0x7f */ 205 need_disk_file = B_FALSE; 206 func = smb2_fsctl_notsup; 207 break; 208 case FSCTL_VALIDATE_NEGOTIATE_INFO: /* 0x81 */ 209 need_disk_file = B_FALSE; 210 func = smb2_nego_validate; 211 break; 212 default: 213 func = smb2_fsctl_unknown; 214 break; 215 } 216 217 /* 218 * Most "net fs" sub-codes require a disk file, 219 * except a couple that clear need_disk_file. 220 */ 221 if (need_disk_file && (sr->fid_ofile == NULL || 222 !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype))) 223 return (NT_STATUS_INVALID_PARAMETER); 224 225 status = (*func)(sr, fsctl); 226 return (status); 227 } 228