Line data Source code
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
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
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"
35 :
36 : extern const struct generic_mapping file_generic_mapping;
37 :
38 : /*********************************************************************
39 : Windows seems to do canonicalization of inheritance bits. Do the
40 : same.
41 : *********************************************************************/
42 :
43 132 : static void canonicalize_inheritance_bits(struct files_struct *fsp,
44 : struct security_descriptor *psd)
45 : {
46 132 : bool set_auto_inherited = false;
47 :
48 : /*
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:
55 : *
56 : * http://social.msdn.microsoft.com/Forums/eu/os_fileservices/thread/11f77b68-731e-407d-b1b3-064750716531
57 : *
58 : * for details.
59 : */
60 :
61 132 : if (!lp_acl_flag_inherited_canonicalization(SNUM(fsp->conn))) {
62 0 : psd->type &= ~SEC_DESC_DACL_AUTO_INHERIT_REQ;
63 0 : return;
64 : }
65 :
66 132 : 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 0 : set_auto_inherited = true;
69 : }
70 :
71 132 : psd->type &= ~(SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ);
72 132 : if (set_auto_inherited) {
73 0 : psd->type |= SEC_DESC_DACL_AUTO_INHERITED;
74 : }
75 : }
76 :
77 : /****************************************************************************
78 : Internal fn to set security descriptors.
79 : ****************************************************************************/
80 :
81 132 : NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
82 : uint32_t security_info_sent)
83 : {
84 132 : files_struct *sd_fsp = NULL;
85 : NTSTATUS status;
86 :
87 132 : if (!CAN_WRITE(fsp->conn)) {
88 0 : return NT_STATUS_ACCESS_DENIED;
89 : }
90 :
91 132 : if (!lp_nt_acl_support(SNUM(fsp->conn))) {
92 0 : return NT_STATUS_OK;
93 : }
94 :
95 132 : status = refuse_symlink_fsp(fsp);
96 132 : if (!NT_STATUS_IS_OK(status)) {
97 0 : DBG_DEBUG("ACL set on symlink %s denied.\n",
98 : fsp_str_dbg(fsp));
99 0 : return status;
100 : }
101 :
102 132 : if (psd->owner_sid == NULL) {
103 7 : security_info_sent &= ~SECINFO_OWNER;
104 : }
105 132 : if (psd->group_sid == NULL) {
106 3 : security_info_sent &= ~SECINFO_GROUP;
107 : }
108 :
109 : /* Ensure we have at least one thing set. */
110 132 : if ((security_info_sent & (SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL)) == 0) {
111 : /* Just like W2K3 */
112 0 : return NT_STATUS_OK;
113 : }
114 :
115 : /* Ensure we have the rights to do this. */
116 132 : if (security_info_sent & SECINFO_OWNER) {
117 123 : status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER);
118 123 : if (!NT_STATUS_IS_OK(status)) {
119 0 : return status;
120 : }
121 : }
122 :
123 132 : if (security_info_sent & SECINFO_GROUP) {
124 127 : status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER);
125 127 : if (!NT_STATUS_IS_OK(status)) {
126 0 : return status;
127 : }
128 : }
129 :
130 132 : if (security_info_sent & SECINFO_DACL) {
131 132 : status = check_any_access_fsp(fsp, SEC_STD_WRITE_DAC);
132 132 : if (!NT_STATUS_IS_OK(status)) {
133 0 : return status;
134 : }
135 : /* Convert all the generic bits. */
136 132 : if (psd->dacl) {
137 130 : security_acl_map_generic(psd->dacl, &file_generic_mapping);
138 : }
139 : }
140 :
141 132 : if (security_info_sent & SECINFO_SACL) {
142 0 : status = check_any_access_fsp(fsp, SEC_FLAG_SYSTEM_SECURITY);
143 0 : if (!NT_STATUS_IS_OK(status)) {
144 0 : return status;
145 : }
146 : /*
147 : * Setting a SACL also requires WRITE_DAC.
148 : * See the smbtorture3 SMB2-SACL test.
149 : */
150 0 : status = check_any_access_fsp(fsp, SEC_STD_WRITE_DAC);
151 0 : if (!NT_STATUS_IS_OK(status)) {
152 0 : return status;
153 : }
154 : /* Convert all the generic bits. */
155 0 : if (psd->sacl) {
156 0 : security_acl_map_generic(psd->sacl, &file_generic_mapping);
157 : }
158 : }
159 :
160 132 : canonicalize_inheritance_bits(fsp, psd);
161 :
162 132 : if (DEBUGLEVEL >= 10) {
163 0 : DEBUG(10,("set_sd for file %s\n", fsp_str_dbg(fsp)));
164 0 : NDR_PRINT_DEBUG(security_descriptor, psd);
165 : }
166 :
167 132 : sd_fsp = metadata_fsp(fsp);
168 132 : status = SMB_VFS_FSET_NT_ACL(sd_fsp, security_info_sent, psd);
169 :
170 132 : TALLOC_FREE(psd);
171 :
172 132 : return status;
173 : }
174 :
175 : /****************************************************************************
176 : Internal fn to set security descriptors from a data blob.
177 : ****************************************************************************/
178 :
179 126 : NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len,
180 : uint32_t security_info_sent)
181 : {
182 126 : struct security_descriptor *psd = NULL;
183 : NTSTATUS status;
184 :
185 126 : if (sd_len == 0) {
186 0 : return NT_STATUS_INVALID_PARAMETER;
187 : }
188 :
189 126 : status = unmarshall_sec_desc(talloc_tos(), data, sd_len, &psd);
190 :
191 126 : if (!NT_STATUS_IS_OK(status)) {
192 0 : return status;
193 : }
194 :
195 126 : return set_sd(fsp, psd, security_info_sent);
196 : }
197 :
198 : /****************************************************************************
199 : Copy a file.
200 : ****************************************************************************/
201 :
202 0 : NTSTATUS copy_internals(TALLOC_CTX *ctx,
203 : connection_struct *conn,
204 : struct smb_request *req,
205 : struct files_struct *src_dirfsp,
206 : struct smb_filename *smb_fname_src,
207 : struct files_struct *dst_dirfsp,
208 : struct smb_filename *smb_fname_dst,
209 : uint32_t attrs)
210 : {
211 : files_struct *fsp1,*fsp2;
212 : uint32_t fattr;
213 : int info;
214 0 : off_t ret=-1;
215 0 : NTSTATUS status = NT_STATUS_OK;
216 0 : struct smb_filename *parent = NULL;
217 0 : struct smb_filename *pathref = NULL;
218 :
219 0 : if (!CAN_WRITE(conn)) {
220 0 : status = NT_STATUS_MEDIA_WRITE_PROTECTED;
221 0 : goto out;
222 : }
223 :
224 : /* Source must already exist. */
225 0 : if (!VALID_STAT(smb_fname_src->st)) {
226 0 : status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
227 0 : goto out;
228 : }
229 :
230 : /* Ensure attributes match. */
231 0 : fattr = fdos_mode(smb_fname_src->fsp);
232 0 : if ((fattr & ~attrs) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
233 0 : status = NT_STATUS_NO_SUCH_FILE;
234 0 : goto out;
235 : }
236 :
237 : /* Disallow if dst file already exists. */
238 0 : if (VALID_STAT(smb_fname_dst->st)) {
239 0 : status = NT_STATUS_OBJECT_NAME_COLLISION;
240 0 : goto out;
241 : }
242 :
243 : /* No links from a directory. */
244 0 : if (S_ISDIR(smb_fname_src->st.st_ex_mode)) {
245 0 : status = NT_STATUS_FILE_IS_A_DIRECTORY;
246 0 : goto out;
247 : }
248 :
249 0 : DEBUG(10,("copy_internals: doing file copy %s to %s\n",
250 : smb_fname_str_dbg(smb_fname_src),
251 : smb_fname_str_dbg(smb_fname_dst)));
252 :
253 0 : status = SMB_VFS_CREATE_FILE(
254 : conn, /* conn */
255 : req, /* req */
256 : src_dirfsp, /* dirfsp */
257 : smb_fname_src, /* fname */
258 : FILE_READ_DATA|FILE_READ_ATTRIBUTES|
259 : FILE_READ_EA, /* access_mask */
260 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
261 : FILE_SHARE_DELETE),
262 : FILE_OPEN, /* create_disposition*/
263 : 0, /* create_options */
264 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
265 : NO_OPLOCK, /* oplock_request */
266 : NULL, /* lease */
267 : 0, /* allocation_size */
268 : 0, /* private_flags */
269 : NULL, /* sd */
270 : NULL, /* ea_list */
271 : &fsp1, /* result */
272 : &info, /* pinfo */
273 : NULL, NULL); /* create context */
274 :
275 0 : if (!NT_STATUS_IS_OK(status)) {
276 0 : goto out;
277 : }
278 :
279 0 : status = SMB_VFS_CREATE_FILE(
280 : conn, /* conn */
281 : req, /* req */
282 : dst_dirfsp, /* dirfsp */
283 : smb_fname_dst, /* fname */
284 : FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|
285 : FILE_WRITE_EA, /* access_mask */
286 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
287 : FILE_SHARE_DELETE),
288 : FILE_CREATE, /* create_disposition*/
289 : 0, /* create_options */
290 : fattr, /* file_attributes */
291 : NO_OPLOCK, /* oplock_request */
292 : NULL, /* lease */
293 : 0, /* allocation_size */
294 : 0, /* private_flags */
295 : NULL, /* sd */
296 : NULL, /* ea_list */
297 : &fsp2, /* result */
298 : &info, /* pinfo */
299 : NULL, NULL); /* create context */
300 :
301 0 : if (!NT_STATUS_IS_OK(status)) {
302 0 : close_file_free(NULL, &fsp1, ERROR_CLOSE);
303 0 : goto out;
304 : }
305 :
306 0 : if (smb_fname_src->st.st_ex_size) {
307 0 : ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
308 : }
309 :
310 : /*
311 : * As we are opening fsp1 read-only we only expect
312 : * an error on close on fsp2 if we are out of space.
313 : * Thus we don't look at the error return from the
314 : * close of fsp1.
315 : */
316 0 : close_file_free(NULL, &fsp1, NORMAL_CLOSE);
317 :
318 : /* Ensure the modtime is set correctly on the destination file. */
319 0 : set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
320 :
321 0 : status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
322 0 : if (!NT_STATUS_IS_OK(status)) {
323 0 : DBG_WARNING("close_file_free() failed: %s\n",
324 : nt_errstr(status));
325 : /*
326 : * We can't do much but leak the fsp
327 : */
328 0 : goto out;
329 : }
330 :
331 : /* Grrr. We have to do this as open_file_ntcreate adds FILE_ATTRIBUTE_ARCHIVE when it
332 : creates the file. This isn't the correct thing to do in the copy
333 : case. JRA */
334 :
335 0 : status = SMB_VFS_PARENT_PATHNAME(conn,
336 : talloc_tos(),
337 : smb_fname_dst,
338 : &parent,
339 : NULL);
340 0 : if (!NT_STATUS_IS_OK(status)) {
341 0 : goto out;
342 : }
343 0 : if (smb_fname_dst->fsp == NULL) {
344 0 : status = synthetic_pathref(parent,
345 : conn->cwd_fsp,
346 0 : smb_fname_dst->base_name,
347 0 : smb_fname_dst->stream_name,
348 : NULL,
349 : smb_fname_dst->twrp,
350 : smb_fname_dst->flags,
351 : &pathref);
352 :
353 : /* should we handle NT_STATUS_OBJECT_NAME_NOT_FOUND specially here ???? */
354 0 : if (!NT_STATUS_IS_OK(status)) {
355 0 : TALLOC_FREE(parent);
356 0 : goto out;
357 : }
358 0 : file_set_dosmode(conn, pathref, fattr, parent, false);
359 0 : smb_fname_dst->st.st_ex_mode = pathref->st.st_ex_mode;
360 : } else {
361 0 : file_set_dosmode(conn, smb_fname_dst, fattr, parent, false);
362 : }
363 0 : TALLOC_FREE(parent);
364 :
365 0 : if (ret < (off_t)smb_fname_src->st.st_ex_size) {
366 0 : status = NT_STATUS_DISK_FULL;
367 0 : goto out;
368 : }
369 0 : out:
370 0 : if (!NT_STATUS_IS_OK(status)) {
371 0 : DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
372 : nt_errstr(status), smb_fname_str_dbg(smb_fname_src),
373 : smb_fname_str_dbg(smb_fname_dst)));
374 : }
375 :
376 0 : return status;
377 : }
378 :
379 : /******************************************************************************
380 : Fake up a completely empty SD.
381 : *******************************************************************************/
382 :
383 0 : static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, struct security_descriptor **ppsd)
384 : {
385 : size_t sd_size;
386 :
387 0 : *ppsd = make_standard_sec_desc( mem_ctx, &global_sid_World, &global_sid_World, NULL, &sd_size);
388 0 : if(!*ppsd) {
389 0 : DEBUG(0,("get_null_nt_acl: Unable to malloc space for security descriptor.\n"));
390 0 : return NT_STATUS_NO_MEMORY;
391 : }
392 :
393 0 : return NT_STATUS_OK;
394 : }
395 :
396 : /****************************************************************************
397 : Get a security descriptor from the file system, normalize for components
398 : requested.
399 : ****************************************************************************/
400 :
401 331 : static NTSTATUS smbd_fetch_security_desc(connection_struct *conn,
402 : TALLOC_CTX *mem_ctx,
403 : files_struct *fsp,
404 : uint32_t security_info_wanted,
405 : struct security_descriptor **ppsd)
406 : {
407 : NTSTATUS status;
408 331 : struct security_descriptor *psd = NULL;
409 331 : bool need_to_read_sd = false;
410 :
411 : /*
412 : * Get the permissions to return.
413 : */
414 :
415 331 : if (security_info_wanted & SECINFO_SACL) {
416 298 : status = check_any_access_fsp(fsp, SEC_FLAG_SYSTEM_SECURITY);
417 298 : if (!NT_STATUS_IS_OK(status)) {
418 0 : DBG_DEBUG("Access to SACL denied.\n");
419 0 : return status;
420 : }
421 : }
422 :
423 331 : if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|SECINFO_GROUP)) {
424 331 : status = check_any_access_fsp(fsp, SEC_STD_READ_CONTROL);
425 331 : if (!NT_STATUS_IS_OK(status)) {
426 0 : DBG_DEBUG("Access to DACL, OWNER, or GROUP denied.\n");
427 0 : return status;
428 : }
429 : }
430 :
431 331 : status = refuse_symlink_fsp(fsp);
432 331 : if (!NT_STATUS_IS_OK(status)) {
433 0 : DBG_DEBUG("ACL get on symlink %s denied.\n",
434 : fsp_str_dbg(fsp));
435 0 : return status;
436 : }
437 :
438 331 : if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|
439 : SECINFO_GROUP|SECINFO_SACL)) {
440 : /* Don't return SECINFO_LABEL if anything else was
441 : requested. See bug #8458. */
442 331 : security_info_wanted &= ~SECINFO_LABEL;
443 :
444 : /*
445 : * Only query the file system SD if the caller asks
446 : * for any bits. This allows a caller to open without
447 : * READ_CONTROL but still issue a query sd. See
448 : * smb2.sdread test.
449 : */
450 331 : need_to_read_sd = true;
451 : }
452 :
453 331 : if (lp_nt_acl_support(SNUM(conn)) &&
454 331 : ((security_info_wanted & SECINFO_LABEL) == 0) &&
455 : need_to_read_sd)
456 331 : {
457 331 : files_struct *sd_fsp = metadata_fsp(fsp);
458 331 : status = SMB_VFS_FGET_NT_ACL(
459 : sd_fsp, security_info_wanted, mem_ctx, &psd);
460 : } else {
461 0 : status = get_null_nt_acl(mem_ctx, &psd);
462 : }
463 :
464 331 : if (!NT_STATUS_IS_OK(status)) {
465 0 : return status;
466 : }
467 :
468 331 : if (!(security_info_wanted & SECINFO_OWNER)) {
469 0 : psd->owner_sid = NULL;
470 : }
471 331 : if (!(security_info_wanted & SECINFO_GROUP)) {
472 0 : psd->group_sid = NULL;
473 : }
474 331 : if (!(security_info_wanted & SECINFO_DACL)) {
475 0 : psd->type &= ~SEC_DESC_DACL_PRESENT;
476 0 : psd->dacl = NULL;
477 : }
478 331 : if (!(security_info_wanted & SECINFO_SACL)) {
479 33 : psd->type &= ~SEC_DESC_SACL_PRESENT;
480 33 : psd->sacl = NULL;
481 : }
482 :
483 : /* If the SACL/DACL is NULL, but was requested, we mark that it is
484 : * present in the reply to match Windows behavior */
485 331 : if (psd->sacl == NULL &&
486 331 : security_info_wanted & SECINFO_SACL)
487 298 : psd->type |= SEC_DESC_SACL_PRESENT;
488 331 : if (psd->dacl == NULL &&
489 2 : security_info_wanted & SECINFO_DACL)
490 2 : psd->type |= SEC_DESC_DACL_PRESENT;
491 :
492 331 : if (security_info_wanted & SECINFO_LABEL) {
493 : /* Like W2K3 return a null object. */
494 0 : psd->owner_sid = NULL;
495 0 : psd->group_sid = NULL;
496 0 : psd->dacl = NULL;
497 0 : psd->sacl = NULL;
498 0 : psd->type &= ~(SEC_DESC_DACL_PRESENT|SEC_DESC_SACL_PRESENT);
499 : }
500 :
501 331 : *ppsd = psd;
502 331 : return NT_STATUS_OK;
503 : }
504 :
505 : /****************************************************************************
506 : Write a securty descriptor into marshalled format.
507 : ****************************************************************************/
508 :
509 331 : static NTSTATUS smbd_marshall_security_desc(TALLOC_CTX *mem_ctx,
510 : files_struct *fsp,
511 : struct security_descriptor *psd,
512 : uint32_t max_data_count,
513 : uint8_t **ppmarshalled_sd,
514 : size_t *psd_size)
515 : {
516 331 : *psd_size = ndr_size_security_descriptor(psd, 0);
517 :
518 331 : DBG_NOTICE("sd_size = %zu.\n", *psd_size);
519 :
520 331 : if (DEBUGLEVEL >= 10) {
521 0 : DBG_DEBUG("security desc for file %s\n",
522 : fsp_str_dbg(fsp));
523 0 : NDR_PRINT_DEBUG(security_descriptor, psd);
524 : }
525 :
526 331 : if (max_data_count < *psd_size) {
527 0 : return NT_STATUS_BUFFER_TOO_SMALL;
528 : }
529 :
530 331 : return marshall_sec_desc(mem_ctx,
531 : psd,
532 : ppmarshalled_sd,
533 : psd_size);
534 : }
535 :
536 : /****************************************************************************
537 : Reply to query a security descriptor.
538 : Callable from SMB1 and SMB2.
539 : If it returns NT_STATUS_BUFFER_TOO_SMALL, psd_size is initialized with
540 : the required size.
541 : ****************************************************************************/
542 :
543 331 : NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
544 : TALLOC_CTX *mem_ctx,
545 : files_struct *fsp,
546 : uint32_t security_info_wanted,
547 : uint32_t max_data_count,
548 : uint8_t **ppmarshalled_sd,
549 : size_t *psd_size)
550 : {
551 : NTSTATUS status;
552 331 : struct security_descriptor *psd = NULL;
553 :
554 : /*
555 : * Get the permissions to return.
556 : */
557 :
558 331 : status = smbd_fetch_security_desc(conn,
559 : mem_ctx,
560 : fsp,
561 : security_info_wanted,
562 : &psd);
563 331 : if (!NT_STATUS_IS_OK(status)) {
564 0 : return status;
565 : }
566 :
567 331 : status = smbd_marshall_security_desc(mem_ctx,
568 : fsp,
569 : psd,
570 : max_data_count,
571 : ppmarshalled_sd,
572 : psd_size);
573 331 : TALLOC_FREE(psd);
574 331 : return status;
575 : }
576 :
577 : #ifdef HAVE_SYS_QUOTAS
578 0 : static enum ndr_err_code fill_qtlist_from_sids(TALLOC_CTX *mem_ctx,
579 : struct files_struct *fsp,
580 : SMB_NTQUOTA_HANDLE *qt_handle,
581 : struct dom_sid *sids,
582 : uint32_t elems)
583 : {
584 : uint32_t i;
585 0 : TALLOC_CTX *list_ctx = NULL;
586 :
587 0 : list_ctx = talloc_init("quota_sid_list");
588 :
589 0 : if (list_ctx == NULL) {
590 0 : DBG_ERR("failed to allocate\n");
591 0 : return NDR_ERR_ALLOC;
592 : }
593 :
594 0 : if (qt_handle->quota_list!=NULL) {
595 0 : free_ntquota_list(&(qt_handle->quota_list));
596 : }
597 0 : for (i = 0; i < elems; i++) {
598 : SMB_NTQUOTA_STRUCT qt;
599 : SMB_NTQUOTA_LIST *list_item;
600 : bool ok;
601 :
602 0 : if (!NT_STATUS_IS_OK(vfs_get_ntquota(fsp,
603 : SMB_USER_QUOTA_TYPE,
604 : &sids[i], &qt))) {
605 : /* non fatal error, return empty item in result */
606 0 : ZERO_STRUCT(qt);
607 0 : continue;
608 : }
609 :
610 :
611 0 : list_item = talloc_zero(list_ctx, SMB_NTQUOTA_LIST);
612 0 : if (list_item == NULL) {
613 0 : DBG_ERR("failed to allocate\n");
614 0 : return NDR_ERR_ALLOC;
615 : }
616 :
617 0 : ok = sid_to_uid(&sids[i], &list_item->uid);
618 0 : if (!ok) {
619 : struct dom_sid_buf buf;
620 0 : DBG_WARNING("Could not convert SID %s to uid\n",
621 : dom_sid_str_buf(&sids[i], &buf));
622 : /* No idea what to return here... */
623 0 : return NDR_ERR_INVALID_POINTER;
624 : }
625 :
626 0 : list_item->quotas = talloc_zero(list_item, SMB_NTQUOTA_STRUCT);
627 0 : if (list_item->quotas == NULL) {
628 0 : DBG_ERR("failed to allocate\n");
629 0 : return NDR_ERR_ALLOC;
630 : }
631 :
632 0 : *list_item->quotas = qt;
633 0 : list_item->mem_ctx = list_ctx;
634 0 : DLIST_ADD(qt_handle->quota_list, list_item);
635 : }
636 0 : qt_handle->tmp_list = qt_handle->quota_list;
637 0 : return NDR_ERR_SUCCESS;
638 : }
639 :
640 0 : static enum ndr_err_code extract_sids_from_buf(TALLOC_CTX *mem_ctx,
641 : uint32_t sidlistlength,
642 : DATA_BLOB *sid_buf,
643 : struct dom_sid **sids,
644 : uint32_t *num)
645 : {
646 : DATA_BLOB blob;
647 0 : uint32_t i = 0;
648 : enum ndr_err_code err;
649 :
650 : struct sid_list_elem {
651 : struct sid_list_elem *prev, *next;
652 : struct dom_sid sid;
653 : };
654 :
655 0 : struct sid_list_elem *sid_list = NULL;
656 0 : struct sid_list_elem *iter = NULL;
657 0 : TALLOC_CTX *list_ctx = talloc_init("sid_list");
658 0 : if (!list_ctx) {
659 0 : DBG_ERR("OOM\n");
660 0 : err = NDR_ERR_ALLOC;
661 0 : goto done;
662 : }
663 :
664 0 : *num = 0;
665 0 : *sids = NULL;
666 :
667 0 : if (sidlistlength) {
668 0 : uint32_t offset = 0;
669 0 : struct ndr_pull *ndr_pull = NULL;
670 :
671 0 : if (sidlistlength > sid_buf->length) {
672 0 : DBG_ERR("sid_list_length 0x%x exceeds "
673 : "available bytes %zx\n",
674 : sidlistlength,
675 : sid_buf->length);
676 0 : err = NDR_ERR_OFFSET;
677 0 : goto done;
678 : }
679 0 : while (true) {
680 : struct file_get_quota_info info;
681 0 : struct sid_list_elem *item = NULL;
682 0 : uint32_t new_offset = 0;
683 0 : blob.data = sid_buf->data + offset;
684 0 : blob.length = sidlistlength - offset;
685 0 : ndr_pull = ndr_pull_init_blob(&blob, list_ctx);
686 0 : if (!ndr_pull) {
687 0 : DBG_ERR("OOM\n");
688 0 : err = NDR_ERR_ALLOC;
689 0 : goto done;
690 : }
691 0 : err = ndr_pull_file_get_quota_info(ndr_pull,
692 : NDR_SCALARS | NDR_BUFFERS, &info);
693 0 : if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
694 0 : DBG_ERR("Failed to pull file_get_quota_info "
695 : "from sidlist buffer\n");
696 0 : goto done;
697 : }
698 0 : item = talloc_zero(list_ctx, struct sid_list_elem);
699 0 : if (!item) {
700 0 : DBG_ERR("OOM\n");
701 0 : err = NDR_ERR_ALLOC;
702 0 : goto done;
703 : }
704 0 : item->sid = info.sid;
705 0 : DLIST_ADD(sid_list, item);
706 0 : i++;
707 0 : if (i == UINT32_MAX) {
708 0 : DBG_ERR("Integer overflow\n");
709 0 : err = NDR_ERR_ARRAY_SIZE;
710 0 : goto done;
711 : }
712 0 : new_offset = info.next_entry_offset;
713 :
714 : /* if new_offset == 0 no more sid(s) to read. */
715 0 : if (new_offset == 0) {
716 0 : break;
717 : }
718 :
719 : /* Integer wrap? */
720 0 : if ((offset + new_offset) < offset) {
721 0 : DBG_ERR("Integer wrap while adding "
722 : "new_offset 0x%x to current "
723 : "buffer offset 0x%x\n",
724 : new_offset, offset);
725 0 : err = NDR_ERR_OFFSET;
726 0 : goto done;
727 : }
728 :
729 0 : offset += new_offset;
730 :
731 : /* check if new offset is outside buffer boundry. */
732 0 : if (offset >= sidlistlength) {
733 0 : DBG_ERR("bufsize 0x%x exceeded by "
734 : "new offset 0x%x)\n",
735 : sidlistlength,
736 : offset);
737 0 : err = NDR_ERR_OFFSET;
738 0 : goto done;
739 : }
740 : }
741 0 : *sids = talloc_zero_array(mem_ctx, struct dom_sid, i);
742 0 : if (*sids == NULL) {
743 0 : DBG_ERR("OOM\n");
744 0 : err = NDR_ERR_ALLOC;
745 0 : goto done;
746 : }
747 :
748 0 : *num = i;
749 :
750 0 : for (iter = sid_list, i = 0; iter; iter = iter->next, i++) {
751 : struct dom_sid_buf buf;
752 0 : (*sids)[i] = iter->sid;
753 0 : DBG_DEBUG("quota SID[%u] %s\n",
754 : (unsigned int)i,
755 : dom_sid_str_buf(&iter->sid, &buf));
756 : }
757 : }
758 0 : err = NDR_ERR_SUCCESS;
759 0 : done:
760 0 : TALLOC_FREE(list_ctx);
761 0 : return err;
762 : }
763 :
764 0 : NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx,
765 : files_struct *fsp,
766 : bool restart_scan,
767 : bool return_single,
768 : uint32_t sid_list_length,
769 : DATA_BLOB *sid_buf,
770 : uint32_t max_data_count,
771 : uint8_t **p_data,
772 : uint32_t *p_data_size)
773 : {
774 : NTSTATUS status;
775 0 : SMB_NTQUOTA_HANDLE *qt_handle = NULL;
776 0 : SMB_NTQUOTA_LIST *qt_list = NULL;
777 0 : DATA_BLOB blob = data_blob_null;
778 : enum ndr_err_code err;
779 :
780 0 : qt_handle =
781 0 : (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data;
782 :
783 0 : if (sid_list_length ) {
784 : struct dom_sid *sids;
785 0 : uint32_t elems = 0;
786 : /*
787 : * error check pulled offsets and lengths for wrap and
788 : * exceeding available bytes.
789 : */
790 0 : if (sid_list_length > sid_buf->length) {
791 0 : DBG_ERR("sid_list_length 0x%x exceeds "
792 : "available bytes %zx\n",
793 : sid_list_length,
794 : sid_buf->length);
795 0 : return NT_STATUS_INVALID_PARAMETER;
796 : }
797 :
798 0 : err = extract_sids_from_buf(mem_ctx, sid_list_length,
799 : sid_buf, &sids, &elems);
800 0 : if (!NDR_ERR_CODE_IS_SUCCESS(err) || elems == 0) {
801 0 : return NT_STATUS_INVALID_PARAMETER;
802 : }
803 0 : err = fill_qtlist_from_sids(mem_ctx,
804 : fsp,
805 : qt_handle,
806 : sids,
807 : elems);
808 0 : if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
809 0 : return NT_STATUS_INVALID_PARAMETER;
810 : }
811 0 : } else if (restart_scan) {
812 0 : if (vfs_get_user_ntquota_list(fsp,
813 : &(qt_handle->quota_list))!=0) {
814 0 : return NT_STATUS_INTERNAL_ERROR;
815 : }
816 : } else {
817 0 : if (qt_handle->quota_list!=NULL &&
818 0 : qt_handle->tmp_list==NULL) {
819 0 : free_ntquota_list(&(qt_handle->quota_list));
820 : }
821 : }
822 :
823 0 : if (restart_scan !=0 ) {
824 0 : qt_list = qt_handle->quota_list;
825 : } else {
826 0 : qt_list = qt_handle->tmp_list;
827 : }
828 0 : status = fill_quota_buffer(mem_ctx, qt_list,
829 : return_single != 0,
830 : max_data_count,
831 : &blob,
832 : &qt_handle->tmp_list);
833 0 : if (!NT_STATUS_IS_OK(status)) {
834 0 : return status;
835 : }
836 0 : if (blob.length > max_data_count) {
837 0 : return NT_STATUS_BUFFER_TOO_SMALL;
838 : }
839 :
840 0 : *p_data = blob.data;
841 0 : *p_data_size = blob.length;
842 0 : return NT_STATUS_OK;
843 : }
844 : #endif /* HAVE_SYS_QUOTAS */
|