Coverage Report

Created: 2025-11-16 06:57

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