utils: Fix up 14a533680245
[samba4-gss.git] / source3 / smbd / smb2_nttrans.c
blob916bde53986fa58616a321871bccc863b19f4b15
1 /*
2 Unix SMB/CIFS implementation.
3 SMB NT transaction handling
4 Copyright (C) Jeremy Allison 1994-2007
5 Copyright (C) Stefan (metze) Metzmacher 2003
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "fake_file.h"
26 #include "../libcli/security/security.h"
27 #include "../librpc/gen_ndr/ndr_security.h"
28 #include "passdb/lookup_sid.h"
29 #include "auth.h"
30 #include "smbprofile.h"
31 #include "libsmb/libsmb.h"
32 #include "lib/util_ea.h"
33 #include "librpc/gen_ndr/ndr_quota.h"
34 #include "librpc/gen_ndr/ndr_security.h"
36 extern const struct generic_mapping file_generic_mapping;
38 /*********************************************************************
39 Windows seems to do canonicalization of inheritance bits. Do the
40 same.
41 *********************************************************************/
43 static void canonicalize_inheritance_bits(struct files_struct *fsp,
44 struct security_descriptor *psd)
46 bool set_auto_inherited = false;
49 * We need to filter out the
50 * SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ
51 * bits. If both are set we store SEC_DESC_DACL_AUTO_INHERITED
52 * as this alters whether SEC_ACE_FLAG_INHERITED_ACE is set
53 * when an ACE is inherited. Otherwise we zero these bits out.
54 * See:
56 * http://social.msdn.microsoft.com/Forums/eu/os_fileservices/thread/11f77b68-731e-407d-b1b3-064750716531
58 * for details.
61 if (!lp_acl_flag_inherited_canonicalization(SNUM(fsp->conn))) {
62 psd->type &= ~SEC_DESC_DACL_AUTO_INHERIT_REQ;
63 return;
66 if ((psd->type & (SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ))
67 == (SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ)) {
68 set_auto_inherited = true;
71 psd->type &= ~(SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ);
72 if (set_auto_inherited) {
73 psd->type |= SEC_DESC_DACL_AUTO_INHERITED;
77 /****************************************************************************
78 Internal fn to set security descriptors.
79 ****************************************************************************/
81 NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
82 uint32_t security_info_sent)
84 files_struct *sd_fsp = NULL;
85 NTSTATUS status;
87 if (!CAN_WRITE(fsp->conn)) {
88 return NT_STATUS_ACCESS_DENIED;
91 if (!lp_nt_acl_support(SNUM(fsp->conn))) {
92 return NT_STATUS_OK;
95 status = refuse_symlink_fsp(fsp);
96 if (!NT_STATUS_IS_OK(status)) {
97 DBG_DEBUG("ACL set on symlink %s denied.\n",
98 fsp_str_dbg(fsp));
99 return status;
102 if (psd->owner_sid == NULL) {
103 security_info_sent &= ~SECINFO_OWNER;
105 if (psd->group_sid == NULL) {
106 security_info_sent &= ~SECINFO_GROUP;
109 /* Ensure we have at least one thing set. */
110 if ((security_info_sent & (SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL)) == 0) {
111 /* Just like W2K3 */
112 return NT_STATUS_OK;
115 /* Ensure we have the rights to do this. */
116 if (security_info_sent & SECINFO_OWNER) {
117 status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER);
118 if (!NT_STATUS_IS_OK(status)) {
119 return status;
123 if (security_info_sent & SECINFO_GROUP) {
124 status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER);
125 if (!NT_STATUS_IS_OK(status)) {
126 return status;
130 if (security_info_sent & SECINFO_DACL) {
131 status = check_any_access_fsp(fsp, SEC_STD_WRITE_DAC);
132 if (!NT_STATUS_IS_OK(status)) {
133 return status;
135 /* Convert all the generic bits. */
136 if (psd->dacl) {
137 security_acl_map_generic(psd->dacl, &file_generic_mapping);
141 if (security_info_sent & SECINFO_SACL) {
142 status = check_any_access_fsp(fsp, SEC_FLAG_SYSTEM_SECURITY);
143 if (!NT_STATUS_IS_OK(status)) {
144 return status;
147 * Setting a SACL also requires WRITE_DAC.
148 * See the smbtorture3 SMB2-SACL test.
150 status = check_any_access_fsp(fsp, SEC_STD_WRITE_DAC);
151 if (!NT_STATUS_IS_OK(status)) {
152 return status;
154 /* Convert all the generic bits. */
155 if (psd->sacl) {
156 security_acl_map_generic(psd->sacl, &file_generic_mapping);
160 canonicalize_inheritance_bits(fsp, psd);
162 if (DEBUGLEVEL >= 10) {
163 DEBUG(10,("set_sd for file %s\n", fsp_str_dbg(fsp)));
164 NDR_PRINT_DEBUG(security_descriptor, psd);
167 sd_fsp = metadata_fsp(fsp);
168 status = SMB_VFS_FSET_NT_ACL(sd_fsp, security_info_sent, psd);
170 TALLOC_FREE(psd);
172 return status;
175 static bool check_smb2_posix_chmod_ace(const struct files_struct *fsp,
176 uint32_t security_info_sent,
177 struct security_descriptor *psd,
178 mode_t *pmode)
180 struct security_ace *ace = NULL;
181 int cmp;
184 * This must be an ACL with one ACE containing an
185 * MS NFS style mode entry coming in on a POSIX
186 * handle over SMB2+.
188 if (!conn_using_smb2(fsp->conn->sconn)) {
189 return false;
192 if (!(fsp->posix_flags & FSP_POSIX_FLAGS_OPEN)) {
193 return false;
196 if (!(security_info_sent & SECINFO_DACL)) {
197 return false;
200 if (psd->dacl == NULL) {
201 return false;
204 if (psd->dacl->num_aces != 1) {
205 return false;
207 ace = &psd->dacl->aces[0];
209 if (ace->trustee.num_auths != 3) {
210 return false;
213 cmp = dom_sid_compare_domain(&global_sid_Unix_NFS_Mode, &ace->trustee);
214 if (cmp != 0) {
215 return false;
218 *pmode = (mode_t)ace->trustee.sub_auths[2];
219 *pmode &= (S_IRWXU | S_IRWXG | S_IRWXO);
221 return true;
224 /****************************************************************************
225 Internal fn to set security descriptors from a data blob.
226 ****************************************************************************/
228 NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len,
229 uint32_t security_info_sent)
231 struct security_descriptor *psd = NULL;
232 NTSTATUS status;
233 bool do_chmod = false;
234 mode_t smb2_posix_mode = 0;
235 int ret;
237 if (sd_len == 0) {
238 return NT_STATUS_INVALID_PARAMETER;
241 status = unmarshall_sec_desc(talloc_tos(), data, sd_len, &psd);
243 if (!NT_STATUS_IS_OK(status)) {
244 return status;
247 do_chmod = check_smb2_posix_chmod_ace(fsp,
248 security_info_sent,
249 psd,
250 &smb2_posix_mode);
251 if (!do_chmod) {
252 return set_sd(fsp, psd, security_info_sent);
255 TALLOC_FREE(psd);
257 ret = SMB_VFS_FCHMOD(fsp, smb2_posix_mode);
258 if (ret != 0) {
259 status = map_nt_error_from_unix(errno);
260 DBG_ERR("smb2_posix_chmod [%s] [%04o] failed: %s\n",
261 fsp_str_dbg(fsp),
262 (unsigned)smb2_posix_mode,
263 nt_errstr(status));
264 return status;
267 return NT_STATUS_OK;
270 /****************************************************************************
271 Copy a file.
272 ****************************************************************************/
274 NTSTATUS copy_internals(TALLOC_CTX *ctx,
275 connection_struct *conn,
276 struct smb_request *req,
277 struct files_struct *src_dirfsp,
278 struct smb_filename *smb_fname_src,
279 struct files_struct *dst_dirfsp,
280 struct smb_filename *smb_fname_dst,
281 uint32_t attrs)
283 files_struct *fsp1,*fsp2;
284 uint32_t fattr;
285 int info;
286 off_t ret=-1;
287 NTSTATUS status = NT_STATUS_OK;
288 struct smb_filename *parent = NULL;
289 struct smb_filename *pathref = NULL;
291 if (!CAN_WRITE(conn)) {
292 status = NT_STATUS_MEDIA_WRITE_PROTECTED;
293 goto out;
296 /* Source must already exist. */
297 if (!VALID_STAT(smb_fname_src->st)) {
298 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
299 goto out;
302 /* Ensure attributes match. */
303 fattr = fdos_mode(smb_fname_src->fsp);
304 if ((fattr & ~attrs) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
305 status = NT_STATUS_NO_SUCH_FILE;
306 goto out;
309 /* Disallow if dst file already exists. */
310 if (VALID_STAT(smb_fname_dst->st)) {
311 status = NT_STATUS_OBJECT_NAME_COLLISION;
312 goto out;
315 /* No links from a directory. */
316 if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
317 status = NT_STATUS_FILE_IS_A_DIRECTORY;
318 goto out;
321 DBG_DEBUG("doing file copy %s to %s\n",
322 smb_fname_str_dbg(smb_fname_src),
323 smb_fname_str_dbg(smb_fname_dst));
325 status = SMB_VFS_CREATE_FILE(
326 conn, /* conn */
327 req, /* req */
328 src_dirfsp, /* dirfsp */
329 smb_fname_src, /* fname */
330 FILE_READ_DATA|FILE_READ_ATTRIBUTES|
331 FILE_READ_EA, /* access_mask */
332 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
333 FILE_SHARE_DELETE),
334 FILE_OPEN, /* create_disposition*/
335 0, /* create_options */
336 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
337 NO_OPLOCK, /* oplock_request */
338 NULL, /* lease */
339 0, /* allocation_size */
340 0, /* private_flags */
341 NULL, /* sd */
342 NULL, /* ea_list */
343 &fsp1, /* result */
344 &info, /* pinfo */
345 NULL, NULL); /* create context */
347 if (!NT_STATUS_IS_OK(status)) {
348 goto out;
351 status = SMB_VFS_CREATE_FILE(
352 conn, /* conn */
353 req, /* req */
354 dst_dirfsp, /* dirfsp */
355 smb_fname_dst, /* fname */
356 FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|
357 FILE_WRITE_EA, /* access_mask */
358 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
359 FILE_SHARE_DELETE),
360 FILE_CREATE, /* create_disposition*/
361 0, /* create_options */
362 fattr, /* file_attributes */
363 NO_OPLOCK, /* oplock_request */
364 NULL, /* lease */
365 0, /* allocation_size */
366 0, /* private_flags */
367 NULL, /* sd */
368 NULL, /* ea_list */
369 &fsp2, /* result */
370 &info, /* pinfo */
371 NULL, NULL); /* create context */
373 if (!NT_STATUS_IS_OK(status)) {
374 close_file_free(NULL, &fsp1, ERROR_CLOSE);
375 goto out;
378 if (smb_fname_src->st.st_ex_size) {
379 ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
383 * As we are opening fsp1 read-only we only expect
384 * an error on close on fsp2 if we are out of space.
385 * Thus we don't look at the error return from the
386 * close of fsp1.
388 close_file_free(NULL, &fsp1, NORMAL_CLOSE);
390 /* Ensure the modtime is set correctly on the destination file. */
391 set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
393 status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
394 if (!NT_STATUS_IS_OK(status)) {
395 DBG_WARNING("close_file_free() failed: %s\n",
396 nt_errstr(status));
398 * We can't do much but leak the fsp
400 goto out;
403 /* Grrr. We have to do this as open_file_ntcreate adds FILE_ATTRIBUTE_ARCHIVE when it
404 creates the file. This isn't the correct thing to do in the copy
405 case. JRA */
407 status = SMB_VFS_PARENT_PATHNAME(conn,
408 talloc_tos(),
409 smb_fname_dst,
410 &parent,
411 NULL);
412 if (!NT_STATUS_IS_OK(status)) {
413 goto out;
415 if (smb_fname_dst->fsp == NULL) {
416 status = synthetic_pathref(parent,
417 conn->cwd_fsp,
418 smb_fname_dst->base_name,
419 smb_fname_dst->stream_name,
420 NULL,
421 smb_fname_dst->twrp,
422 smb_fname_dst->flags,
423 &pathref);
425 /* should we handle NT_STATUS_OBJECT_NAME_NOT_FOUND specially here ???? */
426 if (!NT_STATUS_IS_OK(status)) {
427 TALLOC_FREE(parent);
428 goto out;
430 file_set_dosmode(conn, pathref, fattr, parent, false);
431 smb_fname_dst->st.st_ex_mode = pathref->st.st_ex_mode;
432 } else {
433 file_set_dosmode(conn, smb_fname_dst, fattr, parent, false);
435 TALLOC_FREE(parent);
437 if (ret < (off_t)smb_fname_src->st.st_ex_size) {
438 status = NT_STATUS_DISK_FULL;
439 goto out;
441 out:
442 if (!NT_STATUS_IS_OK(status)) {
443 DBG_NOTICE("Error %s copy file %s to %s\n",
444 nt_errstr(status),
445 smb_fname_str_dbg(smb_fname_src),
446 smb_fname_str_dbg(smb_fname_dst));
449 return status;
452 /******************************************************************************
453 Fake up a completely empty SD.
454 *******************************************************************************/
456 static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, struct security_descriptor **ppsd)
458 size_t sd_size;
460 *ppsd = make_standard_sec_desc( mem_ctx, &global_sid_World, &global_sid_World, NULL, &sd_size);
461 if(!*ppsd) {
462 DBG_ERR("Unable to malloc space for security descriptor.\n");
463 return NT_STATUS_NO_MEMORY;
466 return NT_STATUS_OK;
469 /****************************************************************************
470 Get a security descriptor from the file system, normalize for components
471 requested.
472 ****************************************************************************/
474 static NTSTATUS smbd_fetch_security_desc(connection_struct *conn,
475 TALLOC_CTX *mem_ctx,
476 files_struct *fsp,
477 uint32_t security_info_wanted,
478 struct security_descriptor **ppsd)
480 NTSTATUS status;
481 struct security_descriptor *psd = NULL;
482 bool need_to_read_sd = false;
485 * Get the permissions to return.
488 if (security_info_wanted & SECINFO_SACL) {
489 status = check_any_access_fsp(fsp, SEC_FLAG_SYSTEM_SECURITY);
490 if (!NT_STATUS_IS_OK(status)) {
491 DBG_DEBUG("Access to SACL denied.\n");
492 return status;
496 if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|SECINFO_GROUP)) {
497 status = check_any_access_fsp(fsp, SEC_STD_READ_CONTROL);
498 if (!NT_STATUS_IS_OK(status)) {
499 DBG_DEBUG("Access to DACL, OWNER, or GROUP denied.\n");
500 return status;
504 status = refuse_symlink_fsp(fsp);
505 if (!NT_STATUS_IS_OK(status)) {
506 DBG_DEBUG("ACL get on symlink %s denied.\n",
507 fsp_str_dbg(fsp));
508 return status;
511 if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|
512 SECINFO_GROUP|SECINFO_SACL)) {
513 /* Don't return SECINFO_LABEL if anything else was
514 requested. See bug #8458. */
515 security_info_wanted &= ~SECINFO_LABEL;
518 * Only query the file system SD if the caller asks
519 * for any bits. This allows a caller to open without
520 * READ_CONTROL but still issue a query sd. See
521 * smb2.sdread test.
523 need_to_read_sd = true;
526 if (lp_nt_acl_support(SNUM(conn)) &&
527 ((security_info_wanted & SECINFO_LABEL) == 0) &&
528 need_to_read_sd)
530 files_struct *sd_fsp = metadata_fsp(fsp);
531 status = SMB_VFS_FGET_NT_ACL(
532 sd_fsp, security_info_wanted, mem_ctx, &psd);
533 } else {
534 status = get_null_nt_acl(mem_ctx, &psd);
537 if (!NT_STATUS_IS_OK(status)) {
538 return status;
541 if (!(security_info_wanted & SECINFO_OWNER)) {
542 psd->owner_sid = NULL;
544 if (!(security_info_wanted & SECINFO_GROUP)) {
545 psd->group_sid = NULL;
547 if (!(security_info_wanted & SECINFO_DACL)) {
548 psd->type &= ~SEC_DESC_DACL_PRESENT;
549 psd->dacl = NULL;
551 if (!(security_info_wanted & SECINFO_SACL)) {
552 psd->type &= ~SEC_DESC_SACL_PRESENT;
553 psd->sacl = NULL;
556 /* If the SACL/DACL is NULL, but was requested, we mark that it is
557 * present in the reply to match Windows behavior */
558 if (psd->sacl == NULL &&
559 security_info_wanted & SECINFO_SACL)
560 psd->type |= SEC_DESC_SACL_PRESENT;
561 if (psd->dacl == NULL &&
562 security_info_wanted & SECINFO_DACL)
563 psd->type |= SEC_DESC_DACL_PRESENT;
565 if (security_info_wanted & SECINFO_LABEL) {
566 /* Like W2K3 return a null object. */
567 psd->owner_sid = NULL;
568 psd->group_sid = NULL;
569 psd->dacl = NULL;
570 psd->sacl = NULL;
571 psd->type &= ~(SEC_DESC_DACL_PRESENT|SEC_DESC_SACL_PRESENT);
574 *ppsd = psd;
575 return NT_STATUS_OK;
578 /****************************************************************************
579 Write a security descriptor into marshalled format.
580 ****************************************************************************/
582 static NTSTATUS smbd_marshall_security_desc(TALLOC_CTX *mem_ctx,
583 files_struct *fsp,
584 struct security_descriptor *psd,
585 uint32_t max_data_count,
586 uint8_t **ppmarshalled_sd,
587 size_t *psd_size)
589 *psd_size = ndr_size_security_descriptor(psd, 0);
591 DBG_NOTICE("sd_size = %zu.\n", *psd_size);
593 if (DEBUGLEVEL >= 10) {
594 DBG_DEBUG("security desc for file %s\n",
595 fsp_str_dbg(fsp));
596 NDR_PRINT_DEBUG(security_descriptor, psd);
599 if (max_data_count < *psd_size) {
600 return NT_STATUS_BUFFER_TOO_SMALL;
603 return marshall_sec_desc(mem_ctx,
604 psd,
605 ppmarshalled_sd,
606 psd_size);
609 /****************************************************************************
610 Reply to query a security descriptor.
611 Callable from SMB1 and SMB2.
612 If it returns NT_STATUS_BUFFER_TOO_SMALL, psd_size is initialized with
613 the required size.
614 ****************************************************************************/
616 NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
617 TALLOC_CTX *mem_ctx,
618 files_struct *fsp,
619 uint32_t security_info_wanted,
620 uint32_t max_data_count,
621 uint8_t **ppmarshalled_sd,
622 size_t *psd_size)
624 NTSTATUS status;
625 struct security_descriptor *psd = NULL;
628 * Get the permissions to return.
631 status = smbd_fetch_security_desc(conn,
632 mem_ctx,
633 fsp,
634 security_info_wanted,
635 &psd);
636 if (!NT_STATUS_IS_OK(status)) {
637 return status;
640 status = smbd_marshall_security_desc(mem_ctx,
641 fsp,
642 psd,
643 max_data_count,
644 ppmarshalled_sd,
645 psd_size);
646 TALLOC_FREE(psd);
647 return status;
650 #ifdef HAVE_SYS_QUOTAS
651 static enum ndr_err_code fill_qtlist_from_sids(TALLOC_CTX *mem_ctx,
652 struct files_struct *fsp,
653 SMB_NTQUOTA_HANDLE *qt_handle,
654 struct dom_sid *sids,
655 uint32_t elems)
657 uint32_t i;
658 TALLOC_CTX *list_ctx = NULL;
660 list_ctx = talloc_init("quota_sid_list");
662 if (list_ctx == NULL) {
663 DBG_ERR("failed to allocate\n");
664 return NDR_ERR_ALLOC;
667 if (qt_handle->quota_list!=NULL) {
668 free_ntquota_list(&(qt_handle->quota_list));
670 for (i = 0; i < elems; i++) {
671 SMB_NTQUOTA_STRUCT qt;
672 SMB_NTQUOTA_LIST *list_item;
673 bool ok;
675 if (!NT_STATUS_IS_OK(vfs_get_ntquota(fsp,
676 SMB_USER_QUOTA_TYPE,
677 &sids[i], &qt))) {
678 /* non fatal error, return empty item in result */
679 ZERO_STRUCT(qt);
680 continue;
684 list_item = talloc_zero(list_ctx, SMB_NTQUOTA_LIST);
685 if (list_item == NULL) {
686 DBG_ERR("failed to allocate\n");
687 return NDR_ERR_ALLOC;
690 ok = sid_to_uid(&sids[i], &list_item->uid);
691 if (!ok) {
692 struct dom_sid_buf buf;
693 DBG_WARNING("Could not convert SID %s to uid\n",
694 dom_sid_str_buf(&sids[i], &buf));
695 /* No idea what to return here... */
696 return NDR_ERR_INVALID_POINTER;
699 list_item->quotas = talloc_zero(list_item, SMB_NTQUOTA_STRUCT);
700 if (list_item->quotas == NULL) {
701 DBG_ERR("failed to allocate\n");
702 return NDR_ERR_ALLOC;
705 *list_item->quotas = qt;
706 list_item->mem_ctx = list_ctx;
707 DLIST_ADD(qt_handle->quota_list, list_item);
709 qt_handle->tmp_list = qt_handle->quota_list;
710 return NDR_ERR_SUCCESS;
713 static enum ndr_err_code extract_sids_from_buf(TALLOC_CTX *mem_ctx,
714 uint32_t sidlistlength,
715 DATA_BLOB *sid_buf,
716 struct dom_sid **sids,
717 uint32_t *num)
719 DATA_BLOB blob;
720 uint32_t i = 0;
721 enum ndr_err_code err;
723 struct sid_list_elem {
724 struct sid_list_elem *prev, *next;
725 struct dom_sid sid;
728 struct sid_list_elem *sid_list = NULL;
729 struct sid_list_elem *iter = NULL;
730 TALLOC_CTX *list_ctx = talloc_init("sid_list");
731 if (!list_ctx) {
732 DBG_ERR("OOM\n");
733 err = NDR_ERR_ALLOC;
734 goto done;
737 *num = 0;
738 *sids = NULL;
740 if (sidlistlength) {
741 uint32_t offset = 0;
742 struct ndr_pull *ndr_pull = NULL;
744 if (sidlistlength > sid_buf->length) {
745 DBG_ERR("sid_list_length 0x%x exceeds "
746 "available bytes %zx\n",
747 sidlistlength,
748 sid_buf->length);
749 err = NDR_ERR_OFFSET;
750 goto done;
752 while (true) {
753 struct file_get_quota_info info;
754 struct sid_list_elem *item = NULL;
755 uint32_t new_offset = 0;
756 blob.data = sid_buf->data + offset;
757 blob.length = sidlistlength - offset;
758 ndr_pull = ndr_pull_init_blob(&blob, list_ctx);
759 if (!ndr_pull) {
760 DBG_ERR("OOM\n");
761 err = NDR_ERR_ALLOC;
762 goto done;
764 err = ndr_pull_file_get_quota_info(ndr_pull,
765 NDR_SCALARS | NDR_BUFFERS, &info);
766 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
767 DBG_ERR("Failed to pull file_get_quota_info "
768 "from sidlist buffer\n");
769 goto done;
771 item = talloc_zero(list_ctx, struct sid_list_elem);
772 if (!item) {
773 DBG_ERR("OOM\n");
774 err = NDR_ERR_ALLOC;
775 goto done;
777 item->sid = info.sid;
778 DLIST_ADD(sid_list, item);
779 i++;
780 if (i == UINT32_MAX) {
781 DBG_ERR("Integer overflow\n");
782 err = NDR_ERR_ARRAY_SIZE;
783 goto done;
785 new_offset = info.next_entry_offset;
787 /* if new_offset == 0 no more sid(s) to read. */
788 if (new_offset == 0) {
789 break;
792 /* Integer wrap? */
793 if ((offset + new_offset) < offset) {
794 DBG_ERR("Integer wrap while adding "
795 "new_offset 0x%x to current "
796 "buffer offset 0x%x\n",
797 new_offset, offset);
798 err = NDR_ERR_OFFSET;
799 goto done;
802 offset += new_offset;
804 /* check if new offset is outside buffer boundary. */
805 if (offset >= sidlistlength) {
806 DBG_ERR("bufsize 0x%x exceeded by "
807 "new offset 0x%x)\n",
808 sidlistlength,
809 offset);
810 err = NDR_ERR_OFFSET;
811 goto done;
814 *sids = talloc_zero_array(mem_ctx, struct dom_sid, i);
815 if (*sids == NULL) {
816 DBG_ERR("OOM\n");
817 err = NDR_ERR_ALLOC;
818 goto done;
821 *num = i;
823 for (iter = sid_list, i = 0; iter; iter = iter->next, i++) {
824 struct dom_sid_buf buf;
825 (*sids)[i] = iter->sid;
826 DBG_DEBUG("quota SID[%u] %s\n",
827 (unsigned int)i,
828 dom_sid_str_buf(&iter->sid, &buf));
831 err = NDR_ERR_SUCCESS;
832 done:
833 TALLOC_FREE(list_ctx);
834 return err;
837 NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx,
838 files_struct *fsp,
839 bool restart_scan,
840 bool return_single,
841 uint32_t sid_list_length,
842 DATA_BLOB *sid_buf,
843 uint32_t max_data_count,
844 uint8_t **p_data,
845 uint32_t *p_data_size)
847 NTSTATUS status;
848 SMB_NTQUOTA_HANDLE *qt_handle = NULL;
849 SMB_NTQUOTA_LIST *qt_list = NULL;
850 DATA_BLOB blob = data_blob_null;
851 enum ndr_err_code err;
853 qt_handle =
854 (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data;
856 if (sid_list_length ) {
857 struct dom_sid *sids;
858 uint32_t elems = 0;
860 * error check pulled offsets and lengths for wrap and
861 * exceeding available bytes.
863 if (sid_list_length > sid_buf->length) {
864 DBG_ERR("sid_list_length 0x%x exceeds "
865 "available bytes %zx\n",
866 sid_list_length,
867 sid_buf->length);
868 return NT_STATUS_INVALID_PARAMETER;
871 err = extract_sids_from_buf(mem_ctx, sid_list_length,
872 sid_buf, &sids, &elems);
873 if (!NDR_ERR_CODE_IS_SUCCESS(err) || elems == 0) {
874 return NT_STATUS_INVALID_PARAMETER;
876 err = fill_qtlist_from_sids(mem_ctx,
877 fsp,
878 qt_handle,
879 sids,
880 elems);
881 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
882 return NT_STATUS_INVALID_PARAMETER;
884 } else if (restart_scan) {
885 if (vfs_get_user_ntquota_list(fsp,
886 &(qt_handle->quota_list))!=0) {
887 return NT_STATUS_INTERNAL_ERROR;
889 } else {
890 if (qt_handle->quota_list!=NULL &&
891 qt_handle->tmp_list==NULL) {
892 free_ntquota_list(&(qt_handle->quota_list));
896 if (restart_scan !=0 ) {
897 qt_list = qt_handle->quota_list;
898 } else {
899 qt_list = qt_handle->tmp_list;
901 status = fill_quota_buffer(mem_ctx, qt_list,
902 return_single != 0,
903 max_data_count,
904 &blob,
905 &qt_handle->tmp_list);
906 if (!NT_STATUS_IS_OK(status)) {
907 return status;
909 if (blob.length > max_data_count) {
910 return NT_STATUS_BUFFER_TOO_SMALL;
913 *p_data = blob.data;
914 *p_data_size = blob.length;
915 return NT_STATUS_OK;
917 #endif /* HAVE_SYS_QUOTAS */