Leaked source code of windows server 2003
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.

543 lines
15 KiB

  1. /*--
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. sacls.c
  5. Abstract:
  6. Extended version of cacls.exe
  7. Author:
  8. 14-Dec-1996 (macm)
  9. Environment:
  10. User mode only.
  11. Requires ANSI C extensions: slash-slash comments, long external names.
  12. Revision History:
  13. --*/
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <seopaque.h>
  18. #include <windows.h>
  19. #include <caclscom.h>
  20. #include <dsysdbg.h>
  21. #include <stdio.h>
  22. #include <aclapi.h>
  23. #define CMD_PRESENT(index, list) ((list)[index].iIndex != -1)
  24. #define NO_INHERIT_ONLY
  25. //
  26. // Enumeration of command tags
  27. //
  28. typedef enum _CMD_TAGS {
  29. CmdTree = 0,
  30. CmdEdit,
  31. CmdContinue,
  32. CmdSuccess,
  33. CmdRevoke,
  34. CmdFail,
  35. CmdICont,
  36. CmdIObj,
  37. #ifndef NO_INHERIT_ONLY
  38. CmdIOnly,
  39. #endif
  40. CmdIProp
  41. } CMD_TAGS, *PCMD_TAGS;
  42. VOID
  43. Usage (
  44. IN PCACLS_STR_RIGHTS pStrRights,
  45. IN INT cStrRights,
  46. IN PCACLS_CMDLINE pCmdVals
  47. )
  48. /*++
  49. Routine Description:
  50. Displays the expected usage
  51. Arguments:
  52. Return Value:
  53. VOID
  54. --*/
  55. {
  56. INT i;
  57. printf("Displays or modifies audit control lists (ACLs) of files. You need \"Manage "
  58. "auditing and security log\" privilege to run this utility.\n\n" );
  59. printf("SACLS filename [/T] [/E] [/C] [/G user:perm] [/R user [...]]\n");
  60. printf(" [/P user:perm [...]] [/D user [...]]\n");
  61. printf(" filename Displays ACLs.\n");
  62. printf(" /%s Changes ACLs of specified files in\n", pCmdVals[CmdTree].pszSwitch);
  63. printf(" the current directory and all subdirectories.\n");
  64. printf(" /%s Edit ACL instead of replacing it.\n", pCmdVals[CmdEdit].pszSwitch);
  65. printf(" /%s Continue on access denied errors.\n",
  66. pCmdVals[CmdContinue].pszSwitch);
  67. printf(" /%s user:perms Add specified user successful access auditing\n",
  68. pCmdVals[CmdSuccess].pszSwitch);
  69. printf(" /%s user Revoke specified user's auditing rights (only valid with /E).\n",
  70. pCmdVals[CmdRevoke].pszSwitch);
  71. printf(" /%s user:perms Add specified user failed access auditing.\n",
  72. pCmdVals[CmdFail].pszSwitch);
  73. printf(" /%s Mark the ace as CONTAINER_INHERIT (directory inherit)\n",
  74. pCmdVals[CmdICont].pszSwitch);
  75. printf(" /%s Mark the ace as OBJECT_INHERIT\n", pCmdVals[CmdIObj].pszSwitch);
  76. #ifndef NO_INHERIT_ONLY
  77. printf(" /%s Mark the ace as INHERIT_ONLY\n", pCmdVals[CmdIOnly].pszSwitch);
  78. #endif
  79. printf(" /%s Mark the ace as INHERIT_NO_PROPAGATE\n",
  80. pCmdVals[CmdIProp].pszSwitch);
  81. printf("The list of supported perms for Success and Failure auditing are:\n");
  82. for (i = 0; i < cStrRights; i++) {
  83. printf(" %c%c %s\n",
  84. pStrRights[i].szRightsTag[0],
  85. pStrRights[i].szRightsTag[1],
  86. pStrRights[i].pszDisplayTag);
  87. }
  88. printf("\nMultiple perms can be specified per user\n");
  89. printf("Wildcards can be used to specify more that one file in a command.\n");
  90. printf("You can specify more than one user in a command.\n\n");
  91. printf("Example: SACLS c:\\temp /S user1:GRGW user2:SDRC /F user3:GF\n");
  92. }
  93. DWORD
  94. MergeAcls (
  95. IN PACL pOldAcl,
  96. IN PACL pNewAcl
  97. )
  98. /*++
  99. Routine Description:
  100. Merges the old acl into the new one, by combining any identical aces. It is assumed that
  101. the destintation acl is of sufficient size. No allocations will be done, but an error will
  102. be returned if it isn't
  103. Arguments:
  104. pOldAcl - The acl to be merged
  105. pNewAcl - The acl to be merged into
  106. Return Value:
  107. ERROR_SUCCESS -- Success
  108. --*/
  109. {
  110. DWORD dwErr = ERROR_SUCCESS;
  111. PACE_HEADER pNewAce, pOldAce;
  112. DWORD iNewAce, iOldAce;
  113. BOOL fFound;
  114. //
  115. // If the new acl is empty, simply copy the new one over
  116. //
  117. if (pNewAcl->AceCount == 0 ) {
  118. memcpy((PVOID)((PBYTE)pNewAcl + sizeof(ACL)), (PBYTE)pOldAcl + sizeof(ACL),
  119. pOldAcl->AclSize - sizeof(ACL));
  120. pNewAcl->AceCount = pOldAcl->AceCount;
  121. return(ERROR_SUCCESS);
  122. }
  123. pOldAce = (PACE_HEADER)FirstAce(pOldAcl);
  124. for ( iOldAce = 0;
  125. iOldAce < pOldAcl->AceCount && dwErr == ERROR_SUCCESS;
  126. iOldAce++, pOldAce = (PACE_HEADER)NextAce(pOldAce) ) {
  127. fFound = FALSE;
  128. //
  129. // We'll walk each of the existing acls, and try and compress the new
  130. // acls out of existance
  131. //
  132. pNewAce = (PACE_HEADER)FirstAce(pNewAcl);
  133. for ( iNewAce = 0;
  134. iNewAce < pOldAcl->AceCount && dwErr == ERROR_SUCCESS;
  135. iNewAce++, pNewAce = (PACE_HEADER)NextAce(pNewAce) ) {
  136. if ( EqualSid ( (PSID)(&((PSYSTEM_AUDIT_ACE)pNewAce)->SidStart),
  137. (PSID)(&((PSYSTEM_AUDIT_ACE)pOldAce)->SidStart) ) &&
  138. pNewAce->AceType == pOldAce->AceType &&
  139. (pNewAce->AceFlags & VALID_INHERIT_FLAGS) == 0 &&
  140. (pOldAce->AceFlags & VALID_INHERIT_FLAGS) == 0 &&
  141. ((PSYSTEM_AUDIT_ACE)pNewAce)->Mask == ((PSYSTEM_AUDIT_ACE)pOldAce)->Mask) {
  142. ((PSYSTEM_AUDIT_ACE)pNewAce)->Mask |=
  143. ((PSYSTEM_AUDIT_ACE)pOldAce)->Mask;
  144. pNewAce->AceFlags |= pOldAce->AceFlags;
  145. fFound = TRUE;
  146. break;
  147. }
  148. }
  149. if ( fFound != TRUE ) {
  150. //
  151. // We'll have to add it
  152. //
  153. if ( !AddAuditAccessAce (
  154. pNewAcl,
  155. ACL_REVISION2,
  156. ((PSYSTEM_AUDIT_ACE)pOldAce)->Mask,
  157. (PSID)(&((PSYSTEM_AUDIT_ACE)pOldAce)->SidStart),
  158. (pOldAce->AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG),
  159. (pOldAce->AceFlags & FAILED_ACCESS_ACE_FLAG) ) ) {
  160. dwErr = GetLastError();
  161. break;
  162. }
  163. }
  164. }
  165. return(dwErr);
  166. }
  167. INT
  168. __cdecl main (
  169. int argc,
  170. char *argv[])
  171. /*++
  172. Routine Description:
  173. The main the for this executable
  174. Arguments:
  175. argc - Count of arguments
  176. argv - List of arguments
  177. Return Value:
  178. VOID
  179. --*/
  180. {
  181. DWORD dwErr = 0;
  182. CACLS_STR_RIGHTS pStrRights[] = {
  183. "GR", GENERIC_READ, "Read",
  184. "GC", GENERIC_WRITE, "Change (write)",
  185. "GF", GENERIC_ALL, "Full rights",
  186. "SD", DELETE, "Delete",
  187. "RC", READ_CONTROL, "Read Control",
  188. "WP", WRITE_DAC, "Write DAC",
  189. "WO", WRITE_OWNER, "Write Owner",
  190. "RD", FILE_READ_DATA, "Read Data (on file) / List Directory (on Dir)",
  191. "WD", FILE_WRITE_DATA, "Write Data (on file) / Add File (on Dir)",
  192. "AD", FILE_APPEND_DATA, "Append Data (on file) / Add SubDir (on Dir)",
  193. "FE", FILE_EXECUTE, "Execute (on file) / Traverse (on Dir)",
  194. "DC", FILE_DELETE_CHILD, "Delete Child (on Dir only)",
  195. "RA", FILE_READ_ATTRIBUTES, "Read Attributes",
  196. "WA", FILE_WRITE_ATTRIBUTES, "Write Attributes",
  197. "RE", FILE_READ_EA, "Read Extended Attributes",
  198. "WE", FILE_WRITE_EA, "Write Extended Attributes"
  199. };
  200. INT cStrRights = sizeof(pStrRights) / sizeof(CACLS_STR_RIGHTS);
  201. CACLS_CMDLINE pCmdVals[] = {
  202. "T", -1, FALSE, 0, // CmdTree
  203. "E", -1, FALSE, 0, // CmdEdit
  204. "C", -1, FALSE, 0, // CmdContinue
  205. "S", -1, TRUE, 0, // CmdSuccess
  206. "R", -1, TRUE, 0, // CmdRevoke
  207. "F", -1, TRUE, 0, // CmdFail
  208. "D", -1, FALSE, 0, // CmdICont
  209. "O", -1, FALSE, 0, // CmdIObj
  210. #ifndef NO_INHERIT_ONLY
  211. "I", -1, FALSE, 0, // CmdIOnly
  212. #endif
  213. "N", -1, FALSE, 0, // CmdIProp
  214. };
  215. INT cCmdVals = sizeof(pCmdVals) / sizeof(CACLS_CMDLINE);
  216. INT i;
  217. PSECURITY_DESCRIPTOR pInitialSD = NULL, pFinalSD;
  218. PACL pOldAcl = NULL, pSuccessAcl = NULL, pFailAcl = NULL;
  219. DWORD fInherit = 0;
  220. HANDLE hProcessToken;
  221. if (argc < 2) {
  222. Usage( pStrRights, cStrRights, pCmdVals );
  223. return(1);
  224. } else if (argc == 2 && (strcmp(argv[1], "-?") == 0 || strcmp(argv[1], "/?") == 0)) {
  225. Usage( pStrRights, cStrRights, pCmdVals );
  226. return(0);
  227. }
  228. //
  229. // Parse the command line
  230. //
  231. dwErr = ParseCmdline(argv, argc, 2, pCmdVals, cCmdVals);
  232. if (dwErr != ERROR_SUCCESS) {
  233. Usage( pStrRights, cStrRights, pCmdVals );
  234. return(1);
  235. }
  236. //
  237. // Set our inheritance flags
  238. //
  239. if (CMD_PRESENT(CmdICont, pCmdVals)) {
  240. fInherit |= CONTAINER_INHERIT_ACE;
  241. }
  242. if (CMD_PRESENT(CmdIObj, pCmdVals)) {
  243. fInherit |= OBJECT_INHERIT_ACE;
  244. }
  245. #ifndef NO_INHERIT_ONLY
  246. if (CMD_PRESENT(CmdIOnly, pCmdVals)) {
  247. fInherit |= INHERIT_ONLY_ACE;
  248. }
  249. #endif
  250. if (CMD_PRESENT(CmdIProp, pCmdVals)) {
  251. fInherit |= NO_PROPAGATE_INHERIT_ACE;
  252. }
  253. //
  254. // Enable the read sacl privs
  255. //
  256. if ( OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &hProcessToken ) == FALSE) {
  257. dwErr = GetLastError();
  258. } else {
  259. TOKEN_PRIVILEGES EnableSeSecurity;
  260. TOKEN_PRIVILEGES Previous;
  261. DWORD PreviousSize;
  262. EnableSeSecurity.PrivilegeCount = 1;
  263. EnableSeSecurity.Privileges[0].Luid.LowPart = SE_SECURITY_PRIVILEGE;
  264. EnableSeSecurity.Privileges[0].Luid.HighPart = 0;
  265. EnableSeSecurity.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  266. PreviousSize = sizeof(Previous);
  267. if (AdjustTokenPrivileges( hProcessToken, FALSE, &EnableSeSecurity,
  268. sizeof(EnableSeSecurity), &Previous,
  269. &PreviousSize ) == FALSE) {
  270. dwErr = GetLastError();
  271. }
  272. }
  273. //
  274. // Ok, see if we need to read the existing security
  275. //
  276. if ( dwErr == ERROR_SUCCESS && (CMD_PRESENT(CmdEdit, pCmdVals) || argc == 2 )) {
  277. dwErr = GetNamedSecurityInfoA( argv[1], SE_FILE_OBJECT, SACL_SECURITY_INFORMATION,
  278. NULL, NULL, NULL, &pOldAcl, &pInitialSD );
  279. if ( dwErr != ERROR_SUCCESS ) {
  280. fprintf(stderr, "Failed to read the security off of %s: %lu\n", argv[1], dwErr);
  281. }
  282. }
  283. //
  284. // Either display the existing access or do the sets as requested
  285. //
  286. if (dwErr == ERROR_SUCCESS && argc == 2) {
  287. dwErr = DisplayAcl ( argv[1], pOldAcl, pStrRights, cStrRights );
  288. } else {
  289. //
  290. // Ok, first we do the revokes
  291. //
  292. if (dwErr == ERROR_SUCCESS && CMD_PRESENT(CmdRevoke, pCmdVals)) {
  293. PACL pNewAcl;
  294. //
  295. // Make sure we've read it first...
  296. //
  297. if (CMD_PRESENT(CmdEdit, pCmdVals)) {
  298. dwErr = ProcessOperation( argv, &pCmdVals[CmdRevoke], REVOKE_ACCESS, pStrRights,
  299. cStrRights, fInherit, pOldAcl, &pNewAcl );
  300. if (dwErr == ERROR_SUCCESS) {
  301. LocalFree(pOldAcl);
  302. pOldAcl = pNewAcl;
  303. }
  304. } else {
  305. dwErr = ERROR_INVALID_PARAMETER;
  306. }
  307. }
  308. //
  309. // Then the audit failures
  310. //
  311. if (dwErr == ERROR_SUCCESS && CMD_PRESENT(CmdFail, pCmdVals)) {
  312. dwErr = ProcessOperation(argv, &pCmdVals[CmdFail], SET_AUDIT_FAILURE, pStrRights,
  313. cStrRights, 0, NULL, &pFailAcl);
  314. }
  315. //
  316. // Finally, the audit success
  317. //
  318. if (dwErr == ERROR_SUCCESS && CMD_PRESENT(CmdSuccess, pCmdVals)) {
  319. dwErr = ProcessOperation(argv, &pCmdVals[CmdSuccess], SET_AUDIT_SUCCESS, pStrRights,
  320. cStrRights, 0, NULL, &pSuccessAcl);
  321. }
  322. //
  323. // Finally, do the set
  324. //
  325. if (dwErr == ERROR_SUCCESS) {
  326. PACL pNewAcl;
  327. USHORT usSize = 0;
  328. //
  329. // In order to do this, we'll have to combine any of the up to 3 acls we created
  330. // above. The order will be:
  331. // FAILURE
  332. // SUCCESS
  333. // OLD SACL
  334. //
  335. if ( pOldAcl != NULL ) {
  336. usSize += pOldAcl->AclSize;
  337. }
  338. if ( pFailAcl != NULL ) {
  339. usSize += pFailAcl->AclSize;
  340. }
  341. if ( pSuccessAcl != NULL ) {
  342. usSize += pSuccessAcl->AclSize;
  343. }
  344. ASSERT(usSize != 0);
  345. pNewAcl = (PACL)LocalAlloc(LMEM_FIXED, sizeof(ACL) + usSize);
  346. if ( pNewAcl == NULL ) {
  347. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  348. } else {
  349. pNewAcl->AclRevision = ACL_REVISION2;
  350. pNewAcl->Sbz1 = 0;
  351. pNewAcl->AclSize = usSize + sizeof(ACL);
  352. pNewAcl->AceCount = 0;
  353. pNewAcl->Sbz2 = 0;
  354. if( pFailAcl != NULL ) {
  355. dwErr = MergeAcls( pFailAcl, pNewAcl );
  356. }
  357. if( pSuccessAcl != NULL ) {
  358. dwErr = MergeAcls( pSuccessAcl, pNewAcl );
  359. }
  360. if( pOldAcl != NULL ) {
  361. dwErr = MergeAcls( pOldAcl, pNewAcl );
  362. }
  363. }
  364. if (dwErr == ERROR_SUCCESS ) {
  365. dwErr = SetAndPropagateFileRights(argv[1], pNewAcl, SACL_SECURITY_INFORMATION,
  366. CMD_PRESENT(CmdTree, pCmdVals),
  367. CMD_PRESENT(CmdContinue, pCmdVals), TRUE,
  368. fInherit);
  369. LocalFree(pNewAcl);
  370. }
  371. }
  372. if (dwErr == ERROR_INVALID_PARAMETER) {
  373. Usage( pStrRights, cStrRights, pCmdVals );
  374. }
  375. LocalFree(pInitialSD);
  376. }
  377. LocalFree(pOldAcl);
  378. LocalFree(pFailAcl);
  379. LocalFree(pSuccessAcl);
  380. if(dwErr == ERROR_SUCCESS) {
  381. printf("The command completed successfully\n");
  382. } else {
  383. printf("The command failed with an error %lu\n", dwErr);
  384. }
  385. return(dwErr == 0 ? 0 : 1);
  386. }