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 2 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, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23BOOL cli_get_quota_handle(struct cli_state *cli, int *quota_fnum) 24{ 25 *quota_fnum = cli_nt_create_full(cli, FAKE_FILE_NAME_QUOTA_WIN32, 26 0x00000016, DESIRED_ACCESS_PIPE, 27 0x00000000, FILE_SHARE_READ|FILE_SHARE_WRITE, 28 FILE_OPEN, 0x00000000, 0x03); 29 30 if (*quota_fnum == (-1)) { 31 return False; 32 } 33 34 return True; 35} 36 37void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list) 38{ 39 if (!qt_list) 40 return; 41 42 if ((*qt_list)->mem_ctx) 43 talloc_destroy((*qt_list)->mem_ctx); 44 45 (*qt_list) = NULL; 46 47 return; 48} 49 50static BOOL parse_user_quota_record(const char *rdata, unsigned int rdata_count, unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt) 51{ 52 int sid_len; 53 SMB_NTQUOTA_STRUCT qt; 54 55 ZERO_STRUCT(qt); 56 57 if (!rdata||!offset||!pqt) 58 smb_panic("parse_quota_record: called with NULL POINTER!\n"); 59 60 if (rdata_count < 40) { 61 return False; 62 } 63 64 /* offset to next quota record. 65 * 4 bytes IVAL(rdata,0) 66 * unused here... 67 */ 68 *offset = IVAL(rdata,0); 69 70 /* sid len */ 71 sid_len = IVAL(rdata,4); 72 73 if (rdata_count < 40+sid_len) { 74 return False; 75 } 76 77 /* unknown 8 bytes in pdata 78 * maybe its the change time in NTTIME 79 */ 80 81 /* the used space 8 bytes (SMB_BIG_UINT)*/ 82 qt.usedspace = (SMB_BIG_UINT)IVAL(rdata,16); 83#ifdef LARGE_SMB_OFF_T 84 qt.usedspace |= (((SMB_BIG_UINT)IVAL(rdata,20)) << 32); 85#else /* LARGE_SMB_OFF_T */ 86 if ((IVAL(rdata,20) != 0)&& 87 ((qt.usedspace != 0xFFFFFFFF)|| 88 (IVAL(rdata,20)!=0xFFFFFFFF))) { 89 /* more than 32 bits? */ 90 return False; 91 } 92#endif /* LARGE_SMB_OFF_T */ 93 94 /* the soft quotas 8 bytes (SMB_BIG_UINT)*/ 95 qt.softlim = (SMB_BIG_UINT)IVAL(rdata,24); 96#ifdef LARGE_SMB_OFF_T 97 qt.softlim |= (((SMB_BIG_UINT)IVAL(rdata,28)) << 32); 98#else /* LARGE_SMB_OFF_T */ 99 if ((IVAL(rdata,28) != 0)&& 100 ((qt.softlim != 0xFFFFFFFF)|| 101 (IVAL(rdata,28)!=0xFFFFFFFF))) { 102 /* more than 32 bits? */ 103 return False; 104 } 105#endif /* LARGE_SMB_OFF_T */ 106 107 /* the hard quotas 8 bytes (SMB_BIG_UINT)*/ 108 qt.hardlim = (SMB_BIG_UINT)IVAL(rdata,32); 109#ifdef LARGE_SMB_OFF_T 110 qt.hardlim |= (((SMB_BIG_UINT)IVAL(rdata,36)) << 32); 111#else /* LARGE_SMB_OFF_T */ 112 if ((IVAL(rdata,36) != 0)&& 113 ((qt.hardlim != 0xFFFFFFFF)|| 114 (IVAL(rdata,36)!=0xFFFFFFFF))) { 115 /* more than 32 bits? */ 116 return False; 117 } 118#endif /* LARGE_SMB_OFF_T */ 119 120 sid_parse(rdata+40,sid_len,&qt.sid); 121 122 qt.qtype = SMB_USER_QUOTA_TYPE; 123 124 *pqt = qt; 125 126 return True; 127} 128 129BOOL cli_get_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt) 130{ 131 BOOL ret = False; 132 uint16 setup; 133 char params[16]; 134 unsigned int data_len; 135 char data[SID_MAX_SIZE+8]; 136 char *rparam=NULL, *rdata=NULL; 137 unsigned int rparam_count=0, rdata_count=0; 138 unsigned int sid_len; 139 unsigned int offset; 140 141 if (!cli||!pqt) 142 smb_panic("cli_get_user_quota() called with NULL Pointer!"); 143 144 setup = NT_TRANSACT_GET_USER_QUOTA; 145 146 SSVAL(params, 0,quota_fnum); 147 SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID); 148 SIVAL(params, 4,0x00000024); 149 SIVAL(params, 8,0x00000000); 150 SIVAL(params,12,0x00000024); 151 152 sid_len = sid_size(&pqt->sid); 153 data_len = sid_len+8; 154 SIVAL(data, 0, 0x00000000); 155 SIVAL(data, 4, sid_len); 156 sid_linearize(data+8, sid_len, &pqt->sid); 157 158 if (!cli_send_nt_trans(cli, 159 NT_TRANSACT_GET_USER_QUOTA, 160 0, 161 &setup, 1, 0, 162 params, 16, 4, 163 data, data_len, 112)) { 164 DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n")); 165 goto cleanup; 166 } 167 168 169 if (!cli_receive_nt_trans(cli, 170 &rparam, &rparam_count, 171 &rdata, &rdata_count)) { 172 DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n")); 173 goto cleanup; 174 } 175 176 if (cli_is_error(cli)) { 177 ret = False; 178 goto cleanup; 179 } else { 180 ret = True; 181 } 182 183 if ((rparam&&rdata)&&(rparam_count>=4&&rdata_count>=8)) { 184 ret = parse_user_quota_record(rdata, rdata_count, &offset, pqt); 185 } else { 186 DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n")); 187 ret = False; 188 } 189 190 cleanup: 191 SAFE_FREE(rparam); 192 SAFE_FREE(rdata); 193 return ret; 194} 195 196BOOL cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt) 197{ 198 BOOL ret = False; 199 uint16 setup; 200 char params[2]; 201 char data[112]; 202 char *rparam=NULL, *rdata=NULL; 203 unsigned int rparam_count=0, rdata_count=0; 204 unsigned int sid_len; 205 memset(data,'\0',112); 206 207 if (!cli||!pqt) 208 smb_panic("cli_set_user_quota() called with NULL Pointer!"); 209 210 setup = NT_TRANSACT_SET_USER_QUOTA; 211 212 SSVAL(params,0,quota_fnum); 213 214 sid_len = sid_size(&pqt->sid); 215 SIVAL(data,0,0); 216 SIVAL(data,4,sid_len); 217 SBIG_UINT(data, 8,(SMB_BIG_UINT)0); 218 SBIG_UINT(data,16,pqt->usedspace); 219 SBIG_UINT(data,24,pqt->softlim); 220 SBIG_UINT(data,32,pqt->hardlim); 221 sid_linearize(data+40, sid_len, &pqt->sid); 222 223 if (!cli_send_nt_trans(cli, 224 NT_TRANSACT_SET_USER_QUOTA, 225 0, 226 &setup, 1, 0, 227 params, 2, 0, 228 data, 112, 0)) { 229 DEBUG(1,("Failed to send NT_TRANSACT_SET_USER_QUOTA\n")); 230 goto cleanup; 231 } 232 233 234 if (!cli_receive_nt_trans(cli, 235 &rparam, &rparam_count, 236 &rdata, &rdata_count)) { 237 DEBUG(1,("NT_TRANSACT_SET_USER_QUOTA failed\n")); 238 goto cleanup; 239 } 240 241 if (cli_is_error(cli)) { 242 ret = False; 243 goto cleanup; 244 } else { 245 ret = True; 246 } 247 248 cleanup: 249 SAFE_FREE(rparam); 250 SAFE_FREE(rdata); 251 return ret; 252} 253 254BOOL cli_list_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST **pqt_list) 255{ 256 BOOL ret = False; 257 uint16 setup; 258 char params[16]; 259 char *rparam=NULL, *rdata=NULL; 260 unsigned int rparam_count=0, rdata_count=0; 261 unsigned int offset; 262 const char *curdata = NULL; 263 unsigned int curdata_count = 0; 264 TALLOC_CTX *mem_ctx = NULL; 265 SMB_NTQUOTA_STRUCT qt; 266 SMB_NTQUOTA_LIST *tmp_list_ent; 267 268 if (!cli||!pqt_list) 269 smb_panic("cli_list_user_quota() called with NULL Pointer!"); 270 271 setup = NT_TRANSACT_GET_USER_QUOTA; 272 273 SSVAL(params, 0,quota_fnum); 274 SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START); 275 SIVAL(params, 4,0x00000000); 276 SIVAL(params, 8,0x00000000); 277 SIVAL(params,12,0x00000000); 278 279 if (!cli_send_nt_trans(cli, 280 NT_TRANSACT_GET_USER_QUOTA, 281 0, 282 &setup, 1, 0, 283 params, 16, 4, 284 NULL, 0, 2048)) { 285 DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n")); 286 goto cleanup; 287 } 288 289 290 if (!cli_receive_nt_trans(cli, 291 &rparam, &rparam_count, 292 &rdata, &rdata_count)) { 293 DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n")); 294 goto cleanup; 295 } 296 297 if (cli_is_error(cli)) { 298 ret = False; 299 goto cleanup; 300 } else { 301 ret = True; 302 } 303 304 if (rdata_count == 0) { 305 *pqt_list = NULL; 306 return True; 307 } 308 309 if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) { 310 DEBUG(0,("talloc_init() failed\n")); 311 return (-1); 312 } 313 314 offset = 1; 315 for (curdata=rdata,curdata_count=rdata_count; 316 ((curdata)&&(curdata_count>=8)&&(offset>0)); 317 curdata +=offset,curdata_count -= offset) { 318 ZERO_STRUCT(qt); 319 if (!parse_user_quota_record(curdata, curdata_count, &offset, &qt)) { 320 DEBUG(1,("Failed to parse the quota record\n")); 321 goto cleanup; 322 } 323 324 if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) { 325 DEBUG(0,("talloc_zero() failed\n")); 326 return (-1); 327 } 328 329 if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) { 330 DEBUG(0,("talloc_zero() failed\n")); 331 return (-1); 332 } 333 334 memcpy(tmp_list_ent->quotas,&qt,sizeof(qt)); 335 tmp_list_ent->mem_ctx = mem_ctx; 336 337 DLIST_ADD((*pqt_list),tmp_list_ent); 338 } 339 340 SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_CONTINUE); 341 while(1) { 342 if (!cli_send_nt_trans(cli, 343 NT_TRANSACT_GET_USER_QUOTA, 344 0, 345 &setup, 1, 0, 346 params, 16, 4, 347 NULL, 0, 2048)) { 348 DEBUG(1,("Failed to send NT_TRANSACT_GET_USER_QUOTA\n")); 349 goto cleanup; 350 } 351 352 SAFE_FREE(rparam); 353 SAFE_FREE(rdata); 354 if (!cli_receive_nt_trans(cli, 355 &rparam, &rparam_count, 356 &rdata, &rdata_count)) { 357 DEBUG(1,("Failed to recv NT_TRANSACT_GET_USER_QUOTA\n")); 358 goto cleanup; 359 } 360 361 if (cli_is_error(cli)) { 362 ret = False; 363 goto cleanup; 364 } else { 365 ret = True; 366 } 367 368 if (rdata_count == 0) { 369 break; 370 } 371 372 offset = 1; 373 for (curdata=rdata,curdata_count=rdata_count; 374 ((curdata)&&(curdata_count>=8)&&(offset>0)); 375 curdata +=offset,curdata_count -= offset) { 376 ZERO_STRUCT(qt); 377 if (!parse_user_quota_record(curdata, curdata_count, &offset, &qt)) { 378 DEBUG(1,("Failed to parse the quota record\n")); 379 goto cleanup; 380 } 381 382 if ((tmp_list_ent=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_LIST))==NULL) { 383 DEBUG(0,("talloc_zero() failed\n")); 384 talloc_destroy(mem_ctx); 385 goto cleanup; 386 } 387 388 if ((tmp_list_ent->quotas=TALLOC_ZERO_P(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) { 389 DEBUG(0,("talloc_zero() failed\n")); 390 talloc_destroy(mem_ctx); 391 goto cleanup; 392 } 393 394 memcpy(tmp_list_ent->quotas,&qt,sizeof(qt)); 395 tmp_list_ent->mem_ctx = mem_ctx; 396 397 DLIST_ADD((*pqt_list),tmp_list_ent); 398 } 399 } 400 401 402 ret = True; 403 cleanup: 404 SAFE_FREE(rparam); 405 SAFE_FREE(rdata); 406 407 return ret; 408} 409 410BOOL cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt) 411{ 412 BOOL ret = False; 413 uint16 setup; 414 char param[2]; 415 char *rparam=NULL, *rdata=NULL; 416 unsigned int rparam_count=0, rdata_count=0; 417 SMB_NTQUOTA_STRUCT qt; 418 ZERO_STRUCT(qt); 419 420 if (!cli||!pqt) 421 smb_panic("cli_get_fs_quota_info() called with NULL Pointer!"); 422 423 setup = TRANSACT2_QFSINFO; 424 425 SSVAL(param,0,SMB_FS_QUOTA_INFORMATION); 426 427 if (!cli_send_trans(cli, SMBtrans2, 428 NULL, 429 0, 0, 430 &setup, 1, 0, 431 param, 2, 0, 432 NULL, 0, 560)) { 433 goto cleanup; 434 } 435 436 if (!cli_receive_trans(cli, SMBtrans2, 437 &rparam, &rparam_count, 438 &rdata, &rdata_count)) { 439 goto cleanup; 440 } 441 442 if (cli_is_error(cli)) { 443 ret = False; 444 goto cleanup; 445 } else { 446 ret = True; 447 } 448 449 if (rdata_count < 48) { 450 goto cleanup; 451 } 452 453 /* unknown_1 24 NULL bytes in pdata*/ 454 455 /* the soft quotas 8 bytes (SMB_BIG_UINT)*/ 456 qt.softlim = (SMB_BIG_UINT)IVAL(rdata,24); 457#ifdef LARGE_SMB_OFF_T 458 qt.softlim |= (((SMB_BIG_UINT)IVAL(rdata,28)) << 32); 459#else /* LARGE_SMB_OFF_T */ 460 if ((IVAL(rdata,28) != 0)&& 461 ((qt.softlim != 0xFFFFFFFF)|| 462 (IVAL(rdata,28)!=0xFFFFFFFF))) { 463 /* more than 32 bits? */ 464 goto cleanup; 465 } 466#endif /* LARGE_SMB_OFF_T */ 467 468 /* the hard quotas 8 bytes (SMB_BIG_UINT)*/ 469 qt.hardlim = (SMB_BIG_UINT)IVAL(rdata,32); 470#ifdef LARGE_SMB_OFF_T 471 qt.hardlim |= (((SMB_BIG_UINT)IVAL(rdata,36)) << 32); 472#else /* LARGE_SMB_OFF_T */ 473 if ((IVAL(rdata,36) != 0)&& 474 ((qt.hardlim != 0xFFFFFFFF)|| 475 (IVAL(rdata,36)!=0xFFFFFFFF))) { 476 /* more than 32 bits? */ 477 goto cleanup; 478 } 479#endif /* LARGE_SMB_OFF_T */ 480 481 /* quota_flags 2 bytes **/ 482 qt.qflags = SVAL(rdata,40); 483 484 qt.qtype = SMB_USER_FS_QUOTA_TYPE; 485 486 *pqt = qt; 487 488 ret = True; 489cleanup: 490 SAFE_FREE(rparam); 491 SAFE_FREE(rdata); 492 493 return ret; 494} 495 496BOOL cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt) 497{ 498 BOOL ret = False; 499 uint16 setup; 500 char param[4]; 501 char data[48]; 502 char *rparam=NULL, *rdata=NULL; 503 unsigned int rparam_count=0, rdata_count=0; 504 SMB_NTQUOTA_STRUCT qt; 505 ZERO_STRUCT(qt); 506 memset(data,'\0',48); 507 508 if (!cli||!pqt) 509 smb_panic("cli_set_fs_quota_info() called with NULL Pointer!"); 510 511 setup = TRANSACT2_SETFSINFO; 512 513 SSVAL(param,0,quota_fnum); 514 SSVAL(param,2,SMB_FS_QUOTA_INFORMATION); 515 516 /* Unknown1 24 NULL bytes*/ 517 518 /* Default Soft Quota 8 bytes */ 519 SBIG_UINT(data,24,pqt->softlim); 520 521 /* Default Hard Quota 8 bytes */ 522 SBIG_UINT(data,32,pqt->hardlim); 523 524 /* Quota flag 2 bytes */ 525 SSVAL(data,40,pqt->qflags); 526 527 /* Unknown3 6 NULL bytes */ 528 529 if (!cli_send_trans(cli, SMBtrans2, 530 NULL, 531 0, 0, 532 &setup, 1, 0, 533 param, 4, 0, 534 data, 48, 0)) { 535 goto cleanup; 536 } 537 538 if (!cli_receive_trans(cli, SMBtrans2, 539 &rparam, &rparam_count, 540 &rdata, &rdata_count)) { 541 goto cleanup; 542 } 543 544 if (cli_is_error(cli)) { 545 ret = False; 546 goto cleanup; 547 } else { 548 ret = True; 549 } 550 551cleanup: 552 SAFE_FREE(rparam); 553 SAFE_FREE(rdata); 554 555 return ret; 556} 557 558static char *quota_str_static(SMB_BIG_UINT val, BOOL special, BOOL _numeric) 559{ 560 static fstring buffer; 561 562 memset(buffer,'\0',sizeof(buffer)); 563 564 if (!_numeric&&special&&(val == SMB_NTQUOTAS_NO_LIMIT)) { 565 fstr_sprintf(buffer,"NO LIMIT"); 566 return buffer; 567 } 568#if defined(HAVE_LONGLONG) 569 fstr_sprintf(buffer,"%llu",val); 570#else 571 fstr_sprintf(buffer,"%lu",val); 572#endif 573 return buffer; 574} 575 576void dump_ntquota(SMB_NTQUOTA_STRUCT *qt, BOOL _verbose, BOOL _numeric, void (*_sidtostring)(fstring str, DOM_SID *sid, BOOL _numeric)) 577{ 578 if (!qt) 579 smb_panic("dump_ntquota() called with NULL pointer"); 580 581 switch (qt->qtype) { 582 case SMB_USER_FS_QUOTA_TYPE: 583 { 584 d_printf("File System QUOTAS:\n"); 585 d_printf("Limits:\n"); 586 d_printf(" Default Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric)); 587 d_printf(" Default Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric)); 588 d_printf("Quota Flags:\n"); 589 d_printf(" Quotas Enabled: %s\n", 590 ((qt->qflags"AS_ENABLED)||(qt->qflags"AS_DENY_DISK))?"On":"Off"); 591 d_printf(" Deny Disk: %s\n",(qt->qflags"AS_DENY_DISK)?"On":"Off"); 592 d_printf(" Log Soft Limit: %s\n",(qt->qflags"AS_LOG_THRESHOLD)?"On":"Off"); 593 d_printf(" Log Hard Limit: %s\n",(qt->qflags"AS_LOG_LIMIT)?"On":"Off"); 594 } 595 break; 596 case SMB_USER_QUOTA_TYPE: 597 { 598 fstring username_str = {0}; 599 600 if (_sidtostring) { 601 _sidtostring(username_str,&qt->sid,_numeric); 602 } else { 603 fstrcpy(username_str,sid_string_static(&qt->sid)); 604 } 605 606 if (_verbose) { 607 d_printf("Quotas for User: %s\n",username_str); 608 d_printf("Used Space: %15s\n",quota_str_static(qt->usedspace,False,_numeric)); 609 d_printf("Soft Limit: %15s\n",quota_str_static(qt->softlim,True,_numeric)); 610 d_printf("Hard Limit: %15s\n",quota_str_static(qt->hardlim,True,_numeric)); 611 } else { 612 d_printf("%-30s: ",username_str); 613 d_printf("%15s/",quota_str_static(qt->usedspace,False,_numeric)); 614 d_printf("%15s/",quota_str_static(qt->softlim,True,_numeric)); 615 d_printf("%15s\n",quota_str_static(qt->hardlim,True,_numeric)); 616 } 617 } 618 break; 619 default: 620 d_printf("dump_ntquota() invalid qtype(%d)\n",qt->qtype); 621 return; 622 } 623} 624 625void dump_ntquota_list(SMB_NTQUOTA_LIST **qtl, BOOL _verbose, BOOL _numeric, void (*_sidtostring)(fstring str, DOM_SID *sid, BOOL _numeric)) 626{ 627 SMB_NTQUOTA_LIST *cur; 628 629 for (cur = *qtl;cur;cur = cur->next) { 630 if (cur->quotas) 631 dump_ntquota(cur->quotas,_verbose,_numeric,_sidtostring); 632 } 633} 634