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