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 parse_user_quota_record(const uint8_t *rdata,
51 unsigned int rdata_count,
53 SMB_NTQUOTA_STRUCT *pqt)
56 SMB_NTQUOTA_STRUCT qt;
60 if (!rdata||!offset||!pqt) {
61 smb_panic("parse_quota_record: called with NULL POINTER!");
64 if (rdata_count < 40) {
68 /* offset to next quota record.
69 * 4 bytes IVAL(rdata,0)
72 *offset = IVAL(rdata,0);
75 sid_len = IVAL(rdata,4);
76 if (40 + sid_len < 40) {
80 if (rdata_count < 40+sid_len) {
84 if (*offset != 0 && *offset < 40 + sid_len) {
88 /* unknown 8 bytes in pdata
89 * maybe its the change time in NTTIME
92 /* the used space 8 bytes (uint64_t)*/
93 qt.usedspace = BVAL(rdata,16);
95 /* the soft quotas 8 bytes (uint64_t)*/
96 qt.softlim = BVAL(rdata,24);
98 /* the hard quotas 8 bytes (uint64_t)*/
99 qt.hardlim = BVAL(rdata,32);
101 if (!sid_parse(rdata+40,sid_len,&qt.sid)) {
105 qt.qtype = SMB_USER_QUOTA_TYPE;
112 NTSTATUS parse_user_quota_list(const uint8_t *curdata,
113 uint32_t curdata_count,
115 SMB_NTQUOTA_LIST **pqt_list)
117 NTSTATUS status = NT_STATUS_OK;
119 SMB_NTQUOTA_STRUCT qt;
120 SMB_NTQUOTA_LIST *tmp_list_ent;
124 if (!parse_user_quota_record(curdata, curdata_count, &offset,
126 DEBUG(1, ("Failed to parse the quota record\n"));
127 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
131 if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) ==
133 status = NT_STATUS_NO_MEMORY;
137 if ((tmp_list_ent->quotas =
138 talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) == NULL) {
139 status = NT_STATUS_NO_MEMORY;
143 memcpy(tmp_list_ent->quotas, &qt, sizeof(qt));
144 tmp_list_ent->mem_ctx = mem_ctx;
146 DLIST_ADD((*pqt_list), tmp_list_ent);
148 if (offset > curdata_count) {
149 DEBUG(1, ("out of bounds offset in quota record\n"));
150 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
154 if (curdata + offset < curdata) {
155 DEBUG(1, ("Pointer overflow in quota record\n"));
156 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
161 curdata_count -= offset;
171 NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata,
172 unsigned int rdata_count,
173 SMB_NTQUOTA_STRUCT *pqt)
175 SMB_NTQUOTA_STRUCT qt;
179 if (rdata_count < 48) {
180 /* minimum length is not enforced by SMB2 client.
182 DEBUG(1, ("small returned fs quota buffer\n"));
183 return NT_STATUS_INVALID_NETWORK_RESPONSE;
186 /* unknown_1 24 NULL bytes in pdata*/
188 /* the soft quotas 8 bytes (uint64_t)*/
189 qt.softlim = BVAL(rdata, 24);
191 /* the hard quotas 8 bytes (uint64_t)*/
192 qt.hardlim = BVAL(rdata, 32);
194 /* quota_flags 2 bytes **/
195 qt.qflags = SVAL(rdata, 40);
197 qt.qtype = SMB_USER_FS_QUOTA_TYPE;
204 NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
205 SMB_NTQUOTA_STRUCT *pqt)
209 unsigned int data_len;
210 uint8_t data[SID_MAX_SIZE+8];
211 uint8_t *rparam, *rdata;
212 uint32_t rparam_count, rdata_count;
213 unsigned int sid_len;
218 smb_panic("cli_get_user_quota() called with NULL Pointer!");
221 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
222 return cli_smb2_get_user_quota(cli, quota_fnum, pqt);
225 SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
227 SSVAL(params, 0,quota_fnum);
228 SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID);
229 SIVAL(params, 4,0x00000024);
230 SIVAL(params, 8,0x00000000);
231 SIVAL(params,12,0x00000024);
233 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
234 data_len = sid_len+8;
235 SIVAL(data, 0, 0x00000000);
236 SIVAL(data, 4, sid_len);
237 sid_linearize(data+8, sid_len, &pqt->sid);
239 status = cli_trans(talloc_tos(), cli, SMBnttrans,
240 NULL, -1, /* name, fid */
241 NT_TRANSACT_GET_USER_QUOTA, 0,
242 setup, 1, 0, /* setup */
243 params, 16, 4, /* params */
244 data, data_len, 112, /* data */
245 NULL, /* recv_flags2 */
246 NULL, 0, NULL, /* rsetup */
247 &rparam, 4, &rparam_count,
248 &rdata, 8, &rdata_count);
249 if (!NT_STATUS_IS_OK(status)) {
250 DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
255 if (!parse_user_quota_record(rdata, rdata_count, &offset, pqt)) {
256 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
257 DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n"));
265 NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
266 SMB_NTQUOTA_STRUCT *pqt)
271 unsigned int sid_len;
274 memset(data,'\0',112);
277 smb_panic("cli_set_user_quota() called with NULL Pointer!");
280 SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
282 SSVAL(params,0,quota_fnum);
284 sid_len = ndr_size_dom_sid(&pqt->sid, 0);
286 SIVAL(data,4,sid_len);
287 SBIG_UINT(data, 8,(uint64_t)0);
288 SBIG_UINT(data,16,pqt->usedspace);
289 SBIG_UINT(data,24,pqt->softlim);
290 SBIG_UINT(data,32,pqt->hardlim);
291 sid_linearize(data+40, sid_len, &pqt->sid);
293 status = cli_trans(talloc_tos(), cli, SMBnttrans,
294 NULL, -1, /* name, fid */
295 NT_TRANSACT_SET_USER_QUOTA, 0,
296 setup, 1, 0, /* setup */
297 params, 2, 0, /* params */
298 data, 112, 0, /* data */
299 NULL, /* recv_flags2 */
300 NULL, 0, NULL, /* rsetup */
301 NULL, 0, NULL, /* rparams */
302 NULL, 0, NULL); /* rdata */
304 if (!NT_STATUS_IS_OK(status)) {
305 DEBUG(1, ("NT_TRANSACT_SET_USER_QUOTA failed: %s\n",
312 static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
315 SMB_NTQUOTA_LIST **pqt_list,
320 uint8_t *rparam=NULL, *rdata=NULL;
321 uint32_t rparam_count=0, rdata_count=0;
323 uint16_t op = first ? TRANSACT_GET_USER_QUOTA_LIST_START
324 : TRANSACT_GET_USER_QUOTA_LIST_CONTINUE;
326 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
327 return cli_smb2_list_user_quota_step(cli, mem_ctx, quota_fnum,
331 SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
333 SSVAL(params, 0,quota_fnum);
334 SSVAL(params, 2, op);
335 SIVAL(params, 4,0x00000000);
336 SIVAL(params, 8,0x00000000);
337 SIVAL(params,12,0x00000000);
339 status = cli_trans(talloc_tos(), cli, SMBnttrans,
340 NULL, -1, /* name, fid */
341 NT_TRANSACT_GET_USER_QUOTA, 0,
342 setup, 1, 0, /* setup */
343 params, 16, 4, /* params */
344 NULL, 0, 2048, /* data */
345 NULL, /* recv_flags2 */
346 NULL, 0, NULL, /* rsetup */
347 &rparam, 0, &rparam_count,
348 &rdata, 0, &rdata_count);
350 /* compat. with smbd + safeguard against
353 if (NT_STATUS_IS_OK(status) && rdata_count == 0) {
354 status = NT_STATUS_NO_MORE_ENTRIES;
357 if (!NT_STATUS_IS_OK(status)) {
361 status = parse_user_quota_list(rdata, rdata_count, mem_ctx, pqt_list);
370 NTSTATUS cli_list_user_quota(struct cli_state *cli,
372 SMB_NTQUOTA_LIST **pqt_list)
375 TALLOC_CTX *mem_ctx = NULL;
378 if (!cli || !pqt_list) {
379 smb_panic("cli_list_user_quota() called with NULL Pointer!");
384 if ((mem_ctx = talloc_init("SMB_USER_QUOTA_LIST")) == NULL) {
385 return NT_STATUS_NO_MEMORY;
389 status = cli_list_user_quota_step(cli, mem_ctx, quota_fnum,
392 } while (NT_STATUS_IS_OK(status));
394 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
395 status = NT_STATUS_OK;
398 if (!NT_STATUS_IS_OK(status) || *pqt_list == NULL) {
399 TALLOC_FREE(mem_ctx);
405 NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
406 SMB_NTQUOTA_STRUCT *pqt)
411 uint32_t rdata_count=0;
415 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
418 SSVAL(setup + 0, 0, TRANSACT2_QFSINFO);
420 SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
422 status = cli_trans(talloc_tos(), cli, SMBtrans2,
423 NULL, -1, /* name, fid */
424 0, 0, /* function, flags */
425 setup, 1, 0, /* setup */
426 param, 2, 0, /* param */
427 NULL, 0, 560, /* data */
428 NULL, /* recv_flags2 */
429 NULL, 0, NULL, /* rsetup */
430 NULL, 0, NULL, /* rparam */
431 &rdata, 48, &rdata_count);
433 if (!NT_STATUS_IS_OK(status)) {
434 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",
439 status = parse_fs_quota_buffer(rdata, rdata_count, pqt);
445 NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
446 SMB_NTQUOTA_STRUCT *pqt)
451 SMB_NTQUOTA_STRUCT qt;
454 memset(data,'\0',48);
457 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
460 SSVAL(setup + 0, 0,TRANSACT2_SETFSINFO);
462 SSVAL(param,0,quota_fnum);
463 SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
465 /* Unknown1 24 NULL bytes*/
467 /* Default Soft Quota 8 bytes */
468 SBIG_UINT(data,24,pqt->softlim);
470 /* Default Hard Quota 8 bytes */
471 SBIG_UINT(data,32,pqt->hardlim);
473 /* Quota flag 2 bytes */
474 SSVAL(data,40,pqt->qflags);
476 /* Unknown3 6 NULL bytes */
478 status = cli_trans(talloc_tos(), cli, SMBtrans2,
479 NULL, -1, /* name, fid */
480 0, 0, /* function, flags */
481 setup, 1, 0, /* setup */
482 param, 4, 0, /* param */
483 data, 48, 0, /* data */
484 NULL, /* recv_flags2 */
485 NULL, 0, NULL, /* rsetup */
486 NULL, 0, NULL, /* rparam */
487 NULL, 0, NULL); /* rdata */
489 if (!NT_STATUS_IS_OK(status)) {
490 DEBUG(1, ("SMB_FS_QUOTA_INFORMATION failed: %s\n",