Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1066 lines
30 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. aclfuncs.c
  5. Abstract:
  6. This module contians the functions to process the items from the files
  7. containing the ACL entries for registry keys and files
  8. Author:
  9. Bob Watson (a-robw) Dec-94
  10. Revision History:
  11. --*/
  12. #ifdef TEST_MODE
  13. #undef TEST_MODE
  14. #endif
  15. //#define TEST_MODE 1
  16. #include <windows.h>
  17. #include <stdio.h>
  18. #include <c2inc.h>
  19. #include <c2dll.h>
  20. #include <c2utils.h>
  21. #include "c2acls.h"
  22. #include "c2aclres.h"
  23. #include "strings.h"
  24. #define FILE_ENTRY 1
  25. #define DIR_ENTRY 2
  26. // internal flag
  27. #define FILE_PATH_SUBDIRS 8
  28. #define NTFS_NOT_STANDARD 0x00000000
  29. #define NTFS_FULL_CONTROL 0x00010001
  30. #define NTFS_CHANGE 0x00010002
  31. #define NTFS_ADD_READ 0x00010003
  32. #define NTFS_READ 0x00010004
  33. #define NTFS_ADD 0x00010005
  34. #define NTFS_LIST 0x00010006
  35. #define NTFS_NO_ACCESS 0x00010007
  36. #define NTFS_NONE 0x00000008
  37. #define NTFS_ALL 0x00000009
  38. #define NTFS_FILE_ALL_ACCESS (FILE_ALL_ACCESS)
  39. #define NTFS_FILE_CHANGE (FILE_GENERIC_READ | FILE_GENERIC_WRITE | \
  40. FILE_GENERIC_EXECUTE | DELETE)
  41. #define NTFS_FILE_ADD_READ (FILE_GENERIC_READ | FILE_GENERIC_WRITE | \
  42. FILE_GENERIC_EXECUTE)
  43. #define NTFS_FILE_READ (FILE_GENERIC_READ | FILE_GENERIC_EXECUTE)
  44. #define NTFS_FILE_ADD (FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE)
  45. #define NTFS_FILE_LIST (FILE_GENERIC_READ | FILE_GENERIC_EXECUTE)
  46. #define NTFS_FILE_NO_ACCESS (FILE_ALL_ACCESS) /* access denied ace */
  47. #define NTFS_DIR_ALL_ACCESS (GENERIC_ALL)
  48. #define NTFS_DIR_CHANGE (GENERIC_READ | GENERIC_WRITE | \
  49. GENERIC_EXECUTE | DELETE)
  50. #define NTFS_DIR_ADD_READ (GENERIC_READ | GENERIC_EXECUTE)
  51. #define NTFS_DIR_READ (GENERIC_READ | GENERIC_EXECUTE)
  52. #define NTFS_DIR_ADD (GENERIC_WRITE | GENERIC_EXECUTE)
  53. #define NTFS_DIR_LIST (GENERIC_READ | GENERIC_EXECUTE)
  54. #define NTFS_DIR_NO_ACCESS (GENERIC_ALL) /* access denied ace */
  55. #define NTFS_DIR_DIR_FLAGS (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)
  56. #define NTFS_DIR_FILE_FLAGS (CONTAINER_INHERIT_ACE)
  57. #define NTFS_FILE_FILE_FLAGS 0x00
  58. typedef struct _ACCESS_DECODE {
  59. LPTSTR szString;
  60. DWORD dwMask;
  61. } ACCESS_DECODE, *PACCESS_DECODE;
  62. #ifdef TEST_MODE
  63. LONG
  64. DumpAclData (
  65. IN LPCTSTR szFileName,
  66. IN PSECURITY_DESCRIPTOR psdFile
  67. );
  68. #endif
  69. static ACCESS_DECODE adRegistryDecodeList[] = {
  70. // specific access
  71. {TEXT("QV"), (DWORD)KEY_QUERY_VALUE},
  72. {TEXT("SV"), (DWORD)KEY_SET_VALUE},
  73. {TEXT("CS"), (DWORD)KEY_CREATE_SUB_KEY},
  74. {TEXT("ES"), (DWORD)KEY_ENUMERATE_SUB_KEYS},
  75. {TEXT("NT"), (DWORD)KEY_NOTIFY},
  76. {TEXT("CL"), (DWORD)KEY_CREATE_LINK},
  77. // standard rights
  78. {TEXT("DE"), (DWORD)DELETE},
  79. {TEXT("RC"), (DWORD)READ_CONTROL},
  80. {TEXT("WD"), (DWORD)WRITE_DAC},
  81. {TEXT("WO"), (DWORD)WRITE_OWNER},
  82. // predefined groups
  83. {TEXT("NONE"), (DWORD)0},
  84. {TEXT("FULL"), (DWORD)KEY_ALL_ACCESS},
  85. {TEXT("READ"), (DWORD)KEY_READ},
  86. // terminating entry
  87. {NULL, (DWORD)0}
  88. };
  89. static ACCESS_DECODE adNtfsDecodeList[] = {
  90. // predefined "combination" access keywords
  91. {TEXT("FullControl"), (DWORD)NTFS_FULL_CONTROL},
  92. {TEXT("Change"), (DWORD)NTFS_CHANGE},
  93. {TEXT("AddRead"), (DWORD)NTFS_ADD_READ},
  94. {TEXT("Read"), (DWORD)NTFS_READ},
  95. {TEXT("Add"), (DWORD)NTFS_ADD},
  96. {TEXT("List"), (DWORD)NTFS_LIST},
  97. {TEXT("NoAccess"), (DWORD)NTFS_NO_ACCESS},
  98. // predefined single ACE entries
  99. {TEXT("NONE"), (DWORD)NTFS_NONE},
  100. {TEXT("ALL"), (DWORD)NTFS_ALL},
  101. // terminating entry
  102. {NULL, (DWORD)0}
  103. };
  104. static
  105. BOOL
  106. DotOrDotDotDir (
  107. IN LPCTSTR szFileName
  108. )
  109. /*++
  110. Routine Description:
  111. examines the filename in the parameter list to see if it is one
  112. of the default subdirectories (e.g. the . or the .. dirs). This
  113. routine assumes that the argument is a filename only. (i.e. NO
  114. PATH!)
  115. Arguments:
  116. Filename to compare
  117. Return Value:
  118. TRUE if filename is either the . or the .. dir
  119. FALSE if it is any other string
  120. --*/
  121. {
  122. if (szFileName != NULL) { // check for null parameter
  123. if (lstrcmp(szFileName, cszDot) == 0) {
  124. return TRUE; // it's the . dir
  125. } else if (lstrcmp(szFileName, cszDotDot) == 0) {
  126. return TRUE; // it's the .. dir
  127. } else {
  128. return FALSE; // it's neither
  129. }
  130. } else {
  131. return FALSE; // null filename, so not a . or .. dir
  132. }
  133. }
  134. static
  135. BOOL
  136. IsDirectory (
  137. IN LPCTSTR szFilePath
  138. )
  139. {
  140. DWORD dwAttrib;
  141. dwAttrib = QuietGetFileAttributes (szFilePath);
  142. if (dwAttrib != 0xFFFFFFFF) {
  143. return ((dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
  144. } else {
  145. return FALSE;
  146. }
  147. }
  148. static
  149. ACCESS_MASK
  150. ReadNtfsPermissionString (
  151. IN LPCTSTR szPerms,
  152. IN BOOL bDirectory
  153. )
  154. {
  155. LPCTSTR szThisChar;
  156. ACCESS_MASK amReturn = 0;
  157. for (szThisChar = szPerms; *szThisChar != 0; szThisChar++) {
  158. switch (*szThisChar) {
  159. case TEXT('R'):
  160. case TEXT('r'):
  161. amReturn |= (bDirectory ? GENERIC_READ : FILE_GENERIC_READ);
  162. break;
  163. case TEXT('W'):
  164. case TEXT('w'):
  165. amReturn |= (bDirectory ? GENERIC_WRITE : FILE_GENERIC_WRITE);
  166. break;
  167. case TEXT('X'):
  168. case TEXT('x'):
  169. amReturn |= (bDirectory ? GENERIC_EXECUTE : FILE_GENERIC_EXECUTE);
  170. break;
  171. case TEXT('D'):
  172. case TEXT('d'):
  173. amReturn |= DELETE;
  174. break;
  175. case TEXT('P'):
  176. case TEXT('p'):
  177. amReturn |= WRITE_DAC;
  178. break;
  179. case TEXT('O'):
  180. case TEXT('o'):
  181. amReturn |= WRITE_OWNER;
  182. break;
  183. default:
  184. // no change if unrecognized
  185. break;
  186. }
  187. }
  188. return amReturn;
  189. }
  190. HKEY
  191. GetRootKey (
  192. IN LPCTSTR szKeyPath
  193. )
  194. {
  195. TCHAR szLocalPath[MAX_PATH];
  196. LPTSTR szEndOfRoot;
  197. lstrcpy (szLocalPath, szKeyPath);
  198. szEndOfRoot = _tcschr(szLocalPath, cBackslash);
  199. if (szEndOfRoot != NULL) {
  200. *szEndOfRoot = 0; // null terminate here and use just the chars to the left
  201. if (lstrcmpi(szLocalPath, cszLocalMachine) == 0) {
  202. return HKEY_LOCAL_MACHINE;
  203. } else if (lstrcmpi(szLocalPath, cszClassesRoot) == 0) {
  204. return HKEY_CLASSES_ROOT;
  205. } else if (lstrcmpi(szLocalPath, cszCurrentUser) == 0) {
  206. return HKEY_CURRENT_USER;
  207. } else if (lstrcmpi(szLocalPath, cszUsers) == 0) {
  208. return HKEY_USERS;
  209. } else {
  210. return NULL;
  211. }
  212. } else {
  213. return NULL;
  214. }
  215. }
  216. LPCTSTR
  217. GetKeyPath (
  218. IN LPCTSTR szKeyPath,
  219. OUT LPBOOL pbDoSubKeys
  220. )
  221. {
  222. static TCHAR szLocalPath[MAX_PATH];
  223. LPTSTR szEndOfRoot;
  224. BOOL bReturn = FALSE;
  225. szEndOfRoot = _tcschr(szKeyPath, cBackslash);
  226. if (szEndOfRoot != NULL) {
  227. // path found
  228. szEndOfRoot++; // go to first char after '\'
  229. // save in local static buffer
  230. lstrcpy (szLocalPath, szEndOfRoot);
  231. // now see if this is a recursive key
  232. szEndOfRoot = _tcschr(szLocalPath, cAsterisk);
  233. if (szEndOfRoot != NULL) {
  234. // then this is a recursive path
  235. bReturn = TRUE;
  236. szEndOfRoot--; // go back to backslash
  237. *szEndOfRoot = 0; // and terminate there
  238. }
  239. if (pbDoSubKeys != NULL) {
  240. *pbDoSubKeys = bReturn;
  241. }
  242. return szLocalPath;
  243. } else {
  244. // unable to find correct syntax so just return entire string
  245. if (pbDoSubKeys != NULL) {
  246. *pbDoSubKeys = FALSE;
  247. }
  248. return szKeyPath; // or beginning of path after ROOT key
  249. }
  250. }
  251. LPCTSTR
  252. GetFilePathFromHeader (
  253. IN LPCTSTR szHeaderPath,
  254. OUT LPDWORD pdwFlags
  255. )
  256. {
  257. static TCHAR szLocalPath[MAX_PATH];
  258. TCHAR szLocalWorkPath[MAX_PATH];
  259. LPTSTR szEndOfPath;
  260. DWORD dwLastError = ERROR_SUCCESS;
  261. DWORD dwReturn = FILE_PATH_NORMAL;
  262. lstrcpy (szLocalWorkPath, szHeaderPath);
  263. szEndOfPath = _tcsrchr(szLocalWorkPath, cBang);
  264. if (szEndOfPath != NULL) {
  265. // wild card found so remember this and truncate
  266. szEndOfPath--; // go to first char before *
  267. *szEndOfPath = 0; // and terminate there
  268. dwReturn = FILE_PATH_ALL; // remember to do sub-dirs
  269. } else {
  270. // check for wildcard path syntax characters
  271. szEndOfPath = _tcschr (szLocalWorkPath, cAsterisk);
  272. if (szEndOfPath == NULL) {
  273. // check for the other wild card char
  274. szEndOfPath = _tcschr (szLocalWorkPath, cAsterisk);
  275. }
  276. if (szEndOfPath != NULL) {
  277. // keep the path intact but set the flag
  278. dwReturn = FILE_PATH_WILD;
  279. }
  280. // no wildcard, so assume the path is in the valid syntax
  281. }
  282. dwLastError = GetExpandedFileName(
  283. szLocalWorkPath,
  284. sizeof(szLocalPath)/sizeof(TCHAR),
  285. szLocalPath,
  286. NULL);
  287. if (dwLastError != ERROR_SUCCESS) {
  288. SetLastError (dwLastError); // record error
  289. szLocalPath[0] = 0; // and clear buffer
  290. }
  291. if (pdwFlags != NULL) {
  292. *pdwFlags = dwReturn; // update the sub dir flag
  293. }
  294. return (LPCTSTR)&szLocalPath[0];
  295. }
  296. static
  297. DWORD
  298. DecodeRegAccessEntry (
  299. IN LPCTSTR szAccessEntry
  300. )
  301. {
  302. PACCESS_DECODE pEnt;
  303. for (pEnt = &adRegistryDecodeList[0];
  304. pEnt->szString != NULL;
  305. pEnt++) {
  306. if (lstrcmpi (szAccessEntry, pEnt->szString) == 0) {
  307. return pEnt->dwMask;
  308. }
  309. }
  310. return 0; // no entry found
  311. }
  312. static
  313. DWORD
  314. DecodeNtfsAccessEntry (
  315. IN LPCTSTR szAccessEntry
  316. )
  317. {
  318. PACCESS_DECODE pEnt;
  319. for (pEnt = &adNtfsDecodeList[0];
  320. pEnt->szString != NULL;
  321. pEnt++) {
  322. if (lstrcmpi (szAccessEntry, pEnt->szString) == 0) {
  323. return pEnt->dwMask;
  324. }
  325. }
  326. return NTFS_NOT_STANDARD; // no entry found
  327. }
  328. static
  329. BOOL
  330. FillAce (
  331. IN PACCESS_ALLOWED_ACE paaAce,
  332. IN ACCESS_MASK amAccess,
  333. IN BYTE Type,
  334. IN BYTE Flags,
  335. IN PSID pSid
  336. )
  337. {
  338. paaAce->Header.AceType = Type;
  339. paaAce->Header.AceFlags = Flags;
  340. paaAce->Mask = amAccess;
  341. CopySid (
  342. (DWORD)(paaAce->Header.AceSize - (sizeof (ACCESS_ALLOWED_ACE) - sizeof(DWORD))),
  343. (PSID)(&paaAce->SidStart),
  344. pSid);
  345. paaAce->Header.AceSize = (WORD)(GetLengthSid(pSid) +
  346. (sizeof (ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
  347. return TRUE;
  348. }
  349. static
  350. BOOL
  351. MakeAccessDeniedAce (
  352. IN PACCESS_DENIED_ACE padAce,
  353. IN ACCESS_MASK amAccess,
  354. IN BYTE Flags,
  355. IN PSID pSid
  356. )
  357. {
  358. padAce->Header.AceType = ACCESS_DENIED_ACE_TYPE;
  359. padAce->Header.AceFlags = Flags;
  360. padAce->Mask = amAccess;
  361. CopySid (
  362. (DWORD)(padAce->Header.AceSize - (sizeof (ACCESS_ALLOWED_ACE) - sizeof(DWORD))),
  363. (PSID)(&padAce->SidStart),
  364. pSid);
  365. padAce->Header.AceSize = (WORD)(GetLengthSid(pSid) +
  366. (sizeof (ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
  367. return TRUE;
  368. }
  369. static
  370. LONG
  371. MakeAceFromRegEntry (
  372. IN LPCTSTR szAccessList,
  373. IN PSID psidUser,
  374. IN OUT PACCESS_ALLOWED_ACE pAce
  375. )
  376. /*++
  377. Routine Description:
  378. interprets the access string list and returns the corresponding
  379. access mask
  380. Arguments:
  381. list of access strings to include:
  382. --*/
  383. {
  384. DWORD dwIndex = 1;
  385. LPCTSTR szItem;
  386. // see if this is an "inherit" ACE or not
  387. if (lstrcmpi ((LPTSTR)GetItemFromIniEntry(szAccessList, dwIndex),
  388. cszInherit) == 0) {
  389. pAce->Header.AceFlags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
  390. dwIndex++; // go to next entry
  391. } else {
  392. pAce->Header.AceFlags = 0;
  393. }
  394. // walk down the list to set bits as they are defined.
  395. szItem = GetItemFromIniEntry (szAccessList, dwIndex);
  396. while (lstrlen(szItem) > 0) {
  397. pAce->Mask |= DecodeRegAccessEntry(szItem);
  398. dwIndex++;
  399. szItem = (LPTSTR)GetItemFromIniEntry (szAccessList, dwIndex);
  400. }
  401. // now to add the sid and set the ace size
  402. CopySid (
  403. (DWORD)(pAce->Header.AceSize - sizeof(ACE_HEADER) - sizeof (ACCESS_MASK)),
  404. (PSID)(&pAce->SidStart),
  405. psidUser);
  406. pAce->Header.AceSize = (WORD)GetLengthSid(psidUser) +
  407. sizeof(ACE_HEADER) +
  408. sizeof(ACCESS_MASK);
  409. return ERROR_SUCCESS;
  410. }
  411. LONG
  412. MakeAclFromRegSection (
  413. IN LPTSTR mszSection,
  414. OUT PACL pAcl
  415. )
  416. /*++
  417. Routine Description:
  418. interprets the section string as a list of ACE information in the form
  419. of:
  420. DOMAIN\ACCOUNT = Access information
  421. and adds the ACE information to the initialized ACL passed in
  422. Arguments:
  423. mszSection msz Buffer of ACE information
  424. pAcl pointer to intialized ACL buffer
  425. Return Value:
  426. WIN32 Error status of function
  427. --*/
  428. {
  429. LPTSTR szThisEntry;
  430. TCHAR szDomain[MAX_PATH];
  431. DWORD dwSidBuffSize;
  432. DWORD dwDomainSize;
  433. SID_NAME_USE snu;
  434. PSID psidAccount = NULL;
  435. PACCESS_ALLOWED_ACE pAce = NULL;
  436. LONG lStatus;
  437. for (szThisEntry = mszSection;
  438. *szThisEntry != 0;
  439. szThisEntry += lstrlen(szThisEntry)+1) {
  440. psidAccount = GLOBAL_ALLOC (SMALL_BUFFER_SIZE);
  441. pAce = GLOBAL_ALLOC (MAX_PATH); // this should be plenty big
  442. if ((psidAccount != NULL) && (pAce != NULL)){
  443. dwSidBuffSize = SMALL_BUFFER_SIZE;
  444. dwDomainSize = sizeof(szDomain) / sizeof(TCHAR);
  445. if (LookupAccountName (
  446. NULL, // look up on local machine
  447. GetKeyFromIniEntry(szThisEntry),
  448. psidAccount,
  449. &dwSidBuffSize,
  450. szDomain,
  451. &dwDomainSize,
  452. &snu)) {
  453. // account found so make an ACE with it
  454. pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  455. pAce->Header.AceFlags = 0;
  456. pAce->Header.AceSize = MAX_PATH; // initial buffer size
  457. pAce->Mask = 0; // the mask will be added in the next fn.
  458. pAce->SidStart = 0; // the sid will be added in the next fn.
  459. lStatus = MakeAceFromRegEntry (
  460. szThisEntry,
  461. psidAccount,
  462. pAce);
  463. AddAce (
  464. pAcl,
  465. ACL_REVISION,
  466. MAXDWORD, // append this ACE to the end of the list
  467. (LPVOID)pAce,
  468. (DWORD)pAce->Header.AceSize);
  469. } else {
  470. // unable to look up name
  471. }
  472. } else {
  473. // unable to allocate SID buffer
  474. }
  475. GLOBAL_FREE_IF_ALLOC (psidAccount);
  476. GLOBAL_FREE_IF_ALLOC (pAce);
  477. } // end of entry loop
  478. return ERROR_SUCCESS;
  479. }
  480. static
  481. BOOL
  482. MakeDirAce (
  483. IN PACCESS_ALLOWED_ACE pAce,
  484. IN PSID pSid,
  485. IN DWORD dwAccessValue
  486. )
  487. {
  488. BOOL bAddAce = TRUE;
  489. ACCESS_MASK amAce = 0;
  490. BYTE bType = ACCESS_ALLOWED_ACE_TYPE;
  491. switch (dwAccessValue) {
  492. case NTFS_FULL_CONTROL:
  493. amAce = NTFS_DIR_ALL_ACCESS;
  494. break;
  495. case NTFS_CHANGE:
  496. amAce = NTFS_DIR_CHANGE;
  497. break;
  498. case NTFS_ADD_READ:
  499. amAce = NTFS_DIR_ADD_READ;
  500. break;
  501. case NTFS_READ:
  502. amAce = NTFS_DIR_READ;
  503. break;
  504. case NTFS_ADD:
  505. bAddAce = FALSE;
  506. break;
  507. case NTFS_LIST:
  508. bAddAce = FALSE;
  509. break;
  510. case NTFS_NO_ACCESS:
  511. amAce = NTFS_DIR_NO_ACCESS;
  512. bType = ACCESS_DENIED_ACE_TYPE;
  513. break;
  514. default:
  515. bAddAce = FALSE;
  516. break;
  517. }
  518. if (bAddAce) {
  519. bAddAce = FillAce (
  520. pAce,
  521. amAce,
  522. bType,
  523. NTFS_DIR_DIR_FLAGS,
  524. pSid);
  525. }
  526. return bAddAce;
  527. }
  528. static
  529. BOOL
  530. MakeFileAce (
  531. IN PACCESS_ALLOWED_ACE pAce,
  532. IN PSID pSid,
  533. IN DWORD dwAccessValue,
  534. IN BOOL bDirectory
  535. )
  536. {
  537. BOOL bAddAce = TRUE;
  538. ACCESS_MASK amAce = 0;
  539. BYTE bType = ACCESS_ALLOWED_ACE_TYPE;
  540. switch (dwAccessValue) {
  541. case NTFS_FULL_CONTROL:
  542. amAce = NTFS_FILE_ALL_ACCESS;
  543. break;
  544. case NTFS_CHANGE:
  545. amAce = NTFS_FILE_CHANGE;
  546. break;
  547. case NTFS_ADD_READ:
  548. if (bDirectory) {
  549. amAce = NTFS_FILE_ADD_READ;
  550. } else {
  551. bAddAce = FALSE; // not allowed for files
  552. }
  553. break;
  554. case NTFS_READ:
  555. amAce = NTFS_FILE_READ;
  556. break;
  557. case NTFS_ADD:
  558. amAce = NTFS_FILE_ADD;
  559. break;
  560. case NTFS_LIST:
  561. amAce = NTFS_FILE_LIST;
  562. break;
  563. case NTFS_NO_ACCESS:
  564. amAce = NTFS_FILE_NO_ACCESS;
  565. bType = ACCESS_DENIED_ACE_TYPE;
  566. break;
  567. default:
  568. bAddAce = FALSE;
  569. break;
  570. }
  571. if (bAddAce) {
  572. bAddAce = FillAce (
  573. pAce,
  574. amAce,
  575. bType,
  576. (BYTE)(bDirectory ? NTFS_DIR_FILE_FLAGS : NTFS_FILE_FILE_FLAGS),
  577. pSid);
  578. }
  579. return bAddAce;
  580. }
  581. static
  582. LONG
  583. InterpretNtfsAccessEntry (
  584. IN LPCTSTR szThisEntry,
  585. IN BOOL bDirectory,
  586. IN PSID psidAccount,
  587. OUT PACL pAcl
  588. )
  589. {
  590. LONG lStatus = ERROR_SUCCESS;
  591. LPCTSTR szAccessString;
  592. DWORD dwAccessValue;
  593. BOOL bCombinationEntry; // true if access string makes 2 ace's
  594. PACCESS_ALLOWED_ACE pAce;
  595. ACCESS_MASK amAce;
  596. BYTE bAceType;
  597. BYTE bAceFlags;
  598. DWORD dwAllowedEntries;
  599. DWORD dwThisEntry = 1;
  600. szAccessString = GetItemFromIniEntry (szThisEntry, dwThisEntry);
  601. dwAccessValue = DecodeNtfsAccessEntry (szAccessString);
  602. bCombinationEntry = (BOOL)(HIWORD(dwAccessValue) == 1);
  603. if (bCombinationEntry) {
  604. // this is a combination entry so if this is a directory
  605. // we'll make 2 ACE's one for dir access and one to be inherited
  606. // for file access. If this is a file, then only the file access
  607. // ace will be created.
  608. if (bDirectory) {
  609. // make the directory access ACE for the directory entry
  610. pAce = (PACCESS_ALLOWED_ACE)GLOBAL_ALLOC(MAX_PATH);
  611. if (pAce != NULL) {
  612. if (MakeDirAce (pAce, psidAccount, dwAccessValue)) {
  613. // then add ace to acl
  614. AddAce (
  615. pAcl,
  616. ACL_REVISION,
  617. MAXDWORD,
  618. (LPVOID)pAce,
  619. (DWORD)pAce->Header.AceSize);
  620. }
  621. }
  622. GLOBAL_FREE_IF_ALLOC (pAce); // free this one
  623. }
  624. // create the File Access entry
  625. pAce = (PACCESS_ALLOWED_ACE)GLOBAL_ALLOC(MAX_PATH);
  626. if (pAce != NULL) {
  627. if (MakeFileAce (pAce, psidAccount, dwAccessValue, bDirectory)) {
  628. // then add ace to acl
  629. AddAce (
  630. pAcl,
  631. ACL_REVISION,
  632. MAXDWORD,
  633. (LPVOID)pAce,
  634. (DWORD)pAce->Header.AceSize);
  635. }
  636. }
  637. GLOBAL_FREE_IF_ALLOC (pAce); // free this one
  638. } else {
  639. // specific permissions have been specified so process them
  640. // this is the first entry in the list so it's either the "dir"
  641. // entry of a directory or a File entry.
  642. dwAllowedEntries = (bDirectory ? 2 : 1);
  643. while (dwThisEntry <= dwAllowedEntries) {
  644. if (lstrlen(szAccessString) > 0) {
  645. bAceFlags = (bDirectory ? (dwThisEntry == DIR_ENTRY ?
  646. NTFS_DIR_DIR_FLAGS : NTFS_DIR_FILE_FLAGS) : NTFS_FILE_FILE_FLAGS);
  647. bAceType = ACCESS_ALLOWED_ACE_TYPE;
  648. switch (dwAccessValue) {
  649. case NTFS_NONE:
  650. amAce = (bDirectory ? NTFS_DIR_NO_ACCESS : NTFS_FILE_NO_ACCESS);
  651. bAceType = ACCESS_DENIED_ACE_TYPE;
  652. break;
  653. case NTFS_ALL:
  654. amAce = (bDirectory ? NTFS_DIR_NO_ACCESS : NTFS_FILE_ALL_ACCESS);
  655. break;
  656. default:
  657. amAce = ReadNtfsPermissionString (szAccessString, bDirectory);
  658. break;
  659. }
  660. pAce = (PACCESS_ALLOWED_ACE)GLOBAL_ALLOC(MAX_PATH);
  661. if (pAce != NULL) {
  662. FillAce (
  663. pAce,
  664. amAce,
  665. bAceType,
  666. bAceFlags,
  667. psidAccount);
  668. AddAce (
  669. pAcl,
  670. ACL_REVISION,
  671. MAXDWORD,
  672. (LPVOID)pAce,
  673. (DWORD)pAce->Header.AceSize);
  674. }
  675. GLOBAL_FREE_IF_ALLOC (pAce);
  676. }
  677. if (++dwThisEntry <= dwAllowedEntries) {
  678. // get next entry from string
  679. szAccessString = GetItemFromIniEntry (szThisEntry, dwThisEntry);
  680. }
  681. }
  682. }
  683. return lStatus;
  684. }
  685. LONG
  686. MakeAclFromNtfsSection (
  687. IN LPTSTR mszSection,
  688. IN BOOL bDirectory, // true if this is for a directory
  689. OUT PACL pAcl
  690. )
  691. /*++
  692. Routine Description:
  693. interprets the section string as a list of ACE information in the form
  694. of:
  695. DOMAIN\ACCOUNT = Access information
  696. and adds the ACE information to the initialized ACL passed in
  697. Arguments:
  698. mszSection msz Buffer of ACE information
  699. pAcl pointer to intialized ACL buffer
  700. Return Value:
  701. WIN32 Error status of function
  702. --*/
  703. {
  704. LPTSTR szThisEntry;
  705. TCHAR szDomain[MAX_PATH];
  706. DWORD dwSidBuffSize;
  707. DWORD dwDomainSize;
  708. SID_NAME_USE snu;
  709. PSID psidAccount = NULL;
  710. LONG lStatus;
  711. for (szThisEntry = mszSection;
  712. *szThisEntry != 0;
  713. szThisEntry += lstrlen(szThisEntry)+1) {
  714. psidAccount = GLOBAL_ALLOC (SMALL_BUFFER_SIZE);
  715. if (psidAccount != NULL) {
  716. dwSidBuffSize = SMALL_BUFFER_SIZE;
  717. dwDomainSize = sizeof(szDomain) / sizeof(TCHAR);
  718. if (LookupAccountName (
  719. NULL, // look up on local machine
  720. GetKeyFromIniEntry(szThisEntry),
  721. psidAccount,
  722. &dwSidBuffSize,
  723. szDomain,
  724. &dwDomainSize,
  725. &snu)) {
  726. lStatus = InterpretNtfsAccessEntry (
  727. szThisEntry,
  728. bDirectory,
  729. psidAccount,
  730. pAcl);
  731. } else {
  732. // unable to look up name
  733. }
  734. } else {
  735. // unable to allocate SID buffer
  736. }
  737. GLOBAL_FREE_IF_ALLOC (psidAccount);
  738. } // end of entry loop
  739. return ERROR_SUCCESS;
  740. }
  741. LONG
  742. SetRegistryKeySecurity (
  743. IN HKEY hkeyRootKey,
  744. IN LPCTSTR szKeyPath,
  745. IN BOOL bDoSubKeys,
  746. IN PSECURITY_DESCRIPTOR psdSecurity
  747. )
  748. /*++
  749. Routine Description:
  750. opens the key in "KeyPath" and set's the key's security. If the
  751. "bDoSubKeys" flag is set, then all sub keys are set to the same
  752. security using this routine recursively.
  753. Return Value:
  754. WIN32 status value of function
  755. --*/
  756. {
  757. LONG lStatus;
  758. HKEY hkeyThisKey;
  759. DWORD dwKeyIndex;
  760. DWORD dwSubKeyLen;
  761. TCHAR szSubKeyName[MAX_PATH];
  762. FILETIME FileTime;
  763. lStatus = RegOpenKeyEx (
  764. hkeyRootKey,
  765. szKeyPath,
  766. 0L,
  767. KEY_ALL_ACCESS,
  768. &hkeyThisKey);
  769. if (lStatus == ERROR_SUCCESS) {
  770. _tprintf (GetStringResource (GetDllInstance(), IDS_REG_DISPLAY_FORMAT),
  771. szKeyPath);
  772. lStatus = RegSetKeySecurity (
  773. hkeyThisKey,
  774. DACL_SECURITY_INFORMATION,
  775. psdSecurity);
  776. if (bDoSubKeys) {
  777. dwKeyIndex = 0;
  778. dwSubKeyLen = sizeof(szSubKeyName) / sizeof(TCHAR);
  779. while (RegEnumKeyEx (
  780. hkeyThisKey,
  781. dwKeyIndex,
  782. szSubKeyName,
  783. &dwSubKeyLen,
  784. NULL,
  785. NULL, // don't care about the class
  786. NULL, // no class buffer
  787. &FileTime) == ERROR_SUCCESS) {
  788. // subkey found so set subkey security
  789. lStatus = SetRegistryKeySecurity (
  790. hkeyThisKey,
  791. szSubKeyName,
  792. bDoSubKeys,
  793. psdSecurity);
  794. // set variables for next call
  795. dwKeyIndex++;
  796. dwSubKeyLen = sizeof(szSubKeyName) / sizeof(TCHAR);
  797. }
  798. }
  799. RegCloseKey (hkeyThisKey);
  800. } else {
  801. // unable to open key so return ERROR
  802. }
  803. return lStatus;
  804. }
  805. LONG
  806. SetNtfsFileSecurity (
  807. IN LPCTSTR szPath,
  808. IN DWORD dwFlags,
  809. IN PSECURITY_DESCRIPTOR pSdDir,
  810. IN PSECURITY_DESCRIPTOR pSdFile
  811. )
  812. {
  813. LONG lReturn = ERROR_SUCCESS;
  814. LONG lStatus = ERROR_SUCCESS;
  815. WIN32_FIND_DATA fdThisFile;
  816. HANDLE hFileSearch;
  817. BOOL bFileFound = FALSE;
  818. DWORD dwFlagsToPass;
  819. LPTSTR szWildPath;
  820. TCHAR szWildFilePath[MAX_PATH];
  821. LPTSTR szWildFileName;
  822. if ((dwFlags & FILE_PATH_NORMAL) == FILE_PATH_NORMAL) {
  823. // then just set the security on this path
  824. if (FileExists(szPath)) {
  825. if (IsDirectory(szPath)) {
  826. // then apply directory SD
  827. #ifdef TEST_MODE
  828. _tprintf (TEXT("\n_DIR: %s"), szPath);
  829. DumpAclData (szPath, pSdDir);
  830. lReturn = ERROR_SUCCESS;
  831. #else
  832. if (!SetFileSecurity(szPath, DACL_SECURITY_INFORMATION, pSdDir)) {
  833. lReturn = GetLastError();
  834. }
  835. #endif
  836. } else {
  837. // it's not a dir so apply file SD
  838. #ifdef TEST_MODE
  839. _tprintf (TEXT("\nFILE: %s"), szPath);
  840. DumpAclData (szPath, pSdFile);
  841. lReturn = ERROR_SUCCESS;
  842. #else
  843. if (!SetFileSecurity(szPath, DACL_SECURITY_INFORMATION, pSdFile)) {
  844. lReturn = GetLastError();
  845. }
  846. #endif
  847. }
  848. } else {
  849. #ifdef TEST_MODE
  850. _tprintf (TEXT("\n_ERR: %s"), szPath);
  851. #endif
  852. lReturn = ERROR_FILE_NOT_FOUND;
  853. }
  854. } else if ((dwFlags & FILE_PATH_WILD) == FILE_PATH_WILD) {
  855. // the path is (presumably) a wild-card path spec so walk the list
  856. // of matching files
  857. // make a local copy of the path preceeding the wildcard chars
  858. // to build local paths with
  859. lstrcpy (szWildFilePath, szPath);
  860. szWildFileName = _tcsrchr(szWildFilePath, cBackslash); // find last backslash char
  861. if (szWildFileName == NULL) {
  862. // no backslash found so add one to the end of the path string
  863. lstrcat (szWildFilePath, cszBackslash);
  864. szWildFileName = szWildFilePath + lstrlen(szWildFilePath);
  865. } else {
  866. // backslash found so move pointer past it.
  867. szWildFileName++;
  868. }
  869. hFileSearch = FindFirstFile (szPath, &fdThisFile);
  870. if (hFileSearch != INVALID_HANDLE_VALUE) bFileFound = TRUE;
  871. while (bFileFound) {
  872. if (fdThisFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  873. if (!DotOrDotDotDir (fdThisFile.cFileName)) {
  874. // then if this is dir, do see if we should do all the sub dirs
  875. if ((dwFlags & FILE_PATH_SUBDIRS) == FILE_PATH_SUBDIRS) {
  876. dwFlagsToPass = FILE_PATH_ALL;
  877. } else {
  878. dwFlagsToPass = 0; // do not do in this case
  879. }
  880. } else {
  881. // this is a . or a .. dir so ignore
  882. dwFlagsToPass = 0;
  883. }
  884. } else {
  885. // just a file so process as a normal file
  886. dwFlagsToPass = FILE_PATH_NORMAL;
  887. }
  888. if (dwFlagsToPass != 0) {
  889. // make into a full path string
  890. lstrcpy (szWildFileName, fdThisFile.cFileName);
  891. // set the file security of this and any other files
  892. lStatus = SetNtfsFileSecurity (szWildFilePath, dwFlagsToPass,
  893. pSdDir, pSdFile);
  894. if (lStatus != ERROR_SUCCESS) {
  895. // save last "non-success" error for return
  896. lReturn = lStatus;
  897. }
  898. }
  899. bFileFound = FindNextFile (hFileSearch, &fdThisFile);
  900. }
  901. FindClose (hFileSearch);
  902. } else if ((dwFlags & FILE_PATH_ALL) == FILE_PATH_ALL) {
  903. // set the security of this path
  904. lStatus = SetNtfsFileSecurity (szPath, FILE_PATH_NORMAL,
  905. pSdDir, pSdFile);
  906. if (IsDirectory(szPath)) {
  907. // make a wild card path an pass it do all the files and sub-dirs
  908. // of this path
  909. szWildPath = (LPTSTR)GLOBAL_ALLOC(MAX_PATH_BYTES);
  910. if (szWildPath != NULL) {
  911. lstrcpy (szWildPath, szPath);
  912. if (szWildPath[lstrlen(szWildPath)-1] != cBackslash) {
  913. lstrcat (szWildPath, cszBackslash);
  914. }
  915. lstrcat (szWildPath, cszStarDotStar); // make wild
  916. // call this routine with both WILD and ALL flags set
  917. // so all files and sub-dirs will get set.
  918. lStatus = SetNtfsFileSecurity (szWildPath,
  919. (FILE_PATH_WILD | FILE_PATH_SUBDIRS),
  920. pSdDir, pSdFile);
  921. lReturn = lStatus;
  922. } else {
  923. lReturn = ERROR_OUTOFMEMORY;
  924. }
  925. GLOBAL_FREE_IF_ALLOC (szWildPath);
  926. } else {
  927. // path not a dir so just skip the wildcard stuff
  928. }
  929. } else {
  930. // unrecognized flag
  931. lReturn = ERROR_INVALID_PARAMETER;
  932. }
  933. return lReturn;
  934. }