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 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 #include <smbsrv/smb_kproto.h> 28 #include <smbsrv/smb_fsops.h> 29 30 /* 31 * smb_nt_transact_query_quota 32 * 33 * This method allows the client to retrieve quota information from 34 * the server. The result of the call is returned to the client in the 35 * Data part of the transaction response. 36 * 37 * On entry, the 'TotalParameterCount' field must be equal to 16, and the 38 * client parameter block must be encoded with the following parameters: 39 * 40 * Request Description 41 * ========================== ================================== 42 * WORD fid SMB file identifier of the target directory 43 * BYTE ReturnSingleEntry A boolean indicating whether to return 44 * a single entry (TRUE) or multiple entries (FALSE). 45 * BYTE RestartScan A boolean indicating whether to continue from 46 * the previous request (FALSE) or restart a new 47 * sequence (TRUE). 48 * DWORD SidListLength The length, in bytes, of the SidList in the 49 * data block or 0 if there is no SidList. 50 * DWORD StartSidLength If SidListLength is 0 (i.e. there is no SidList 51 * in the data block), then this is either: 52 * 1) the (non-zero) length in bytes of the 53 * StartSid in the parameter buffer, or 54 * 2) if 0, there is no StartSid in the 55 * parameter buffer, in which case, all SIDs 56 * are to be enumerated as if they were 57 * passed in the SidList. 58 * Otherwise, StartSidLength is ignored. 59 * DWORD StartSidOffset The offset, in bytes, to the StartSid in the 60 * parameter block (if one exists). 61 * 62 * One of SidListLength and StartSidLength must be 0. 63 * 64 * An SMB_COM_NT_TRANSACTION response is sent in reply when the request 65 * is successful. The 'TotalParameterCount' is set to 4, and the parameter 66 * block in the server response contains a 32-bit unsigned integer 67 * indicating the length, in bytes, of the returned quota information. 68 * The 'TotalDataCount' is set to indicate the length of the data buffer, 69 * and the data buffer contains the following quota information: 70 * 71 * Data Block Encoding Description 72 * ================================== ================================= 73 * ULONG NextEntryOffset; Offset to start of next entry from 74 * start of this entry, or 0 for the 75 * final entry 76 * ULONG SidLength; Length (bytes) of SID 77 * SMB_TIME ChangeTime; Time that the quota was last changed 78 * LARGE_INTEGER QuotaUsed; Amount of quota (bytes) used by user 79 * LARGE_INTEGER QuotaThreshold; Quota warning limit (bytes) for user 80 * LARGE_INTEGER QuotaLimit; The quota limit (bytes) for this user 81 * USHORT Sid; Search handle 82 */ 83 smb_sdrc_t 84 smb_nt_transact_query_quota(smb_request_t *sr, smb_xa_t *xa) 85 { 86 uint8_t single, restart; 87 uint32_t sidlistlen, startsidlen, startsidoff; 88 smb_node_t *tnode; 89 smb_ofile_t *ofile; 90 smb_quota_query_t request; 91 smb_quota_response_t reply; 92 uint32_t status = NT_STATUS_SUCCESS; 93 94 bzero(&request, sizeof (smb_quota_query_t)); 95 bzero(&reply, sizeof (smb_quota_response_t)); 96 97 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) { 98 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, 0, 0); 99 return (SDRC_ERROR); 100 } 101 102 if (xa->smb_tpscnt != 16) { 103 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 104 return (SDRC_ERROR); 105 } 106 107 if (smb_mbc_decodef(&xa->req_param_mb, "%wbblll", sr, &sr->smb_fid, 108 &single, &restart, &sidlistlen, &startsidlen, &startsidoff)) { 109 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 110 return (SDRC_ERROR); 111 } 112 113 if ((sidlistlen != 0) && (startsidlen != 0)) { 114 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 115 return (SDRC_ERROR); 116 } 117 118 smbsr_lookup_file(sr); 119 ofile = sr->fid_ofile; 120 if (ofile == NULL) { 121 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 122 return (SDRC_ERROR); 123 } 124 125 if ((ofile->f_node == NULL) || (ofile->f_ftype != SMB_FTYPE_DISK)) { 126 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, 127 ERROR_ACCESS_DENIED); 128 smbsr_release_file(sr); 129 return (SDRC_ERROR); 130 } 131 132 tnode = sr->tid_tree->t_snode; 133 request.qq_root_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 134 if (smb_node_getmntpath(tnode, request.qq_root_path, MAXPATHLEN) != 0) { 135 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, 136 ERROR_INVALID_PARAMETER); 137 smbsr_release_file(sr); 138 kmem_free(request.qq_root_path, MAXPATHLEN); 139 return (SDRC_ERROR); 140 } 141 142 if (sidlistlen != 0) 143 request.qq_query_op = SMB_QUOTA_QUERY_SIDLIST; 144 else if (startsidlen != 0) 145 request.qq_query_op = SMB_QUOTA_QUERY_STARTSID; 146 else 147 request.qq_query_op = SMB_QUOTA_QUERY_ALL; 148 149 request.qq_single = single; 150 request.qq_restart = restart; 151 smb_quota_max_quota(&xa->rep_data_mb, &request); 152 153 status = smb_quota_init_sids(&xa->req_data_mb, &request, ofile); 154 155 if (status == NT_STATUS_SUCCESS) { 156 if (smb_quota_query(sr->sr_server, &request, &reply) != 0) { 157 status = NT_STATUS_INTERNAL_ERROR; 158 } else { 159 status = reply.qr_status; 160 if (status == NT_STATUS_SUCCESS) { 161 status = smb_quota_encode_quotas( 162 &xa->rep_data_mb, 163 &request, &reply, ofile); 164 } 165 (void) smb_mbc_encodef(&xa->rep_param_mb, "l", 166 xa->rep_data_mb.chain_offset); 167 xdr_free(smb_quota_response_xdr, (char *)&reply); 168 } 169 } 170 171 kmem_free(request.qq_root_path, MAXPATHLEN); 172 smb_quota_free_sids(&request); 173 174 if (status != NT_STATUS_SUCCESS) { 175 if (status == NT_STATUS_NO_MORE_ENTRIES) { 176 smb_ofile_set_quota_resume(ofile, NULL); 177 smbsr_warn(sr, status, 0, 0); 178 status = NT_STATUS_SUCCESS; 179 } else { 180 smbsr_error(sr, status, 0, 0); 181 } 182 (void) smb_mbc_encodef(&xa->rep_param_mb, "l", 0); 183 } 184 185 smbsr_release_file(sr); 186 return ((status == NT_STATUS_SUCCESS) ? SDRC_SUCCESS : SDRC_ERROR); 187 } 188 189 /* 190 * smb_nt_transact_set_quota 191 * 192 * This method allows the client to set quota information on the server. 193 * The result status of the call is returned to the client in the 194 * 'status' field of the SMB response header. 195 * 196 * On entry, the 'TotalParameterCount' field must be equal to 2, and the 197 * client parameter block must be encoded with the following parameters: 198 * 199 * Data Block Encoding Description 200 * ================================== ================================= 201 * ULONG NextEntryOffset; Offset to start of next entry from 202 * start of this entry, or 0 for the 203 * final entry 204 * ULONG SidLength; Length (bytes) of SID 205 * SMB_TIME ChangeTime; Time that the quota was last changed 206 * LARGE_INTEGER QuotaUsed; Amount of quota (bytes) used by user 207 * LARGE_INTEGER QuotaThreshold; Quota warning limit (bytes) for user 208 * LARGE_INTEGER QuotaLimit; The quota limit (bytes) for this user 209 * VARIABLE Sid; Security identifier of the user 210 * 211 * An SMB_COM_NT_TRANSACTION response is sent in reply when the request 212 * is successful. The 'TotalParameterCount' and the 'TotalDataCount' are set 213 * to 0, and the parameter block 'Status' field in the server SMB response 214 * header contains a 32-bit unsigned integer indicating the result status 215 * (NT_STATUS_SUCCESS if successful). 216 * 217 * Only users with Admin privileges (i.e. of the BUILTIN/Administrators 218 * group) will be allowed to set quotas. 219 */ 220 smb_sdrc_t 221 smb_nt_transact_set_quota(smb_request_t *sr, smb_xa_t *xa) 222 { 223 char *root_path; 224 uint32_t status = NT_STATUS_SUCCESS; 225 smb_node_t *tnode; 226 smb_ofile_t *ofile; 227 smb_quota_set_t request; 228 uint32_t reply; 229 list_t *quota_list; 230 231 bzero(&request, sizeof (smb_quota_set_t)); 232 233 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) { 234 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, 0, 0); 235 return (SDRC_ERROR); 236 } 237 238 if (!smb_user_is_admin(sr->uid_user)) { 239 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 240 return (-1); 241 } 242 243 if (xa->smb_tpscnt != 2) { 244 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 245 return (SDRC_ERROR); 246 } 247 248 if (smb_mbc_decodef(&xa->req_param_mb, "%w", sr, 249 &sr->smb_fid)) { 250 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 251 return (SDRC_ERROR); 252 } 253 254 smbsr_lookup_file(sr); 255 ofile = sr->fid_ofile; 256 if (ofile == NULL) { 257 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 258 return (SDRC_ERROR); 259 } 260 261 if ((ofile->f_node == NULL) || (ofile->f_ftype != SMB_FTYPE_DISK)) { 262 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, 263 ERROR_ACCESS_DENIED); 264 smbsr_release_file(sr); 265 return (SDRC_ERROR); 266 } 267 268 tnode = sr->tid_tree->t_snode; 269 root_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 270 if (smb_node_getmntpath(tnode, root_path, MAXPATHLEN) != 0) { 271 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, 272 ERROR_INVALID_PARAMETER); 273 smbsr_release_file(sr); 274 kmem_free(root_path, MAXPATHLEN); 275 return (SDRC_ERROR); 276 } 277 278 quota_list = &request.qs_quota_list; 279 list_create(quota_list, sizeof (smb_quota_t), 280 offsetof(smb_quota_t, q_list_node)); 281 282 status = smb_quota_decode_quotas(&xa->req_data_mb, quota_list); 283 if (status == NT_STATUS_SUCCESS) { 284 request.qs_root_path = root_path; 285 if (smb_quota_set(sr->sr_server, &request, &reply) != 0) { 286 status = NT_STATUS_INTERNAL_ERROR; 287 } else { 288 status = reply; 289 xdr_free(xdr_uint32_t, (char *)&reply); 290 } 291 } 292 293 kmem_free(root_path, MAXPATHLEN); 294 smb_quota_free_quotas(&request.qs_quota_list); 295 smbsr_release_file(sr); 296 297 if (status != NT_STATUS_SUCCESS) { 298 smbsr_error(sr, status, 0, 0); 299 (void) smb_mbc_encodef(&xa->rep_param_mb, "l", 0); 300 return (SDRC_ERROR); 301 } 302 303 return (SDRC_SUCCESS); 304 } 305