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.

466 lines
12 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: security.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Interfaces:
  13. //
  14. // History: 06-Jul-96 MarkBl Created.
  15. // 03-Mar-01 JBenton Prefix Bug 350196
  16. // invalid pointer could be dereferenced on cleanup
  17. //
  18. //-----------------------------------------------------------------------------
  19. #include "..\pch\headers.hxx"
  20. #pragma hdrstop
  21. #include "common.hxx"
  22. #include "debug.hxx"
  23. #include "security.hxx"
  24. #include "proto.hxx"
  25. typedef struct _MYSIDINFO {
  26. PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority;
  27. DWORD dwSubAuthority;
  28. PSID pSid;
  29. } MYSIDINFO;
  30. #define TASK_ALL (GENERIC_READ | GENERIC_WRITE | \
  31. GENERIC_EXECUTE | GENERIC_ALL)
  32. #define TASK_READ (GENERIC_READ)
  33. DWORD AllocateAndInitializeDomainSid(
  34. PSID pDomainSid,
  35. MYSIDINFO * pDomainSidInfo);
  36. HRESULT GetFileOwnerSid(
  37. LPCWSTR pwszFileName,
  38. PSID * ppSid);
  39. //+---------------------------------------------------------------------------
  40. //
  41. // Function: SetTaskFileSecurity
  42. //
  43. // Synopsis: Grant the following permissions to the task object:
  44. //
  45. // LocalSystem All Access.
  46. // Creator All Access.
  47. // Domain Admininstrators All Access.
  48. //
  49. // Arguments: [fIsATTask] -- TRUE if the task is an AT-submitted task;
  50. // FALSE otherwise.
  51. // [pwszTaskPath] -- Task object path.
  52. //
  53. // Notes: None.
  54. //
  55. //----------------------------------------------------------------------------
  56. HRESULT
  57. SetTaskFileSecurity(LPCWSTR pwszTaskPath, BOOL fIsATTask)
  58. {
  59. #define BASE_SID_COUNT 2
  60. #define DOMAIN_SID_COUNT 1
  61. #define TASK_ACE_COUNT 3
  62. FILESYSTEMTYPE FileSystemType;
  63. HRESULT hr;
  64. hr = GetFileSystemTypeFromPath(pwszTaskPath, &FileSystemType);
  65. if (FAILED(hr))
  66. {
  67. return(hr);
  68. }
  69. if (FileSystemType == FILESYSTEM_FAT)
  70. {
  71. //
  72. // No security on FAT. This isn't an error. Let the caller
  73. // think everything went fine.
  74. //
  75. return(S_OK);
  76. }
  77. //
  78. // Retrieve the SID of the file owner.
  79. //
  80. PSID pOwnerSid = NULL;
  81. hr = GetFileOwnerSid(pwszTaskPath, &pOwnerSid);
  82. if (FAILED(hr))
  83. {
  84. return(hr);
  85. }
  86. //
  87. // OK, the fun begins. Build a security descriptor and set file security.
  88. //
  89. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  90. DWORD Status;
  91. SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
  92. SID_IDENTIFIER_AUTHORITY CreatorSidAuth = SECURITY_CREATOR_SID_AUTHORITY;
  93. MYSIDINFO rgBaseSidInfo[BASE_SID_COUNT] = {
  94. { &NtAuth, // Local System.
  95. SECURITY_LOCAL_SYSTEM_RID,
  96. NULL },
  97. { &NtAuth, // Built in domain.
  98. SECURITY_BUILTIN_DOMAIN_RID,
  99. NULL }
  100. };
  101. MYSIDINFO rgDomainSidInfo[DOMAIN_SID_COUNT] = {
  102. { NULL, // Domain administrators.
  103. DOMAIN_ALIAS_RID_ADMINS,
  104. NULL }
  105. };
  106. SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
  107. //
  108. // Make sure we didn't goof.
  109. //
  110. schAssert(BASE_SID_COUNT == (sizeof(rgBaseSidInfo) / sizeof(MYSIDINFO)));
  111. schAssert(DOMAIN_SID_COUNT == (sizeof(rgDomainSidInfo) /
  112. sizeof(MYSIDINFO)));
  113. //
  114. // Create the base SIDs.
  115. //
  116. DWORD i;
  117. for (i = 0; i < BASE_SID_COUNT; i++)
  118. {
  119. if (!AllocateAndInitializeSid(rgBaseSidInfo[i].pIdentifierAuthority,
  120. 1,
  121. rgBaseSidInfo[i].dwSubAuthority,
  122. 0, 0, 0, 0, 0, 0, 0,
  123. &rgBaseSidInfo[i].pSid))
  124. {
  125. hr = HRESULT_FROM_WIN32(GetLastError());
  126. CHECK_HRESULT(hr);
  127. break;
  128. }
  129. if (!IsValidSid(rgBaseSidInfo[i].pSid))
  130. {
  131. hr = HRESULT_FROM_WIN32(GetLastError());
  132. CHECK_HRESULT(hr);
  133. break;
  134. }
  135. }
  136. if (SUCCEEDED(hr))
  137. {
  138. //
  139. // Create the domain SIDs.
  140. //
  141. for (i = 0; i < DOMAIN_SID_COUNT; i++)
  142. {
  143. DWORD dwError = AllocateAndInitializeDomainSid(
  144. rgBaseSidInfo[1].pSid,
  145. &rgDomainSidInfo[i]);
  146. if (dwError != ERROR_SUCCESS)
  147. {
  148. hr = HRESULT_FROM_WIN32(dwError);
  149. CHECK_HRESULT(hr);
  150. break;
  151. }
  152. }
  153. }
  154. //
  155. // Create the security descriptor.
  156. //
  157. // Possibly adjust the array size to account for two special cases:
  158. // 1. If this job is an AT job, only local system and administrators
  159. // are to have access; don't grant users access. This case
  160. // also encompasses case (2).
  161. // 2. The owner sid and the domain administrator SID will be equal
  162. // if the user is an admin. If the user is an admin, ignore the
  163. // administrator setting.
  164. //
  165. DWORD ActualTaskAceCount;
  166. if (fIsATTask)
  167. {
  168. ActualTaskAceCount = TASK_ACE_COUNT - 1;
  169. }
  170. else if (EqualSid(pOwnerSid, rgDomainSidInfo[0].pSid))
  171. {
  172. ActualTaskAceCount = TASK_ACE_COUNT - 1;
  173. }
  174. else
  175. {
  176. ActualTaskAceCount = TASK_ACE_COUNT;
  177. }
  178. PACCESS_ALLOWED_ACE rgAce[TASK_ACE_COUNT] = {
  179. NULL, NULL, NULL // Supply this to CreateSD so we
  180. }; // so we don't have to allocate
  181. // memory.
  182. MYACE rgMyAce[TASK_ACE_COUNT] = {
  183. { TASK_ALL, // Acess mask.
  184. NO_PROPAGATE_INHERIT_ACE, // Inherit flags.
  185. rgBaseSidInfo[0].pSid }, // SID.
  186. { TASK_ALL,
  187. NO_PROPAGATE_INHERIT_ACE,
  188. rgDomainSidInfo[0].pSid },
  189. { TASK_ALL,
  190. NO_PROPAGATE_INHERIT_ACE,
  191. pOwnerSid }
  192. };
  193. schAssert(TASK_ACE_COUNT == (sizeof(rgAce)/sizeof(PACCESS_ALLOWED_ACE)) &&
  194. TASK_ACE_COUNT == (sizeof(rgMyAce) / sizeof(MYACE)));
  195. if (FAILED(hr))
  196. {
  197. goto CleanExit;
  198. }
  199. if ((pSecurityDescriptor = CreateSecurityDescriptor(ActualTaskAceCount,
  200. rgMyAce,
  201. rgAce,
  202. &Status)) == NULL)
  203. {
  204. hr = HRESULT_FROM_WIN32(Status);
  205. goto CleanExit;
  206. }
  207. //
  208. // Finally, set permissions.
  209. //
  210. if (!SetFileSecurity(pwszTaskPath, si, pSecurityDescriptor))
  211. {
  212. hr = HRESULT_FROM_WIN32(GetLastError());
  213. CHECK_HRESULT(hr);
  214. goto CleanExit;
  215. }
  216. CleanExit:
  217. delete pOwnerSid;
  218. for (i = 0; i < BASE_SID_COUNT; i++)
  219. {
  220. if (rgBaseSidInfo[i].pSid != NULL)
  221. {
  222. FreeSid(rgBaseSidInfo[i].pSid);
  223. }
  224. }
  225. for (i = 0; i < DOMAIN_SID_COUNT; i++)
  226. {
  227. if (rgDomainSidInfo[i].pSid != NULL)
  228. {
  229. delete rgDomainSidInfo[i].pSid;
  230. }
  231. }
  232. if (pSecurityDescriptor != NULL)
  233. {
  234. DeleteSecurityDescriptor(pSecurityDescriptor);
  235. }
  236. return(hr);
  237. }
  238. //+---------------------------------------------------------------------------
  239. //
  240. // Function: AllocateAndInitializeDomainSid
  241. //
  242. // Synopsis:
  243. //
  244. // Arguments: [pDomainSid] --
  245. // [pDomainSidInfo] --
  246. //
  247. // Notes: None.
  248. //
  249. //----------------------------------------------------------------------------
  250. DWORD
  251. AllocateAndInitializeDomainSid(
  252. PSID pDomainSid,
  253. MYSIDINFO * pDomainSidInfo)
  254. {
  255. UCHAR DomainIdSubAuthorityCount;
  256. DWORD SidLength;
  257. //
  258. // Allocate a Sid which has one more sub-authority than the domain ID.
  259. //
  260. DomainIdSubAuthorityCount = *(GetSidSubAuthorityCount(pDomainSid));
  261. SidLength = GetSidLengthRequired(DomainIdSubAuthorityCount + 1);
  262. pDomainSidInfo->pSid = new BYTE[SidLength];
  263. if (pDomainSidInfo->pSid == NULL)
  264. {
  265. CHECK_HRESULT(E_OUTOFMEMORY);
  266. return(ERROR_NOT_ENOUGH_MEMORY);
  267. }
  268. //
  269. // Initialize the new SID to have the same inital value as the
  270. // domain ID.
  271. //
  272. if (!CopySid(SidLength, pDomainSidInfo->pSid, pDomainSid))
  273. {
  274. delete pDomainSidInfo->pSid;
  275. pDomainSidInfo->pSid = NULL;
  276. CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
  277. return(GetLastError());
  278. }
  279. //
  280. // Adjust the sub-authority count and add the relative Id unique
  281. // to the newly allocated SID
  282. //
  283. (*(GetSidSubAuthorityCount(pDomainSidInfo->pSid)))++;
  284. *(GetSidSubAuthority(pDomainSidInfo->pSid,
  285. DomainIdSubAuthorityCount)) =
  286. pDomainSidInfo->dwSubAuthority;
  287. return(ERROR_SUCCESS);
  288. }
  289. //+---------------------------------------------------------------------------
  290. //
  291. // Function: GetFileOwnerSid
  292. //
  293. // Synopsis:
  294. //
  295. // Arguments: [pwszFileName] --
  296. // [ppSid] --
  297. //
  298. // Notes: None.
  299. //
  300. //----------------------------------------------------------------------------
  301. HRESULT
  302. GetFileOwnerSid(LPCWSTR pwszFileName, PSID * ppSid)
  303. {
  304. DWORD cbSizeNeeded;
  305. //
  306. // Retrieve the file owner. Call GetFileSecurity twice - first to get
  307. // the buffer size, then the actual information retrieval.
  308. //
  309. if (GetFileSecurity(pwszFileName,
  310. OWNER_SECURITY_INFORMATION,
  311. NULL,
  312. 0,
  313. &cbSizeNeeded))
  314. {
  315. //
  316. // Didn't expect this to succeed!
  317. //
  318. CHECK_HRESULT(E_UNEXPECTED);
  319. return(E_UNEXPECTED);
  320. }
  321. DWORD Status = GetLastError();
  322. PSECURITY_DESCRIPTOR pOwnerSecDescr = NULL;
  323. HRESULT hr = S_OK;
  324. if ((Status == ERROR_INSUFFICIENT_BUFFER) && (cbSizeNeeded > 0))
  325. {
  326. //
  327. // Allocate the buffer space necessary and retrieve the info.
  328. //
  329. pOwnerSecDescr = (SECURITY_DESCRIPTOR *)new BYTE[cbSizeNeeded];
  330. if (pOwnerSecDescr == NULL)
  331. {
  332. CHECK_HRESULT(E_OUTOFMEMORY);
  333. return(E_OUTOFMEMORY);
  334. }
  335. if (!GetFileSecurity(pwszFileName,
  336. OWNER_SECURITY_INFORMATION,
  337. pOwnerSecDescr,
  338. cbSizeNeeded,
  339. &cbSizeNeeded))
  340. {
  341. delete pOwnerSecDescr;
  342. hr = HRESULT_FROM_WIN32(GetLastError());
  343. CHECK_HRESULT(hr);
  344. return(hr);
  345. }
  346. }
  347. else
  348. {
  349. hr = HRESULT_FROM_WIN32(GetLastError());
  350. CHECK_HRESULT(hr);
  351. return(hr);
  352. }
  353. //
  354. // Retrieve & validate the owner sid.
  355. //
  356. // NB : After this, pOwnerSid will point into the security descriptor,
  357. // pOwnerSecDescr; hence, the descriptor must exist for the
  358. // lifetime of pOwnerSid.
  359. //
  360. DWORD cbOwnerSid;
  361. PSID pOwnerSid;
  362. BOOL fOwnerDefaulted;
  363. if (GetSecurityDescriptorOwner(pOwnerSecDescr,
  364. &pOwnerSid,
  365. &fOwnerDefaulted))
  366. {
  367. if (IsValidSid(pOwnerSid))
  368. {
  369. *ppSid = new BYTE[cbOwnerSid = GetLengthSid(pOwnerSid)];
  370. if (*ppSid != NULL)
  371. {
  372. if (!CopySid(cbOwnerSid, *ppSid, pOwnerSid))
  373. {
  374. delete *ppSid;
  375. *ppSid = NULL;
  376. hr = HRESULT_FROM_WIN32(GetLastError());
  377. CHECK_HRESULT(hr);
  378. }
  379. }
  380. else
  381. {
  382. hr = E_OUTOFMEMORY;
  383. CHECK_HRESULT(hr);
  384. }
  385. }
  386. else
  387. {
  388. hr = HRESULT_FROM_WIN32(GetLastError());
  389. CHECK_HRESULT(hr);
  390. }
  391. }
  392. else
  393. {
  394. hr = HRESULT_FROM_WIN32(GetLastError());
  395. CHECK_HRESULT(hr);
  396. }
  397. delete pOwnerSecDescr;
  398. return(hr);
  399. }