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