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.
382 lines
9.5 KiB
382 lines
9.5 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
strsd.c
|
|
|
|
Abstract:
|
|
|
|
This Module implements wrapper functions to convert from a specialized
|
|
string representation of a security descriptor to the security descriptor
|
|
itself, and the opposite function.
|
|
|
|
Author:
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "headers.h"
|
|
//#include <lmcons.h>
|
|
//#include <secobj.h>
|
|
//#include <netlib.h>
|
|
//#include <ntsecapi.h>
|
|
#include "sddl.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
|
|
DWORD
|
|
ScepGetSecurityInformation(
|
|
IN PSECURITY_DESCRIPTOR pSD,
|
|
OUT SECURITY_INFORMATION *pSeInfo
|
|
);
|
|
|
|
DWORD
|
|
WINAPI
|
|
ConvertTextSecurityDescriptor (
|
|
IN PWSTR pwszTextSD,
|
|
OUT PSECURITY_DESCRIPTOR *ppSD,
|
|
OUT PULONG pcSDSize OPTIONAL,
|
|
OUT PSECURITY_INFORMATION pSeInfo OPTIONAL
|
|
)
|
|
{
|
|
|
|
DWORD rc=ERROR_SUCCESS;
|
|
|
|
if ( NULL == pwszTextSD || NULL == ppSD ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// initialize output buffers
|
|
//
|
|
|
|
*ppSD = NULL;
|
|
|
|
if ( pSeInfo ) {
|
|
*pSeInfo = 0;
|
|
}
|
|
if ( pcSDSize ) {
|
|
*pcSDSize = 0;
|
|
}
|
|
|
|
//
|
|
// call SDDL convert apis
|
|
//
|
|
|
|
if ( ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
|
pwszTextSD,
|
|
SDDL_REVISION_1,
|
|
ppSD,
|
|
pcSDSize
|
|
) ) {
|
|
//
|
|
// conversion succeeds
|
|
//
|
|
|
|
if ( pSeInfo && *ppSD ) {
|
|
|
|
//
|
|
// get the SeInfo
|
|
//
|
|
|
|
rc = ScepGetSecurityInformation(
|
|
*ppSD,
|
|
pSeInfo
|
|
);
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
|
|
LocalFree(*ppSD);
|
|
*ppSD = NULL;
|
|
|
|
if ( pcSDSize ) {
|
|
*pcSDSize = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// Replace any of the new SDDL acronyms with SIDs, so we can keep SDDL strings
|
|
// compatible with older systems.
|
|
//
|
|
// Caller is responsible for free'ing the return string unless input string
|
|
// is returned directly, when no replacement is performed.
|
|
//
|
|
// Returns:
|
|
// ERROR_SUCCESS
|
|
// ERROR_NOT_ENOUGH_MEMORY
|
|
//
|
|
DWORD
|
|
ScepReplaceNewAcronymsInSDDL(
|
|
IN LPWSTR pwszOldSDDL,
|
|
OUT LPWSTR *ppwszNewSDDL,
|
|
ULONG *pcchNewSDDL
|
|
)
|
|
{
|
|
typedef struct _SDDLMapNode
|
|
{
|
|
PCWSTR pcwszAcronym;
|
|
PCWSTR pcwszSid;
|
|
DWORD cbSid; // pcwszSid byte size (excluding trailing zero), for optimization
|
|
} SDDLMapNode;
|
|
|
|
static const WCHAR pcwszSidAnonymous[] = L"S-1-5-7";
|
|
static const WCHAR pcwszLocalService[] = L"S-1-5-19";
|
|
static const WCHAR pcwszNetworkService[] = L"S-1-5-20";
|
|
static const WCHAR pcwszRemoteDesktop[] = L"S-1-5-32-555";
|
|
static const WCHAR pcwszNetConfigOps[] = L"S-1-5-32-556";
|
|
static const WCHAR pcwszPerfmonUsers[] = L"S-1-5-32-558";
|
|
static const WCHAR pcwszPerflogUser[] = L"S-1-5-32-559";
|
|
|
|
static SDDLMapNode SDDLMap[7] = {
|
|
{ SDDL_ANONYMOUS, pcwszSidAnonymous, sizeof(pcwszSidAnonymous)-sizeof(WCHAR) },
|
|
{ SDDL_LOCAL_SERVICE, pcwszLocalService , sizeof(pcwszLocalService)-sizeof(WCHAR) },
|
|
{ SDDL_NETWORK_SERVICE, pcwszNetworkService,sizeof(pcwszNetworkService)-sizeof(WCHAR) },
|
|
{ SDDL_REMOTE_DESKTOP, pcwszRemoteDesktop ,sizeof(pcwszRemoteDesktop)-sizeof(WCHAR) },
|
|
{ SDDL_NETWORK_CONFIGURATION_OPS, pcwszNetConfigOps , sizeof(pcwszNetConfigOps)-sizeof(WCHAR) },
|
|
{ SDDL_PERFMON_USERS, pcwszPerfmonUsers , sizeof(pcwszPerfmonUsers)-sizeof(WCHAR) },
|
|
{ SDDL_PERFLOG_USERS, pcwszPerflogUser , sizeof(pcwszPerflogUser)-sizeof(WCHAR) },
|
|
};
|
|
static const DWORD dwSDDLMapSize = sizeof(SDDLMap)/sizeof(SDDLMapNode);
|
|
|
|
DWORD dwCrtSDDL;
|
|
WCHAR *pch, *pchNew;
|
|
DWORD cbNewSDDL;
|
|
bool fMatchFound = false;
|
|
LPWSTR pwszNewSDDL = NULL;
|
|
|
|
*ppwszNewSDDL = NULL;
|
|
*pcchNewSDDL = 0;
|
|
|
|
if(!pwszOldSDDL)
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// We make the following assumptions:
|
|
// - all acronyms are two chars long
|
|
// - they show up either after a ':' or a ';'
|
|
//
|
|
// First pass to calculate the size of new string
|
|
//
|
|
for(pch = pwszOldSDDL, cbNewSDDL = sizeof(WCHAR); // account for trailing zero
|
|
*pch != L'\0';
|
|
pch++, cbNewSDDL += sizeof(WCHAR))
|
|
{
|
|
//
|
|
// Acronyms always show up only after a ':' or a ';'
|
|
//
|
|
if(pch > pwszOldSDDL &&
|
|
(SDDL_SEPERATORC == *(pch - 1) ||
|
|
SDDL_DELIMINATORC == *(pch - 1)))
|
|
{
|
|
for(dwCrtSDDL = 0; dwCrtSDDL < dwSDDLMapSize; dwCrtSDDL++)
|
|
{
|
|
if(*pch == SDDLMap[dwCrtSDDL].pcwszAcronym[0] &&
|
|
*(pch + 1) == SDDLMap[dwCrtSDDL].pcwszAcronym[1])
|
|
{
|
|
//
|
|
// match found
|
|
//
|
|
cbNewSDDL += SDDLMap[dwCrtSDDL].cbSid;
|
|
|
|
pch++; // acronym is 2 chars, need to jump an extra char
|
|
|
|
fMatchFound = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// optimization, if no replacement needed, immediately return old string
|
|
//
|
|
if(!fMatchFound)
|
|
{
|
|
*ppwszNewSDDL = pwszOldSDDL;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
pwszNewSDDL = (LPWSTR)LocalAlloc(0, cbNewSDDL);
|
|
if(!pwszNewSDDL)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Second pass, copy from old string to new one, replacing new acronyms with their SIDs
|
|
//
|
|
for(pch = pwszOldSDDL, pchNew = pwszNewSDDL;
|
|
*pch != L'\0';
|
|
pch++, pchNew++)
|
|
{
|
|
fMatchFound = false;
|
|
|
|
//
|
|
// Acronyms always show up only after a ':' or a ';'
|
|
//
|
|
if(pch > pwszOldSDDL &&
|
|
(SDDL_SEPERATORC == *(pch - 1) ||
|
|
SDDL_DELIMINATORC == *(pch - 1)))
|
|
{
|
|
for(dwCrtSDDL = 0; dwCrtSDDL < dwSDDLMapSize; dwCrtSDDL++)
|
|
{
|
|
if(*pch == SDDLMap[dwCrtSDDL].pcwszAcronym[0] &&
|
|
*(pch + 1) == SDDLMap[dwCrtSDDL].pcwszAcronym[1])
|
|
{
|
|
//
|
|
// match found
|
|
//
|
|
fMatchFound = true;
|
|
|
|
CopyMemory(pchNew, SDDLMap[dwCrtSDDL].pcwszSid, SDDLMap[dwCrtSDDL].cbSid);
|
|
|
|
pch++; // acronym is 2 chars, need to jump an extra char
|
|
|
|
pchNew += SDDLMap[dwCrtSDDL].cbSid/sizeof(WCHAR)-1; // minus one jumped in outer loop
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!fMatchFound)
|
|
{
|
|
*pchNew = *pch;
|
|
}
|
|
}
|
|
*pchNew = L'\0';
|
|
|
|
*ppwszNewSDDL = pwszNewSDDL;
|
|
*pcchNewSDDL = cbNewSDDL/sizeof(WCHAR);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
ConvertSecurityDescriptorToText (
|
|
IN PSECURITY_DESCRIPTOR pSD,
|
|
IN SECURITY_INFORMATION SecurityInfo,
|
|
OUT PWSTR *ppwszTextSD,
|
|
OUT PULONG pcTextSize
|
|
)
|
|
{
|
|
PWSTR pwszTempSD = NULL;
|
|
ULONG cchSDSize;
|
|
|
|
if (! ConvertSecurityDescriptorToStringSecurityDescriptorW(
|
|
pSD,
|
|
SDDL_REVISION_1,
|
|
SecurityInfo,
|
|
&pwszTempSD,
|
|
pcTextSize
|
|
) )
|
|
{
|
|
return(GetLastError());
|
|
}
|
|
|
|
//
|
|
// Replace any of the new SDDL acronyms with SIDs, so we can keep SDDL strings
|
|
// compatible with older systems.
|
|
//
|
|
DWORD dwErr = ScepReplaceNewAcronymsInSDDL(pwszTempSD, ppwszTextSD, &cchSDSize);
|
|
|
|
if(ERROR_SUCCESS != dwErr)
|
|
{
|
|
LocalFree(pwszTempSD);
|
|
return dwErr;
|
|
}
|
|
|
|
if(*ppwszTextSD != pwszTempSD)
|
|
{
|
|
LocalFree(pwszTempSD);
|
|
*pcTextSize = cchSDSize;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepGetSecurityInformation(
|
|
IN PSECURITY_DESCRIPTOR pSD,
|
|
OUT SECURITY_INFORMATION *pSeInfo
|
|
)
|
|
{
|
|
PSID Owner = NULL, Group = NULL;
|
|
BOOLEAN Defaulted;
|
|
NTSTATUS Status;
|
|
SECURITY_DESCRIPTOR_CONTROL ControlCode=0;
|
|
ULONG Revision;
|
|
|
|
|
|
if ( !pSeInfo ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
*pSeInfo = 0;
|
|
|
|
if ( !pSD ) {
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
Status = RtlGetOwnerSecurityDescriptor( pSD, &Owner, &Defaulted );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
if ( Owner && !Defaulted ) {
|
|
*pSeInfo |= OWNER_SECURITY_INFORMATION;
|
|
}
|
|
|
|
Status = RtlGetGroupSecurityDescriptor( pSD, &Group, &Defaulted );
|
|
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
if ( Group && !Defaulted ) {
|
|
*pSeInfo |= GROUP_SECURITY_INFORMATION;
|
|
}
|
|
|
|
Status = RtlGetControlSecurityDescriptor ( pSD, &ControlCode, &Revision);
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
if ( ControlCode & SE_DACL_PRESENT ) {
|
|
*pSeInfo |= DACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
if ( ControlCode & SE_SACL_PRESENT ) {
|
|
*pSeInfo |= SACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
} else {
|
|
|
|
*pSeInfo = 0;
|
|
}
|
|
|
|
return( RtlNtStatusToDosError(Status) );
|
|
}
|
|
|