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