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.

565 lines
14 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. security.c
  5. Abstract:
  6. Routines to deal with security-related stuff.
  7. Externally exposed routines:
  8. pSetupIsUserAdmin
  9. pSetupDoesUserHavePrivilege
  10. pSetupEnablePrivilege
  11. Author:
  12. Ted Miller (tedm) 14-Jun-1995
  13. Revision History:
  14. Jamie Hunter (jamiehun) Jun-27-2000
  15. Moved functions to sputils
  16. Jamie Hunter (JamieHun) Mar-18-2002
  17. Security code review
  18. --*/
  19. #include "precomp.h"
  20. #include <lmaccess.h>
  21. #pragma hdrstop
  22. #ifndef SPUTILSW
  23. BOOL
  24. pSetupIsUserAdmin(
  25. VOID
  26. )
  27. /*++
  28. Routine Description:
  29. This routine returns TRUE if the caller's process is a member of the
  30. administrator group
  31. Caller MAY be impersonating someone.
  32. Arguments:
  33. None.
  34. Return Value:
  35. TRUE - Caller is effectively an Administrator
  36. FALSE - Caller is not an Administrator
  37. --*/
  38. {
  39. BOOL b;
  40. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  41. PSID AdministratorsGroup;
  42. b = AllocateAndInitializeSid(&NtAuthority,
  43. 2,
  44. SECURITY_BUILTIN_DOMAIN_RID,
  45. DOMAIN_ALIAS_RID_ADMINS,
  46. 0,
  47. 0,
  48. 0,
  49. 0,
  50. 0,
  51. 0,
  52. &AdministratorsGroup
  53. );
  54. if (b) {
  55. if (!CheckTokenMembership(NULL,
  56. AdministratorsGroup,
  57. &b
  58. )) {
  59. b = FALSE;
  60. }
  61. FreeSid(AdministratorsGroup);
  62. }
  63. return(b);
  64. }
  65. #endif // !SPUTILSW
  66. BOOL
  67. pSetupDoesUserHavePrivilege(
  68. PCTSTR PrivilegeName
  69. )
  70. /*++
  71. Routine Description:
  72. This routine returns TRUE if the thread (which may be impersonating) has
  73. the specified privilege. The privilege does not have
  74. to be currently enabled. This routine is used to indicate
  75. whether the caller has the potential to enable the privilege.
  76. Caller MAY be impersonating someone and IS
  77. expected to be able to open their own thread and thread
  78. token.
  79. Arguments:
  80. Privilege - the name form of privilege ID (such as
  81. SE_SECURITY_NAME).
  82. Return Value:
  83. TRUE - Caller has the specified privilege.
  84. FALSE - Caller does not have the specified privilege.
  85. --*/
  86. {
  87. HANDLE Token;
  88. ULONG BytesRequired;
  89. PTOKEN_PRIVILEGES Privileges;
  90. BOOL b;
  91. DWORD i;
  92. LUID Luid;
  93. //
  94. // Open the thread token.
  95. //
  96. if(!OpenThreadToken(GetCurrentThread(),TOKEN_QUERY,FALSE,&Token)) {
  97. if(GetLastError() != ERROR_NO_TOKEN) {
  98. return FALSE;
  99. }
  100. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  101. return FALSE;
  102. }
  103. }
  104. b = FALSE;
  105. Privileges = NULL;
  106. //
  107. // Get privilege information.
  108. //
  109. if(!GetTokenInformation(Token,TokenPrivileges,NULL,0,&BytesRequired)
  110. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  111. && (Privileges = pSetupCheckedMalloc(BytesRequired))
  112. && GetTokenInformation(Token,TokenPrivileges,Privileges,BytesRequired,&BytesRequired)
  113. && LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
  114. //
  115. // See if we have the requested privilege
  116. //
  117. for(i=0; i<Privileges->PrivilegeCount; i++) {
  118. if((Luid.LowPart == Privileges->Privileges[i].Luid.LowPart)
  119. && (Luid.HighPart == Privileges->Privileges[i].Luid.HighPart)) {
  120. b = TRUE;
  121. break;
  122. }
  123. }
  124. }
  125. //
  126. // Clean up and return.
  127. //
  128. if(Privileges) {
  129. pSetupFree(Privileges);
  130. }
  131. CloseHandle(Token);
  132. return(b);
  133. }
  134. BOOL
  135. pSetupEnablePrivilege(
  136. IN PCTSTR PrivilegeName,
  137. IN BOOL Enable
  138. )
  139. /*++
  140. Routine Description:
  141. Enable or disable a given named privilege for current ****PROCESS****
  142. Any code that requires to change privilege per thread should not use this
  143. routine.
  144. It remains here for compatability only and will be depreciated as soon
  145. as dependents change (it's used by a few setup routines where it's fine
  146. to enable process priv's)
  147. Arguments:
  148. PrivilegeName - supplies the name of a system privilege.
  149. Enable - flag indicating whether to enable or disable the privilege.
  150. Return Value:
  151. Boolean value indicating whether the operation was successful.
  152. --*/
  153. {
  154. HANDLE Token;
  155. BOOL b;
  156. TOKEN_PRIVILEGES NewPrivileges;
  157. LUID Luid;
  158. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
  159. return(FALSE);
  160. }
  161. if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
  162. CloseHandle(Token);
  163. return(FALSE);
  164. }
  165. NewPrivileges.PrivilegeCount = 1;
  166. NewPrivileges.Privileges[0].Luid = Luid;
  167. NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
  168. b = AdjustTokenPrivileges(
  169. Token,
  170. FALSE,
  171. &NewPrivileges,
  172. 0,
  173. NULL,
  174. NULL
  175. );
  176. CloseHandle(Token);
  177. return(b);
  178. }
  179. static
  180. PSID
  181. _GetUserSid(
  182. IN HANDLE hUserToken
  183. )
  184. /*++
  185. Routine Description:
  186. Retrieves the corresponding user SID for the specified user access token.
  187. Arguments:
  188. hUserToken - Specifies a handle to a user access token.
  189. Return Value:
  190. If successful, returns a pointer to an allocated buffer containing the SID
  191. for the specified user access token. Otherwise, returns NULL.
  192. GetLastError can be called to retrieve information pertaining to the error
  193. encountered.
  194. Notes:
  195. If successful, it is responsibility of the caller to free the the returned
  196. buffer with pSetupFree.
  197. --*/
  198. {
  199. DWORD cbBuffer, cbRequired;
  200. PTOKEN_USER pUserInfo = NULL;
  201. PSID pUserSid = NULL;
  202. DWORD Err;
  203. try {
  204. //
  205. // Determine the size of buffer we need to store the TOKEN_USER information
  206. // for the supplied user access token. The TOKEN_USER structure contains
  207. // the SID_AND_ATTRIBUTES information for the User.
  208. //
  209. cbBuffer = 0;
  210. Err = GLE_FN_CALL(FALSE,
  211. GetTokenInformation(hUserToken,
  212. TokenUser,
  213. NULL,
  214. cbBuffer,
  215. &cbRequired)
  216. );
  217. //
  218. // We'd better not succeed, since we supplied no buffer!
  219. //
  220. ASSERT(Err != NO_ERROR);
  221. if(Err == NO_ERROR) {
  222. Err = ERROR_INVALID_DATA;
  223. }
  224. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  225. leave;
  226. }
  227. ASSERT(cbRequired > 0);
  228. //
  229. // Allocate a buffer for the TOKEN_USER data.
  230. //
  231. cbBuffer = cbRequired;
  232. pUserInfo = (PTOKEN_USER)pSetupCheckedMalloc(cbBuffer);
  233. if(!pUserInfo) {
  234. Err = ERROR_NOT_ENOUGH_MEMORY;
  235. leave;
  236. }
  237. //
  238. // Retrieve the TOKEN_USER data.
  239. //
  240. Err = GLE_FN_CALL(FALSE,
  241. GetTokenInformation(hUserToken,
  242. TokenUser,
  243. pUserInfo,
  244. cbBuffer,
  245. &cbRequired)
  246. );
  247. if(Err != NO_ERROR) {
  248. leave;
  249. }
  250. MYASSERT(pUserInfo->User.Sid != NULL);
  251. //
  252. // Check that the returned SID is valid.
  253. // Note - calling GetLastError is not valid for IsValidSid!
  254. //
  255. MYASSERT(IsValidSid(pUserInfo->User.Sid));
  256. if(!IsValidSid(pUserInfo->User.Sid)) {
  257. Err = ERROR_INVALID_DATA;
  258. leave;
  259. }
  260. //
  261. // Make a copy of the User SID_AND_ATTRIBUTES.
  262. //
  263. cbBuffer = GetLengthSid(pUserInfo->User.Sid);
  264. MYASSERT(cbBuffer > 0);
  265. pUserSid = (PSID)pSetupCheckedMalloc(cbBuffer);
  266. if(!pUserSid) {
  267. Err = ERROR_NOT_ENOUGH_MEMORY;
  268. leave;
  269. }
  270. Err = GLE_FN_CALL(FALSE, CopySid(cbBuffer, pUserSid, pUserInfo->User.Sid));
  271. if(Err != NO_ERROR) {
  272. leave;
  273. }
  274. //
  275. // Check that the returned SID is valid.
  276. // Note - calling GetLastError is not valid for IsValidSid!
  277. //
  278. MYASSERT(IsValidSid(pUserSid));
  279. if(!IsValidSid(pUserSid)) {
  280. Err = ERROR_INVALID_DATA;
  281. leave;
  282. }
  283. } except(_pSpUtilsExceptionFilter(GetExceptionCode())) {
  284. _pSpUtilsExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  285. }
  286. if(pUserInfo) {
  287. pSetupFree(pUserInfo);
  288. }
  289. if(Err == NO_ERROR) {
  290. MYASSERT(pUserSid);
  291. } else if(pUserSid) {
  292. pSetupFree(pUserSid);
  293. pUserSid = NULL;
  294. }
  295. SetLastError(Err);
  296. return pUserSid;
  297. } // _GetUserSid
  298. BOOL
  299. pSetupIsLocalSystem(
  300. VOID
  301. )
  302. /*++
  303. Routine Description:
  304. This function detects whether the process is running in LocalSystem
  305. security context.
  306. Arguments:
  307. none.
  308. Return Value:
  309. If this process is running in LocalSystem, the return value is non-zero
  310. (i.e., TRUE). Otherwise, the return value is FALSE. If FALSE is returned,
  311. GetLastError returns more information about the reason. If the function
  312. encountered no problem when retrieving/comparing the SIDs, GetLastError()
  313. will return ERROR_FUNCTION_FAILED. Otherwise, it will return another
  314. Win32 error code indicating the cause of failure.
  315. --*/
  316. {
  317. DWORD Err;
  318. HANDLE hToken = NULL;
  319. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  320. PSID pUserSid = NULL, pLocalSystemSid = NULL;
  321. try {
  322. //
  323. // Attempt to open the thread token, to see if we are impersonating.
  324. //
  325. Err = GLE_FN_CALL(FALSE,
  326. OpenThreadToken(GetCurrentThread(),
  327. MAXIMUM_ALLOWED,
  328. TRUE,
  329. &hToken)
  330. );
  331. if(Err == ERROR_NO_TOKEN) {
  332. //
  333. // Not impersonating, attempt to open the process token.
  334. //
  335. Err = GLE_FN_CALL(FALSE,
  336. OpenProcessToken(GetCurrentProcess(),
  337. MAXIMUM_ALLOWED,
  338. &hToken)
  339. );
  340. }
  341. if(Err != NO_ERROR) {
  342. //
  343. // Ensure hToken is still NULL so we won't try and free it later.
  344. //
  345. hToken = NULL;
  346. leave;
  347. }
  348. MYASSERT(hToken);
  349. //
  350. // Retrieve the user SID.
  351. //
  352. Err = GLE_FN_CALL(NULL, pUserSid = _GetUserSid(hToken));
  353. if(Err != NO_ERROR) {
  354. leave;
  355. }
  356. //
  357. // Create the LocalSystem SID
  358. //
  359. Err = GLE_FN_CALL(FALSE,
  360. AllocateAndInitializeSid(&NtAuthority,
  361. 1,
  362. SECURITY_LOCAL_SYSTEM_RID,
  363. 0,
  364. 0,
  365. 0,
  366. 0,
  367. 0,
  368. 0,
  369. 0,
  370. &pLocalSystemSid)
  371. );
  372. if(Err != NO_ERROR) {
  373. leave;
  374. }
  375. MYASSERT(pLocalSystemSid);
  376. //
  377. // Check that the returned SID is valid. We must check this ourselves
  378. // because if either SID supplied to IsEquialSid is not valid, the
  379. // return value is undefined.
  380. //
  381. MYASSERT(IsValidSid(pLocalSystemSid));
  382. //
  383. // Note - calling GetLastError is not valid for IsValidSid!
  384. //
  385. if(!IsValidSid(pLocalSystemSid)) {
  386. Err = ERROR_INVALID_DATA;
  387. leave;
  388. }
  389. //
  390. // Check if the two SIDs are equal.
  391. //
  392. if(!EqualSid(pUserSid, pLocalSystemSid)) {
  393. //
  394. // EqualSid doesn't set last error when SIDs are valid but
  395. // different, so we need to set an unsuccessful error here
  396. // ourselves.
  397. //
  398. Err = ERROR_FUNCTION_FAILED;
  399. leave;
  400. }
  401. //
  402. // Our SID equals LocalSystem SID, so we know we're running in
  403. // LocalSystem! (Err is already set to NO_ERROR, which is our signal
  404. // to return TRUE from this routine)
  405. //
  406. } except(_pSpUtilsExceptionFilter(GetExceptionCode())) {
  407. _pSpUtilsExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  408. }
  409. if(pLocalSystemSid) {
  410. FreeSid(pLocalSystemSid);
  411. }
  412. if(pUserSid) {
  413. pSetupFree(pUserSid);
  414. }
  415. if(hToken) {
  416. CloseHandle(hToken);
  417. }
  418. SetLastError(Err);
  419. return(Err == NO_ERROR);
  420. } // pSetupIsLocalSystem