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