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.

601 lines
12 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. secutil.c
  5. Abstract:
  6. This module contains security-related utility routines.
  7. GetUserSid
  8. GetInteractiveSid
  9. IsClientLocal
  10. IsClientUsingLocalConsole
  11. IsClientInteractive
  12. Author:
  13. James G. Cavalaris (jamesca) 31-Jan-2002
  14. Environment:
  15. User-mode only.
  16. Revision History:
  17. 31-Jan-2002 Jim Cavalaris (jamesca)
  18. Creation and initial implementation.
  19. --*/
  20. //
  21. // includes
  22. //
  23. #include "precomp.h"
  24. #pragma hdrstop
  25. #include "umpnpi.h"
  26. #include "umpnpdat.h"
  27. #pragma warning(push)
  28. #pragma warning(disable:4214)
  29. #pragma warning(disable:4201)
  30. #include <winsta.h>
  31. #pragma warning(pop)
  32. #include <syslib.h>
  33. PSID
  34. GetUserSid(
  35. IN HANDLE hUserToken
  36. )
  37. /*++
  38. Routine Description:
  39. Retrieves the corresponding user SID for the specified user access token.
  40. Arguments:
  41. hUserToken -
  42. Specifies a handle to a user access token.
  43. Return Value:
  44. If successful, returns a pointer to an allocated buffer containing the SID
  45. for the specified user access token. Otherwise, returns NULL.
  46. Notes:
  47. If successful, it is responsibility of the caller to free the the returned
  48. buffer from the ghPnPHeap with HeapFree.
  49. --*/
  50. {
  51. BOOL bResult;
  52. DWORD cbBuffer, cbRequired;
  53. PTOKEN_USER pUserInfo = NULL;
  54. PSID pUserSid = NULL;
  55. //
  56. // Determine the size of buffer we need to store the TOKEN_USER information
  57. // for the supplied user access token. The TOKEN_USER structure contains
  58. // the SID_AND_ATTRIBUTES information for the User.
  59. //
  60. cbBuffer = 0;
  61. bResult =
  62. GetTokenInformation(
  63. hUserToken,
  64. TokenUser,
  65. NULL,
  66. cbBuffer,
  67. &cbRequired);
  68. ASSERT(bResult == FALSE);
  69. if (bResult) {
  70. SetLastError(ERROR_INVALID_DATA);
  71. goto Clean0;
  72. } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  73. goto Clean0;
  74. }
  75. ASSERT(cbRequired > 0);
  76. //
  77. // Allocate a buffer for the TOKEN_USER data.
  78. //
  79. cbBuffer = cbRequired;
  80. pUserInfo =
  81. (PTOKEN_USER)HeapAlloc(
  82. ghPnPHeap, 0, cbBuffer);
  83. if (pUserInfo == NULL) {
  84. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  85. goto Clean0;
  86. }
  87. //
  88. // Retrieve the TOKEN_USER data.
  89. //
  90. bResult =
  91. GetTokenInformation(
  92. hUserToken,
  93. TokenUser,
  94. pUserInfo,
  95. cbBuffer,
  96. &cbRequired);
  97. if (!bResult) {
  98. goto Clean0;
  99. }
  100. ASSERT(pUserInfo->User.Sid != NULL);
  101. //
  102. // Check that the returned SID is valid.
  103. // Note - calling GetLastError is not valid for IsValidSid!
  104. //
  105. ASSERT(IsValidSid(pUserInfo->User.Sid));
  106. if (!IsValidSid(pUserInfo->User.Sid)) {
  107. SetLastError(ERROR_INVALID_DATA);
  108. goto Clean0;
  109. }
  110. //
  111. // Make a copy of the User SID_AND_ATTRIBUTES.
  112. //
  113. cbBuffer =
  114. GetLengthSid(pUserInfo->User.Sid);
  115. ASSERT(cbBuffer > 0);
  116. pUserSid =
  117. (PSID)HeapAlloc(
  118. ghPnPHeap, 0, cbBuffer);
  119. if (pUserSid == NULL) {
  120. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  121. goto Clean0;
  122. }
  123. bResult =
  124. CopySid(
  125. cbBuffer,
  126. pUserSid,
  127. pUserInfo->User.Sid);
  128. if (!bResult) {
  129. HeapFree(ghPnPHeap, 0, pUserSid);
  130. pUserSid = NULL;
  131. goto Clean0;
  132. }
  133. //
  134. // Check that the returned SID is valid.
  135. // Note - calling GetLastError is not valid for IsValidSid!
  136. //
  137. ASSERT(IsValidSid(pUserSid));
  138. if (!IsValidSid(pUserSid)) {
  139. SetLastError(ERROR_INVALID_DATA);
  140. HeapFree(ghPnPHeap, 0, pUserSid);
  141. pUserSid = NULL;
  142. goto Clean0;
  143. }
  144. Clean0:
  145. if (pUserInfo != NULL) {
  146. HeapFree(ghPnPHeap, 0, pUserInfo);
  147. }
  148. return pUserSid;
  149. } // GetUserSid
  150. PSID
  151. GetInteractiveSid(
  152. VOID
  153. )
  154. /*++
  155. Routine Description:
  156. Retrieves the Interactive Group SID.
  157. Arguments:
  158. None.
  159. Return Value:
  160. If successful, returns a pointer to an allocated buffer containing the SID
  161. for the Interactive Group. Otherwise, returns NULL.
  162. Notes:
  163. If successful, it is responsibility of the caller to free the the returned
  164. buffer from the ghPnPHeap with HeapFree.
  165. --*/
  166. {
  167. BOOL bResult;
  168. DWORD cbBuffer;
  169. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  170. PSID pSid = NULL, pInteractiveSid = NULL;
  171. //
  172. // Create the Interactive Group SID
  173. //
  174. bResult =
  175. AllocateAndInitializeSid(
  176. &NtAuthority, 1,
  177. SECURITY_INTERACTIVE_RID,
  178. 0, 0, 0, 0, 0, 0, 0,
  179. &pInteractiveSid);
  180. if (!bResult) {
  181. goto Clean0;
  182. }
  183. ASSERT(pInteractiveSid != NULL);
  184. //
  185. // Check that the returned SID is valid.
  186. // Note - calling GetLastError is not valid for IsValidSid!
  187. //
  188. ASSERT(IsValidSid(pInteractiveSid));
  189. if (!IsValidSid(pInteractiveSid)) {
  190. SetLastError(ERROR_INVALID_DATA);
  191. goto Clean0;
  192. }
  193. //
  194. // Make a copy of the Interactive Group SID.
  195. //
  196. cbBuffer =
  197. GetLengthSid(pInteractiveSid);
  198. ASSERT(cbBuffer > 0);
  199. pSid =
  200. (PSID)HeapAlloc(
  201. ghPnPHeap, 0, cbBuffer);
  202. if (pSid == NULL) {
  203. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  204. goto Clean0;
  205. }
  206. bResult =
  207. CopySid(
  208. cbBuffer,
  209. pSid,
  210. pInteractiveSid);
  211. if (!bResult) {
  212. HeapFree(ghPnPHeap, 0, pSid);
  213. pSid = NULL;
  214. goto Clean0;
  215. }
  216. //
  217. // Check that the returned SID is valid.
  218. // Note - calling GetLastError is not valid for IsValidSid!
  219. //
  220. ASSERT(IsValidSid(pSid));
  221. if (!IsValidSid(pSid)) {
  222. SetLastError(ERROR_INVALID_DATA);
  223. HeapFree(ghPnPHeap, 0, pSid);
  224. pSid = NULL;
  225. goto Clean0;
  226. }
  227. Clean0:
  228. if (pInteractiveSid != NULL) {
  229. FreeSid(pInteractiveSid);
  230. }
  231. return pSid;
  232. } // GetInteractiveSid
  233. //
  234. // RPC client attributes and group membership routines
  235. //
  236. BOOL
  237. IsClientLocal(
  238. IN handle_t hBinding
  239. )
  240. /*++
  241. Routine Description:
  242. This routine determines if the client associated with hBinding is on the
  243. local machine.
  244. Arguments:
  245. hBinding RPC Binding handle
  246. Return value:
  247. The return value is TRUE if the client is local to this machine, FALSE if
  248. not or if an error occurs.
  249. --*/
  250. {
  251. RPC_STATUS RpcStatus;
  252. UINT ClientLocalFlag;
  253. //
  254. // If the specified RPC binding handle is NULL, this is an internal call so
  255. // we assume that the privilege has already been checked.
  256. //
  257. if (hBinding == NULL) {
  258. return TRUE;
  259. }
  260. //
  261. // Retrieve the ClientLocalFlags from the RPC binding handle.
  262. //
  263. RpcStatus =
  264. I_RpcBindingIsClientLocal(
  265. hBinding,
  266. &ClientLocalFlag);
  267. if (RpcStatus != RPC_S_OK) {
  268. KdPrintEx((DPFLTR_PNPMGR_ID,
  269. DBGF_ERRORS,
  270. "UMPNPMGR: I_RpcBindingIsClientLocal failed, RpcStatus=%d\n",
  271. RpcStatus));
  272. return FALSE;
  273. }
  274. //
  275. // If the ClientLocalFlag is not zero, RPC client is local to server.
  276. //
  277. if (ClientLocalFlag != 0) {
  278. return TRUE;
  279. }
  280. //
  281. // Client is not local to this server.
  282. //
  283. return FALSE;
  284. } // IsClientLocal
  285. BOOL
  286. IsClientUsingLocalConsole(
  287. IN handle_t hBinding
  288. )
  289. /*++
  290. Routine Description:
  291. This routine impersonates the client associated with hBinding and checks
  292. if the client is using the current active console session.
  293. Arguments:
  294. hBinding RPC Binding handle
  295. Return value:
  296. The return value is TRUE if the client is using the current active console
  297. session, FALSE if not or if an error occurs.
  298. --*/
  299. {
  300. RPC_STATUS rpcStatus;
  301. BOOL bResult = FALSE;
  302. //
  303. // First, make sure the client is local to the server.
  304. //
  305. if (!IsClientLocal(hBinding)) {
  306. return FALSE;
  307. }
  308. //
  309. // Impersonate the client to retrieve the impersonation token.
  310. //
  311. rpcStatus = RpcImpersonateClient(hBinding);
  312. if (rpcStatus != RPC_S_OK) {
  313. KdPrintEx((DPFLTR_PNPMGR_ID,
  314. DBGF_ERRORS,
  315. "UMPNPMGR: RpcImpersonateClient failed, error = %d\n",
  316. rpcStatus));
  317. return FALSE;
  318. }
  319. //
  320. // Compare the client's session with the currently active Console session.
  321. //
  322. if (GetClientLogonId() == GetActiveConsoleSessionId()) {
  323. bResult = TRUE;
  324. }
  325. rpcStatus = RpcRevertToSelf();
  326. if (rpcStatus != RPC_S_OK) {
  327. KdPrintEx((DPFLTR_PNPMGR_ID,
  328. DBGF_ERRORS,
  329. "UMPNPMGR: RpcRevertToSelf failed, error = %d\n",
  330. rpcStatus));
  331. ASSERT(rpcStatus == RPC_S_OK);
  332. }
  333. return bResult;
  334. } // IsClientUsingLocalConsole
  335. BOOL
  336. IsClientInteractive(
  337. IN handle_t hBinding
  338. )
  339. /*++
  340. Routine Description:
  341. This routine impersonates the client associated with hBinding and checks
  342. if the client is a member of the INTERACTIVE well-known group.
  343. Arguments:
  344. hBinding RPC Binding handle
  345. Return value:
  346. The return value is TRUE if the client is interactive, FALSE if not
  347. or if an error occurs.
  348. --*/
  349. {
  350. RPC_STATUS rpcStatus;
  351. BOOL bIsMember;
  352. HANDLE hToken;
  353. PSID pInteractiveSid;
  354. BOOL bResult = FALSE;
  355. //
  356. // First, make sure the client is local to the server.
  357. //
  358. if (!IsClientLocal(hBinding)) {
  359. return FALSE;
  360. }
  361. //
  362. // If the specified RPC binding handle is NULL, this is an internal call so
  363. // we assume that the privilege has already been checked.
  364. //
  365. if (hBinding == NULL) {
  366. return TRUE;
  367. }
  368. //
  369. // Retrieve the Interactive Group SID
  370. //
  371. pInteractiveSid =
  372. GetInteractiveSid();
  373. if (pInteractiveSid == NULL) {
  374. return FALSE;
  375. }
  376. //
  377. // Impersonate the client to retrieve the impersonation token.
  378. //
  379. rpcStatus = RpcImpersonateClient(hBinding);
  380. if (rpcStatus != RPC_S_OK) {
  381. KdPrintEx((DPFLTR_PNPMGR_ID,
  382. DBGF_ERRORS,
  383. "UMPNPMGR: RpcImpersonateClient failed, error = %d\n",
  384. rpcStatus));
  385. HeapFree(ghPnPHeap, 0, pInteractiveSid);
  386. return FALSE;
  387. }
  388. if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)) {
  389. if (CheckTokenMembership(hToken,
  390. pInteractiveSid,
  391. &bIsMember)) {
  392. if (bIsMember) {
  393. bResult = TRUE;
  394. }
  395. } else {
  396. KdPrintEx((DPFLTR_PNPMGR_ID,
  397. DBGF_ERRORS,
  398. "UMPNPMGR: CheckTokenMembership failed, error = %d\n",
  399. GetLastError()));
  400. }
  401. CloseHandle(hToken);
  402. } else {
  403. KdPrintEx((DPFLTR_PNPMGR_ID,
  404. DBGF_ERRORS,
  405. "UMPNPMGR: OpenThreadToken failed, error = %d\n",
  406. GetLastError()));
  407. }
  408. HeapFree(ghPnPHeap, 0, pInteractiveSid);
  409. rpcStatus = RpcRevertToSelf();
  410. if (rpcStatus != RPC_S_OK) {
  411. KdPrintEx((DPFLTR_PNPMGR_ID,
  412. DBGF_ERRORS,
  413. "UMPNPMGR: RpcRevertToSelf failed, error = %d\n",
  414. rpcStatus));
  415. ASSERT(rpcStatus == RPC_S_OK);
  416. }
  417. return bResult;
  418. } // IsClientInteractive
  419.