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 
cli_get_quota_handle(struct cli_state * cli,uint16_t * quota_fnum)29 NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum)
30 {
31 	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 
free_ntquota_list(SMB_NTQUOTA_LIST ** qt_list)37 void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
38 {
39 	if (!qt_list || !*qt_list) {
40 		return;
41 	}
42 
43 	if ((*qt_list)->mem_ctx)
44 		talloc_destroy((*qt_list)->mem_ctx);
45 
46 	(*qt_list) = NULL;
47 
48 	return;
49 }
50 
add_record_to_ntquota_list(TALLOC_CTX * mem_ctx,SMB_NTQUOTA_STRUCT * pqt,SMB_NTQUOTA_LIST ** pqt_list)51 bool add_record_to_ntquota_list(TALLOC_CTX *mem_ctx,
52 				SMB_NTQUOTA_STRUCT *pqt,
53 				SMB_NTQUOTA_LIST **pqt_list)
54 {
55 	SMB_NTQUOTA_LIST *tmp_list_ent;
56 
57 	if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) == NULL) {
58 		return false;
59 	}
60 
61 	if ((tmp_list_ent->quotas = talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) ==
62 	    NULL) {
63 		return false;
64 	}
65 
66 	*tmp_list_ent->quotas = *pqt;
67 	tmp_list_ent->mem_ctx = mem_ctx;
68 
69 	DLIST_ADD((*pqt_list), tmp_list_ent);
70 
71 	return true;
72 }
73 
parse_user_quota_record(const uint8_t * rdata,unsigned int rdata_count,unsigned int * offset,SMB_NTQUOTA_STRUCT * pqt)74 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 	struct file_quota_information info = {0};
80 	TALLOC_CTX *frame = talloc_stackframe();
81 	DATA_BLOB blob;
82 	enum ndr_err_code err;
83 	bool result = false;
84 
85 	blob.data = discard_const_p(uint8_t, rdata);
86 	blob.length = rdata_count;
87 	err = ndr_pull_struct_blob(
88 			&blob,
89 			frame,
90 			&info,
91 			(ndr_pull_flags_fn_t)ndr_pull_file_quota_information);
92 
93 	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
94 		goto out;
95 	}
96 
97 	*offset = info.next_entry_offset;
98 
99 	ZERO_STRUCTP(pqt);
100 	pqt->usedspace = info.quota_used;
101 
102 	pqt->softlim = info.quota_threshold;
103 
104 	pqt->hardlim = info.quota_limit;
105 
106 	pqt->qtype = SMB_USER_QUOTA_TYPE;
107 	pqt->sid = info.sid;
108 	result = true;
109 out:
110 	TALLOC_FREE(frame);
111 	return result;
112 }
113 
parse_user_quota_list(const uint8_t * curdata,uint32_t curdata_count,TALLOC_CTX * mem_ctx,SMB_NTQUOTA_LIST ** pqt_list)114 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 	NTSTATUS status = NT_STATUS_OK;
120 	unsigned offset;
121 	SMB_NTQUOTA_STRUCT qt;
122 
123 	while (true) {
124 		ZERO_STRUCT(qt);
125 		if (!parse_user_quota_record(curdata, curdata_count, &offset,
126 					     &qt)) {
127 			DEBUG(1, ("Failed to parse the quota record\n"));
128 			status = NT_STATUS_INVALID_NETWORK_RESPONSE;
129 			break;
130 		}
131 
132 		if (offset > curdata_count) {
133 			DEBUG(1, ("out of bounds offset in quota record\n"));
134 			status = NT_STATUS_INVALID_NETWORK_RESPONSE;
135 			break;
136 		}
137 
138 		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 		if (!add_record_to_ntquota_list(mem_ctx, &qt, pqt_list)) {
145 			status = NT_STATUS_NO_MEMORY;
146 			break;
147 		}
148 
149 		curdata += offset;
150 		curdata_count -= offset;
151 
152 		if (offset == 0) {
153 			break;
154 		}
155 	}
156 
157 	return status;
158 }
159 
parse_fs_quota_buffer(const uint8_t * rdata,unsigned int rdata_count,SMB_NTQUOTA_STRUCT * pqt)160 NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata,
161 			       unsigned int rdata_count,
162 			       SMB_NTQUOTA_STRUCT *pqt)
163 {
164 	SMB_NTQUOTA_STRUCT qt;
165 
166 	ZERO_STRUCT(qt);
167 
168 	if (rdata_count < 48) {
169 		/* minimum length is not enforced by SMB2 client.
170 		 */
171 		DEBUG(1, ("small returned fs quota buffer\n"));
172 		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 	qt.softlim = BVAL(rdata, 24);
179 
180 	/* the hard quotas 8 bytes (uint64_t)*/
181 	qt.hardlim = BVAL(rdata, 32);
182 
183 	/* quota_flags 2 bytes **/
184 	qt.qflags = SVAL(rdata, 40);
185 
186 	qt.qtype = SMB_USER_FS_QUOTA_TYPE;
187 
188 	*pqt = qt;
189 
190 	return NT_STATUS_OK;
191 }
192 
build_user_quota_buffer(SMB_NTQUOTA_LIST * qt_list,uint32_t maxlen,TALLOC_CTX * mem_ctx,DATA_BLOB * outbuf,SMB_NTQUOTA_LIST ** end_ptr)193 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 	return fill_quota_buffer(mem_ctx,
200 				 qt_list,
201 				 false,
202 				 maxlen,
203 				 outbuf,
204 				 end_ptr);
205 }
206 
build_fs_quota_buffer(TALLOC_CTX * mem_ctx,const SMB_NTQUOTA_STRUCT * pqt,DATA_BLOB * blob,uint32_t maxlen)207 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 	uint8_t *buf;
213 
214 	if (maxlen > 0 && maxlen < 48) {
215 		return NT_STATUS_BUFFER_TOO_SMALL;
216 	}
217 
218 	*blob = data_blob_talloc_zero(mem_ctx, 48);
219 
220 	if (!blob->data) {
221 		return NT_STATUS_NO_MEMORY;
222 	}
223 
224 	buf = blob->data;
225 
226 	/* Unknown1 24 NULL bytes*/
227 	SBIG_UINT(buf, 0, (uint64_t)0);
228 	SBIG_UINT(buf, 8, (uint64_t)0);
229 	SBIG_UINT(buf, 16, (uint64_t)0);
230 
231 	/* Default Soft Quota 8 bytes */
232 	SBIG_UINT(buf, 24, pqt->softlim);
233 
234 	/* Default Hard Quota 8 bytes */
235 	SBIG_UINT(buf, 32, pqt->hardlim);
236 
237 	/* Quota flag 4 bytes */
238 	SIVAL(buf, 40, pqt->qflags);
239 
240 	/* 4 padding bytes */
241 	SIVAL(buf, 44, 0);
242 
243 	return NT_STATUS_OK;
244 }
245 
cli_get_user_quota(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)246 NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
247 			    SMB_NTQUOTA_STRUCT *pqt)
248 {
249 	uint16_t setup[1];
250 	uint8_t *rparam = NULL, *rdata = NULL;
251 	uint32_t rparam_count, rdata_count;
252 	unsigned int sid_len;
253 	unsigned int offset;
254 	struct nttrans_query_quota_params get_quota = {0};
255 	struct file_get_quota_info info =  {0};
256 	enum ndr_err_code err;
257 	NTSTATUS status;
258 	TALLOC_CTX *frame = talloc_stackframe();
259 	DATA_BLOB data_blob = data_blob_null;
260 	DATA_BLOB param_blob = data_blob_null;
261 
262 	if (!cli||!pqt) {
263 		smb_panic("cli_get_user_quota() called with NULL Pointer!");
264 	}
265 
266 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
267 		TALLOC_FREE(frame);
268 		return cli_smb2_get_user_quota(cli, quota_fnum, pqt);
269 	}
270 
271 	get_quota.fid = quota_fnum;
272 	get_quota.return_single_entry = 1;
273 	get_quota.restart_scan = 0;
274 
275 	sid_len = ndr_size_dom_sid(&pqt->sid, 0);
276 
277 	info.next_entry_offset = 0;
278 	info.sid_length = sid_len;
279 	info.sid = pqt->sid;
280 
281 	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 	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
288 		status = NT_STATUS_INTERNAL_ERROR;
289 		goto out;
290 	}
291 
292 	get_quota.sid_list_length = data_blob.length;
293 	get_quota.start_sid_offset = data_blob.length;
294 
295 	err = ndr_push_struct_blob(
296 		&param_blob,
297 		frame,
298 		&get_quota,
299 		(ndr_push_flags_fn_t)ndr_push_nttrans_query_quota_params);
300 
301 	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
302 		status = NT_STATUS_INTERNAL_ERROR;
303 		goto out;
304 	}
305 
306 	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 			   param_blob.data, param_blob.length, 4, /* params */
311 			   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 	if (!NT_STATUS_IS_OK(status)) {
317 		DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
318 			  nt_errstr(status)));
319 		goto out;
320 	}
321 
322 	if (!parse_user_quota_record(rdata, rdata_count, &offset, pqt)) {
323 		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
324 		DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
325 	}
326 
327 out:
328 	TALLOC_FREE(rparam);
329 	TALLOC_FREE(rdata);
330 	TALLOC_FREE(frame);
331 	return status;
332 }
333 
334 NTSTATUS
cli_set_user_quota(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_LIST * qtl)335 cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST *qtl)
336 {
337 	uint16_t setup[1];
338 	uint8_t params[2];
339 	DATA_BLOB data = data_blob_null;
340 	NTSTATUS status;
341 
342 	if (!cli || !qtl) {
343 		smb_panic("cli_set_user_quota() called with NULL Pointer!");
344 	}
345 
346 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
347 		return cli_smb2_set_user_quota(cli, quota_fnum, qtl);
348 	}
349 
350 	status = build_user_quota_buffer(qtl, 0, talloc_tos(), &data, NULL);
351 	if (!NT_STATUS_IS_OK(status)) {
352 		/*
353 		 * smb1 doesn't send NT_STATUS_NO_MORE_ENTRIES so swallow
354 		 * this status.
355 		 */
356 		if (!NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
357 			goto cleanup;
358 		}
359 	}
360 
361 	SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
362 
363 	SSVAL(params,0,quota_fnum);
364 
365 	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 			   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 	if (!NT_STATUS_IS_OK(status)) {
377 		DEBUG(1, ("NT_TRANSACT_SET_USER_QUOTA failed: %s\n",
378 			  nt_errstr(status)));
379 	}
380 
381 cleanup:
382 	data_blob_free(&data);
383 	return status;
384 }
385 
cli_list_user_quota_step(struct cli_state * cli,TALLOC_CTX * mem_ctx,int quota_fnum,SMB_NTQUOTA_LIST ** pqt_list,bool first)386 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 	uint16_t setup[1];
393 	DATA_BLOB params_blob = data_blob_null;
394 	uint8_t *rparam=NULL, *rdata=NULL;
395 	uint32_t rparam_count=0, rdata_count=0;
396 	NTSTATUS status;
397 	struct nttrans_query_quota_params quota_params = {0};
398 	enum ndr_err_code err;
399 
400 	TALLOC_CTX *frame = NULL;
401 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
402 		return cli_smb2_list_user_quota_step(cli, mem_ctx, quota_fnum,
403 						     pqt_list, first);
404 	}
405 	frame = talloc_stackframe();
406 
407 	SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
408 
409 	quota_params.fid = quota_fnum;
410 	if (first) {
411 		quota_params.restart_scan = 1;
412 	}
413 	err = ndr_push_struct_blob(
414 		&params_blob,
415 		frame,
416 		&quota_params,
417 		(ndr_push_flags_fn_t)ndr_push_nttrans_query_quota_params);
418 
419 	if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
420 		status = NT_STATUS_INVALID_PARAMETER;
421 		goto cleanup;
422 	}
423 
424 	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 			   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 	if (NT_STATUS_IS_OK(status) && rdata_count == 0) {
439 		status = NT_STATUS_NO_MORE_ENTRIES;
440 	}
441 
442 	if (!NT_STATUS_IS_OK(status)) {
443 		goto cleanup;
444 	}
445 
446 	status = parse_user_quota_list(rdata, rdata_count, mem_ctx, pqt_list);
447 
448 cleanup:
449 	TALLOC_FREE(rparam);
450 	TALLOC_FREE(rdata);
451 	TALLOC_FREE(frame);
452 
453 	return status;
454 }
455 
cli_list_user_quota(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_LIST ** pqt_list)456 NTSTATUS cli_list_user_quota(struct cli_state *cli,
457 			     int quota_fnum,
458 			     SMB_NTQUOTA_LIST **pqt_list)
459 {
460 	NTSTATUS status;
461 	TALLOC_CTX *mem_ctx = NULL;
462 	bool first = true;
463 
464 	if (!cli || !pqt_list) {
465 		smb_panic("cli_list_user_quota() called with NULL Pointer!");
466 	}
467 
468 	*pqt_list = NULL;
469 
470 	if ((mem_ctx = talloc_init("SMB_USER_QUOTA_LIST")) == NULL) {
471 		return NT_STATUS_NO_MEMORY;
472 	}
473 
474 	do {
475 		status = cli_list_user_quota_step(cli, mem_ctx, quota_fnum,
476 						  pqt_list, first);
477 		first = false;
478 	} while (NT_STATUS_IS_OK(status));
479 
480 	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
481 		status = NT_STATUS_OK;
482 	}
483 
484 	if (!NT_STATUS_IS_OK(status) || *pqt_list == NULL) {
485 		TALLOC_FREE(mem_ctx);
486 	}
487 
488 	return status;
489 }
490 
cli_get_fs_quota_info(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)491 NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
492 			       SMB_NTQUOTA_STRUCT *pqt)
493 {
494 	uint16_t setup[1];
495 	uint8_t param[2];
496 	uint8_t *rdata=NULL;
497 	uint32_t rdata_count=0;
498 	NTSTATUS status;
499 
500 	if (!cli||!pqt) {
501 		smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
502 	}
503 
504 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
505 		return cli_smb2_get_fs_quota_info(cli, quota_fnum, pqt);
506 	}
507 
508 	SSVAL(setup + 0, 0, TRANSACT2_QFSINFO);
509 
510 	SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
511 
512 	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 	if (!NT_STATUS_IS_OK(status)) {
524 		DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
525 			  nt_errstr(status)));
526 		return status;
527 	}
528 
529 	status = parse_fs_quota_buffer(rdata, rdata_count, pqt);
530 
531 	TALLOC_FREE(rdata);
532 	return status;
533 }
534 
cli_set_fs_quota_info(struct cli_state * cli,int quota_fnum,SMB_NTQUOTA_STRUCT * pqt)535 NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
536 			       SMB_NTQUOTA_STRUCT *pqt)
537 {
538 	uint16_t setup[1];
539 	uint8_t param[4];
540 	DATA_BLOB data = data_blob_null;
541 	NTSTATUS status;
542 
543 	if (!cli||!pqt) {
544 		smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
545 	}
546 
547 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
548 		return cli_smb2_set_fs_quota_info(cli, quota_fnum, pqt);
549 	}
550 
551 	status = build_fs_quota_buffer(talloc_tos(), pqt, &data, 0);
552 	if (!NT_STATUS_IS_OK(status)) {
553 		return status;
554 	}
555 
556 	SSVAL(setup + 0, 0,TRANSACT2_SETFSINFO);
557 
558 	SSVAL(param,0,quota_fnum);
559 	SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
560 
561 	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 			   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 	if (!NT_STATUS_IS_OK(status)) {
573 		DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
574 			  nt_errstr(status)));
575 	}
576 
577 	return status;
578 }
579 
fill_quota_buffer(TALLOC_CTX * mem_ctx,SMB_NTQUOTA_LIST * qlist,bool return_single,uint32_t max_data,DATA_BLOB * blob,SMB_NTQUOTA_LIST ** end_ptr)580 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 	int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
588 	struct ndr_push *qndr = NULL;
589 	uint32_t start_offset = 0;
590 	uint32_t padding = 0;
591 	if (qlist == NULL) {
592 		/* We must push at least one. */
593 		return NT_STATUS_NO_MORE_ENTRIES;
594 	}
595 
596 	qndr = ndr_push_init_ctx(mem_ctx);
597 	if (qndr == NULL) {
598 		return NT_STATUS_NO_MEMORY;
599 	}
600 
601 	for (;qlist != NULL; qlist = qlist->next) {
602 		struct file_quota_information info = {0};
603 		enum ndr_err_code err;
604 		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 		info.sid_length = ndr_size_dom_sid(&qlist->quotas->sid, 0);
613 
614 		if (max_data) {
615 			uint32_t curr_pos_no_padding = qndr->offset - padding;
616 			uint32_t payload = dsize + info.sid_length;
617 			uint32_t new_pos = (curr_pos_no_padding + payload);
618 			if (new_pos < curr_pos_no_padding) {
619 				/* Detect unlikely integer wrap */
620 				DBG_ERR("Integer wrap while adjusting pos "
621 					"0x%x by offset 0x%x\n",
622 					curr_pos_no_padding, payload);
623 				return NT_STATUS_INTERNAL_ERROR;
624 			}
625 			if (new_pos > max_data) {
626 				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 				break;
635 			}
636 		}
637 
638 		start_offset = qndr->offset;
639 		info.sid = qlist->quotas->sid;
640 		info.quota_used = qlist->quotas->usedspace;
641 		info.quota_threshold = qlist->quotas->softlim;
642 		info.quota_limit = qlist->quotas->hardlim;
643 
644 		err = ndr_push_file_quota_information(qndr,
645 						      ndr_flags,
646 						      &info);
647 
648 		if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
649 			DBG_DEBUG("Failed to push the quota sid\n");
650 			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 		padding = qndr->offset;
656 
657 		err = ndr_push_align(qndr, 8);
658 		if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
659 			DBG_DEBUG("ndr_push_align returned %s\n",
660 				  ndr_map_error2string(err));
661 			return ndr_map_error2ntstatus(err);
662 		}
663 
664 		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 		info.next_entry_offset = qndr->offset - start_offset;
673 		SIVAL(qndr->data, start_offset, info.next_entry_offset);
674 
675 		if (return_single) {
676 			break;
677 		}
678 	}
679 
680 	if (end_ptr != NULL) {
681 		*end_ptr = qlist;
682 	}
683 
684 	/* Remove the padding alignment on the last element pushed. */
685 	blob->length = qndr->offset - padding;
686 	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 	if (blob->length >= sizeof(uint32_t)) {
693 		SIVAL(qndr->data, start_offset, 0);
694 	}
695 	return NT_STATUS_OK;
696 }
697