Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/libsmb/cliquota.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   client quota functions
4
   Copyright (C) Stefan (metze) Metzmacher  2003
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "includes.h"
21
#include "source3/include/client.h"
22
#include "source3/libsmb/proto.h"
23
#include "source3/libsmb/cli_smb2_fnum.h"
24
#include "../librpc/gen_ndr/ndr_security.h"
25
#include "fake_file.h"
26
#include "../libcli/security/security.h"
27
#include "trans2.h"
28
#include "../libcli/smb/smbXcli_base.h"
29
#include "librpc/gen_ndr/ndr_quota.h"
30
#include "lib/util/overflow.h"
31
32
NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum)
33
0
{
34
0
  return cli_ntcreate(cli, FAKE_FILE_NAME_QUOTA_WIN32,
35
0
     0x00000016, DESIRED_ACCESS_PIPE,
36
0
     0x00000000, FILE_SHARE_READ|FILE_SHARE_WRITE,
37
0
     FILE_OPEN, 0x00000000, 0x03, quota_fnum, NULL);
38
0
}
39
40
void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
41
0
{
42
0
  if (!qt_list || !*qt_list) {
43
0
    return;
44
0
  }
45
46
0
  TALLOC_FREE((*qt_list)->mem_ctx);
47
48
0
  (*qt_list) = NULL;
49
50
0
  return;
51
0
}
52
53
bool add_record_to_ntquota_list(TALLOC_CTX *mem_ctx,
54
        SMB_NTQUOTA_STRUCT *pqt,
55
        SMB_NTQUOTA_LIST **pqt_list)
56
0
{
57
0
  SMB_NTQUOTA_LIST *tmp_list_ent;
58
59
0
  if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) == NULL) {
60
0
    return false;
61
0
  }
62
63
0
  if ((tmp_list_ent->quotas = talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) ==
64
0
      NULL) {
65
0
    return false;
66
0
  }
67
68
0
  *tmp_list_ent->quotas = *pqt;
69
0
  tmp_list_ent->mem_ctx = mem_ctx;
70
71
0
  DLIST_ADD((*pqt_list), tmp_list_ent);
72
73
0
  return true;
74
0
}
75
76
bool parse_user_quota_record(const uint8_t *rdata,
77
           unsigned int rdata_count,
78
           unsigned int *offset,
79
           SMB_NTQUOTA_STRUCT *pqt)
80
0
{
81
0
  struct file_quota_information info = {0};
82
0
  TALLOC_CTX *frame = talloc_stackframe();
83
0
  DATA_BLOB blob;
84
0
  enum ndr_err_code err;
85
0
  bool result = false;
86
87
0
  blob.data = discard_const_p(uint8_t, rdata);
88
0
  blob.length = rdata_count;
89
0
  err = ndr_pull_struct_blob(
90
0
      &blob,
91
0
      frame,
92
0
      &info,
93
0
      (ndr_pull_flags_fn_t)ndr_pull_file_quota_information);
94
95
0
  if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
96
0
    goto out;
97
0
  }
98
99
0
  *offset = info.next_entry_offset;
100
101
0
  ZERO_STRUCTP(pqt);
102
0
  pqt->usedspace = info.quota_used;
103
104
0
  pqt->softlim = info.quota_threshold;
105
106
0
  pqt->hardlim = info.quota_limit;
107
108
0
  pqt->qtype = SMB_USER_QUOTA_TYPE;
109
0
  pqt->sid = info.sid;
110
0
  result = true;
111
0
out:
112
0
  TALLOC_FREE(frame);
113
0
  return result;
114
0
}
115
116
NTSTATUS parse_user_quota_list(const uint8_t *curdata,
117
             uint32_t curdata_count,
118
             TALLOC_CTX *mem_ctx,
119
             SMB_NTQUOTA_LIST **pqt_list)
120
0
{
121
0
  NTSTATUS status = NT_STATUS_OK;
122
0
  unsigned offset;
123
0
  SMB_NTQUOTA_STRUCT qt;
124
125
0
  while (true) {
126
0
    ZERO_STRUCT(qt);
127
0
    if (!parse_user_quota_record(curdata, curdata_count, &offset,
128
0
               &qt)) {
129
0
      DEBUG(1, ("Failed to parse the quota record\n"));
130
0
      status = NT_STATUS_INVALID_NETWORK_RESPONSE;
131
0
      break;
132
0
    }
133
134
0
    if (offset > curdata_count) {
135
0
      DEBUG(1, ("out of bounds offset in quota record\n"));
136
0
      status = NT_STATUS_INVALID_NETWORK_RESPONSE;
137
0
      break;
138
0
    }
139
140
0
    if (ptr_overflow(curdata, offset, uint8_t)) {
141
0
      DEBUG(1, ("Pointer overflow in quota record\n"));
142
0
      status = NT_STATUS_INVALID_NETWORK_RESPONSE;
143
0
      break;
144
0
    }
145
146
0
    if (!add_record_to_ntquota_list(mem_ctx, &qt, pqt_list)) {
147
0
      status = NT_STATUS_NO_MEMORY;
148
0
      break;
149
0
    }
150
151
0
    curdata += offset;
152
0
    curdata_count -= offset;
153
154
0
    if (offset == 0) {
155
0
      break;
156
0
    }
157
0
  }
158
159
0
  return status;
160
0
}
161
162
NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata,
163
             unsigned int rdata_count,
164
             SMB_NTQUOTA_STRUCT *pqt)
165
0
{
166
0
  SMB_NTQUOTA_STRUCT qt;
167
168
0
  ZERO_STRUCT(qt);
169
170
0
  if (rdata_count < 48) {
171
    /* minimum length is not enforced by SMB2 client.
172
     */
173
0
    DEBUG(1, ("small returned fs quota buffer\n"));
174
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
175
0
  }
176
177
  /* unknown_1 24 NULL bytes in pdata*/
178
179
  /* the soft quotas 8 bytes (uint64_t)*/
180
0
  qt.softlim = BVAL(rdata, 24);
181
182
  /* the hard quotas 8 bytes (uint64_t)*/
183
0
  qt.hardlim = BVAL(rdata, 32);
184
185
  /* quota_flags 2 bytes **/
186
0
  qt.qflags = SVAL(rdata, 40);
187
188
0
  qt.qtype = SMB_USER_FS_QUOTA_TYPE;
189
190
0
  *pqt = qt;
191
192
0
  return NT_STATUS_OK;
193
0
}
194
195
NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list,
196
         uint32_t maxlen,
197
         TALLOC_CTX *mem_ctx,
198
         DATA_BLOB *outbuf,
199
         SMB_NTQUOTA_LIST **end_ptr)
200
0
{
201
0
  return fill_quota_buffer(mem_ctx,
202
0
         qt_list,
203
0
         false,
204
0
         maxlen,
205
0
         outbuf,
206
0
         end_ptr);
207
0
}
208
209
NTSTATUS build_fs_quota_buffer(TALLOC_CTX *mem_ctx,
210
             const SMB_NTQUOTA_STRUCT *pqt,
211
             DATA_BLOB *blob,
212
             uint32_t maxlen)
213
0
{
214
0
  uint8_t *buf;
215
216
0
  if (maxlen > 0 && maxlen < 48) {
217
0
    return NT_STATUS_BUFFER_TOO_SMALL;
218
0
  }
219
220
0
  *blob = data_blob_talloc_zero(mem_ctx, 48);
221
222
0
  if (!blob->data) {
223
0
    return NT_STATUS_NO_MEMORY;
224
0
  }
225
226
0
  buf = blob->data;
227
228
  /* Unknown1 24 NULL bytes*/
229
0
  PUSH_LE_U64(buf, 0, 0);
230
0
  PUSH_LE_U64(buf, 8, 0);
231
0
  PUSH_LE_U64(buf, 16, 0);
232
233
  /* Default Soft Quota 8 bytes */
234
0
  PUSH_LE_U64(buf, 24, pqt->softlim);
235
236
  /* Default Hard Quota 8 bytes */
237
0
  PUSH_LE_U64(buf, 32, pqt->hardlim);
238
239
  /* Quota flag 4 bytes */
240
0
  SIVAL(buf, 40, pqt->qflags);
241
242
  /* 4 padding bytes */
243
0
  SIVAL(buf, 44, 0);
244
245
0
  return NT_STATUS_OK;
246
0
}
247
248
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
249
          SMB_NTQUOTA_STRUCT *pqt)
250
0
{
251
0
  uint16_t setup[1];
252
0
  uint8_t *rparam = NULL, *rdata = NULL;
253
0
  uint32_t rparam_count, rdata_count;
254
0
  unsigned int sid_len;
255
0
  unsigned int offset;
256
0
  struct nttrans_query_quota_params get_quota = {0};
257
0
  struct file_get_quota_info info =  {0};
258
0
  enum ndr_err_code err;
259
0
  NTSTATUS status;
260
0
  TALLOC_CTX *frame = talloc_stackframe();
261
0
  DATA_BLOB data_blob = data_blob_null;
262
0
  DATA_BLOB param_blob = data_blob_null;
263
264
0
  if (!cli||!pqt) {
265
0
    smb_panic("cli_get_user_quota() called with NULL Pointer!");
266
0
  }
267
268
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
269
0
    TALLOC_FREE(frame);
270
0
    return cli_smb2_get_user_quota(cli, quota_fnum, pqt);
271
0
  }
272
273
0
  get_quota.fid = quota_fnum;
274
0
  get_quota.return_single_entry = 1;
275
0
  get_quota.restart_scan = 0;
276
277
0
  sid_len = ndr_size_dom_sid(&pqt->sid, 0);
278
279
0
  info.next_entry_offset = 0;
280
0
  info.sid_length = sid_len;
281
0
  info.sid = pqt->sid;
282
283
0
  err = ndr_push_struct_blob(
284
0
      &data_blob,
285
0
      frame,
286
0
      &info,
287
0
      (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
288
289
0
  if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
290
0
    status = NT_STATUS_INTERNAL_ERROR;
291
0
    goto out;
292
0
  }
293
294
0
  get_quota.sid_list_length = data_blob.length;
295
0
  get_quota.start_sid_offset = data_blob.length;
296
297
0
  err = ndr_push_struct_blob(
298
0
    &param_blob,
299
0
    frame,
300
0
    &get_quota,
301
0
    (ndr_push_flags_fn_t)ndr_push_nttrans_query_quota_params);
302
303
0
  if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
304
0
    status = NT_STATUS_INTERNAL_ERROR;
305
0
    goto out;
306
0
  }
307
308
0
  status = cli_trans(talloc_tos(), cli, SMBnttrans,
309
0
         NULL, -1, /* name, fid */
310
0
         NT_TRANSACT_GET_USER_QUOTA, 0,
311
0
         setup, 1, 0, /* setup */
312
0
         param_blob.data, param_blob.length, 4, /* params */
313
0
         data_blob.data, data_blob.length, 112, /* data */
314
0
         NULL,   /* recv_flags2 */
315
0
         NULL, 0, NULL, /* rsetup */
316
0
         &rparam, 4, &rparam_count,
317
0
         &rdata, 8, &rdata_count);
318
0
  if (!NT_STATUS_IS_OK(status)) {
319
0
    DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
320
0
        nt_errstr(status)));
321
0
    goto out;
322
0
  }
323
324
0
  if (!parse_user_quota_record(rdata, rdata_count, &offset, pqt)) {
325
0
    status = NT_STATUS_INVALID_NETWORK_RESPONSE;
326
0
    DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
327
0
  }
328
329
0
out:
330
0
  TALLOC_FREE(rparam);
331
0
  TALLOC_FREE(rdata);
332
0
  TALLOC_FREE(frame);
333
0
  return status;
334
0
}
335
336
NTSTATUS
337
cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST *qtl)
338
0
{
339
0
  uint16_t setup[1];
340
0
  uint8_t params[2];
341
0
  DATA_BLOB data = data_blob_null;
342
0
  NTSTATUS status;
343
344
0
  if (!cli || !qtl) {
345
0
    smb_panic("cli_set_user_quota() called with NULL Pointer!");
346
0
  }
347
348
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
349
0
    return cli_smb2_set_user_quota(cli, quota_fnum, qtl);
350
0
  }
351
352
0
  status = build_user_quota_buffer(qtl, 0, talloc_tos(), &data, NULL);
353
0
  if (!NT_STATUS_IS_OK(status)) {
354
    /*
355
     * smb1 doesn't send NT_STATUS_NO_MORE_ENTRIES so swallow
356
     * this status.
357
     */
358
0
    if (!NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
359
0
      goto cleanup;
360
0
    }
361
0
  }
362
363
0
  SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
364
365
0
  SSVAL(params,0,quota_fnum);
366
367
0
  status = cli_trans(talloc_tos(), cli, SMBnttrans,
368
0
         NULL, -1, /* name, fid */
369
0
         NT_TRANSACT_SET_USER_QUOTA, 0,
370
0
         setup, 1, 0, /* setup */
371
0
         params, 2, 0, /* params */
372
0
         data.data, data.length, 0, /* data */
373
0
         NULL,   /* recv_flags2 */
374
0
         NULL, 0, NULL, /* rsetup */
375
0
         NULL, 0, NULL, /* rparams */
376
0
         NULL, 0, NULL);  /* rdata */
377
378
0
  if (!NT_STATUS_IS_OK(status)) {
379
0
    DEBUG(1, ("NT_TRANSACT_SET_USER_QUOTA failed: %s\n",
380
0
        nt_errstr(status)));
381
0
  }
382
383
0
cleanup:
384
0
  data_blob_free(&data);
385
0
  return status;
386
0
}
387
388
static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
389
           TALLOC_CTX *mem_ctx,
390
           int quota_fnum,
391
           SMB_NTQUOTA_LIST **pqt_list,
392
           bool first)
393
0
{
394
0
  uint16_t setup[1];
395
0
  DATA_BLOB params_blob = data_blob_null;
396
0
  uint8_t *rparam=NULL, *rdata=NULL;
397
0
  uint32_t rparam_count=0, rdata_count=0;
398
0
  NTSTATUS status;
399
0
  struct nttrans_query_quota_params quota_params = {0};
400
0
  enum ndr_err_code err;
401
402
0
  TALLOC_CTX *frame = NULL;
403
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
404
0
    return cli_smb2_list_user_quota_step(cli, mem_ctx, quota_fnum,
405
0
                 pqt_list, first);
406
0
  }
407
0
  frame = talloc_stackframe();
408
409
0
  SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
410
411
0
  quota_params.fid = quota_fnum;
412
0
  if (first) {
413
0
    quota_params.restart_scan = 1;
414
0
  }
415
0
  err = ndr_push_struct_blob(
416
0
    &params_blob,
417
0
    frame,
418
0
    &quota_params,
419
0
    (ndr_push_flags_fn_t)ndr_push_nttrans_query_quota_params);
420
421
0
  if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
422
0
    status = NT_STATUS_INVALID_PARAMETER;
423
0
    goto cleanup;
424
0
  }
425
426
0
  status = cli_trans(talloc_tos(), cli, SMBnttrans,
427
0
         NULL, -1, /* name, fid */
428
0
         NT_TRANSACT_GET_USER_QUOTA, 0,
429
0
         setup, 1, 0, /* setup */
430
0
         params_blob.data, params_blob.length, 4, /* params */
431
0
         NULL, 0, 2048, /* data */
432
0
         NULL,   /* recv_flags2 */
433
0
         NULL, 0, NULL, /* rsetup */
434
0
         &rparam, 0, &rparam_count,
435
0
         &rdata, 0, &rdata_count);
436
437
  /* compat. with smbd + safeguard against
438
   * endless loop
439
   */
440
0
  if (NT_STATUS_IS_OK(status) && rdata_count == 0) {
441
0
    status = NT_STATUS_NO_MORE_ENTRIES;
442
0
  }
443
444
0
  if (!NT_STATUS_IS_OK(status)) {
445
0
    goto cleanup;
446
0
  }
447
448
0
  status = parse_user_quota_list(rdata, rdata_count, mem_ctx, pqt_list);
449
450
0
cleanup:
451
0
  TALLOC_FREE(rparam);
452
0
  TALLOC_FREE(rdata);
453
0
  TALLOC_FREE(frame);
454
455
0
  return status;
456
0
}
457
458
NTSTATUS cli_list_user_quota(struct cli_state *cli,
459
           int quota_fnum,
460
           SMB_NTQUOTA_LIST **pqt_list)
461
0
{
462
0
  NTSTATUS status;
463
0
  TALLOC_CTX *mem_ctx = NULL;
464
0
  bool first = true;
465
466
0
  if (!cli || !pqt_list) {
467
0
    smb_panic("cli_list_user_quota() called with NULL Pointer!");
468
0
  }
469
470
0
  *pqt_list = NULL;
471
472
0
  if ((mem_ctx = talloc_init("SMB_USER_QUOTA_LIST")) == NULL) {
473
0
    return NT_STATUS_NO_MEMORY;
474
0
  }
475
476
0
  do {
477
0
    status = cli_list_user_quota_step(cli, mem_ctx, quota_fnum,
478
0
              pqt_list, first);
479
0
    first = false;
480
0
  } while (NT_STATUS_IS_OK(status));
481
482
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
483
0
    status = NT_STATUS_OK;
484
0
  }
485
486
0
  if (!NT_STATUS_IS_OK(status) || *pqt_list == NULL) {
487
0
    TALLOC_FREE(mem_ctx);
488
0
  }
489
490
0
  return status;
491
0
}
492
493
NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
494
             SMB_NTQUOTA_STRUCT *pqt)
495
0
{
496
0
  uint16_t setup[1];
497
0
  uint8_t param[2];
498
0
  uint8_t *rdata=NULL;
499
0
  uint32_t rdata_count=0;
500
0
  NTSTATUS status;
501
502
0
  if (!cli||!pqt) {
503
0
    smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
504
0
  }
505
506
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
507
0
    return cli_smb2_get_fs_quota_info(cli, quota_fnum, pqt);
508
0
  }
509
510
0
  SSVAL(setup + 0, 0, TRANSACT2_QFSINFO);
511
512
0
  SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
513
514
0
  status = cli_trans(talloc_tos(), cli, SMBtrans2,
515
0
         NULL, -1, /* name, fid */
516
0
         0, 0,     /* function, flags */
517
0
         setup, 1, 0, /* setup */
518
0
         param, 2, 0, /* param */
519
0
         NULL, 0, 560, /* data */
520
0
         NULL,  /* recv_flags2 */
521
0
         NULL, 0, NULL, /* rsetup */
522
0
         NULL, 0, NULL, /* rparam */
523
0
         &rdata, 48, &rdata_count);
524
525
0
  if (!NT_STATUS_IS_OK(status)) {
526
0
    DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
527
0
        nt_errstr(status)));
528
0
    return status;
529
0
  }
530
531
0
  status = parse_fs_quota_buffer(rdata, rdata_count, pqt);
532
533
0
  TALLOC_FREE(rdata);
534
0
  return status;
535
0
}
536
537
NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
538
             SMB_NTQUOTA_STRUCT *pqt)
539
0
{
540
0
  uint16_t setup[1];
541
0
  uint8_t param[4];
542
0
  DATA_BLOB data = data_blob_null;
543
0
  NTSTATUS status;
544
545
0
  if (!cli||!pqt) {
546
0
    smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
547
0
  }
548
549
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
550
0
    return cli_smb2_set_fs_quota_info(cli, quota_fnum, pqt);
551
0
  }
552
553
0
  status = build_fs_quota_buffer(talloc_tos(), pqt, &data, 0);
554
0
  if (!NT_STATUS_IS_OK(status)) {
555
0
    return status;
556
0
  }
557
558
0
  SSVAL(setup + 0, 0,TRANSACT2_SETFSINFO);
559
560
0
  SSVAL(param,0,quota_fnum);
561
0
  SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
562
563
0
  status = cli_trans(talloc_tos(), cli, SMBtrans2,
564
0
         NULL, -1, /* name, fid */
565
0
         0, 0,     /* function, flags */
566
0
         setup, 1, 0, /* setup */
567
0
         param, 4, 0, /* param */
568
0
         data.data, data.length, 0, /* data */
569
0
         NULL,  /* recv_flags2 */
570
0
         NULL, 0, NULL, /* rsetup */
571
0
         NULL, 0, NULL, /* rparam */
572
0
         NULL, 0, NULL); /* rdata */
573
574
0
  if (!NT_STATUS_IS_OK(status)) {
575
0
    DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
576
0
        nt_errstr(status)));
577
0
  }
578
579
0
  return status;
580
0
}
581
582
NTSTATUS fill_quota_buffer(TALLOC_CTX *mem_ctx,
583
            SMB_NTQUOTA_LIST *qlist,
584
            bool return_single,
585
            uint32_t max_data,
586
            DATA_BLOB *blob,
587
            SMB_NTQUOTA_LIST **end_ptr)
588
0
{
589
0
  ndr_flags_type ndr_flags = NDR_SCALARS | NDR_BUFFERS;
590
0
  struct ndr_push *qndr = NULL;
591
0
  uint32_t start_offset = 0;
592
0
  uint32_t padding = 0;
593
0
  if (qlist == NULL) {
594
    /* We must push at least one. */
595
0
    return NT_STATUS_NO_MORE_ENTRIES;
596
0
  }
597
598
0
  qndr = ndr_push_init_ctx(mem_ctx);
599
0
  if (qndr == NULL) {
600
0
    return NT_STATUS_NO_MEMORY;
601
0
  }
602
603
0
  for (;qlist != NULL; qlist = qlist->next) {
604
0
    struct file_quota_information info = {0};
605
0
    enum ndr_err_code err;
606
0
    uint32_t dsize = sizeof(info.next_entry_offset)
607
0
      + sizeof(info.sid_length)
608
0
      + sizeof(info.change_time)
609
0
      + sizeof(info.quota_used)
610
0
      + sizeof(info.quota_threshold)
611
0
      + sizeof(info.quota_limit);
612
613
614
0
    info.sid_length = ndr_size_dom_sid(&qlist->quotas->sid, 0);
615
616
0
    if (max_data) {
617
0
      uint32_t curr_pos_no_padding = qndr->offset - padding;
618
0
      uint32_t payload = dsize + info.sid_length;
619
0
      uint32_t new_pos = (curr_pos_no_padding + payload);
620
0
      if (new_pos < curr_pos_no_padding) {
621
        /* Detect unlikely integer wrap */
622
0
        DBG_ERR("Integer wrap while adjusting pos "
623
0
          "0x%x by offset 0x%x\n",
624
0
          curr_pos_no_padding, payload);
625
0
        return NT_STATUS_INTERNAL_ERROR;
626
0
      }
627
0
      if (new_pos > max_data) {
628
0
        DBG_WARNING("Max data will be exceeded "
629
0
              "writing next query info. "
630
0
              "cur_pos 0x%x, sid_length 0x%x, "
631
0
              "dsize 0x%x, max_data 0x%x\n",
632
0
              curr_pos_no_padding,
633
0
              info.sid_length,
634
0
              dsize,
635
0
              max_data);
636
0
        break;
637
0
      }
638
0
    }
639
640
0
    start_offset = qndr->offset;
641
0
    info.sid = qlist->quotas->sid;
642
0
    info.quota_used = qlist->quotas->usedspace;
643
0
    info.quota_threshold = qlist->quotas->softlim;
644
0
    info.quota_limit = qlist->quotas->hardlim;
645
646
0
    err = ndr_push_file_quota_information(qndr,
647
0
                  ndr_flags,
648
0
                  &info);
649
650
0
    if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
651
0
      DBG_DEBUG("Failed to push the quota sid\n");
652
0
      return NT_STATUS_INTERNAL_ERROR;
653
0
    }
654
655
    /* pidl will align to 8 bytes due to 8 byte members*/
656
    /* Remember how much align padding we've used. */
657
0
    padding = qndr->offset;
658
659
0
    err = ndr_push_align(qndr, 8);
660
0
    if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
661
0
      DBG_DEBUG("ndr_push_align returned %s\n",
662
0
          ndr_map_error2string(err));
663
0
      return ndr_map_error2ntstatus(err);
664
0
    }
665
666
0
    padding = qndr->offset - padding;
667
668
    /*
669
     * Overwrite next_entry_offset for this entry now
670
     * we know what it should be. We know we're using
671
     * LIBNDR_FLAG_LITTLE_ENDIAN here so we can use
672
     * SIVAL.
673
     */
674
0
    info.next_entry_offset = qndr->offset - start_offset;
675
0
    SIVAL(qndr->data, start_offset, info.next_entry_offset);
676
677
0
    if (return_single) {
678
0
      break;
679
0
    }
680
0
  }
681
682
0
  if (end_ptr != NULL) {
683
0
    *end_ptr = qlist;
684
0
  }
685
686
  /* Remove the padding alignment on the last element pushed. */
687
0
  blob->length = qndr->offset - padding;
688
0
  blob->data = qndr->data;
689
690
  /*
691
   * Terminate the pushed array by setting next_entry_offset
692
   * for the last element to zero.
693
   */
694
0
  if (blob->length >= sizeof(uint32_t)) {
695
0
    SIVAL(qndr->data, start_offset, 0);
696
0
  }
697
0
  return NT_STATUS_OK;
698
0
}