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 2011 Nexenta Systems, Inc. All rights reserved. 24 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 25 */ 26 27 #include <smbsrv/smb_kproto.h> 28 #include <smbsrv/smb_fsops.h> 29 #include <smbsrv/smb_share.h> 30 #include <smbsrv/string.h> 31 #include <sys/fs/zfs.h> 32 #include <smbsrv/smb_xdr.h> 33 #include <smbsrv/smb_door.h> 34 #include <smbsrv/smb_idmap.h> 35 36 /* 37 * A user/group quota entry passed over the wire consists of: 38 * - next offset (uint32_t) 39 * - length of SID (uint32_t) 40 * - last modified time (uint64_t) 41 * - quota used (uint64_t) 42 * - quota limit (uint64_t) 43 * - quota threahold (uint64_t) 44 * - variable length sid - max = 32 bytes 45 * SMB_QUOTA_SIZE_NO_SID is the size of the above, excluding the sid. 46 */ 47 #define SMB_QUOTA_SIZE_NO_SID \ 48 ((2 * sizeof (uint32_t)) + (4 * sizeof (uint64_t))) 49 #define SMB_QUOTA_EST_SIZE (SMB_QUOTA_SIZE_NO_SID + SMB_EST_SID_SIZE) 50 #define SMB_QUOTA_MAX_SIZE (SMB_QUOTA_SIZE_NO_SID + SMB_MAX_SID_SIZE) 51 52 static int smb_quota_query(smb_server_t *, smb_quota_query_t *, 53 smb_quota_response_t *); 54 static int smb_quota_set(smb_server_t *, smb_quota_set_t *, uint32_t *); 55 static uint32_t smb_quota_init_sids(smb_xa_t *, smb_quota_query_t *, 56 smb_ofile_t *); 57 static uint32_t smb_quota_decode_sids(smb_xa_t *, list_t *); 58 static void smb_quota_free_sids(smb_quota_query_t *); 59 static void smb_quota_max_quota(smb_xa_t *, smb_quota_query_t *); 60 static uint32_t smb_quota_decode_quotas(smb_xa_t *, list_t *); 61 static uint32_t smb_quota_encode_quotas(smb_xa_t *, smb_quota_query_t *, 62 smb_quota_response_t *, smb_ofile_t *); 63 static void smb_quota_free_quotas(list_t *); 64 65 /* 66 * smb_nt_transact_query_quota 67 * 68 * This method allows the client to retrieve quota information from 69 * the server. The result of the call is returned to the client in the 70 * Data part of the transaction response. 71 * 72 * On entry, the 'TotalParameterCount' field must be equal to 16, and the 73 * client parameter block must be encoded with the following parameters: 74 * 75 * Request Description 76 * ========================== ================================== 77 * WORD fid SMB file identifier of the target directory 78 * BYTE ReturnSingleEntry A boolean indicating whether to return 79 * a single entry (TRUE) or multiple entries (FALSE). 80 * BYTE RestartScan A boolean indicating whether to continue from 81 * the previous request (FALSE) or restart a new 82 * sequence (TRUE). 83 * DWORD SidListLength The length, in bytes, of the SidList in the 84 * data block or 0 if there is no SidList. 85 * DWORD StartSidLength If SidListLength is 0 (i.e. there is no SidList 86 * in the data block), then this is either: 87 * 1) the (non-zero) length in bytes of the 88 * StartSid in the parameter buffer, or 89 * 2) if 0, there is no StartSid in the 90 * parameter buffer, in which case, all SIDs 91 * are to be enumerated as if they were 92 * passed in the SidList. 93 * Otherwise, StartSidLength is ignored. 94 * DWORD StartSidOffset The offset, in bytes, to the StartSid in the 95 * parameter block (if one exists). 96 * 97 * One of SidListLength and StartSidLength must be 0. 98 * 99 * An SMB_COM_NT_TRANSACTION response is sent in reply when the request 100 * is successful. The 'TotalParameterCount' is set to 4, and the parameter 101 * block in the server response contains a 32-bit unsigned integer 102 * indicating the length, in bytes, of the returned quota information. 103 * The 'TotalDataCount' is set to indicate the length of the data buffer, 104 * and the data buffer contains the following quota information: 105 * 106 * Data Block Encoding Description 107 * ================================== ================================= 108 * ULONG NextEntryOffset; Offset to start of next entry from 109 * start of this entry, or 0 for the 110 * final entry 111 * ULONG SidLength; Length (bytes) of SID 112 * SMB_TIME ChangeTime; Time that the quota was last changed 113 * LARGE_INTEGER QuotaUsed; Amount of quota (bytes) used by user 114 * LARGE_INTEGER QuotaThreshold; Quota warning limit (bytes) for user 115 * LARGE_INTEGER QuotaLimit; The quota limit (bytes) for this user 116 * USHORT Sid; Search handle 117 */ 118 smb_sdrc_t 119 smb_nt_transact_query_quota(smb_request_t *sr, smb_xa_t *xa) 120 { 121 uint8_t single, restart; 122 uint32_t sidlistlen, startsidlen, startsidoff; 123 smb_node_t *tnode; 124 smb_ofile_t *ofile; 125 smb_quota_query_t request; 126 smb_quota_response_t reply; 127 uint32_t status = NT_STATUS_SUCCESS; 128 129 bzero(&request, sizeof (smb_quota_query_t)); 130 bzero(&reply, sizeof (smb_quota_response_t)); 131 132 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) { 133 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, 0, 0); 134 return (SDRC_ERROR); 135 } 136 137 if (xa->smb_tpscnt != 16) { 138 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 139 return (SDRC_ERROR); 140 } 141 142 if (smb_mbc_decodef(&xa->req_param_mb, "%wbblll", sr, &sr->smb_fid, 143 &single, &restart, &sidlistlen, &startsidlen, &startsidoff)) { 144 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 145 return (SDRC_ERROR); 146 } 147 148 if ((sidlistlen != 0) && (startsidlen != 0)) { 149 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 150 return (SDRC_ERROR); 151 } 152 153 smbsr_lookup_file(sr); 154 ofile = sr->fid_ofile; 155 if (ofile == NULL) { 156 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 157 return (SDRC_ERROR); 158 } 159 160 if ((ofile->f_node == NULL) || (ofile->f_ftype != SMB_FTYPE_DISK)) { 161 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, 162 ERROR_ACCESS_DENIED); 163 smbsr_release_file(sr); 164 return (SDRC_ERROR); 165 } 166 167 tnode = sr->tid_tree->t_snode; 168 request.qq_root_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 169 if (smb_node_getmntpath(tnode, request.qq_root_path, MAXPATHLEN) != 0) { 170 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, 171 ERROR_INVALID_PARAMETER); 172 smbsr_release_file(sr); 173 kmem_free(request.qq_root_path, MAXPATHLEN); 174 return (SDRC_ERROR); 175 } 176 177 if (sidlistlen != 0) 178 request.qq_query_op = SMB_QUOTA_QUERY_SIDLIST; 179 else if (startsidlen != 0) 180 request.qq_query_op = SMB_QUOTA_QUERY_STARTSID; 181 else 182 request.qq_query_op = SMB_QUOTA_QUERY_ALL; 183 184 request.qq_single = single; 185 request.qq_restart = restart; 186 smb_quota_max_quota(xa, &request); 187 188 status = smb_quota_init_sids(xa, &request, ofile); 189 190 if (status == NT_STATUS_SUCCESS) { 191 if (smb_quota_query(sr->sr_server, &request, &reply) != 0) { 192 status = NT_STATUS_INTERNAL_ERROR; 193 } else { 194 status = reply.qr_status; 195 if (status == NT_STATUS_SUCCESS) { 196 status = smb_quota_encode_quotas(xa, 197 &request, &reply, ofile); 198 } 199 xdr_free(smb_quota_response_xdr, (char *)&reply); 200 } 201 } 202 203 kmem_free(request.qq_root_path, MAXPATHLEN); 204 smb_quota_free_sids(&request); 205 206 if (status != NT_STATUS_SUCCESS) { 207 if (status == NT_STATUS_NO_MORE_ENTRIES) { 208 smb_ofile_set_quota_resume(ofile, NULL); 209 smbsr_warn(sr, status, 0, 0); 210 status = NT_STATUS_SUCCESS; 211 } else { 212 smbsr_error(sr, status, 0, 0); 213 } 214 (void) smb_mbc_encodef(&xa->rep_param_mb, "l", 0); 215 } 216 217 smbsr_release_file(sr); 218 return ((status == NT_STATUS_SUCCESS) ? SDRC_SUCCESS : SDRC_ERROR); 219 } 220 221 /* 222 * smb_nt_transact_set_quota 223 * 224 * This method allows the client to set quota information on the server. 225 * The result status of the call is returned to the client in the 226 * 'status' field of the SMB response header. 227 * 228 * On entry, the 'TotalParameterCount' field must be equal to 2, and the 229 * client parameter block must be encoded with the following parameters: 230 * 231 * Data Block Encoding Description 232 * ================================== ================================= 233 * ULONG NextEntryOffset; Offset to start of next entry from 234 * start of this entry, or 0 for the 235 * final entry 236 * ULONG SidLength; Length (bytes) of SID 237 * SMB_TIME ChangeTime; Time that the quota was last changed 238 * LARGE_INTEGER QuotaUsed; Amount of quota (bytes) used by user 239 * LARGE_INTEGER QuotaThreshold; Quota warning limit (bytes) for user 240 * LARGE_INTEGER QuotaLimit; The quota limit (bytes) for this user 241 * VARIABLE Sid; Security identifier of the user 242 * 243 * An SMB_COM_NT_TRANSACTION response is sent in reply when the request 244 * is successful. The 'TotalParameterCount' and the 'TotalDataCount' are set 245 * to 0, and the parameter block 'Status' field in the server SMB response 246 * header contains a 32-bit unsigned integer indicating the result status 247 * (NT_STATUS_SUCCESS if successful). 248 * 249 * Only users with Admin privileges (i.e. of the BUILTIN/Administrators 250 * group) will be allowed to set quotas. 251 */ 252 smb_sdrc_t 253 smb_nt_transact_set_quota(smb_request_t *sr, smb_xa_t *xa) 254 { 255 char *root_path; 256 uint32_t status = NT_STATUS_SUCCESS; 257 smb_node_t *tnode; 258 smb_ofile_t *ofile; 259 smb_quota_set_t request; 260 uint32_t reply; 261 list_t *quota_list; 262 263 bzero(&request, sizeof (smb_quota_set_t)); 264 265 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) { 266 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, 0, 0); 267 return (SDRC_ERROR); 268 } 269 270 if (!smb_user_is_admin(sr->uid_user)) { 271 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); 272 return (-1); 273 } 274 275 if (xa->smb_tpscnt != 2) { 276 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 277 return (SDRC_ERROR); 278 } 279 280 if (smb_mbc_decodef(&xa->req_param_mb, "%w", sr, 281 &sr->smb_fid)) { 282 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); 283 return (SDRC_ERROR); 284 } 285 286 smbsr_lookup_file(sr); 287 ofile = sr->fid_ofile; 288 if (ofile == NULL) { 289 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 290 return (SDRC_ERROR); 291 } 292 293 if ((ofile->f_node == NULL) || (ofile->f_ftype != SMB_FTYPE_DISK)) { 294 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, 295 ERROR_ACCESS_DENIED); 296 smbsr_release_file(sr); 297 return (SDRC_ERROR); 298 } 299 300 tnode = sr->tid_tree->t_snode; 301 root_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 302 if (smb_node_getmntpath(tnode, root_path, MAXPATHLEN) != 0) { 303 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, 304 ERROR_INVALID_PARAMETER); 305 smbsr_release_file(sr); 306 kmem_free(root_path, MAXPATHLEN); 307 return (SDRC_ERROR); 308 } 309 310 quota_list = &request.qs_quota_list; 311 list_create(quota_list, sizeof (smb_quota_t), 312 offsetof(smb_quota_t, q_list_node)); 313 314 status = smb_quota_decode_quotas(xa, quota_list); 315 if (status == NT_STATUS_SUCCESS) { 316 request.qs_root_path = root_path; 317 if (smb_quota_set(sr->sr_server, &request, &reply) != 0) { 318 status = NT_STATUS_INTERNAL_ERROR; 319 } else { 320 status = reply; 321 xdr_free(xdr_uint32_t, (char *)&reply); 322 } 323 } 324 325 kmem_free(root_path, MAXPATHLEN); 326 smb_quota_free_quotas(&request.qs_quota_list); 327 smbsr_release_file(sr); 328 329 if (status != NT_STATUS_SUCCESS) { 330 smbsr_error(sr, status, 0, 0); 331 (void) smb_mbc_encodef(&xa->rep_param_mb, "l", 0); 332 return (SDRC_ERROR); 333 } 334 335 return (SDRC_SUCCESS); 336 } 337 338 /* 339 * smb_quota_init_sids 340 * 341 * If the query is of type SMB_QUOTA_QUERY_SIDLIST or 342 * SMB_QUOTA_QUERY_STARTSID decode the list of sids from 343 * the client request into request->qq_sid_list. 344 * Otherwise (type SMB_QUOTA_QUERY_ALL) find the resume sid 345 * and insert it into request->qq_sid_list, or reset the 346 * resume sid to NULL if request->qq_restart. 347 * 348 * Returns: NT_STATUS codes 349 */ 350 static uint32_t 351 smb_quota_init_sids(smb_xa_t *xa, smb_quota_query_t *request, 352 smb_ofile_t *ofile) 353 { 354 smb_quota_sid_t *sid; 355 list_t *sid_list; 356 uint32_t status = NT_STATUS_SUCCESS; 357 358 sid_list = &request->qq_sid_list; 359 list_create(sid_list, sizeof (smb_quota_sid_t), 360 offsetof(smb_quota_sid_t, qs_list_node)); 361 362 switch (request->qq_query_op) { 363 case SMB_QUOTA_QUERY_SIDLIST: 364 case SMB_QUOTA_QUERY_STARTSID: 365 status = smb_quota_decode_sids(xa, sid_list); 366 break; 367 case SMB_QUOTA_QUERY_ALL: 368 if (request->qq_restart) 369 smb_ofile_set_quota_resume(ofile, NULL); 370 else { 371 sid = kmem_zalloc(sizeof (smb_quota_sid_t), KM_SLEEP); 372 list_insert_tail(sid_list, sid); 373 smb_ofile_get_quota_resume(ofile, sid->qs_sidstr, 374 SMB_SID_STRSZ); 375 if (*sid->qs_sidstr == '\0') 376 status = NT_STATUS_INVALID_PARAMETER; 377 } 378 break; 379 default: 380 status = NT_STATUS_INVALID_PARAMETER; 381 break; 382 } 383 384 return (status); 385 } 386 387 /* 388 * smb_quota_free_sids 389 */ 390 static void 391 smb_quota_free_sids(smb_quota_query_t *request) 392 { 393 list_t *sid_list; 394 smb_quota_sid_t *sid; 395 396 sid_list = &request->qq_sid_list; 397 398 while ((sid = list_head(sid_list)) != NULL) { 399 list_remove(sid_list, sid); 400 kmem_free(sid, sizeof (smb_quota_sid_t)); 401 } 402 403 list_destroy(sid_list); 404 } 405 406 /* 407 * smb_quota_decode_sids 408 * 409 * Decode the SIDs from the data block and stores them in string form in list. 410 * Eaxh sid entry comprises: 411 * next_offset (4 bytes) - offset of next entry 412 * sid length (4 bytes) 413 * sid (variable length = sidlen) 414 * The last entry will have a next_offset value of 0. 415 * 416 * Returns NT_STATUS codes. 417 */ 418 static uint32_t 419 smb_quota_decode_sids(smb_xa_t *xa, list_t *list) 420 { 421 uint32_t offset, mb_offset, sid_offset, bytes_left; 422 uint32_t next_offset, sidlen; 423 smb_sid_t *sid; 424 smb_quota_sid_t *qsid; 425 uint32_t status = NT_STATUS_SUCCESS; 426 struct mbuf_chain sidbuf; 427 428 offset = 0; 429 do { 430 mb_offset = offset + xa->req_data_mb.chain_offset; 431 bytes_left = xa->req_data_mb.max_bytes - mb_offset; 432 (void) MBC_SHADOW_CHAIN(&sidbuf, &xa->req_data_mb, 433 mb_offset, bytes_left); 434 435 if (smb_mbc_decodef(&sidbuf, "ll", &next_offset, &sidlen)) { 436 status = NT_STATUS_INVALID_PARAMETER; 437 break; 438 } 439 440 sid_offset = offset + (2 * sizeof (uint32_t)); 441 sid = smb_decode_sid(xa, sid_offset); 442 if (sid == NULL) { 443 status = NT_STATUS_INVALID_PARAMETER; 444 break; 445 } 446 447 qsid = kmem_zalloc(sizeof (smb_quota_sid_t), KM_SLEEP); 448 smb_sid_tostr(sid, qsid->qs_sidstr); 449 smb_sid_free(sid); 450 sid = NULL; 451 452 list_insert_tail(list, qsid); 453 offset += next_offset; 454 } while ((next_offset != 0) && (bytes_left > 0)); 455 456 return (status); 457 } 458 459 /* 460 * smb_quota_max_quota 461 * 462 * If the query is if type SMB_QUOTA_QUERY_SIDLIST a quota entry 463 * is returned for each sid in the sidlist. request->qr_max_quota 464 * is set to 0 and is unused. 465 * Otherwise (for SMB_QUOTA_QUERY_STARTSID and SMB_QUOTA_QUERY_ALL) 466 * max_quota is the maximum number of quota entries requested from 467 * the file system (via door call smb_quota_query()). 468 * If single is set max_quota is set to 1. If single is not set 469 * max quota is calculated as the number of quotas of size 470 * SMB_QUOTA_EST_SIZE that would fit in the response buffer. 471 */ 472 static void 473 smb_quota_max_quota(smb_xa_t *xa, smb_quota_query_t *request) 474 { 475 if (request->qq_query_op == SMB_QUOTA_QUERY_SIDLIST) 476 request->qq_max_quota = 0; 477 else if (request->qq_single) 478 request->qq_max_quota = 1; 479 else 480 request->qq_max_quota = (xa->smb_mdrcnt / SMB_QUOTA_EST_SIZE); 481 } 482 483 /* 484 * smb_quota_decode_quotas 485 * 486 * Decode the quota entries into a list_t of smb_quota_t. 487 * SMB_QUOTA_SIZE_NO_SID is the size of a quota entry, 488 * excluding the sid. 489 * The last entry will have a next_offset value of 0. 490 * 491 * Returns NT_STATUS codes. 492 */ 493 static uint32_t 494 smb_quota_decode_quotas(smb_xa_t *xa, list_t *list) 495 { 496 uint32_t offset, mb_offset, sid_offset, bytes_left; 497 uint32_t next_offset, sidlen; 498 uint64_t mtime; 499 smb_sid_t *sid; 500 smb_quota_t *quota; 501 uint32_t status = NT_STATUS_SUCCESS; 502 struct mbuf_chain quotabuf; 503 504 offset = 0; 505 do { 506 mb_offset = offset + xa->req_data_mb.chain_offset; 507 bytes_left = xa->req_data_mb.max_bytes - mb_offset; 508 (void) MBC_SHADOW_CHAIN("abuf, &xa->req_data_mb, 509 mb_offset, bytes_left); 510 511 quota = kmem_zalloc(sizeof (smb_quota_t), KM_SLEEP); 512 513 if (smb_mbc_decodef("abuf, "llqqqq", 514 &next_offset, &sidlen, &mtime, 515 "a->q_used, "a->q_thresh, "a->q_limit)) { 516 kmem_free(quota, sizeof (smb_quota_t)); 517 status = NT_STATUS_INVALID_PARAMETER; 518 break; 519 } 520 521 sid_offset = offset + SMB_QUOTA_SIZE_NO_SID; 522 sid = smb_decode_sid(xa, sid_offset); 523 if (sid == NULL) { 524 kmem_free(quota, sizeof (smb_quota_t)); 525 status = NT_STATUS_INVALID_PARAMETER; 526 break; 527 } 528 529 bzero(quota->q_sidstr, SMB_SID_STRSZ); 530 smb_sid_tostr(sid, quota->q_sidstr); 531 smb_sid_free(sid); 532 sid = NULL; 533 534 list_insert_tail(list, quota); 535 offset += next_offset; 536 } while ((next_offset != 0) && (bytes_left > 0)); 537 538 return (status); 539 } 540 541 /* 542 * smb_quota_free_quotas 543 */ 544 static void 545 smb_quota_free_quotas(list_t *list) 546 { 547 smb_quota_t *quota; 548 549 while ((quota = list_head(list)) != NULL) { 550 list_remove(list, quota); 551 kmem_free(quota, sizeof (smb_quota_t)); 552 } 553 554 list_destroy(list); 555 } 556 557 /* 558 * smb_quota_encode_quotas 559 * 560 * Encode the quota entries from a list_t of smb_quota_t. 561 * SMB_QUOTA_SIZE_NO_SID is the size of a quota entry, 562 * excluding the sid. 563 * The last entry will have a next_offset value of 0. 564 * Sets the last encoded SID as the resume sid. 565 */ 566 static uint32_t 567 smb_quota_encode_quotas(smb_xa_t *xa, smb_quota_query_t *request, 568 smb_quota_response_t *reply, smb_ofile_t *ofile) 569 { 570 uint32_t next_offset, sid_offset, total_bytes; 571 uint64_t mtime = 0; 572 uint32_t sidlen, pad; 573 smb_sid_t *sid; 574 char *sidstr = NULL, *resume = NULL; 575 smb_quota_t *quota, *next_quota; 576 list_t *list = &reply->qr_quota_list; 577 578 int rc; 579 uint32_t status = NT_STATUS_SUCCESS; 580 581 total_bytes = 0; 582 quota = list_head(list); 583 while (quota) { 584 next_quota = list_next(list, quota); 585 sidstr = quota->q_sidstr; 586 if ((sid = smb_sid_fromstr(sidstr)) == NULL) { 587 quota = next_quota; 588 continue; 589 } 590 591 sidlen = smb_sid_len(sid); 592 sid_offset = SMB_QUOTA_SIZE_NO_SID; 593 next_offset = sid_offset + sidlen; 594 pad = smb_pad_align(next_offset, 8); 595 next_offset += pad; 596 597 if (!MBC_ROOM_FOR(&xa->rep_data_mb, next_offset)) { 598 smb_sid_free(sid); 599 break; 600 } 601 if (!MBC_ROOM_FOR(&xa->rep_data_mb, 602 next_offset + SMB_QUOTA_MAX_SIZE)) { 603 next_quota = NULL; 604 } 605 606 rc = smb_mbc_encodef(&xa->rep_data_mb, "llqqqq", 607 next_quota ? next_offset : 0, sidlen, mtime, 608 quota->q_used, quota->q_thresh, quota->q_limit); 609 if (rc == 0) { 610 smb_encode_sid(xa, sid); 611 rc = smb_mbc_encodef(&xa->rep_data_mb, "#.", pad); 612 } 613 614 smb_sid_free(sid); 615 616 if (rc != 0) { 617 status = NT_STATUS_INTERNAL_ERROR; 618 break; 619 } 620 621 resume = sidstr; 622 total_bytes += next_offset; 623 quota = next_quota; 624 } 625 626 rc = smb_mbc_encodef(&xa->rep_param_mb, "l", total_bytes); 627 628 if ((status == NT_STATUS_SUCCESS) && 629 ((request->qq_query_op == SMB_QUOTA_QUERY_STARTSID) || 630 (request->qq_query_op == SMB_QUOTA_QUERY_ALL))) { 631 smb_ofile_set_quota_resume(ofile, resume); 632 } 633 634 return (status); 635 } 636 637 /* 638 * smb_quota_query_user_quota 639 * 640 * Get user quota information for a single user (uid) 641 * for the current file system. 642 * Find the user's sid, insert it in the sidlist of a 643 * smb_quota_query_t request and invoke the door call 644 * smb_quota_query() to obtain the quota information. 645 * 646 * Returns: NT_STATUS codes. 647 */ 648 uint32_t 649 smb_quota_query_user_quota(smb_request_t *sr, uid_t uid, smb_quota_t *quota) 650 { 651 smb_sid_t *sid; 652 smb_quota_sid_t qsid; 653 smb_quota_query_t request; 654 smb_quota_response_t reply; 655 list_t *sid_list; 656 smb_quota_t *q; 657 smb_node_t *tnode; 658 uint32_t status = NT_STATUS_SUCCESS; 659 660 if (smb_idmap_getsid(uid, SMB_IDMAP_USER, &sid) != IDMAP_SUCCESS) 661 return (NT_STATUS_INTERNAL_ERROR); 662 663 smb_sid_tostr(sid, qsid.qs_sidstr); 664 smb_sid_free(sid); 665 666 bzero(&request, sizeof (smb_quota_query_t)); 667 bzero(&reply, sizeof (smb_quota_response_t)); 668 669 tnode = sr->tid_tree->t_snode; 670 request.qq_root_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 671 if (smb_node_getmntpath(tnode, request.qq_root_path, MAXPATHLEN) != 0) { 672 kmem_free(request.qq_root_path, MAXPATHLEN); 673 return (NT_STATUS_INTERNAL_ERROR); 674 } 675 676 sid_list = &request.qq_sid_list; 677 list_create(sid_list, sizeof (smb_quota_sid_t), 678 offsetof(smb_quota_sid_t, qs_list_node)); 679 list_insert_tail(sid_list, &qsid); 680 681 request.qq_query_op = SMB_QUOTA_QUERY_SIDLIST; 682 request.qq_single = B_TRUE; 683 684 if (smb_quota_query(sr->sr_server, &request, &reply) != 0) { 685 status = NT_STATUS_INTERNAL_ERROR; 686 } else { 687 if (reply.qr_status != NT_STATUS_SUCCESS) { 688 status = reply.qr_status; 689 } else { 690 q = list_head(&reply.qr_quota_list); 691 if ((q == NULL) || 692 (strcmp(qsid.qs_sidstr, q->q_sidstr) != 0)) { 693 /* should never happen */ 694 status = NT_STATUS_INTERNAL_ERROR; 695 } else { 696 bcopy(q, quota, sizeof (smb_quota_t)); 697 } 698 } 699 xdr_free(smb_quota_response_xdr, (char *)&reply); 700 } 701 702 kmem_free(request.qq_root_path, MAXPATHLEN); 703 list_remove(sid_list, &qsid); 704 list_destroy(sid_list); 705 706 return (status); 707 } 708 709 /* 710 * smb_quota_query 711 * 712 * Door call to query quotas for the provided filesystem path. 713 * Returns: -1 - door call (or encode/decode) failure. 714 * 0 - success. Status set in reply. 715 */ 716 static int 717 smb_quota_query(smb_server_t *sv, smb_quota_query_t *request, 718 smb_quota_response_t *reply) 719 { 720 int rc; 721 722 rc = smb_kdoor_upcall(sv, SMB_DR_QUOTA_QUERY, 723 request, smb_quota_query_xdr, reply, smb_quota_response_xdr); 724 725 return (rc); 726 } 727 728 /* 729 * smb_quota_set 730 * 731 * Door call to set quotas for the provided filesystem path. 732 * Returns: -1 - door call (or encode/decode) failure. 733 * 0 - success. Status set in reply. 734 */ 735 static int 736 smb_quota_set(smb_server_t *sv, smb_quota_set_t *request, uint32_t *reply) 737 { 738 int rc; 739 740 rc = smb_kdoor_upcall(sv, SMB_DR_QUOTA_SET, 741 request, smb_quota_set_xdr, reply, xdr_uint32_t); 742 743 return (rc); 744 } 745