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.

335 lines
10 KiB

  1. #include "priv.h"
  2. #pragma hdrstop
  3. //---------------------------------------------------------------------------
  4. // GetUserToken - Gets the current process's user token and returns
  5. // it. It can later be free'd with LocalFree.
  6. //
  7. // REARCHITECT (reinerf) - stolen from shell32\securent.c, we should consolidate
  8. // the code somewhere and export it
  9. //---------------------------------------------------------------------------
  10. PTOKEN_USER GetUserToken(HANDLE hUser)
  11. {
  12. PTOKEN_USER pUser;
  13. DWORD dwSize = 64;
  14. HANDLE hToClose = NULL;
  15. if (hUser == NULL)
  16. {
  17. OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUser);
  18. hToClose = hUser;
  19. }
  20. pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwSize);
  21. if (pUser)
  22. {
  23. DWORD dwNewSize;
  24. BOOL fOk = GetTokenInformation(hUser, TokenUser, pUser, dwSize, &dwNewSize);
  25. if (!fOk && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
  26. {
  27. LocalFree((HLOCAL)pUser);
  28. pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwNewSize);
  29. if (pUser)
  30. {
  31. fOk = GetTokenInformation(hUser, TokenUser, pUser, dwNewSize, &dwNewSize);
  32. }
  33. }
  34. if (!fOk)
  35. {
  36. LocalFree((HLOCAL)pUser);
  37. pUser = NULL;
  38. }
  39. }
  40. if (hToClose)
  41. {
  42. CloseHandle(hToClose);
  43. }
  44. return pUser;
  45. }
  46. //
  47. // checks to see if the SHELL_USER_SID is all zeros (flag which means we should really use the users current sid)
  48. //
  49. __inline BOOL IsCurrentUserShellSID(PSHELL_USER_SID psusID)
  50. {
  51. SID_IDENTIFIER_AUTHORITY sidNULL = {0};
  52. if ((psusID->dwUserGroupID == 0) &&
  53. (psusID->dwUserID == 0) &&
  54. memcmp(&psusID->sidAuthority, &sidNULL, sizeof(SID_IDENTIFIER_AUTHORITY)) == 0)
  55. {
  56. return TRUE;
  57. }
  58. return FALSE;
  59. }
  60. //
  61. // Sets the specified ACE in the ACL to have dwAccessMask permissions.
  62. //
  63. __inline BOOL MakeACEInheritable(PACL pAcl, int iIndex, DWORD dwAccessMask)
  64. {
  65. ACE_HEADER* pAceHeader;
  66. if (GetAce(pAcl, iIndex, (LPVOID*)&pAceHeader))
  67. {
  68. pAceHeader->AceFlags |= dwAccessMask;
  69. return TRUE;
  70. }
  71. return FALSE;
  72. }
  73. //
  74. // Helper function to generate a SECURITY_DESCRIPTOR with the specified rights
  75. //
  76. // OUT: psd - A pointer to a uninitialized SECURITY_DESCRIPTOR struct to be inited and filled in
  77. // in by this function
  78. //
  79. // IN: PSHELL_USER_PERMISSION - An array of PSHELL_USER_PERMISSION pointers that specify what access to grant
  80. // cUserPerm - The count of PSHELL_USER_PERMISSION pointers in the array above
  81. //
  82. //
  83. STDAPI_(SECURITY_DESCRIPTOR*) GetShellSecurityDescriptor(PSHELL_USER_PERMISSION* apUserPerm, int cUserPerm)
  84. {
  85. BOOL fSuccess = TRUE; // assume success
  86. SECURITY_DESCRIPTOR* pSD = NULL;
  87. PSID* apSids = NULL;
  88. int cAces = cUserPerm; // one ACE for each entry to start with
  89. int iAceIndex = 0; // helps us keep count of how many ACE's we have added (count as we go)
  90. PTOKEN_USER pUserToken = NULL;
  91. DWORD cbSidLength = 0;
  92. DWORD cbAcl;
  93. PACL pAcl;
  94. int i;
  95. ASSERT(!IsBadReadPtr(apUserPerm, sizeof(PSHELL_USER_PERMISSION) * cUserPerm));
  96. // healthy parameter checking
  97. if (!apUserPerm || cUserPerm <= 0)
  98. {
  99. return NULL;
  100. }
  101. // first find out how many additional ACE's we are going to need
  102. // because of inheritance
  103. for (i = 0; i < cUserPerm; i++)
  104. {
  105. if (apUserPerm[i]->fInherit)
  106. {
  107. cAces++;
  108. }
  109. // also check to see if any of these are using susCurrentUser, in which case
  110. // we want to get the users token now so we have it already
  111. if ((pUserToken == NULL) && IsCurrentUserShellSID(&apUserPerm[i]->susID))
  112. {
  113. pUserToken = GetUserToken(NULL);
  114. if (!pUserToken)
  115. {
  116. DWORD dwLastError = GetLastError();
  117. TraceMsg(TF_WARNING, "Failed to get the users token. Error = %d", dwLastError);
  118. fSuccess = FALSE;
  119. goto cleanup;
  120. }
  121. }
  122. }
  123. // alloc the array to hold all the SID's
  124. apSids = (PSID*)LocalAlloc(LPTR, cUserPerm * sizeof(PSID));
  125. if (!apSids)
  126. {
  127. DWORD dwLastError = GetLastError();
  128. TraceMsg(TF_WARNING, "Failed allocate memory for %i SID's. Error = %d", cUserPerm, dwLastError);
  129. fSuccess = FALSE;
  130. goto cleanup;
  131. }
  132. // initialize the SID's
  133. for (i = 0; i < cUserPerm; i++)
  134. {
  135. DWORD cbSid;
  136. // check for the special case of susCurrentUser
  137. if (IsCurrentUserShellSID(&apUserPerm[i]->susID))
  138. {
  139. ASSERT(pUserToken);
  140. apSids[i] = pUserToken->User.Sid;
  141. }
  142. else
  143. {
  144. SID_IDENTIFIER_AUTHORITY sidAuthority = apUserPerm[i]->susID.sidAuthority;
  145. if (!AllocateAndInitializeSid(&sidAuthority,
  146. (BYTE)(apUserPerm[i]->susID.dwUserID ? 2 : 1), // if dwUserID is nonzero, then there are two SubAuthorities
  147. apUserPerm[i]->susID.dwUserGroupID,
  148. apUserPerm[i]->susID.dwUserID,
  149. 0, 0, 0, 0, 0, 0, &apSids[i]))
  150. {
  151. DWORD dwLastError = GetLastError();
  152. TraceMsg(TF_WARNING, "AllocateAndInitializeSid: Failed to initialze SID. Error = %d", cUserPerm, dwLastError);
  153. fSuccess = FALSE;
  154. goto cleanup;
  155. }
  156. }
  157. // add up all the SID lengths for an easy ACL size computation later...
  158. cbSid = GetLengthSid(apSids[i]);
  159. cbSidLength += cbSid;
  160. if (apUserPerm[i]->fInherit)
  161. {
  162. // if we have an inherit ACE as well, we need to add in the size of the SID again
  163. cbSidLength += cbSid;
  164. }
  165. }
  166. // calculate the size of the ACL we will be building (note: used sizeof(ACCESS_ALLOWED_ACE) b/c all ACE's are the same
  167. // size (excepting wacko object ACE's which we dont deal with).
  168. //
  169. // this makes the size computation easy, since the size of the ACL will be the size of all the ACE's + the size of the SID's.
  170. cbAcl = SIZEOF(ACL) + (cAces * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))) + cbSidLength;
  171. // HACKHACK (reinerf)
  172. //
  173. // we allocate enough space for the SECURITY_DESCRIPTOR and the ACL together and pass them both back to the
  174. // caller to free. we need to to this since the SECURITY_DESCRIPTOR contains a pointer to the ACL
  175. pSD = (SECURITY_DESCRIPTOR*)LocalAlloc(LPTR, SIZEOF(SECURITY_DESCRIPTOR) + cbAcl);
  176. if (!pSD)
  177. {
  178. DWORD dwLastError = GetLastError();
  179. TraceMsg(TF_WARNING, "Failed to allocate space for the SECURITY_DESCRIPTOR and the ACL. Error = %d", dwLastError);
  180. fSuccess = FALSE;
  181. goto cleanup;
  182. }
  183. // set the address of the ACL to right after the SECURITY_DESCRIPTOR in the
  184. // block of memory we just allocated
  185. pAcl = (PACL)(pSD + 1);
  186. if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION))
  187. {
  188. DWORD dwLastError = GetLastError();
  189. TraceMsg(TF_WARNING, "InitializeAcl: Failed to init the ACL. Error = %d", dwLastError);
  190. fSuccess = FALSE;
  191. goto cleanup;
  192. }
  193. for (i = 0; i < cUserPerm; i++)
  194. {
  195. BOOL bRet;
  196. // add the ACE's to the ACL
  197. if (apUserPerm[i]->dwAccessType == ACCESS_ALLOWED_ACE_TYPE)
  198. {
  199. bRet = AddAccessAllowedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwAccessMask, apSids[i]);
  200. }
  201. else
  202. {
  203. bRet = AddAccessDeniedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwAccessMask, apSids[i]);
  204. }
  205. if (!bRet)
  206. {
  207. DWORD dwLastError = GetLastError();
  208. TraceMsg(TF_WARNING, "AddAccessAllowed/DeniedAce: Failed to add SID. Error = %d", dwLastError);
  209. fSuccess = FALSE;
  210. goto cleanup;
  211. }
  212. // sucessfully added an ace
  213. iAceIndex++;
  214. ASSERT(iAceIndex <= cAces);
  215. // if its an inherit ACL, also add another ACE for the inheritance part
  216. if (apUserPerm[i]->fInherit)
  217. {
  218. // add the ACE's to the ACL
  219. if (apUserPerm[i]->dwAccessType == ACCESS_ALLOWED_ACE_TYPE)
  220. {
  221. bRet = AddAccessAllowedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwInheritAccessMask, apSids[i]);
  222. }
  223. else
  224. {
  225. bRet = AddAccessDeniedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwInheritAccessMask, apSids[i]);
  226. }
  227. if (!bRet)
  228. {
  229. DWORD dwLastError = GetLastError();
  230. TraceMsg(TF_WARNING, "AddAccessAllowed/DeniedAce: Failed to add SID. Error = %d", dwLastError);
  231. fSuccess = FALSE;
  232. goto cleanup;
  233. }
  234. if (!MakeACEInheritable(pAcl, iAceIndex, apUserPerm[i]->dwInheritMask))
  235. {
  236. DWORD dwLastError = GetLastError();
  237. TraceMsg(TF_WARNING, "MakeACEInheritable: Failed to add SID. Error = %d", dwLastError);
  238. fSuccess = FALSE;
  239. goto cleanup;
  240. }
  241. // sucessfully added another ace
  242. iAceIndex++;
  243. ASSERT(iAceIndex <= cAces);
  244. }
  245. }
  246. if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
  247. {
  248. DWORD dwLastError = GetLastError();
  249. TraceMsg(TF_WARNING, "InitializeSecurityDescriptor: Failed to init the descriptor. Error = %d", dwLastError);
  250. fSuccess = FALSE;
  251. goto cleanup;
  252. }
  253. if (!SetSecurityDescriptorDacl(pSD, TRUE, pAcl, FALSE))
  254. {
  255. DWORD dwLastError = GetLastError();
  256. TraceMsg(TF_WARNING, "SetSecurityDescriptorDacl: Failed to set the DACL. Error = %d", dwLastError);
  257. fSuccess = FALSE;
  258. goto cleanup;
  259. }
  260. cleanup:
  261. if (apSids)
  262. {
  263. for (i = 0; i < cUserPerm; i++)
  264. {
  265. if (apSids[i])
  266. {
  267. // if this is one of the ones we allocated (eg not the users sid), free it
  268. if (!pUserToken || (apSids[i] != pUserToken->User.Sid))
  269. {
  270. FreeSid(apSids[i]);
  271. }
  272. }
  273. }
  274. LocalFree(apSids);
  275. }
  276. if (pUserToken)
  277. LocalFree(pUserToken);
  278. if (!fSuccess && pSD)
  279. {
  280. LocalFree(pSD);
  281. pSD = NULL;
  282. }
  283. return pSD;
  284. }