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.

389 lines
8.1 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. secutils.cpp
  5. Abstract:
  6. The utility functions for the shims.
  7. History:
  8. 02/09/2001 maonis Created
  9. 08/14/2001 robkenny Moved code inside the ShimLib namespace.
  10. --*/
  11. #include "secutils.h"
  12. namespace ShimLib
  13. {
  14. /*++
  15. Function Description:
  16. Determine if the log on user is a member of the group.
  17. Arguments:
  18. IN dwGroup - specify the alias of the group.
  19. OUT pfIsMember - TRUE if it's a member, FALSE if not.
  20. Return Value:
  21. TRUE - we successfully determined if it's a member.
  22. FALSE otherwise.
  23. DevNote:
  24. We are assuming the calling thread is not impersonating.
  25. History:
  26. 02/12/2001 maonis Created
  27. --*/
  28. BOOL
  29. SearchGroupForSID(
  30. DWORD dwGroup,
  31. BOOL* pfIsMember
  32. )
  33. {
  34. PSID pSID = NULL;
  35. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  36. BOOL fRes = TRUE;
  37. if (!AllocateAndInitializeSid(
  38. &SIDAuth,
  39. 2,
  40. SECURITY_BUILTIN_DOMAIN_RID,
  41. dwGroup,
  42. 0,
  43. 0,
  44. 0,
  45. 0,
  46. 0,
  47. 0,
  48. &pSID))
  49. {
  50. DPF("SecurityUtils", eDbgLevelError, "[SearchGroupForSID] AllocateAndInitializeSid failed %d", GetLastError());
  51. return FALSE;
  52. }
  53. if (!CheckTokenMembership(NULL, pSID, pfIsMember))
  54. {
  55. DPF("SecurityUtils", eDbgLevelError, "[SearchGroupForSID] CheckTokenMembership failed: %d", GetLastError());
  56. fRes = FALSE;
  57. }
  58. FreeSid(pSID);
  59. return fRes;
  60. }
  61. /*++
  62. Function Description:
  63. Determine if we should shim this app or not.
  64. If the user is
  65. 1) a member of the Users and
  66. 2) not a member of the Administrators group and
  67. 3) not a member of the Power Users group and
  68. 3) not a member of the Guest group
  69. we'll apply the shim.
  70. Arguments:
  71. None.
  72. Return Value:
  73. TRUE - we should apply the shim.
  74. FALSE otherwise.
  75. History:
  76. 02/12/2001 maonis Created
  77. --*/
  78. BOOL
  79. ShouldApplyShim()
  80. {
  81. BOOL fIsUser, fIsAdmin, fIsPowerUser, fIsGuest;
  82. if (!SearchGroupForSID(DOMAIN_ALIAS_RID_USERS, &fIsUser) ||
  83. !SearchGroupForSID(DOMAIN_ALIAS_RID_ADMINS, &fIsAdmin) ||
  84. !SearchGroupForSID(DOMAIN_ALIAS_RID_POWER_USERS, &fIsPowerUser) ||
  85. !SearchGroupForSID(DOMAIN_ALIAS_RID_GUESTS, &fIsGuest))
  86. {
  87. //
  88. // Don't do anything if we are not sure.
  89. //
  90. return FALSE;
  91. }
  92. return (fIsUser && !fIsPowerUser && !fIsAdmin && !fIsGuest);
  93. }
  94. /*++
  95. Function Description:
  96. Get the current thread on user's SID. If the thread is not
  97. impersonating we get the current process SID instead.
  98. Arguments:
  99. OUT ppThreadSid - points to the current thread's SID.
  100. Return Value:
  101. TRUE - successfully got the SID, the caller is responsible for
  102. freeing it with free().
  103. FALSE otherwise.
  104. History:
  105. 02/12/2001 maonis Created
  106. --*/
  107. BOOL
  108. GetCurrentThreadSid(
  109. OUT PSID* ppThreadSid
  110. )
  111. {
  112. HANDLE hToken;
  113. DWORD dwLastErr;
  114. DWORD cbBuffer, cbRequired;
  115. PTOKEN_USER pUserInfo;
  116. BOOL fRes = FALSE;
  117. // Get the thread token.
  118. if (!OpenThreadToken(
  119. GetCurrentThread(),
  120. TOKEN_QUERY,
  121. FALSE,
  122. &hToken))
  123. {
  124. if ((dwLastErr = GetLastError()) == ERROR_NO_TOKEN)
  125. {
  126. // The thread isn't impersonating so we get the process token instead.
  127. if (!OpenProcessToken(
  128. GetCurrentProcess(),
  129. TOKEN_QUERY,
  130. &hToken))
  131. {
  132. DPF("SecurityUtils", eDbgLevelError, "[GetThreadSid] OpenProcessToken failed: %d", GetLastError());
  133. return FALSE;
  134. }
  135. }
  136. else
  137. {
  138. DPF("SecurityUtils", eDbgLevelError,
  139. "[GetThreadSid] OpenThreadToken failed (and not with no token): %d",
  140. dwLastErr);
  141. return FALSE;
  142. }
  143. }
  144. // Call GetTokenInformation with 0 buffer length to get the
  145. // required buffer size for the token info.
  146. cbBuffer = 0;
  147. if (!GetTokenInformation(
  148. hToken,
  149. TokenUser,
  150. NULL,
  151. cbBuffer,
  152. &cbRequired) &&
  153. (dwLastErr = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  154. {
  155. DPF("SecurityUtils", eDbgLevelError,
  156. "[GetThreadSid] 1st time calling GetTokenInformation "
  157. "didn't failed with ERROR_INSUFFICIENT_BUFFER: %d",
  158. dwLastErr);
  159. return FALSE;
  160. }
  161. cbBuffer = cbRequired;
  162. pUserInfo = (PTOKEN_USER)malloc(cbBuffer);
  163. if (!pUserInfo)
  164. {
  165. DPF("SecurityUtils", eDbgLevelError, "[GetThreadSid] HeapAlloc for user data failed");
  166. return FALSE;
  167. }
  168. // Make the "real" call.
  169. if (!GetTokenInformation(
  170. hToken,
  171. TokenUser,
  172. pUserInfo,
  173. cbBuffer,
  174. &cbRequired))
  175. {
  176. DPF("SecurityUtils", eDbgLevelError,
  177. "[GetThreadSid] 2nd time calling GetTokenInformation failed: %d",
  178. GetLastError());
  179. goto EXIT;
  180. }
  181. cbBuffer = GetLengthSid(pUserInfo->User.Sid);
  182. *ppThreadSid = (PSID)malloc(cbBuffer);
  183. if (!(*ppThreadSid))
  184. {
  185. DPF("SecurityUtils", eDbgLevelError, "[GetThreadSid] HeapAlloc for SID failed");
  186. goto EXIT;
  187. }
  188. if (!CopySid(cbBuffer, *ppThreadSid, pUserInfo->User.Sid))
  189. {
  190. DPF("SecurityUtils", eDbgLevelError, "[GetThreadSid] CopySid failed: %d", GetLastError());
  191. goto EXIT;
  192. }
  193. fRes = TRUE;
  194. EXIT:
  195. free(pUserInfo);
  196. return fRes;
  197. }
  198. // The GENERIC_MAPPING from generic file access rights to specific and standard
  199. // access types.
  200. static GENERIC_MAPPING s_gmFile =
  201. {
  202. FILE_GENERIC_READ,
  203. FILE_GENERIC_WRITE,
  204. FILE_GENERIC_EXECUTE,
  205. FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE
  206. };
  207. /*++
  208. Function Description:
  209. Given the creation dispositon and the desired access when calling
  210. CreateFile, we determine if the caller is requesting write access.
  211. This is specific for files.
  212. Arguments:
  213. IN pszObject - name of the file or directory.
  214. OUT pam - points to the access mask of the user to this object.
  215. Return Value:
  216. TRUE - successfully got the access mask.
  217. FALSE otherwise.
  218. DevNote:
  219. UNDONE - This might not be a complete list...can add as we debug more apps.
  220. History:
  221. 02/12/2001 maonis Created
  222. --*/
  223. BOOL
  224. RequestWriteAccess(
  225. IN DWORD dwCreationDisposition,
  226. IN DWORD dwDesiredAccess
  227. )
  228. {
  229. MapGenericMask(&dwDesiredAccess, &s_gmFile);
  230. if ((dwCreationDisposition != OPEN_EXISTING) ||
  231. (dwDesiredAccess & DELETE) ||
  232. // Generally, app would not specify FILE_WRITE_DATA directly, and if
  233. // it specifies GENERIC_WRITE, it will get mapped to FILE_WRITE_DATA
  234. // OR other things so checking FILE_WRITE_DATA is sufficient.
  235. (dwDesiredAccess & FILE_WRITE_DATA))
  236. {
  237. return TRUE;
  238. }
  239. return FALSE;
  240. }
  241. /*++
  242. Function Description:
  243. Given the name of a directory, determine if the user can create
  244. new files in this directory.
  245. Arguments:
  246. IN pszDir - name of the directory.
  247. IN pUserSid - the user that's requesting to create files.
  248. OUT pfCanCreate.
  249. Return Value:
  250. TRUE - successfully enabled or disabled the privilege.
  251. FALSE - otherwise.
  252. History:
  253. 04/03/2001 maonis Created
  254. --*/
  255. BOOL
  256. AdjustPrivilege(
  257. LPCWSTR pwszPrivilege,
  258. BOOL fEnable
  259. )
  260. {
  261. HANDLE hToken;
  262. TOKEN_PRIVILEGES tp;
  263. BOOL fRes = FALSE;
  264. // Obtain the process token.
  265. if (OpenProcessToken(
  266. GetCurrentProcess(),
  267. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  268. &hToken))
  269. {
  270. // Get the LUID.
  271. if (LookupPrivilegeValueW(NULL, pwszPrivilege, &tp.Privileges[0].Luid))
  272. {
  273. tp.PrivilegeCount = 1;
  274. tp.Privileges[0].Attributes = (fEnable ? SE_PRIVILEGE_ENABLED : 0);
  275. // Enable or disable the privilege.
  276. if (AdjustTokenPrivileges(
  277. hToken,
  278. FALSE,
  279. &tp,
  280. 0,
  281. (PTOKEN_PRIVILEGES)NULL,
  282. 0))
  283. {
  284. fRes = TRUE;
  285. }
  286. }
  287. CloseHandle(hToken);
  288. }
  289. return fRes;
  290. }
  291. }; // end of namespace ShimLib