473 lines
12 KiB
C
473 lines
12 KiB
C
|
/****************************** Module Header ******************************\
|
||
|
* Module Name: security.c
|
||
|
*
|
||
|
* Copyright (c) 1992, Microsoft Corporation
|
||
|
*
|
||
|
* Handles security aspects of progman operation.
|
||
|
*
|
||
|
* History:
|
||
|
* 01-16-92 JohanneC Created - mostly taken from old winlogon.c
|
||
|
\***************************************************************************/
|
||
|
|
||
|
#include "sec.h"
|
||
|
#include <string.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <io.h>
|
||
|
#include <stdio.h>
|
||
|
#include <lm.h>
|
||
|
|
||
|
|
||
|
/***************************************************************************\
|
||
|
* SetMyAce
|
||
|
*
|
||
|
* Helper routine that fills in a MYACE structure.
|
||
|
*
|
||
|
* History:
|
||
|
* 02-06-92 Davidc Created
|
||
|
\***************************************************************************/
|
||
|
VOID
|
||
|
SetMyAce(
|
||
|
PMYACE MyAce,
|
||
|
PSID Sid,
|
||
|
ACCESS_MASK Mask,
|
||
|
UCHAR InheritFlags
|
||
|
)
|
||
|
{
|
||
|
MyAce->Sid = Sid;
|
||
|
MyAce->AccessMask= Mask;
|
||
|
MyAce->InheritFlags = InheritFlags;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************\
|
||
|
* SetWorldSecurity
|
||
|
*
|
||
|
* Sets the security given the logon sid passed.
|
||
|
*
|
||
|
* If the UserSid = NULL, no access is given to anyone other than world
|
||
|
* Users will have read access and if bWriteAccess is TRUE, they will also
|
||
|
* have write access.
|
||
|
*
|
||
|
* Returns TRUE on success, FALSE on failure
|
||
|
*
|
||
|
* History:
|
||
|
* 04-16-91 Johannec Created
|
||
|
\***************************************************************************/
|
||
|
BOOL
|
||
|
SetWorldSecurity(
|
||
|
PSID UserSid,
|
||
|
PSECURITY_DESCRIPTOR *pSecDesc,
|
||
|
BOOL bWriteAccess
|
||
|
)
|
||
|
{
|
||
|
MYACE Ace[4];
|
||
|
ACEINDEX AceCount = 0;
|
||
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
||
|
PSID WorldSid = NULL;
|
||
|
PSID AdminAliasSid = NULL;
|
||
|
PSID PowerUserAliasSid = NULL;
|
||
|
PSID SystemOpsAliasSid = NULL;
|
||
|
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
||
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
||
|
NTSTATUS Status;
|
||
|
ACCESS_MASK AccessMask;
|
||
|
|
||
|
// Create the world Sid
|
||
|
Status = RtlAllocateAndInitializeSid(
|
||
|
&WorldSidAuthority,
|
||
|
1, // Sub authority count
|
||
|
SECURITY_WORLD_RID, // Sub authorities
|
||
|
0, 0, 0, 0, 0, 0, 0,
|
||
|
&WorldSid);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
DbgOnlyPrint("progman failed to allocate memory for world sid\n");
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
Status = RtlAllocateAndInitializeSid(
|
||
|
&NtAuthority,
|
||
|
2, // Sub authority count
|
||
|
SECURITY_BUILTIN_DOMAIN_RID, // Sub authority[0]
|
||
|
DOMAIN_ALIAS_RID_ADMINS, // Sub authority[1]
|
||
|
0, 0, 0, 0, 0, 0,
|
||
|
&AdminAliasSid);
|
||
|
|
||
|
Status = RtlAllocateAndInitializeSid(
|
||
|
&NtAuthority,
|
||
|
2, // Sub authority count
|
||
|
SECURITY_BUILTIN_DOMAIN_RID, // Sub authority[0]
|
||
|
DOMAIN_ALIAS_RID_POWER_USERS, // Sub authority[1]
|
||
|
0, 0, 0, 0, 0, 0,
|
||
|
&PowerUserAliasSid);
|
||
|
|
||
|
Status = RtlAllocateAndInitializeSid(
|
||
|
&NtAuthority,
|
||
|
2, // Sub authority count
|
||
|
SECURITY_BUILTIN_DOMAIN_RID, // Sub authority[0]
|
||
|
DOMAIN_ALIAS_RID_SYSTEM_OPS, // Sub authority[1]
|
||
|
0, 0, 0, 0, 0, 0,
|
||
|
&SystemOpsAliasSid);
|
||
|
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
DbgOnlyPrint("progman failed to allocate memory for admin sid\n");
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Define the World ACEs
|
||
|
//
|
||
|
|
||
|
if (bWriteAccess) {
|
||
|
AccessMask = KEY_READ | KEY_WRITE | DELETE;
|
||
|
}
|
||
|
else {
|
||
|
AccessMask = KEY_READ;
|
||
|
}
|
||
|
|
||
|
SetMyAce(&(Ace[AceCount++]),
|
||
|
WorldSid,
|
||
|
AccessMask,
|
||
|
NO_PROPAGATE_INHERIT_ACE
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Define the Admins ACEs
|
||
|
//
|
||
|
|
||
|
SetMyAce(&(Ace[AceCount++]),
|
||
|
AdminAliasSid,
|
||
|
GENERIC_ALL,
|
||
|
NO_PROPAGATE_INHERIT_ACE
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Define the Power Users ACEs
|
||
|
//
|
||
|
|
||
|
SetMyAce(&(Ace[AceCount++]),
|
||
|
PowerUserAliasSid,
|
||
|
GENERIC_ALL,
|
||
|
NO_PROPAGATE_INHERIT_ACE
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Define the System Operators ACEs
|
||
|
//
|
||
|
|
||
|
SetMyAce(&(Ace[AceCount++]),
|
||
|
SystemOpsAliasSid,
|
||
|
GENERIC_ALL,
|
||
|
NO_PROPAGATE_INHERIT_ACE
|
||
|
);
|
||
|
|
||
|
// Check we didn't goof
|
||
|
ASSERT((sizeof(Ace) / sizeof(MYACE)) >= AceCount);
|
||
|
|
||
|
//
|
||
|
// Create the security descriptor
|
||
|
//
|
||
|
|
||
|
SecurityDescriptor = CreateSecurityDescriptor(Ace, AceCount);
|
||
|
if (SecurityDescriptor == NULL) {
|
||
|
DbgOnlyPrint("Progman failed to create security descriptor\n\r");
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// Keep security descriptor global
|
||
|
// delete only when exiting the program
|
||
|
|
||
|
//
|
||
|
// Free up the security descriptor
|
||
|
//
|
||
|
|
||
|
DeleteSecurityDescriptor(SecurityDescriptor);
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Return success status
|
||
|
//
|
||
|
|
||
|
*pSecDesc = SecurityDescriptor;
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/***************************************************************************\
|
||
|
* InitializeSecurityAttributes
|
||
|
*
|
||
|
*
|
||
|
* Returns TRUE on success, FALSE on failure
|
||
|
*
|
||
|
* History:
|
||
|
* 04-14-92 JohanneC Created
|
||
|
\***************************************************************************/
|
||
|
BOOL InitializeSecurityAttributes(PSECURITY_ATTRIBUTES pSecurityAttributes,
|
||
|
BOOL bWriteAccess)
|
||
|
{
|
||
|
PSECURITY_DESCRIPTOR pSecDesc;
|
||
|
|
||
|
if (!SetWorldSecurity(NULL, &pSecDesc, bWriteAccess)) {
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
pSecurityAttributes->nLength = sizeof(SECURITY_ATTRIBUTES);
|
||
|
pSecurityAttributes->lpSecurityDescriptor = pSecDesc;
|
||
|
pSecurityAttributes->bInheritHandle = TRUE;
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
TestTokenForAdmin(
|
||
|
HANDLE Token
|
||
|
);
|
||
|
|
||
|
/***************************************************************************\
|
||
|
* TestUserForAdmin
|
||
|
*
|
||
|
*
|
||
|
* Returns TRUE if the current user is part of the ADMIN group,
|
||
|
* FALSE otherwise
|
||
|
*
|
||
|
* History:
|
||
|
* 07-15-92 JohanneC Created
|
||
|
\***************************************************************************/
|
||
|
BOOL TestUserForAdmin()
|
||
|
{
|
||
|
BOOL UserIsAdmin = FALSE;
|
||
|
HANDLE Token;
|
||
|
#if 0
|
||
|
ACCESS_MASK GrantedAccess;
|
||
|
GENERIC_MAPPING GenericMapping;
|
||
|
PPRIVILEGE_SET pPrivilegeSet;
|
||
|
DWORD dwPrivilegeSetLength;
|
||
|
MYACE Ace[1];
|
||
|
PSECURITY_DESCRIPTOR pSecDesc;
|
||
|
NTSTATUS Status;
|
||
|
#endif
|
||
|
PSID AdminAliasSid = NULL;
|
||
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
||
|
|
||
|
//
|
||
|
// Get the token of the current process.
|
||
|
//
|
||
|
|
||
|
if (!OpenProcessToken(
|
||
|
GetCurrentProcess(),
|
||
|
TOKEN_QUERY,
|
||
|
&Token
|
||
|
) ) {
|
||
|
DbgOnlyPrint("Progman: Can't open own process token for token_query access\n\r");
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
// not working because of error = STATUS_NO_IMPERSONATION_TOKEN
|
||
|
so use the code from winlogon instead (see #else)
|
||
|
|
||
|
Status = RtlAllocateAndInitializeSid(
|
||
|
&NtAuthority,
|
||
|
2, // Sub authority count
|
||
|
SECURITY_BUILTIN_DOMAIN_RID, // Sub authority[0]
|
||
|
DOMAIN_ALIAS_RID_ADMINS, // Sub authority[1]
|
||
|
0, 0, 0, 0, 0, 0,
|
||
|
&AdminAliasSid);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
DbgOnlyPrint(TEXT("progman failed to allocate memory for admin sid\n"));
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Define the Admins ACEs
|
||
|
//
|
||
|
|
||
|
SetMyAce(&(Ace[0]),
|
||
|
AdminAliasSid,
|
||
|
GENERIC_ALL,
|
||
|
NO_PROPAGATE_INHERIT_ACE
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Create the security descriptor
|
||
|
//
|
||
|
|
||
|
pSecDesc = CreateSecurityDescriptor(Ace, 1);
|
||
|
if (pSecDesc == NULL) {
|
||
|
DbgOnlyPrint(TEXT("Progman failed to create security descriptor\n\r"));
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate memory for the PrivilegeSet buffer
|
||
|
//
|
||
|
|
||
|
dwPrivilegeSetLength = 256;
|
||
|
pPrivilegeSet = Alloc(dwPrivilegeSetLength);
|
||
|
if (!pPrivilegeSet) {
|
||
|
DbgOnlyPrint(TEXT("Progman: Can't alloc memory for privilege set\n\r"));
|
||
|
goto FreeSecDesc;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Test if user has admin privileges.
|
||
|
//
|
||
|
|
||
|
if(!AccessCheck(pSecDesc,
|
||
|
Token,
|
||
|
STANDARD_RIGHTS_ALL,
|
||
|
&GenericMapping,
|
||
|
pPrivilegeSet,
|
||
|
&dwPrivilegeSetLength,
|
||
|
&GrantedAccess,
|
||
|
&UserIsAdmin) ){
|
||
|
|
||
|
DbgOnlyPrint(TEXT("Progman: AccessCheck failed, error = %d\n\r"), GetLastError());
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Free up the the PrivilegeSet
|
||
|
//
|
||
|
|
||
|
Free(pPrivilegeSet);
|
||
|
|
||
|
FreeSecDesc:
|
||
|
|
||
|
//
|
||
|
// Free up the security descriptor
|
||
|
//
|
||
|
|
||
|
DeleteSecurityDescriptor(pSecDesc);
|
||
|
|
||
|
#else
|
||
|
|
||
|
UserIsAdmin = TestTokenForAdmin(Token);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//Exit:
|
||
|
|
||
|
//
|
||
|
// We are finished with the token.
|
||
|
//
|
||
|
|
||
|
CloseHandle(Token);
|
||
|
|
||
|
return(UserIsAdmin);
|
||
|
}
|
||
|
/***************************************************************************\
|
||
|
* TestTokenForAdmin
|
||
|
*
|
||
|
* Returns TRUE if the token passed represents an admin user, otherwise FALSE
|
||
|
*
|
||
|
* The token handle passed must have TOKEN_QUERY access.
|
||
|
*
|
||
|
* History:
|
||
|
* 08-01-92 JohanneC Extracted code from winlogon
|
||
|
* 05-06-92 Davidc Created
|
||
|
\***************************************************************************/
|
||
|
BOOL
|
||
|
TestTokenForAdmin(
|
||
|
HANDLE Token
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
DWORD InfoLength;
|
||
|
PTOKEN_GROUPS TokenGroupList;
|
||
|
DWORD GroupIndex;
|
||
|
PSID AdminSid;
|
||
|
BOOL FoundAdmin;
|
||
|
SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
|
||
|
|
||
|
//
|
||
|
// Get a list of groups in the token
|
||
|
//
|
||
|
|
||
|
Status = NtQueryInformationToken(
|
||
|
Token, // Handle
|
||
|
TokenGroups, // TokenInformationClass
|
||
|
NULL, // TokenInformation
|
||
|
0, // TokenInformationLength
|
||
|
&InfoLength // ReturnLength
|
||
|
);
|
||
|
|
||
|
if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) {
|
||
|
|
||
|
DbgOnlyPrint("Winlogon failed to get group info for admin token, status = 0x%lx\n", Status);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
TokenGroupList = Alloc(InfoLength);
|
||
|
|
||
|
if (TokenGroupList == NULL) {
|
||
|
DbgOnlyPrint("Winlogon unable to allocate memory for token groups\n");
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
Status = NtQueryInformationToken(
|
||
|
Token, // Handle
|
||
|
TokenGroups, // TokenInformationClass
|
||
|
TokenGroupList, // TokenInformation
|
||
|
InfoLength, // TokenInformationLength
|
||
|
&InfoLength // ReturnLength
|
||
|
);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
DbgOnlyPrint("Winlogon failed to query groups for admin token, status = 0x%lx\n", Status);
|
||
|
Free(TokenGroupList);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Create the admin sid
|
||
|
//
|
||
|
|
||
|
Status = RtlAllocateAndInitializeSid(
|
||
|
&SystemSidAuthority, 2,
|
||
|
SECURITY_BUILTIN_DOMAIN_RID,
|
||
|
DOMAIN_ALIAS_RID_ADMINS,
|
||
|
0, 0, 0, 0, 0, 0,
|
||
|
&AdminSid);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
DbgOnlyPrint("Winlogon failed to initialize admin alias sid\n");
|
||
|
Free(TokenGroupList);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Search group list for admin alias
|
||
|
//
|
||
|
|
||
|
FoundAdmin = FALSE;
|
||
|
|
||
|
for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) {
|
||
|
|
||
|
if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, AdminSid)) {
|
||
|
FoundAdmin = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Tidy up
|
||
|
//
|
||
|
|
||
|
RtlFreeSid(AdminSid);
|
||
|
Free(TokenGroupList);
|
||
|
|
||
|
|
||
|
|
||
|
return(FoundAdmin);
|
||
|
}
|