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