2 Unix SMB/CIFS implementation.
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/>.
21 #include "libsmb/libsmb.h"
22 #include "../librpc/gen_ndr/ndr_security.h"
23 #include "fake_file.h"
24 #include "../libcli/security/security.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
) {
42 if ((*qt_list
)->mem_ctx
)
43 talloc_destroy((*qt_list
)->mem_ctx
);
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
) {
60 if ((tmp_list_ent
->quotas
= talloc_zero(mem_ctx
, SMB_NTQUOTA_STRUCT
)) ==
65 *tmp_list_ent
->quotas
= *pqt
;
66 tmp_list_ent
->mem_ctx
= mem_ctx
;
68 DLIST_ADD((*pqt_list
), tmp_list_ent
);
73 bool parse_user_quota_record(const uint8_t *rdata
,
74 unsigned int rdata_count
,
76 SMB_NTQUOTA_STRUCT
*pqt
)
79 SMB_NTQUOTA_STRUCT qt
;
83 if (!rdata
||!offset
||!pqt
) {
84 smb_panic("parse_quota_record: called with NULL POINTER!");
87 if (rdata_count
< 40) {
91 /* offset to next quota record.
92 * 4 bytes IVAL(rdata,0)
95 *offset
= IVAL(rdata
,0);
98 sid_len
= IVAL(rdata
,4);
99 if (40 + sid_len
< 40) {
103 if (rdata_count
< 40+sid_len
) {
107 if (*offset
!= 0 && *offset
< 40 + sid_len
) {
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
)) {
128 qt
.qtype
= SMB_USER_QUOTA_TYPE
;
135 NTSTATUS
parse_user_quota_list(const uint8_t *curdata
,
136 uint32_t curdata_count
,
138 SMB_NTQUOTA_LIST
**pqt_list
)
140 NTSTATUS status
= NT_STATUS_OK
;
142 SMB_NTQUOTA_STRUCT qt
;
146 if (!parse_user_quota_record(curdata
, curdata_count
, &offset
,
148 DEBUG(1, ("Failed to parse the quota record\n"));
149 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
153 if (offset
> curdata_count
) {
154 DEBUG(1, ("out of bounds offset in quota record\n"));
155 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
159 if (curdata
+ offset
< curdata
) {
160 DEBUG(1, ("Pointer overflow in quota record\n"));
161 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
165 if (!add_record_to_ntquota_list(mem_ctx
, &qt
, pqt_list
)) {
166 status
= NT_STATUS_NO_MEMORY
;
171 curdata_count
-= offset
;
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
;
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
;
214 NTSTATUS
build_user_quota_buffer(SMB_NTQUOTA_LIST
*qt_list
,
218 SMB_NTQUOTA_LIST
**end_ptr
)
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
;
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
;
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
;
254 if (maxlen
> 0 && qt_len
> maxlen
) {
258 qbuf
= data_blob_talloc_zero(mem_ctx
, qt_len
);
259 if (qbuf
.data
== NULL
) {
260 status
= NT_STATUS_NO_MEMORY
;
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
276 status
= NT_STATUS_BUFFER_TOO_SMALL
;
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
;
314 qbuf
= data_blob_null
;
315 status
= NT_STATUS_OK
;
322 data_blob_free(&qbuf
);
327 NTSTATUS
build_fs_quota_buffer(TALLOC_CTX
*mem_ctx
,
328 const SMB_NTQUOTA_STRUCT
*pqt
,
334 if (maxlen
> 0 && maxlen
< 48) {
335 return NT_STATUS_BUFFER_TOO_SMALL
;
338 *blob
= data_blob_talloc_zero(mem_ctx
, 48);
341 return NT_STATUS_NO_MEMORY
;
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 */
366 NTSTATUS
cli_get_user_quota(struct cli_state
*cli
, int quota_fnum
,
367 SMB_NTQUOTA_STRUCT
*pqt
)
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
;
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",
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"));
428 cli_set_user_quota(struct cli_state
*cli
, int quota_fnum
, SMB_NTQUOTA_LIST
*qtl
)
432 DATA_BLOB data
= data_blob_null
;
433 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
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
)) {
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",
469 data_blob_free(&data
);
473 static NTSTATUS
cli_list_user_quota_step(struct cli_state
*cli
,
476 SMB_NTQUOTA_LIST
**pqt_list
,
481 uint8_t *rparam
=NULL
, *rdata
=NULL
;
482 uint32_t rparam_count
=0, rdata_count
=0;
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
,
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
514 if (NT_STATUS_IS_OK(status
) && rdata_count
== 0) {
515 status
= NT_STATUS_NO_MORE_ENTRIES
;
518 if (!NT_STATUS_IS_OK(status
)) {
522 status
= parse_user_quota_list(rdata
, rdata_count
, mem_ctx
, pqt_list
);
531 NTSTATUS
cli_list_user_quota(struct cli_state
*cli
,
533 SMB_NTQUOTA_LIST
**pqt_list
)
536 TALLOC_CTX
*mem_ctx
= NULL
;
539 if (!cli
|| !pqt_list
) {
540 smb_panic("cli_list_user_quota() called with NULL Pointer!");
545 if ((mem_ctx
= talloc_init("SMB_USER_QUOTA_LIST")) == NULL
) {
546 return NT_STATUS_NO_MEMORY
;
550 status
= cli_list_user_quota_step(cli
, mem_ctx
, quota_fnum
,
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
);
566 NTSTATUS
cli_get_fs_quota_info(struct cli_state
*cli
, int quota_fnum
,
567 SMB_NTQUOTA_STRUCT
*pqt
)
572 uint32_t rdata_count
=0;
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",
604 status
= parse_fs_quota_buffer(rdata
, rdata_count
, pqt
);
610 NTSTATUS
cli_set_fs_quota_info(struct cli_state
*cli
, int quota_fnum
,
611 SMB_NTQUOTA_STRUCT
*pqt
)
615 DATA_BLOB data
= data_blob_null
;
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
)) {
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",