/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: secutil.c Abstract: This module contains security-related utility routines. GetUserSid GetInteractiveSid IsClientLocal IsClientUsingLocalConsole IsClientInteractive Author: James G. Cavalaris (jamesca) 31-Jan-2002 Environment: User-mode only. Revision History: 31-Jan-2002 Jim Cavalaris (jamesca) Creation and initial implementation. --*/ // // includes // #include "precomp.h" #pragma hdrstop #include "umpnpi.h" #include "umpnpdat.h" #pragma warning(push) #pragma warning(disable:4214) #pragma warning(disable:4201) #include #pragma warning(pop) #include PSID GetUserSid( IN HANDLE hUserToken ) /*++ Routine Description: Retrieves the corresponding user SID for the specified user access token. Arguments: hUserToken - Specifies a handle to a user access token. Return Value: If successful, returns a pointer to an allocated buffer containing the SID for the specified user access token. Otherwise, returns NULL. Notes: If successful, it is responsibility of the caller to free the the returned buffer from the ghPnPHeap with HeapFree. --*/ { BOOL bResult; DWORD cbBuffer, cbRequired; PTOKEN_USER pUserInfo = NULL; PSID pUserSid = NULL; // // Determine the size of buffer we need to store the TOKEN_USER information // for the supplied user access token. The TOKEN_USER structure contains // the SID_AND_ATTRIBUTES information for the User. // cbBuffer = 0; bResult = GetTokenInformation( hUserToken, TokenUser, NULL, cbBuffer, &cbRequired); ASSERT(bResult == FALSE); if (bResult) { SetLastError(ERROR_INVALID_DATA); goto Clean0; } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { goto Clean0; } ASSERT(cbRequired > 0); // // Allocate a buffer for the TOKEN_USER data. // cbBuffer = cbRequired; pUserInfo = (PTOKEN_USER)HeapAlloc( ghPnPHeap, 0, cbBuffer); if (pUserInfo == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto Clean0; } // // Retrieve the TOKEN_USER data. // bResult = GetTokenInformation( hUserToken, TokenUser, pUserInfo, cbBuffer, &cbRequired); if (!bResult) { goto Clean0; } ASSERT(pUserInfo->User.Sid != NULL); // // Check that the returned SID is valid. // Note - calling GetLastError is not valid for IsValidSid! // ASSERT(IsValidSid(pUserInfo->User.Sid)); if (!IsValidSid(pUserInfo->User.Sid)) { SetLastError(ERROR_INVALID_DATA); goto Clean0; } // // Make a copy of the User SID_AND_ATTRIBUTES. // cbBuffer = GetLengthSid(pUserInfo->User.Sid); ASSERT(cbBuffer > 0); pUserSid = (PSID)HeapAlloc( ghPnPHeap, 0, cbBuffer); if (pUserSid == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto Clean0; } bResult = CopySid( cbBuffer, pUserSid, pUserInfo->User.Sid); if (!bResult) { HeapFree(ghPnPHeap, 0, pUserSid); pUserSid = NULL; goto Clean0; } // // Check that the returned SID is valid. // Note - calling GetLastError is not valid for IsValidSid! // ASSERT(IsValidSid(pUserSid)); if (!IsValidSid(pUserSid)) { SetLastError(ERROR_INVALID_DATA); HeapFree(ghPnPHeap, 0, pUserSid); pUserSid = NULL; goto Clean0; } Clean0: if (pUserInfo != NULL) { HeapFree(ghPnPHeap, 0, pUserInfo); } return pUserSid; } // GetUserSid PSID GetInteractiveSid( VOID ) /*++ Routine Description: Retrieves the Interactive Group SID. Arguments: None. Return Value: If successful, returns a pointer to an allocated buffer containing the SID for the Interactive Group. Otherwise, returns NULL. Notes: If successful, it is responsibility of the caller to free the the returned buffer from the ghPnPHeap with HeapFree. --*/ { BOOL bResult; DWORD cbBuffer; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID pSid = NULL, pInteractiveSid = NULL; // // Create the Interactive Group SID // bResult = AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_INTERACTIVE_RID, 0, 0, 0, 0, 0, 0, 0, &pInteractiveSid); if (!bResult) { goto Clean0; } ASSERT(pInteractiveSid != NULL); // // Check that the returned SID is valid. // Note - calling GetLastError is not valid for IsValidSid! // ASSERT(IsValidSid(pInteractiveSid)); if (!IsValidSid(pInteractiveSid)) { SetLastError(ERROR_INVALID_DATA); goto Clean0; } // // Make a copy of the Interactive Group SID. // cbBuffer = GetLengthSid(pInteractiveSid); ASSERT(cbBuffer > 0); pSid = (PSID)HeapAlloc( ghPnPHeap, 0, cbBuffer); if (pSid == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto Clean0; } bResult = CopySid( cbBuffer, pSid, pInteractiveSid); if (!bResult) { HeapFree(ghPnPHeap, 0, pSid); pSid = NULL; goto Clean0; } // // Check that the returned SID is valid. // Note - calling GetLastError is not valid for IsValidSid! // ASSERT(IsValidSid(pSid)); if (!IsValidSid(pSid)) { SetLastError(ERROR_INVALID_DATA); HeapFree(ghPnPHeap, 0, pSid); pSid = NULL; goto Clean0; } Clean0: if (pInteractiveSid != NULL) { FreeSid(pInteractiveSid); } return pSid; } // GetInteractiveSid // // RPC client attributes and group membership routines // BOOL IsClientLocal( IN handle_t hBinding ) /*++ Routine Description: This routine determines if the client associated with hBinding is on the local machine. Arguments: hBinding RPC Binding handle Return value: The return value is TRUE if the client is local to this machine, FALSE if not or if an error occurs. --*/ { RPC_STATUS RpcStatus; UINT ClientLocalFlag; // // If the specified RPC binding handle is NULL, this is an internal call so // we assume that the privilege has already been checked. // if (hBinding == NULL) { return TRUE; } // // Retrieve the ClientLocalFlags from the RPC binding handle. // RpcStatus = I_RpcBindingIsClientLocal( hBinding, &ClientLocalFlag); if (RpcStatus != RPC_S_OK) { KdPrintEx((DPFLTR_PNPMGR_ID, DBGF_ERRORS, "UMPNPMGR: I_RpcBindingIsClientLocal failed, RpcStatus=%d\n", RpcStatus)); return FALSE; } // // If the ClientLocalFlag is not zero, RPC client is local to server. // if (ClientLocalFlag != 0) { return TRUE; } // // Client is not local to this server. // return FALSE; } // IsClientLocal BOOL IsClientUsingLocalConsole( IN handle_t hBinding ) /*++ Routine Description: This routine impersonates the client associated with hBinding and checks if the client is using the current active console session. Arguments: hBinding RPC Binding handle Return value: The return value is TRUE if the client is using the current active console session, FALSE if not or if an error occurs. --*/ { RPC_STATUS rpcStatus; BOOL bResult = FALSE; // // First, make sure the client is local to the server. // if (!IsClientLocal(hBinding)) { return FALSE; } // // Impersonate the client to retrieve the impersonation token. // rpcStatus = RpcImpersonateClient(hBinding); if (rpcStatus != RPC_S_OK) { KdPrintEx((DPFLTR_PNPMGR_ID, DBGF_ERRORS, "UMPNPMGR: RpcImpersonateClient failed, error = %d\n", rpcStatus)); return FALSE; } // // Compare the client's session with the currently active Console session. // if (GetClientLogonId() == GetActiveConsoleSessionId()) { bResult = TRUE; } rpcStatus = RpcRevertToSelf(); if (rpcStatus != RPC_S_OK) { KdPrintEx((DPFLTR_PNPMGR_ID, DBGF_ERRORS, "UMPNPMGR: RpcRevertToSelf failed, error = %d\n", rpcStatus)); ASSERT(rpcStatus == RPC_S_OK); } return bResult; } // IsClientUsingLocalConsole BOOL IsClientInteractive( IN handle_t hBinding ) /*++ Routine Description: This routine impersonates the client associated with hBinding and checks if the client is a member of the INTERACTIVE well-known group. Arguments: hBinding RPC Binding handle Return value: The return value is TRUE if the client is interactive, FALSE if not or if an error occurs. --*/ { RPC_STATUS rpcStatus; BOOL bIsMember; HANDLE hToken; PSID pInteractiveSid; BOOL bResult = FALSE; // // First, make sure the client is local to the server. // if (!IsClientLocal(hBinding)) { return FALSE; } // // If the specified RPC binding handle is NULL, this is an internal call so // we assume that the privilege has already been checked. // if (hBinding == NULL) { return TRUE; } // // Retrieve the Interactive Group SID // pInteractiveSid = GetInteractiveSid(); if (pInteractiveSid == NULL) { return FALSE; } // // Impersonate the client to retrieve the impersonation token. // rpcStatus = RpcImpersonateClient(hBinding); if (rpcStatus != RPC_S_OK) { KdPrintEx((DPFLTR_PNPMGR_ID, DBGF_ERRORS, "UMPNPMGR: RpcImpersonateClient failed, error = %d\n", rpcStatus)); HeapFree(ghPnPHeap, 0, pInteractiveSid); return FALSE; } if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)) { if (CheckTokenMembership(hToken, pInteractiveSid, &bIsMember)) { if (bIsMember) { bResult = TRUE; } } else { KdPrintEx((DPFLTR_PNPMGR_ID, DBGF_ERRORS, "UMPNPMGR: CheckTokenMembership failed, error = %d\n", GetLastError())); } CloseHandle(hToken); } else { KdPrintEx((DPFLTR_PNPMGR_ID, DBGF_ERRORS, "UMPNPMGR: OpenThreadToken failed, error = %d\n", GetLastError())); } HeapFree(ghPnPHeap, 0, pInteractiveSid); rpcStatus = RpcRevertToSelf(); if (rpcStatus != RPC_S_OK) { KdPrintEx((DPFLTR_PNPMGR_ID, DBGF_ERRORS, "UMPNPMGR: RpcRevertToSelf failed, error = %d\n", rpcStatus)); ASSERT(rpcStatus == RPC_S_OK); } return bResult; } // IsClientInteractive