Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

656 lines
18 KiB

//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation 1991-1995
//
// File: security.c
//
// History:
// 06-07-95 BobDay Created.
//
// This file contains a set of routines for the management of security
//
//---------------------------------------------------------------------------
#include "shellprv.h"
#pragma hdrstop
#ifdef NOT_NEEDED_ANYMORE
const TCHAR c_szProfile[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList");
const TCHAR c_szProfileName[] = TEXT("ProfileName");
const TCHAR c_szProfilePath[] = TEXT("ProfileImagePath");
static TCHAR szCurrentUser[MAX_PATH] = TEXT("");
#endif
//---------------------------------------------------------------------------
// GetCurrentUserToken - Gets the current process's user token and returns
// it. It can later be free'd with LocalFree.
//---------------------------------------------------------------------------
PTOKEN_USER GetCurrentUserToken( void )
{
BOOL fOk;
HANDLE hUser;
PTOKEN_USER pUser;
DWORD dwSize = 10;
DWORD dwNewSize;
fOk = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUser);
if (!fOk)
return NULL;
pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwSize);
if (!pUser)
{
CloseHandle(hUser);
return NULL;
}
fOk = GetTokenInformation( hUser, TokenUser, pUser, dwSize, &dwNewSize);
if (!fOk)
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
LocalFree((HLOCAL)pUser);
CloseHandle(hUser);
return NULL;
}
LocalFree((HLOCAL)pUser);
pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwNewSize);
if (!pUser)
{
CloseHandle(hUser);
return NULL;
}
dwSize = dwNewSize;
fOk = GetTokenInformation( hUser, TokenUser, pUser, dwSize, &dwNewSize);
if (!fOk)
{
LocalFree((HLOCAL)pUser);
CloseHandle(hUser);
return NULL;
}
}
CloseHandle(hUser);
return pUser;
}
//---------------------------------------------------------------------------
// GetCurrentUserSid() - Returns a localalloc'd string containing the text
// version of the current user's SID.
//---------------------------------------------------------------------------
LPTSTR GetCurrentUserSid( void )
{
HANDLE hUser;
PTOKEN_USER pUser;
BOOL fOk;
DWORD dwSize = 10;
DWORD dwNewSize;
UNICODE_STRING UnicodeString;
NTSTATUS NtStatus;
UINT nChars;
LPTSTR pString;
pUser = GetCurrentUserToken();
if (!pUser)
return NULL;
NtStatus = RtlConvertSidToUnicodeString(
&UnicodeString,
pUser->User.Sid,
(BOOLEAN)TRUE // Allocate
);
LocalFree((HLOCAL)pUser);
nChars = (UnicodeString.Length/2);
pString = (LPTSTR)LocalAlloc(LPTR, (nChars+1)*SIZEOF(TCHAR));
if (!pString)
{
RtlFreeUnicodeString(&UnicodeString);
return NULL;
}
#ifdef UNICODE
memcpy(pString,UnicodeString.Buffer,nChars*SIZEOF(TCHAR));
#else
WideCharToMultiByte(CP_ACP, 0,
UnicodeString.Buffer, nChars,
pString, nChars,
NULL, NULL);
#endif
pString[nChars] = TEXT('\0');
RtlFreeUnicodeString(&UnicodeString);
return pString;
}
#ifdef NOT_NEEDED_ANYMORE
//----------------------------------------------------------------------------
// GetCurrentUser - Fills in a buffer with the unique name that we are using
// for the currently logged on user. On NT, this name is
// used for the name of the profile directory and for the
// name of the per-user recycle bin directory on a security
// aware drive.
//----------------------------------------------------------------------------
BOOL GetCurrentUser(
LPTSTR lpBuff,
UINT iSize
) {
LPTSTR lpUserSid;
HKEY hkeyProfileList;
HKEY hkeyUser;
LONG lStatus;
TCHAR szProfilePath[MAX_PATH];
DWORD dwType;
DWORD dwSize;
LPTSTR lpName;
*lpBuff = TEXT('\0');
if (szCurrentUser[0] != TEXT('\0'))
{
lstrcpyn(lpBuff, szCurrentUser, iSize);
return TRUE;
}
lpUserSid = GetCurrentUserSid();
if (!lpUserSid)
{
return FALSE;
}
//
// Open the registry and find the appropriate name
//
lStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, c_szProfile, 0,
KEY_READ, &hkeyProfileList);
if (lStatus != ERROR_SUCCESS)
{
LocalFree((HLOCAL)lpUserSid);
return FALSE;
}
lStatus = RegOpenKeyEx( hkeyProfileList, lpUserSid, 0, KEY_READ, &hkeyUser);
RegCloseKey(hkeyProfileList);
LocalFree((HLOCAL)lpUserSid);
if (lStatus != ERROR_SUCCESS)
return FALSE;
//
// First check for a "ProfileName" key
//
dwSize = SIZEOF(szProfilePath);
lStatus = RegQueryValueEx(hkeyUser, c_szProfileName, NULL, &dwType,
(LPBYTE)szProfilePath, &dwSize);
if (lStatus == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ))
{
RegCloseKey(hkeyUser);
//
// Return the profile name
//
lstrcpyn(szCurrentUser,szProfilePath,ARRAYSIZE(szCurrentUser));
lstrcpyn(lpBuff,szProfilePath,iSize);
return TRUE;
}
//
// Otherwise, grab the "ProfilePath" and get the last part of the name
//
dwSize = SIZEOF(szProfilePath);
lStatus = RegQueryValueEx(hkeyUser,c_szProfilePath, NULL, &dwType,
(LPBYTE)szProfilePath, &dwSize);
RegCloseKey(hkeyUser);
if (lStatus != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
return FALSE;
//
// Return just the directory name portion of the profile path
//
lpName = PathFindFileName(szProfilePath);
lstrcpyn(szCurrentUser, lpName, ARRAYSIZE(szCurrentUser));
lstrcpyn(lpBuff, lpName, iSize);
return TRUE;
}
#endif
//---------------------------------------------------------------------------
// GetUserSecurityAttributes() - Creates a security attributes structure for
// allowing access for only the current user,
// the administrators group, or the system.
// Returns a pointer to security attributes
// structure in the local heap; it can be
// free'd with LocalFree.
//---------------------------------------------------------------------------
LPSECURITY_ATTRIBUTES GetUserSecurityAttributes( BOOL fContainer )
{
SECURITY_DESCRIPTOR sd;
PSECURITY_DESCRIPTOR lpsd;
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
PACL pAcl = NULL;
PTOKEN_USER pUser = NULL;
PSECURITY_ATTRIBUTES lpsa = NULL;
PSID psidSystem = NULL;
PSID psidAdmin = NULL;
DWORD cbAcl;
DWORD cbSA;
DWORD aceIndex;
ACE_HEADER * lpAceHeader;
BOOL bRetVal = FALSE;
BOOL bFreeSA = TRUE;
UINT nCnt;
//
// Get the USER token so we can grab its SID for the DACL.
//
pUser = GetCurrentUserToken();
if (!pUser)
{
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to get user. Error = %d"), GetLastError());
goto Exit;
}
//
// Get the system sid
//
if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to initialize system sid. Error = %d"), GetLastError());
goto Exit;
}
//
// Get the Admin sid
//
if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0,
0, 0, 0, 0, &psidAdmin)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to initialize admin sid. Error = %d"), GetLastError());
goto Exit;
}
//
// Allocate space for the DACL
//
if (fContainer)
nCnt = 2;
else
nCnt = 1;
cbAcl = SIZEOF(ACL) +
(nCnt * GetLengthSid(pUser->User.Sid)) +
(nCnt * GetLengthSid(psidSystem)) +
(nCnt * GetLengthSid(psidAdmin)) +
(nCnt * 3 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
pAcl = (PACL)LocalAlloc(LPTR, cbAcl);
if (!pAcl) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to allocate acl. Error = %d"), GetLastError());
goto Exit;
}
if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to initialize acl. Error = %d"), GetLastError());
goto Exit;
}
//
// Add Aces for User, System, and Admin. Non-inheritable ACEs first
//
aceIndex = 0;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, pUser->User.Sid)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSystem)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidAdmin)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
if (fContainer)
{
//
// Now the inheritable ACEs
//
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, pUser->User.Sid)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
aceIndex++;
if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
if (!GetAce(pAcl, aceIndex, &lpAceHeader)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError());
goto Exit;
}
lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
}
//
// Put together the security descriptor
//
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to initialize security descriptor. Error = %d"), GetLastError());
goto Exit;
}
if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to set security descriptor dacl. Error = %d"), GetLastError());
goto Exit;
}
//
// Now make a Security Attributes buffer
//
cbSA = SIZEOF(SECURITY_ATTRIBUTES) +
GetSecurityDescriptorLength(&sd);
lpsa = (PSECURITY_ATTRIBUTES)LocalAlloc(LPTR, cbSA);
if (!lpsa) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to allocate Security Attributes. Error = %d"), GetLastError());
goto Exit;
}
lpsd = (PSECURITY_DESCRIPTOR)(lpsa+1);
cbSA -= SIZEOF(SECURITY_ATTRIBUTES);
if (!MakeSelfRelativeSD(&sd,lpsd,&cbSA)) {
DebugMsg(DM_TRACE, TEXT("GetUserSecurityAttributes: Failed to make self relative security descriptor. Size = %d, Error = %d"), cbSA, GetLastError());
goto Exit;
}
//
// Build the security attributes structure
//
lpsa->nLength = SIZEOF(*lpsa);
lpsa->lpSecurityDescriptor = lpsd;
lpsa->bInheritHandle = FALSE;
bFreeSA = FALSE;
Exit:
if (pUser)
LocalFree(pUser);
if (psidSystem) {
FreeSid(psidSystem);
}
if (psidAdmin) {
FreeSid(psidAdmin);
}
if (pAcl) {
LocalFree((HLOCAL)pAcl);
}
if (bFreeSA && lpsa)
{
LocalFree((HLOCAL)lpsa);
lpsa = NULL;
}
return lpsa;
}
DWORD
SetPrivilegeAttribute(
LPCTSTR PrivilegeName,
DWORD NewPrivilegeAttribute,
DWORD *OldPrivilegeAttribute
)
/*++
Routine Description:
This routine sets the security attributes for a given privilege.
Arguments:
PrivilegeName - Name of the privilege we are manipulating.
NewPrivilegeAttribute - The new attribute value to use.
OldPrivilegeAttribute - Pointer to receive the old privilege value. OPTIONAL
Return value:
NO_ERROR or WIN32 error.
--*/
{
LUID PrivilegeValue;
BOOL Result;
TOKEN_PRIVILEGES TokenPrivileges, OldTokenPrivileges;
DWORD ReturnLength;
HANDLE TokenHandle;
//
// First, find out the LUID Value of the privilege
//
if(!LookupPrivilegeValue(NULL, PrivilegeName, &PrivilegeValue)) {
return GetLastError();
}
//
// Get the token handle
//
if (!OpenProcessToken (
GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&TokenHandle
)) {
return GetLastError();
}
//
// Set up the privilege set we will need
//
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Luid = PrivilegeValue;
TokenPrivileges.Privileges[0].Attributes = NewPrivilegeAttribute;
ReturnLength = SIZEOF( TOKEN_PRIVILEGES );
if (!AdjustTokenPrivileges (
TokenHandle,
FALSE,
&TokenPrivileges,
SIZEOF( TOKEN_PRIVILEGES ),
&OldTokenPrivileges,
&ReturnLength
)) {
CloseHandle(TokenHandle);
return GetLastError();
}
else {
if (OldPrivilegeAttribute != NULL) {
*OldPrivilegeAttribute = OldTokenPrivileges.Privileges[0].Attributes;
}
CloseHandle(TokenHandle);
return NO_ERROR;
}
}
//*************************************************************
//
// IsUserAnAdmin()
//
// Purpose: Determines if the user is a member of the administrators group.
//
// Parameters: void
//
// Return: TRUE if user is a admin
// FALSE if not
// Comments:
//
// History: Date Author Comment
// 4/12/95 ericflo Created
//
//*************************************************************
BOOL IsUserAnAdmin(void)
{
#ifdef WINNT
SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
NTSTATUS Status;
ULONG InfoLength;
PTOKEN_GROUPS TokenGroupList;
ULONG GroupIndex;
BOOL FoundAdmins;
PSID AdminsDomainSid;
HANDLE hUserToken;
//
// Open the user's token
//
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUserToken)) {
return FALSE;
}
//
// Create Admins domain sid.
//
Status = RtlAllocateAndInitializeSid(
&authNT,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdminsDomainSid
);
//
// Test if user is in the Admins domain
//
//
// Get a list of groups in the token
//
Status = NtQueryInformationToken(
hUserToken, // Handle
TokenGroups, // TokenInformationClass
NULL, // TokenInformation
0, // TokenInformationLength
&InfoLength // ReturnLength
);
if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) {
RtlFreeSid(AdminsDomainSid);
CloseHandle(hUserToken);
return FALSE;
}
TokenGroupList = GlobalAlloc(GPTR, InfoLength);
if (TokenGroupList == NULL) {
RtlFreeSid(AdminsDomainSid);
CloseHandle(hUserToken);
return FALSE;
}
Status = NtQueryInformationToken(
hUserToken, // Handle
TokenGroups, // TokenInformationClass
TokenGroupList, // TokenInformation
InfoLength, // TokenInformationLength
&InfoLength // ReturnLength
);
if (!NT_SUCCESS(Status)) {
GlobalFree(TokenGroupList);
RtlFreeSid(AdminsDomainSid);
CloseHandle(hUserToken);
return FALSE;
}
//
// Search group list for Admins alias
//
FoundAdmins = FALSE;
for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) {
if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, AdminsDomainSid)) {
FoundAdmins = TRUE;
break;
}
}
//
// Tidy up
//
GlobalFree(TokenGroupList);
RtlFreeSid(AdminsDomainSid);
CloseHandle(hUserToken);
return(FoundAdmins);
#else
//
// On Win95 everyone has the same privilage. Someday this might
// change if we want to special case the supervisor account.
//
return FALSE;
#endif
}