1 /* 2 * ReactOS Control ACLs Program 3 * Copyright (C) 2006 Thomas Weidenmueller 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #include "precomp.h" 21 22 /* command line options */ 23 BOOL OptionT = FALSE, OptionE = FALSE, OptionC = FALSE; 24 BOOL OptionG = FALSE, OptionR = FALSE, OptionP = FALSE, OptionD = FALSE; 25 LPCTSTR GUser, GPerm, RUser, PUser, PPerm, DUser; 26 27 static GENERIC_MAPPING FileGenericMapping = 28 { 29 FILE_GENERIC_READ, 30 FILE_GENERIC_WRITE, 31 FILE_GENERIC_EXECUTE, 32 FILE_ALL_ACCESS 33 }; 34 35 36 static VOID 37 PrintError(DWORD dwError) 38 { 39 if (dwError == ERROR_SUCCESS) 40 return; 41 42 ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM, 43 NULL, dwError, LANG_USER_DEFAULT); 44 } 45 46 static BOOL 47 PrintFileDacl(IN LPTSTR FilePath, 48 IN LPTSTR FileName) 49 { 50 SIZE_T Length; 51 PSECURITY_DESCRIPTOR SecurityDescriptor; 52 DWORD SDSize = 0; 53 TCHAR FullFileName[MAX_PATH + 1]; 54 BOOL Error = FALSE, Ret = FALSE; 55 56 Length = _tcslen(FilePath) + _tcslen(FileName); 57 if (Length > MAX_PATH) 58 { 59 /* file name too long */ 60 SetLastError(ERROR_FILE_NOT_FOUND); 61 return FALSE; 62 } 63 64 _tcscpy(FullFileName, FilePath); 65 _tcscat(FullFileName, FileName); 66 67 /* find out how much memory we need */ 68 if (!GetFileSecurity(FullFileName, 69 DACL_SECURITY_INFORMATION, 70 NULL, 71 0, 72 &SDSize) && 73 GetLastError() != ERROR_INSUFFICIENT_BUFFER) 74 { 75 return FALSE; 76 } 77 78 SecurityDescriptor = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), 79 0, 80 SDSize); 81 if (SecurityDescriptor != NULL) 82 { 83 if (GetFileSecurity(FullFileName, 84 DACL_SECURITY_INFORMATION, 85 SecurityDescriptor, 86 SDSize, 87 &SDSize)) 88 { 89 PACL Dacl; 90 BOOL DaclPresent; 91 BOOL DaclDefaulted; 92 93 if (GetSecurityDescriptorDacl(SecurityDescriptor, 94 &DaclPresent, 95 &Dacl, 96 &DaclDefaulted)) 97 { 98 if (DaclPresent) 99 { 100 PACCESS_ALLOWED_ACE Ace; 101 DWORD AceIndex = 0; 102 103 /* dump the ACL */ 104 while (GetAce(Dacl, 105 AceIndex, 106 (PVOID*)&Ace)) 107 { 108 SID_NAME_USE Use; 109 DWORD NameSize = 0; 110 DWORD DomainSize = 0; 111 LPTSTR Name = NULL; 112 LPTSTR Domain = NULL; 113 LPTSTR SidString = NULL; 114 DWORD IndentAccess; 115 DWORD AccessMask = Ace->Mask; 116 PSID Sid = (PSID)&Ace->SidStart; 117 118 /* attempt to translate the SID into a readable string */ 119 if (!LookupAccountSid(NULL, 120 Sid, 121 Name, 122 &NameSize, 123 Domain, 124 &DomainSize, 125 &Use)) 126 { 127 if (GetLastError() == ERROR_NONE_MAPPED || NameSize == 0) 128 { 129 goto BuildSidString; 130 } 131 else 132 { 133 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 134 { 135 Error = TRUE; 136 break; 137 } 138 139 Name = (LPTSTR)HeapAlloc(GetProcessHeap(), 140 0, 141 (NameSize + DomainSize) * sizeof(TCHAR)); 142 if (Name == NULL) 143 { 144 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 145 Error = TRUE; 146 break; 147 } 148 149 Domain = Name + NameSize; 150 Name[0] = _T('\0'); 151 if (DomainSize != 0) 152 Domain[0] = _T('\0'); 153 if (!LookupAccountSid(NULL, 154 Sid, 155 Name, 156 &NameSize, 157 Domain, 158 &DomainSize, 159 &Use)) 160 { 161 HeapFree(GetProcessHeap(), 162 0, 163 Name); 164 Name = NULL; 165 goto BuildSidString; 166 } 167 } 168 } 169 else 170 { 171 BuildSidString: 172 if (!ConvertSidToStringSid(Sid, 173 &SidString)) 174 { 175 Error = TRUE; 176 break; 177 } 178 } 179 180 /* print the file name or space */ 181 ConPrintf(StdOut, L"%s ", FullFileName); 182 183 /* attempt to map the SID to a user name */ 184 if (AceIndex == 0) 185 { 186 DWORD i = 0; 187 188 /* overwrite the full file name with spaces so we 189 only print the file name once */ 190 while (FullFileName[i] != _T('\0')) 191 FullFileName[i++] = _T(' '); 192 } 193 194 /* print the domain and/or user if possible, or the SID string */ 195 if (Name != NULL && Domain[0] != _T('\0')) 196 { 197 ConPrintf(StdOut, L"%s\\%s:", Domain, Name); 198 IndentAccess = (DWORD)_tcslen(Domain) + _tcslen(Name); 199 } 200 else 201 { 202 LPTSTR DisplayString = (Name != NULL ? Name : SidString); 203 204 ConPrintf(StdOut, L"%s:", DisplayString); 205 IndentAccess = (DWORD)_tcslen(DisplayString); 206 } 207 208 /* print the ACE Flags */ 209 if (Ace->Header.AceFlags & CONTAINER_INHERIT_ACE) 210 { 211 IndentAccess += ConResPuts(StdOut, IDS_ABBR_CI); 212 } 213 if (Ace->Header.AceFlags & OBJECT_INHERIT_ACE) 214 { 215 IndentAccess += ConResPuts(StdOut, IDS_ABBR_OI); 216 } 217 if (Ace->Header.AceFlags & INHERIT_ONLY_ACE) 218 { 219 IndentAccess += ConResPuts(StdOut, IDS_ABBR_IO); 220 } 221 222 IndentAccess += 2; 223 224 /* print the access rights */ 225 MapGenericMask(&AccessMask, 226 &FileGenericMapping); 227 if (Ace->Header.AceType & ACCESS_DENIED_ACE_TYPE) 228 { 229 if (AccessMask == FILE_ALL_ACCESS) 230 { 231 ConResPuts(StdOut, IDS_ABBR_NONE); 232 } 233 else 234 { 235 ConResPuts(StdOut, IDS_DENY); 236 goto PrintSpecialAccess; 237 } 238 } 239 else 240 { 241 if (AccessMask == FILE_ALL_ACCESS) 242 { 243 ConResPuts(StdOut, IDS_ABBR_FULL); 244 } 245 else if (!(Ace->Mask & (GENERIC_READ | GENERIC_EXECUTE)) && 246 AccessMask == (FILE_GENERIC_READ | FILE_EXECUTE)) 247 { 248 ConResPuts(StdOut, IDS_ABBR_READ); 249 } 250 else if (AccessMask == (FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_EXECUTE | DELETE)) 251 { 252 ConResPuts(StdOut, IDS_ABBR_CHANGE); 253 } 254 else if (AccessMask == FILE_GENERIC_WRITE) 255 { 256 ConResPuts(StdOut, IDS_ABBR_WRITE); 257 } 258 else 259 { 260 DWORD x, x2; 261 static const struct 262 { 263 DWORD Access; 264 UINT uID; 265 } 266 AccessRights[] = 267 { 268 {FILE_WRITE_ATTRIBUTES, IDS_FILE_WRITE_ATTRIBUTES}, 269 {FILE_READ_ATTRIBUTES, IDS_FILE_READ_ATTRIBUTES}, 270 {FILE_DELETE_CHILD, IDS_FILE_DELETE_CHILD}, 271 {FILE_EXECUTE, IDS_FILE_EXECUTE}, 272 {FILE_WRITE_EA, IDS_FILE_WRITE_EA}, 273 {FILE_READ_EA, IDS_FILE_READ_EA}, 274 {FILE_APPEND_DATA, IDS_FILE_APPEND_DATA}, 275 {FILE_WRITE_DATA, IDS_FILE_WRITE_DATA}, 276 {FILE_READ_DATA, IDS_FILE_READ_DATA}, 277 {FILE_GENERIC_EXECUTE, IDS_FILE_GENERIC_EXECUTE}, 278 {FILE_GENERIC_WRITE, IDS_FILE_GENERIC_WRITE}, 279 {FILE_GENERIC_READ, IDS_FILE_GENERIC_READ}, 280 {GENERIC_ALL, IDS_GENERIC_ALL}, 281 {GENERIC_EXECUTE, IDS_GENERIC_EXECUTE}, 282 {GENERIC_WRITE, IDS_GENERIC_WRITE}, 283 {GENERIC_READ, IDS_GENERIC_READ}, 284 {MAXIMUM_ALLOWED, IDS_MAXIMUM_ALLOWED}, 285 {ACCESS_SYSTEM_SECURITY, IDS_ACCESS_SYSTEM_SECURITY}, 286 {SPECIFIC_RIGHTS_ALL, IDS_SPECIFIC_RIGHTS_ALL}, 287 {STANDARD_RIGHTS_REQUIRED, IDS_STANDARD_RIGHTS_REQUIRED}, 288 {SYNCHRONIZE, IDS_SYNCHRONIZE}, 289 {WRITE_OWNER, IDS_WRITE_OWNER}, 290 {WRITE_DAC, IDS_WRITE_DAC}, 291 {READ_CONTROL, IDS_READ_CONTROL}, 292 {DELETE, IDS_DELETE}, 293 {STANDARD_RIGHTS_ALL, IDS_STANDARD_RIGHTS_ALL}, 294 }; 295 296 ConResPuts(StdOut, IDS_ALLOW); 297 298 PrintSpecialAccess: 299 ConResPuts(StdOut, IDS_SPECIAL_ACCESS); 300 301 /* print the special access rights */ 302 x = ARRAYSIZE(AccessRights); 303 while (x-- != 0) 304 { 305 if ((Ace->Mask & AccessRights[x].Access) == AccessRights[x].Access) 306 { 307 ConPrintf(StdOut, L"\n%s ", FullFileName); 308 for (x2 = 0; x2 < IndentAccess; x2++) 309 { 310 ConPuts(StdOut, L" "); 311 } 312 313 ConResPuts(StdOut, AccessRights[x].uID); 314 } 315 } 316 317 ConPuts(StdOut, L"\n"); 318 } 319 } 320 321 ConPuts(StdOut, L"\n"); 322 323 /* free up all resources */ 324 if (Name != NULL) 325 { 326 HeapFree(GetProcessHeap(), 327 0, 328 Name); 329 } 330 331 if (SidString != NULL) 332 { 333 LocalFree((HLOCAL)SidString); 334 } 335 336 AceIndex++; 337 } 338 339 if (!Error) 340 Ret = TRUE; 341 } 342 else 343 { 344 SetLastError(ERROR_NO_SECURITY_ON_OBJECT); 345 } 346 } 347 } 348 349 HeapFree(GetProcessHeap(), 350 0, 351 SecurityDescriptor); 352 } 353 else 354 { 355 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 356 } 357 358 return Ret; 359 } 360 361 /* add a backslash at end to a path string if necessary */ 362 static VOID 363 AddBackslash(LPTSTR FilePath) 364 { 365 INT len = lstrlen(FilePath); 366 LPTSTR pch = CharPrev(FilePath, FilePath + len); 367 if (*pch != _T('\\')) 368 lstrcat(pch, _T("\\")); 369 } 370 371 static BOOL 372 GetPathOfFile(LPTSTR FilePath, LPCTSTR pszFiles) 373 { 374 TCHAR FullPath[MAX_PATH]; 375 LPTSTR pch; 376 DWORD attrs; 377 378 lstrcpyn(FilePath, pszFiles, MAX_PATH); 379 pch = _tcsrchr(FilePath, _T('\\')); 380 if (pch != NULL) 381 { 382 *pch = 0; 383 if (!GetFullPathName(FilePath, MAX_PATH, FullPath, NULL)) 384 { 385 PrintError(GetLastError()); 386 return FALSE; 387 } 388 lstrcpyn(FilePath, FullPath, MAX_PATH); 389 390 attrs = GetFileAttributes(FilePath); 391 if (attrs == 0xFFFFFFFF || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) 392 { 393 PrintError(ERROR_DIRECTORY); 394 return FALSE; 395 } 396 } 397 else 398 GetCurrentDirectory(MAX_PATH, FilePath); 399 400 AddBackslash(FilePath); 401 return TRUE; 402 } 403 404 static BOOL 405 PrintDaclsOfFiles(LPCTSTR pszFiles) 406 { 407 TCHAR FilePath[MAX_PATH]; 408 WIN32_FIND_DATA FindData; 409 HANDLE hFind; 410 DWORD LastError; 411 412 /* 413 * get the file path 414 */ 415 if (!GetPathOfFile(FilePath, pszFiles)) 416 return FALSE; 417 418 /* 419 * search for the files 420 */ 421 hFind = FindFirstFile(pszFiles, &FindData); 422 if (hFind == INVALID_HANDLE_VALUE) 423 return FALSE; 424 425 do 426 { 427 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 428 continue; 429 430 if (!PrintFileDacl(FilePath, FindData.cFileName)) 431 { 432 LastError = GetLastError(); 433 if (LastError == ERROR_ACCESS_DENIED) 434 { 435 PrintError(LastError); 436 if (!OptionC) 437 { 438 FindClose(hFind); 439 return FALSE; 440 } 441 } 442 else 443 { 444 break; 445 } 446 } 447 else 448 { 449 ConPuts(StdOut, L"\n"); 450 } 451 } while(FindNextFile(hFind, &FindData)); 452 LastError = GetLastError(); 453 FindClose(hFind); 454 455 if (LastError != ERROR_NO_MORE_FILES) 456 { 457 PrintError(LastError); 458 return FALSE; 459 } 460 461 return TRUE; 462 } 463 464 static BOOL 465 GrantUserAccessRights(LPCTSTR FilePath, LPCTSTR File, LPCTSTR User, TCHAR Perm) 466 { 467 /* TODO & FIXME */ 468 switch(Perm) 469 { 470 case _T('R'): // Read 471 break; 472 case _T('W'): // Write 473 break; 474 case _T('C'): // Change (write) 475 break; 476 case _T('F'): // Full control 477 break; 478 default: 479 break; 480 } 481 return FALSE; 482 } 483 484 static BOOL 485 ReplaceUserAccessRights( 486 LPCTSTR FilePath, 487 LPCTSTR File, 488 LPCTSTR User, 489 TCHAR Perm) 490 { 491 /* TODO & FIXME */ 492 switch(Perm) 493 { 494 case _T('N'): // None 495 break; 496 case _T('R'): // Read 497 break; 498 case _T('W'): // Write 499 break; 500 case _T('C'): // Change (write) 501 break; 502 case _T('F'): // Full control 503 break; 504 default: 505 break; 506 } 507 return FALSE; 508 } 509 510 static BOOL 511 EditUserAccessRights( 512 LPCTSTR FilePath, 513 LPCTSTR File, 514 LPCTSTR User, 515 TCHAR Perm) 516 { 517 /* TODO & FIXME */ 518 switch(Perm) 519 { 520 case _T('N'): // None 521 break; 522 case _T('R'): // Read 523 break; 524 case _T('W'): // Write 525 break; 526 case _T('C'): // Change (write) 527 break; 528 case _T('F'): // Full control 529 break; 530 default: 531 break; 532 } 533 return FALSE; 534 } 535 536 static BOOL 537 DenyUserAccess(LPCTSTR FilePath, LPCTSTR File, LPCTSTR User) 538 { 539 /* TODO & FIXME */ 540 return FALSE; 541 } 542 543 static BOOL 544 RevokeUserAccessRights(LPCTSTR FilePath, LPCTSTR File, LPCTSTR User) 545 { 546 /* TODO & FIXME */ 547 return FALSE; 548 } 549 550 static BOOL 551 ChangeFileACL(LPCTSTR FilePath, LPCTSTR File) 552 { 553 if (OptionG) 554 { 555 /* Grant specified user access rights. */ 556 GrantUserAccessRights(FilePath, File, GUser, *GPerm); 557 } 558 559 if (OptionP) 560 { 561 if (!OptionE) 562 { 563 /* Replace specified user's access rights. */ 564 ReplaceUserAccessRights(FilePath, File, PUser, *PPerm); 565 } 566 else 567 { 568 /* Edit ACL instead of replacing it. */ 569 EditUserAccessRights(FilePath, File, PUser, *PPerm); 570 } 571 } 572 573 if (OptionD) 574 { 575 /* Deny specified user access. */ 576 DenyUserAccess(FilePath, File, DUser); 577 } 578 579 if (OptionR) 580 { 581 /* Revoke specified user's access rights. */ 582 RevokeUserAccessRights(FilePath, File, RUser); 583 } 584 585 return TRUE; 586 } 587 588 static BOOL 589 ChangeACLsOfFiles(LPCTSTR pszFiles) 590 { 591 TCHAR FilePath[MAX_PATH]; 592 HANDLE hFind; 593 WIN32_FIND_DATA FindData; 594 DWORD LastError; 595 596 /* 597 * get the file path 598 */ 599 if (!GetPathOfFile(FilePath, pszFiles)) 600 return FALSE; 601 602 /* 603 * search for files in current directory 604 */ 605 hFind = FindFirstFile(pszFiles, &FindData); 606 if (hFind == INVALID_HANDLE_VALUE) 607 return FALSE; 608 609 do 610 { 611 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 612 continue; 613 614 if (!ChangeFileACL(FilePath, FindData.cFileName)) 615 { 616 LastError = GetLastError(); 617 if (LastError == ERROR_ACCESS_DENIED) 618 { 619 PrintError(LastError); 620 if (!OptionC) 621 { 622 FindClose(hFind); 623 return FALSE; 624 } 625 } 626 else 627 break; 628 } 629 } while(FindNextFile(hFind, &FindData)); 630 631 LastError = GetLastError(); 632 FindClose(hFind); 633 634 if (LastError != ERROR_NO_MORE_FILES) 635 { 636 PrintError(LastError); 637 return FALSE; 638 } 639 640 return TRUE; 641 } 642 643 static BOOL 644 ChangeACLsOfFilesInCurDir(LPCTSTR pszFiles) 645 { 646 HANDLE hFind; 647 WIN32_FIND_DATA FindData; 648 TCHAR szCurDir[MAX_PATH]; 649 DWORD LastError; 650 651 /* 652 * get the file path (current directory) 653 */ 654 GetCurrentDirectory(MAX_PATH, szCurDir); 655 AddBackslash(szCurDir); 656 657 /* 658 * search for files in current directory 659 */ 660 hFind = FindFirstFile(pszFiles, &FindData); 661 if (hFind == INVALID_HANDLE_VALUE) 662 return FALSE; 663 664 do 665 { 666 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 667 continue; 668 669 if (!ChangeFileACL(szCurDir, FindData.cFileName)) 670 { 671 LastError = GetLastError(); 672 if (LastError == ERROR_ACCESS_DENIED) 673 { 674 PrintError(LastError); 675 if (!OptionC) 676 { 677 FindClose(hFind); 678 return FALSE; 679 } 680 } 681 else 682 break; 683 } 684 } while(FindNextFile(hFind, &FindData)); 685 686 LastError = GetLastError(); 687 FindClose(hFind); 688 689 if (LastError != ERROR_NO_MORE_FILES) 690 { 691 PrintError(LastError); 692 return FALSE; 693 } 694 695 /* 696 * search for subdirectory in current directory 697 */ 698 hFind = FindFirstFile(_T("*"), &FindData); 699 if (hFind == INVALID_HANDLE_VALUE) 700 return FALSE; 701 do 702 { 703 if (_tcscmp(FindData.cFileName, _T(".")) == 0 || 704 _tcscmp(FindData.cFileName, _T("..")) == 0) 705 continue; 706 707 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 708 { 709 GetCurrentDirectory(MAX_PATH, szCurDir); 710 if (SetCurrentDirectory(FindData.cFileName)) 711 { 712 ChangeACLsOfFilesInCurDir(pszFiles); 713 SetCurrentDirectory(szCurDir); 714 } 715 else 716 { 717 LastError = GetLastError(); 718 if (LastError == ERROR_ACCESS_DENIED) 719 { 720 PrintError(LastError); 721 if (!OptionC) 722 { 723 FindClose(hFind); 724 return FALSE; 725 } 726 } 727 else 728 break; 729 } 730 } 731 } while(FindNextFile(hFind, &FindData)); 732 LastError = GetLastError(); 733 FindClose(hFind); 734 735 if (LastError != ERROR_NO_MORE_FILES) 736 { 737 PrintError(LastError); 738 return FALSE; 739 } 740 return TRUE; 741 } 742 743 int _tmain(int argc, const TCHAR *argv[]) 744 { 745 INT i; 746 LPTSTR pch; 747 BOOL InvalidParameter = FALSE; 748 749 /* Initialize the Console Standard Streams */ 750 ConInitStdStreams(); 751 752 if (argc <= 1) 753 { 754 ConResPuts(StdOut, IDS_HELP); 755 return 0; 756 } 757 758 // FIXME: Convert to proper parsing, with support for /? 759 760 /* 761 * parse command line options 762 */ 763 for (i = 2; i < argc; i++) 764 { 765 if (lstrcmpi(argv[i], _T("/T")) == 0) 766 { 767 OptionT = TRUE; 768 } 769 else if (lstrcmpi(argv[i], _T("/E")) == 0) 770 { 771 OptionE = TRUE; 772 } 773 else if (lstrcmpi(argv[i], _T("/C")) == 0) 774 { 775 OptionC = TRUE; 776 } 777 else if (lstrcmpi(argv[i], _T("/G")) == 0) 778 { 779 if (i + 1 < argc) 780 { 781 pch = _tcschr(argv[++i], _T(':')); 782 if (pch != NULL) 783 { 784 OptionG = TRUE; 785 *pch = 0; 786 GUser = argv[i]; 787 GPerm = pch + 1; 788 continue; 789 } 790 } 791 InvalidParameter = TRUE; 792 break; 793 } 794 else if (lstrcmpi(argv[i], _T("/R")) == 0) 795 { 796 if (i + 1 < argc) 797 { 798 RUser = argv[++i]; 799 OptionR = TRUE; 800 continue; 801 } 802 InvalidParameter = TRUE; 803 break; 804 } 805 else if (lstrcmpi(argv[i], _T("/P")) == 0) 806 { 807 if (i + 1 < argc) 808 { 809 pch = _tcschr(argv[++i], _T(':')); 810 if (pch != NULL) 811 { 812 OptionP = TRUE; 813 *pch = 0; 814 PUser = argv[i]; 815 PPerm = pch + 1; 816 continue; 817 } 818 } 819 InvalidParameter = TRUE; 820 break; 821 } 822 else if (lstrcmpi(argv[i], _T("/D")) == 0) 823 { 824 if (i + 1 < argc) 825 { 826 OptionD = TRUE; 827 DUser = argv[++i]; 828 continue; 829 } 830 InvalidParameter = TRUE; 831 break; 832 } 833 else 834 { 835 InvalidParameter = TRUE; 836 break; 837 } 838 } 839 840 if (InvalidParameter) 841 { 842 PrintError(ERROR_INVALID_PARAMETER); 843 ConResPuts(StdOut, IDS_HELP); 844 return 1; 845 } 846 847 /* /R is only valid with /E */ 848 if (OptionR && !OptionE) 849 { 850 OptionR = FALSE; 851 } 852 853 PrintDaclsOfFiles(argv[1]); 854 855 if (OptionT) 856 { 857 ChangeACLsOfFilesInCurDir(argv[1]); 858 } 859 else 860 { 861 ChangeACLsOfFiles(argv[1]); 862 } 863 864 return 0; 865 } 866