//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1996. // // File: security.cxx // // Contents: // // Classes: None. // // Functions: None. // // History: 26-Jun-96 MarkBl Created // //---------------------------------------------------------------------------- #include "..\pch\headers.hxx" #pragma hdrstop #include // MAX_SID_SIZE #include "..\inc\debug.hxx" #include "..\inc\security.hxx" //+--------------------------------------------------------------------------- // // Function: CreateSecurityDescriptor // // Synopsis: Create a security descriptor with the ACE information // specified. // // Arguments: [AceCount] -- ACE count (no. of rgMyAce and rgAce elements). // [rgMyAce] -- ACE specification array. // [rgAce] -- Caller allocated array of ptrs to ACEs so // this function doesn't have to allocate it. // // Returns: TRUE -- Function succeeded, // FALSE -- Otherwise. // // Notes: None. // //---------------------------------------------------------------------------- PSECURITY_DESCRIPTOR CreateSecurityDescriptor( DWORD AceCount, MYACE rgMyAce[], PACCESS_ALLOWED_ACE rgAce[], DWORD * pStatus) { PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; PACL pAcl = NULL; DWORD LengthAces = 0; DWORD LengthAcl; DWORD i; DWORD Status; for (i = 0; i < AceCount; i++) { rgAce[i] = CreateAccessAllowedAce(rgMyAce[i].pSid, rgMyAce[i].AccessMask, 0, rgMyAce[i].InheritFlags, &Status); if (rgAce[i] == NULL) { goto ErrorExit; } LengthAces += rgAce[i]->Header.AceSize; } // // Calculate ACL and SD sizes // LengthAcl = sizeof(ACL) + LengthAces; // // Create the ACL. // pAcl = (PACL)LocalAlloc(LMEM_FIXED, LengthAcl); if (pAcl == NULL) { Status = ERROR_NOT_ENOUGH_MEMORY; schDebugOut((DEB_ERROR, "CreateSecurityDescriptor, ACL allocation failed\n")); goto ErrorExit; } if (!InitializeAcl(pAcl, LengthAcl, ACL_REVISION)) { Status = GetLastError(); schDebugOut((DEB_ERROR, "CreateSecurityDescriptor, InitializeAcl failed, " \ "status = 0x%lx\n", Status)); goto ErrorExit; } for (i = 0; i < AceCount; i++) { if (!AddAce(pAcl, ACL_REVISION, 0, rgAce[i], rgAce[i]->Header.AceSize)) { Status = GetLastError(); schDebugOut((DEB_ERROR, "CreateSecurityDescriptor, AddAce[%l] failed, " \ "status = 0x%lx\n", i, Status)); goto ErrorExit; } LocalFree(rgAce[i]); rgAce[i] = NULL; } // // Create the security descriptor. // pSecurityDescriptor = LocalAlloc(LMEM_FIXED, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pSecurityDescriptor == NULL) { Status = ERROR_NOT_ENOUGH_MEMORY; schDebugOut((DEB_ERROR, "CreateSecurityDescriptor, SECURITY_DESCRIPTOR allocation " \ "failed\n")); goto ErrorExit; } if (!InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)) { Status = GetLastError(); schDebugOut((DEB_ERROR, "CreateSecurityDescriptor, InitializeSecurityDescriptor " \ "failed, status = 0x%lx\n", Status)); goto ErrorExit; } if (!SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, pAcl, FALSE)) { Status = GetLastError(); schDebugOut((DEB_ERROR, "CreateSecurityDescriptor, SetSecurityDescriptorDacl " \ "failed, status = 0x%lx\n", Status)); goto ErrorExit; } if (pStatus != NULL) *pStatus = ERROR_SUCCESS; return(pSecurityDescriptor); ErrorExit: for (i = 0; i < AceCount; i++) { if (rgAce[i] != NULL) { LocalFree(rgAce[i]); rgAce[i] = NULL; } } if (pAcl != NULL) LocalFree(pAcl); if (pSecurityDescriptor != NULL) LocalFree(pSecurityDescriptor); if (pStatus != NULL) *pStatus = Status; return(NULL); } //+--------------------------------------------------------------------------- // // Function: DeleteSecurityDescriptor // // Synopsis: Deallocate the security descriptor allocated in // CreateSecurityDescriptor. // // Arguments: [pSecurityDescriptor] -- SD returned from // CreateSecurityDescriptor. // // Returns: None. // // Notes: None. // //---------------------------------------------------------------------------- void DeleteSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor) { BOOL fPresent; BOOL fDefaulted; PACL pAcl; schAssert(pSecurityDescriptor != NULL); if (GetSecurityDescriptorDacl(pSecurityDescriptor, &fPresent, &pAcl, &fDefaulted)) { if (fPresent && pAcl != NULL) { LocalFree(pAcl); } } else { schDebugOut((DEB_ERROR, "DeleteSecurityDescriptor, GetSecurityDescriptorDacl failed, " \ "status = 0x%lx\n", GetLastError())); } LocalFree(pSecurityDescriptor); } //+--------------------------------------------------------------------------- // // Function: CreateAccessAllowedAce // // Synopsis: Scavenged code from winlogon to create an access allowed ACE. // Modified a bit to use Win32 vs. Rtl. // // Arguments: [pSid] -- Sid to which this ACE is applied. // [AccessMask] -- ACE access mask value. // [AceFlags] -- ACE flags value. // [InheritFlags] -- ACE inherit flags value. // // Returns: Created ACE if successful. // NULL on error. // // Notes: None. // //---------------------------------------------------------------------------- PACCESS_ALLOWED_ACE CreateAccessAllowedAce( PSID pSid, ACCESS_MASK AccessMask, UCHAR AceFlags, UCHAR InheritFlags, DWORD * pStatus) { ULONG LengthSid = GetLengthSid(pSid); ULONG LengthACE = sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) + LengthSid; PACCESS_ALLOWED_ACE Ace; Ace = (PACCESS_ALLOWED_ACE)LocalAlloc(LMEM_FIXED, LengthACE); if (Ace == NULL) { if (pStatus != NULL) *pStatus = ERROR_NOT_ENOUGH_MEMORY; schDebugOut((DEB_ERROR, "CreateAccessAllowedAce, ACE allocation failed\n")); return(NULL); } Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; Ace->Header.AceSize = (UCHAR)LengthACE; Ace->Header.AceFlags = AceFlags | InheritFlags; Ace->Mask = AccessMask; CopySid(LengthSid, (PSID)(&(Ace->SidStart)), pSid); if (pStatus != NULL) *pStatus = ERROR_SUCCESS; return(Ace); } //+--------------------------------------------------------------------------- // // Function: IsThreadCallerAnAdmin // // Synopsis: Determine if the user represented by the specified token is a // member of the administrators group. // // Arguments: [hThreadToken] -- Token to check. If NULL, the current // thread's token is used if there is one, or else the // current process' token. // // Returns: TRUE -- Match // FALSE -- Thread caller not an admin or an error occurred. // //---------------------------------------------------------------------------- BOOL IsThreadCallerAnAdmin(HANDLE hThreadToken) { // // Create an admin SID to compare against. // #if 1 // // Efficient way - relies on the format of the SID structure (which is // published in winnt.h) - valid for at least NT 4 and NT 5 // schAssert(sizeof SID == 12); const struct { SID Sid; DWORD SubAuthority1; } AdminSid = { { SID_REVISION, // Revision 2, // SubAuthorityCount SECURITY_NT_AUTHORITY, // IdentifierAuthority SECURITY_BUILTIN_DOMAIN_RID }, // SubAuthority[0] DOMAIN_ALIAS_RID_ADMINS // SubAuthority[1] }; #else /* #error SID structure has changed! // // Inefficient way, initialize at run time // BYTE AdminSid[MAX_SID_SIZE]; SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY; if (! InitializeSid(rgbAdminSid, &IdentifierAuthority, 2)) { schAssert(0); CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError())); return FALSE; } *GetSidSubAuthority(rgbAdminSid, 0) = SECURITY_BUILTIN_DOMAIN_RID; *GetSidSubAuthority(rgbAdminSid, 1) = DOMAIN_ALIAS_RID_ADMINS; */ #endif // // See if the token is a member. // BOOL fIsCallerAdmin; if (!CheckTokenMembership(hThreadToken, (PSID) &AdminSid, &fIsCallerAdmin)) { CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError())); return FALSE; } return fIsCallerAdmin; } //+--------------------------------------------------------------------------- // // Function: EnablePrivilege // // Synopsis: Tries to enable / disable a privilege for the current process. // // Arguments: [pszPrivName] - name of privilege to enable / disable. // [bEnable] - enable / disable switch. // [pbWasEnabled] - optional pointer to receive the previous // state of the privilege. // // Returns: win32 error code. // //---------------------------------------------------------------------------- DWORD EnablePrivilege( IN PCWSTR pszPrivName, IN BOOL bEnable, OUT PBOOL pbWasEnabled OPTIONAL ) { DWORD dwError = ERROR_SUCCESS; BOOL bSuccess; HANDLE hToken = 0; DWORD dwSize; TOKEN_PRIVILEGES privNew; TOKEN_PRIVILEGES privOld; bSuccess = OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); if (!bSuccess) { dwError = GetLastError(); goto Cleanup; } bSuccess = LookupPrivilegeValue( 0, pszPrivName, &privNew.Privileges[0].Luid); if (!bSuccess) { dwError = GetLastError(); goto Cleanup; } privNew.PrivilegeCount = 1; privNew.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0; bSuccess = AdjustTokenPrivileges( hToken, FALSE, &privNew, sizeof(privOld), &privOld, &dwSize); if (!bSuccess) { dwError = GetLastError(); goto Cleanup; } if (pbWasEnabled) { *pbWasEnabled = (privOld.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED) ? TRUE : FALSE; } Cleanup: if (hToken) { CloseHandle(hToken); } return dwError; }