s3: client: Add new utility function client_clean_name().
[Samba.git] / source3 / libsmb / cliquota.c
blobe22ccdd1931b7329bde1b383f41efc623ef166f3
1 /*
2 Unix SMB/CIFS implementation.
3 client quota functions
4 Copyright (C) Stefan (metze) Metzmacher 2003
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.
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.
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/>.
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"
28 NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum)
30 return cli_ntcreate(cli, FAKE_FILE_NAME_QUOTA_WIN32,
31 0x00000016, DESIRED_ACCESS_PIPE,
32 0x00000000, FILE_SHARE_READ|FILE_SHARE_WRITE,
33 FILE_OPEN, 0x00000000, 0x03, quota_fnum, NULL);
36 void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
38 if (!qt_list || !*qt_list) {
39 return;
42 if ((*qt_list)->mem_ctx)
43 talloc_destroy((*qt_list)->mem_ctx);
45 (*qt_list) = NULL;
47 return;
50 bool add_record_to_ntquota_list(TALLOC_CTX *mem_ctx,
51 SMB_NTQUOTA_STRUCT *pqt,
52 SMB_NTQUOTA_LIST **pqt_list)
54 SMB_NTQUOTA_LIST *tmp_list_ent;
56 if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) == NULL) {
57 return false;
60 if ((tmp_list_ent->quotas = talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) ==
61 NULL) {
62 return false;
65 *tmp_list_ent->quotas = *pqt;
66 tmp_list_ent->mem_ctx = mem_ctx;
68 DLIST_ADD((*pqt_list), tmp_list_ent);
70 return true;
73 bool parse_user_quota_record(const uint8_t *rdata,
74 unsigned int rdata_count,
75 unsigned int *offset,
76 SMB_NTQUOTA_STRUCT *pqt)
78 int sid_len;
79 SMB_NTQUOTA_STRUCT qt;
81 ZERO_STRUCT(qt);
83 if (!rdata||!offset||!pqt) {
84 smb_panic("parse_quota_record: called with NULL POINTER!");
87 if (rdata_count < 40) {
88 return False;
91 /* offset to next quota record.
92 * 4 bytes IVAL(rdata,0)
93 * unused here...
95 *offset = IVAL(rdata,0);
97 /* sid len */
98 sid_len = IVAL(rdata,4);
99 if (40 + sid_len < 40) {
100 return false;
103 if (rdata_count < 40+sid_len) {
104 return False;
107 if (*offset != 0 && *offset < 40 + sid_len) {
108 return false;
111 /* unknown 8 bytes in pdata
112 * maybe its the change time in NTTIME
115 /* the used space 8 bytes (uint64_t)*/
116 qt.usedspace = BVAL(rdata,16);
118 /* the soft quotas 8 bytes (uint64_t)*/
119 qt.softlim = BVAL(rdata,24);
121 /* the hard quotas 8 bytes (uint64_t)*/
122 qt.hardlim = BVAL(rdata,32);
124 if (!sid_parse(rdata+40,sid_len,&qt.sid)) {
125 return false;
128 qt.qtype = SMB_USER_QUOTA_TYPE;
130 *pqt = qt;
132 return True;
135 NTSTATUS parse_user_quota_list(const uint8_t *curdata,
136 uint32_t curdata_count,
137 TALLOC_CTX *mem_ctx,
138 SMB_NTQUOTA_LIST **pqt_list)
140 NTSTATUS status = NT_STATUS_OK;
141 unsigned offset;
142 SMB_NTQUOTA_STRUCT qt;
144 while (true) {
145 ZERO_STRUCT(qt);
146 if (!parse_user_quota_record(curdata, curdata_count, &offset,
147 &qt)) {
148 DEBUG(1, ("Failed to parse the quota record\n"));
149 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
150 break;
153 if (offset > curdata_count) {
154 DEBUG(1, ("out of bounds offset in quota record\n"));
155 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
156 break;
159 if (curdata + offset < curdata) {
160 DEBUG(1, ("Pointer overflow in quota record\n"));
161 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
162 break;
165 if (!add_record_to_ntquota_list(mem_ctx, &qt, pqt_list)) {
166 status = NT_STATUS_NO_MEMORY;
167 break;
170 curdata += offset;
171 curdata_count -= offset;
173 if (offset == 0) {
174 break;
178 return status;
181 NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata,
182 unsigned int rdata_count,
183 SMB_NTQUOTA_STRUCT *pqt)
185 SMB_NTQUOTA_STRUCT qt;
187 ZERO_STRUCT(qt);
189 if (rdata_count < 48) {
190 /* minimum length is not enforced by SMB2 client.
192 DEBUG(1, ("small returned fs quota buffer\n"));
193 return NT_STATUS_INVALID_NETWORK_RESPONSE;
196 /* unknown_1 24 NULL bytes in pdata*/
198 /* the soft quotas 8 bytes (uint64_t)*/
199 qt.softlim = BVAL(rdata, 24);
201 /* the hard quotas 8 bytes (uint64_t)*/
202 qt.hardlim = BVAL(rdata, 32);
204 /* quota_flags 2 bytes **/
205 qt.qflags = SVAL(rdata, 40);
207 qt.qtype = SMB_USER_FS_QUOTA_TYPE;
209 *pqt = qt;
211 return NT_STATUS_OK;
214 NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list,
215 uint32_t maxlen,
216 TALLOC_CTX *mem_ctx,
217 DATA_BLOB *outbuf,
218 SMB_NTQUOTA_LIST **end_ptr)
220 uint32_t qt_len = 0;
221 uint8_t *entry;
222 uint32_t entry_len;
223 int sid_len;
224 SMB_NTQUOTA_LIST *qtl;
225 DATA_BLOB qbuf = data_blob_null;
226 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
228 if (qt_list == NULL) {
229 status = NT_STATUS_OK;
230 *outbuf = data_blob_null;
231 if (end_ptr) {
232 *end_ptr = NULL;
234 return NT_STATUS_OK;
237 for (qtl = qt_list; qtl != NULL; qtl = qtl->next) {
239 sid_len = ndr_size_dom_sid(&qtl->quotas->sid, 0);
240 if (47 + sid_len < 47) {
241 status = NT_STATUS_INVALID_PARAMETER;
242 goto fail;
244 entry_len = 40 + sid_len;
245 entry_len = ((entry_len + 7) / 8) * 8;
247 if (qt_len + entry_len < qt_len) {
248 status = NT_STATUS_INVALID_PARAMETER;
249 goto fail;
251 qt_len += entry_len;
254 if (maxlen > 0 && qt_len > maxlen) {
255 qt_len = maxlen;
258 qbuf = data_blob_talloc_zero(mem_ctx, qt_len);
259 if (qbuf.data == NULL) {
260 status = NT_STATUS_NO_MEMORY;
261 goto fail;
264 for (qt_len = 0, entry = qbuf.data; qt_list != NULL;
265 qt_list = qt_list->next, qt_len += entry_len, entry += entry_len) {
267 sid_len = ndr_size_dom_sid(&qt_list->quotas->sid, 0);
268 entry_len = 40 + sid_len;
269 entry_len = ((entry_len + 7) / 8) * 8;
271 if (qt_len + entry_len > qbuf.length) {
272 /* check for not-enough room even for a single
273 * entry
275 if (qt_len == 0) {
276 status = NT_STATUS_BUFFER_TOO_SMALL;
277 goto fail;
280 break;
283 /* nextoffset entry 4 bytes */
284 SIVAL(entry, 0, entry_len);
286 /* then the len of the SID 4 bytes */
287 SIVAL(entry, 4, sid_len);
289 /* NTTIME of last record change */
290 SBIG_UINT(entry, 8, (uint64_t)0);
292 /* the used disk space 8 bytes uint64_t */
293 SBIG_UINT(entry, 16, qt_list->quotas->usedspace);
295 /* the soft quotas 8 bytes uint64_t */
296 SBIG_UINT(entry, 24, qt_list->quotas->softlim);
298 /* the hard quotas 8 bytes uint64_t */
299 SBIG_UINT(entry, 32, qt_list->quotas->hardlim);
301 /* and now the SID */
302 sid_linearize((uint8_t *)(entry + 40), sid_len,
303 &qt_list->quotas->sid);
306 /* overwrite the offset of the last entry */
307 SIVAL(entry - entry_len, 0, 0);
309 /*potentially shrink the buffer if max was given
310 * and we haven't quite reached the max
312 qbuf.length = qt_len;
313 *outbuf = qbuf;
314 qbuf = data_blob_null;
315 status = NT_STATUS_OK;
317 if (end_ptr) {
318 *end_ptr = qt_list;
321 fail:
322 data_blob_free(&qbuf);
324 return status;
327 NTSTATUS build_fs_quota_buffer(TALLOC_CTX *mem_ctx,
328 const SMB_NTQUOTA_STRUCT *pqt,
329 DATA_BLOB *blob,
330 uint32_t maxlen)
332 uint8_t *buf;
334 if (maxlen > 0 && maxlen < 48) {
335 return NT_STATUS_BUFFER_TOO_SMALL;
338 *blob = data_blob_talloc_zero(mem_ctx, 48);
340 if (!blob->data) {
341 return NT_STATUS_NO_MEMORY;
344 buf = blob->data;
346 /* Unknown1 24 NULL bytes*/
347 SBIG_UINT(buf, 0, (uint64_t)0);
348 SBIG_UINT(buf, 8, (uint64_t)0);
349 SBIG_UINT(buf, 16, (uint64_t)0);
351 /* Default Soft Quota 8 bytes */
352 SBIG_UINT(buf, 24, pqt->softlim);
354 /* Default Hard Quota 8 bytes */
355 SBIG_UINT(buf, 32, pqt->hardlim);
357 /* Quota flag 4 bytes */
358 SIVAL(buf, 40, pqt->qflags);
360 /* 4 padding bytes */
361 SIVAL(buf, 44, 0);
363 return NT_STATUS_OK;
366 NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
367 SMB_NTQUOTA_STRUCT *pqt)
369 uint16_t setup[1];
370 uint8_t params[16];
371 unsigned int data_len;
372 uint8_t data[SID_MAX_SIZE+8];
373 uint8_t *rparam, *rdata;
374 uint32_t rparam_count, rdata_count;
375 unsigned int sid_len;
376 unsigned int offset;
377 NTSTATUS status;
379 if (!cli||!pqt) {
380 smb_panic("cli_get_user_quota() called with NULL Pointer!");
383 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
384 return cli_smb2_get_user_quota(cli, quota_fnum, pqt);
387 SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
389 SSVAL(params, 0,quota_fnum);
390 SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID);
391 SIVAL(params, 4,0x00000024);
392 SIVAL(params, 8,0x00000000);
393 SIVAL(params,12,0x00000024);
395 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
396 data_len = sid_len+8;
397 SIVAL(data, 0, 0x00000000);
398 SIVAL(data, 4, sid_len);
399 sid_linearize(data+8, sid_len, &pqt->sid);
401 status = cli_trans(talloc_tos(), cli, SMBnttrans,
402 NULL, -1, /* name, fid */
403 NT_TRANSACT_GET_USER_QUOTA, 0,
404 setup, 1, 0, /* setup */
405 params, 16, 4, /* params */
406 data, data_len, 112, /* data */
407 NULL, /* recv_flags2 */
408 NULL, 0, NULL, /* rsetup */
409 &rparam, 4, &rparam_count,
410 &rdata, 8, &rdata_count);
411 if (!NT_STATUS_IS_OK(status)) {
412 DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
413 nt_errstr(status)));
414 return status;
417 if (!parse_user_quota_record(rdata, rdata_count, &offset, pqt)) {
418 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
419 DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
422 TALLOC_FREE(rparam);
423 TALLOC_FREE(rdata);
424 return status;
427 NTSTATUS
428 cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST *qtl)
430 uint16_t setup[1];
431 uint8_t params[2];
432 DATA_BLOB data = data_blob_null;
433 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
435 if (!cli || !qtl) {
436 smb_panic("cli_set_user_quota() called with NULL Pointer!");
439 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
440 return cli_smb2_set_user_quota(cli, quota_fnum, qtl);
443 status = build_user_quota_buffer(qtl, 0, talloc_tos(), &data, NULL);
444 if (!NT_STATUS_IS_OK(status)) {
445 goto cleanup;
448 SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
450 SSVAL(params,0,quota_fnum);
452 status = cli_trans(talloc_tos(), cli, SMBnttrans,
453 NULL, -1, /* name, fid */
454 NT_TRANSACT_SET_USER_QUOTA, 0,
455 setup, 1, 0, /* setup */
456 params, 2, 0, /* params */
457 data.data, data.length, 0, /* data */
458 NULL, /* recv_flags2 */
459 NULL, 0, NULL, /* rsetup */
460 NULL, 0, NULL, /* rparams */
461 NULL, 0, NULL); /* rdata */
463 if (!NT_STATUS_IS_OK(status)) {
464 DEBUG(1, ("NT_TRANSACT_SET_USER_QUOTA failed: %s\n",
465 nt_errstr(status)));
468 cleanup:
469 data_blob_free(&data);
470 return status;
473 static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
474 TALLOC_CTX *mem_ctx,
475 int quota_fnum,
476 SMB_NTQUOTA_LIST **pqt_list,
477 bool first)
479 uint16_t setup[1];
480 uint8_t params[16];
481 uint8_t *rparam=NULL, *rdata=NULL;
482 uint32_t rparam_count=0, rdata_count=0;
483 NTSTATUS status;
484 uint16_t op = first ? TRANSACT_GET_USER_QUOTA_LIST_START
485 : TRANSACT_GET_USER_QUOTA_LIST_CONTINUE;
487 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
488 return cli_smb2_list_user_quota_step(cli, mem_ctx, quota_fnum,
489 pqt_list, first);
492 SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
494 SSVAL(params, 0,quota_fnum);
495 SSVAL(params, 2, op);
496 SIVAL(params, 4,0x00000000);
497 SIVAL(params, 8,0x00000000);
498 SIVAL(params,12,0x00000000);
500 status = cli_trans(talloc_tos(), cli, SMBnttrans,
501 NULL, -1, /* name, fid */
502 NT_TRANSACT_GET_USER_QUOTA, 0,
503 setup, 1, 0, /* setup */
504 params, 16, 4, /* params */
505 NULL, 0, 2048, /* data */
506 NULL, /* recv_flags2 */
507 NULL, 0, NULL, /* rsetup */
508 &rparam, 0, &rparam_count,
509 &rdata, 0, &rdata_count);
511 /* compat. with smbd + safeguard against
512 * endless loop
514 if (NT_STATUS_IS_OK(status) && rdata_count == 0) {
515 status = NT_STATUS_NO_MORE_ENTRIES;
518 if (!NT_STATUS_IS_OK(status)) {
519 goto cleanup;
522 status = parse_user_quota_list(rdata, rdata_count, mem_ctx, pqt_list);
524 cleanup:
525 TALLOC_FREE(rparam);
526 TALLOC_FREE(rdata);
528 return status;
531 NTSTATUS cli_list_user_quota(struct cli_state *cli,
532 int quota_fnum,
533 SMB_NTQUOTA_LIST **pqt_list)
535 NTSTATUS status;
536 TALLOC_CTX *mem_ctx = NULL;
537 bool first = true;
539 if (!cli || !pqt_list) {
540 smb_panic("cli_list_user_quota() called with NULL Pointer!");
543 *pqt_list = NULL;
545 if ((mem_ctx = talloc_init("SMB_USER_QUOTA_LIST")) == NULL) {
546 return NT_STATUS_NO_MEMORY;
549 do {
550 status = cli_list_user_quota_step(cli, mem_ctx, quota_fnum,
551 pqt_list, first);
552 first = false;
553 } while (NT_STATUS_IS_OK(status));
555 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
556 status = NT_STATUS_OK;
559 if (!NT_STATUS_IS_OK(status) || *pqt_list == NULL) {
560 TALLOC_FREE(mem_ctx);
563 return status;
566 NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
567 SMB_NTQUOTA_STRUCT *pqt)
569 uint16_t setup[1];
570 uint8_t param[2];
571 uint8_t *rdata=NULL;
572 uint32_t rdata_count=0;
573 NTSTATUS status;
575 if (!cli||!pqt) {
576 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
579 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
580 return cli_smb2_get_fs_quota_info(cli, quota_fnum, pqt);
583 SSVAL(setup + 0, 0, TRANSACT2_QFSINFO);
585 SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
587 status = cli_trans(talloc_tos(), cli, SMBtrans2,
588 NULL, -1, /* name, fid */
589 0, 0, /* function, flags */
590 setup, 1, 0, /* setup */
591 param, 2, 0, /* param */
592 NULL, 0, 560, /* data */
593 NULL, /* recv_flags2 */
594 NULL, 0, NULL, /* rsetup */
595 NULL, 0, NULL, /* rparam */
596 &rdata, 48, &rdata_count);
598 if (!NT_STATUS_IS_OK(status)) {
599 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
600 nt_errstr(status)));
601 return status;
604 status = parse_fs_quota_buffer(rdata, rdata_count, pqt);
606 TALLOC_FREE(rdata);
607 return status;
610 NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
611 SMB_NTQUOTA_STRUCT *pqt)
613 uint16_t setup[1];
614 uint8_t param[4];
615 DATA_BLOB data = data_blob_null;
616 NTSTATUS status;
618 if (!cli||!pqt) {
619 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
622 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
623 return cli_smb2_set_fs_quota_info(cli, quota_fnum, pqt);
626 status = build_fs_quota_buffer(talloc_tos(), pqt, &data, 0);
627 if (!NT_STATUS_IS_OK(status)) {
628 return status;
631 SSVAL(setup + 0, 0,TRANSACT2_SETFSINFO);
633 SSVAL(param,0,quota_fnum);
634 SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
636 status = cli_trans(talloc_tos(), cli, SMBtrans2,
637 NULL, -1, /* name, fid */
638 0, 0, /* function, flags */
639 setup, 1, 0, /* setup */
640 param, 4, 0, /* param */
641 data.data, data.length, 0, /* data */
642 NULL, /* recv_flags2 */
643 NULL, 0, NULL, /* rsetup */
644 NULL, 0, NULL, /* rparam */
645 NULL, 0, NULL); /* rdata */
647 if (!NT_STATUS_IS_OK(status)) {
648 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
649 nt_errstr(status)));
652 return status;