windows-nt/Source/XPSP1/NT/inetsrv/iis/admin/adsi/setup/metacfg.cxx
2020-09-26 16:20:57 +08:00

666 lines
19 KiB
C++

#include "schema.h"
#pragma hdrstop
#include "initguid.h"
#include "iadmw.h"
#include "schemini.hxx"
#if _IIS_6_0
#include "..\adsiis\globdata.cxx"
#elif _IIS_5_1
#include "..\adsiis\iis51\globdata.cxx"
#else
#error "Neither _IIS_6_0 nor _IIS_5_1 is defined"
#endif
#define DEFAULT_TIMEOUT_VALUE 30000
HRESULT SetAdminACL(IMSAdminBase * pAdminBase);
DWORD
GetPrincipalSID (
LPTSTR Principal,
PSID *Sid,
BOOL *pbWellKnownSID
);
MetaHandle::MetaHandle(IMSAdminBasePtr _pmb) : pmb(_pmb) {
if (pmb)
pmb->AddRef();
h = 0;
}
MetaHandle::~MetaHandle() {
if (pmb) {
if (h)
pmb->CloseKey(h);
pmb->Release();
}
}
struct WideStrMapEntry {
LPWSTR m_str;
void *m_data;
};
class WideStrMap {
WideStrMapEntry *map;
int count;
int mapSize;
public:
WideStrMap();
~WideStrMap();
BOOL CheckSpace();
BOOL Add(LPWSTR str, void *data);
void *Find(LPWSTR str);
void *operator[] (LPWSTR str);
};
WideStrMap::WideStrMap() {
count = 0;
mapSize = 64;
map = (WideStrMapEntry *)malloc(sizeof(WideStrMapEntry) * mapSize);
}
WideStrMap::~WideStrMap() {
free(map);
}
BOOL WideStrMap::CheckSpace() {
if (count < mapSize)
return TRUE;
mapSize += 32;
if ((map = (WideStrMapEntry *)realloc(map, sizeof(WideStrMapEntry)*mapSize)) == NULL)
return FALSE;
return TRUE;
}
BOOL WideStrMap::Add(LPWSTR str, void *data) {
if (!CheckSpace())
return FALSE;
map[count].m_str = str;
map[count].m_data = data;
count++;
return TRUE;
}
void *WideStrMap::Find(LPWSTR str) {
for (int i=0; i < count; i++) {
if (!_wcsicmp(str, map[i].m_str))
return map[i].m_data;
}
return NULL;
}
void *WideStrMap::operator[] (LPWSTR str) {
return Find(str);
}
#if 0
struct PropValue {
DWORD dwMetaID;
DWORD dwSynID;
DWORD dwMetaType;
DWORD dwFlags;
BOOL fMultiValued;
DWORD dwMask;
DWORD dwMetaFlags;
DWORD dwUserGroup;
};
#endif
void InitPropValue(PropValue *pv, PROPERTYINFO *pi) {
pv->dwSynID = pi->dwSyntaxId;
pv->dwMetaID = pi->dwMetaID;
pv->dwPropID = pi->dwPropID;
pv->dwMaxRange = (DWORD)pi->lMaxRange;
pv->dwMinRange = (DWORD)pi->lMinRange;
switch(pi->dwSyntaxId) {
case IIS_SYNTAX_ID_DWORD:
case IIS_SYNTAX_ID_BOOL:
case IIS_SYNTAX_ID_BOOL_BITMASK:
pv->dwMetaType = DWORD_METADATA;
break;
case IIS_SYNTAX_ID_STRING:
pv->dwMetaType = STRING_METADATA;
break;
case IIS_SYNTAX_ID_EXPANDSZ:
pv->dwMetaType = EXPANDSZ_METADATA;
break;
case IIS_SYNTAX_ID_MIMEMAP:
case IIS_SYNTAX_ID_MULTISZ:
pv->dwMetaType = MULTISZ_METADATA;
break;
case IIS_SYNTAX_ID_NTACL:
case IIS_SYNTAX_ID_IPSECLIST:
pv->dwMetaType = BINARY_METADATA;
break;
}
pv->dwFlags = pi->dwFlags;
pv->fMultiValued = pi->fMultiValued;
pv->dwMask = pi->dwMask;
pv->dwMetaFlags = pi->dwMetaFlags;
pv->dwUserGroup = pi->dwUserGroup;
}
// struct __declspec(__uuid()
static char asciiBuf[2048];
BOOL DataForSyntaxID(PROPERTYINFO *pp, METADATA_RECORD *mdr) {
static DWORD value=0;
WCHAR *ptr;
int i;
switch(pp->dwSyntaxId) {
case IIS_SYNTAX_ID_BOOL:
case IIS_SYNTAX_ID_BOOL_BITMASK:
case IIS_SYNTAX_ID_DWORD:
mdr->dwMDDataType = DWORD_METADATA;
mdr->dwMDDataLen = sizeof(DWORD);
mdr->pbMDData = (unsigned char *)&(pp->dwDefault);
break;
case IIS_SYNTAX_ID_STRING:
mdr->dwMDDataType = STRING_METADATA;
mdr->dwMDDataLen = (wcslen(pp->szDefault)+1)*2;
mdr->pbMDData = (unsigned char *)pp->szDefault;
break;
case IIS_SYNTAX_ID_EXPANDSZ:
mdr->dwMDDataType = EXPANDSZ_METADATA;
mdr->dwMDDataLen = (wcslen(pp->szDefault)+1)*2;
mdr->pbMDData = (unsigned char *)pp->szDefault;
break;
case IIS_SYNTAX_ID_MIMEMAP:
case IIS_SYNTAX_ID_MULTISZ:
//
// Note, ALL multisz types must have an extra \0 in the table.
//
mdr->dwMDDataType = MULTISZ_METADATA;
ptr = pp->szDefault;
do {
ptr += wcslen(ptr)+1;
} while (*ptr != 0);
mdr->dwMDDataLen = DIFF((char *)ptr - (char *)pp->szDefault)+2;
mdr->pbMDData = (unsigned char *)pp->szDefault;
break;
case IIS_SYNTAX_ID_IPSECLIST:
case IIS_SYNTAX_ID_NTACL:
case IIS_SYNTAX_ID_BINARY:
mdr->dwMDDataType = BINARY_METADATA;
mdr->dwMDDataLen = 0;
mdr->pbMDData = NULL;
break;
default:
mdr->dwMDDataType = DWORD_METADATA;
mdr->dwMDDataLen = sizeof(DWORD);
mdr->pbMDData = (unsigned char *)&value;
return FALSE;
}
return TRUE;
}
const DWORD getAllBufSize = 4096;
wchar_t *grabProp(wchar_t *out, wchar_t *in) {
if (!in || *in == L'\0') {
*out = L'\0';
return NULL;
}
while (*in != L',' && *in != L'\0') {
*out++ = *in++;
}
*out = L'\0';
if (*in == L',')
return ++in;
return in;
}
HRESULT StoreSchema() {
DWORD bufSize = getAllBufSize;
BYTE *buf = new BYTE[bufSize];
HRESULT hr;
COSERVERINFO csiName;
COSERVERINFO *pcsiParam = &csiName;
IClassFactory * pcsfFactory = NULL;
IMSAdminBase * pAdminBase = NULL;
METADATA_RECORD mdr;
wchar_t mandProps[MAX_PATH];
wchar_t optProps[MAX_PATH];
wchar_t prop[MAX_PATH], *propList;
MetaHandle root(NULL);
DWORD value = 0;
DWORD i;
//
// nameToProp is used for mapping properties by name to the property structures
// that define the properties. Since we first run through the list of props,
// and write out the names, we add the prop to the map. Then, when we encounter
// the properties by name, which is how the classes maintain them, we can access
// the corresponding property structure.
//
WideStrMap nameToProp;
memset(pcsiParam, 0, sizeof(COSERVERINFO));
pcsiParam->pwszName = NULL;
csiName.pAuthInfo = NULL;
pcsiParam = &csiName;
hr = CoGetClassObject(
CLSID_MSAdminBase,
CLSCTX_SERVER,
pcsiParam,
IID_IClassFactory,
(void**) &pcsfFactory
);
BAIL_ON_FAILURE(hr);
hr = pcsfFactory->CreateInstance(
NULL,
IID_IMSAdminBase,
(void **) &pAdminBase
);
pcsfFactory->Release();
BAIL_ON_FAILURE(hr);
root.setpointer(pAdminBase);
hr = pAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
L"",
METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE,
DEFAULT_TIMEOUT_VALUE,
root);
BAIL_ON_FAILURE(hr);
hr = pAdminBase->AddKey(root, L"Schema");
if (FAILED(hr) && HRESULT_CODE(hr) != ERROR_ALREADY_EXISTS) {
BAIL_ON_FAILURE(hr);
}
hr = pAdminBase->AddKey(root, L"Schema/Properties");
if (FAILED(hr) && HRESULT_CODE(hr) != ERROR_ALREADY_EXISTS) {
BAIL_ON_FAILURE(hr);
}
hr = pAdminBase->AddKey(root, L"Schema/Classes");
if (FAILED(hr) && HRESULT_CODE(hr) != ERROR_ALREADY_EXISTS) {
BAIL_ON_FAILURE(hr);
}
hr = pAdminBase->AddKey(root, L"Schema/Properties/Names");
if (FAILED(hr) && HRESULT_CODE(hr) != ERROR_ALREADY_EXISTS) {
BAIL_ON_FAILURE(hr);
}
hr = pAdminBase->AddKey(root, L"Schema/Properties/Types");
if (FAILED(hr) && HRESULT_CODE(hr) != ERROR_ALREADY_EXISTS) {
BAIL_ON_FAILURE(hr);
}
hr = pAdminBase->AddKey(root, L"Schema/Properties/Defaults");
if (FAILED(hr) && HRESULT_CODE(hr) != ERROR_ALREADY_EXISTS) {
BAIL_ON_FAILURE(hr);
}
root.close();
//
// Now, let's initialize the property dictionary.
//
hr = pAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
L"/Schema/Properties",
METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE,
DEFAULT_TIMEOUT_VALUE,
root);
BAIL_ON_FAILURE(hr);
mdr.dwMDDataTag = 0;
DWORD propData[2];
PropValue pv;
for (i=0; i < g_cIISProperties; i++) {
//
// First, we set the name prop to the string value of the properties name.
//
mdr.dwMDIdentifier = g_aIISProperties[i].dwPropID;
mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = STRING_METADATA;
mdr.dwMDDataLen = (wcslen(g_aIISProperties[i].szPropertyName)+1)*2;
mdr.pbMDData = (unsigned char *)g_aIISProperties[i].szPropertyName;
hr = pAdminBase->SetData(root, L"Names", &mdr);
BAIL_ON_FAILURE(hr);
//
// Next, we need to update the type field.
//
InitPropValue(&pv, &g_aIISProperties[i]);
mdr.dwMDDataType = BINARY_METADATA;
mdr.dwMDDataLen = sizeof(PropValue);
mdr.pbMDData = (unsigned char *)&pv;
hr = pAdminBase->SetData(root, L"Types", &mdr);
BAIL_ON_FAILURE(hr);
//
// update default values
//
mdr.dwMDIdentifier = g_aIISProperties[i].dwPropID;
mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
DataForSyntaxID(&(g_aIISProperties[i]), &mdr);
hr = pAdminBase->SetData(root, L"Defaults", &mdr);
BAIL_ON_FAILURE(hr);
}
root.close();
hr = pAdminBase->SaveData();
BAIL_ON_FAILURE(hr);
hr = pAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
L"/Schema/Classes",
METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE,
DEFAULT_TIMEOUT_VALUE,
root);
BAIL_ON_FAILURE(hr);
for (i=0; i < g_cIISClasses; i++) {
hr = pAdminBase->AddKey(root, g_aIISClasses[i].bstrName);
if (FAILED(hr) && HRESULT_CODE(hr) != ERROR_ALREADY_EXISTS) {
BAIL_ON_FAILURE(hr);
}
//
// setting Containment and Container property for classes
//
mdr.dwMDIdentifier = MD_SCHEMA_CLASS_CONTAINMENT;
mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = STRING_METADATA;
if (g_aIISClasses[i].bstrContainment) {
mdr.dwMDDataLen = (wcslen((LPWSTR)g_aIISClasses[i].bstrContainment)+1)*2;
}
else {
mdr.dwMDDataLen = 0;
}
mdr.pbMDData = (unsigned char *)g_aIISClasses[i].bstrContainment;
hr = pAdminBase->SetData(root, g_aIISClasses[i].bstrName, &mdr);
BAIL_ON_FAILURE(hr);
mdr.dwMDIdentifier = MD_SCHEMA_CLASS_CONTAINER;
mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = DWORD_METADATA;
mdr.dwMDDataLen = sizeof(DWORD);
mdr.pbMDData = (unsigned char *)&(g_aIISClasses[i].fContainer);
hr = pAdminBase->SetData(root, g_aIISClasses[i].bstrName, &mdr);
BAIL_ON_FAILURE(hr);
//
// setting Optional and Mandatory Properties
//
mdr.dwMDIdentifier = MD_SCHEMA_CLASS_MAND_PROPERTIES;
mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = STRING_METADATA;
if (g_aIISClasses[i].bstrMandatoryProperties) {
mdr.dwMDDataLen = (wcslen((LPWSTR)g_aIISClasses[i].bstrMandatoryProperties)+1)*2;
}
else {
mdr.dwMDDataLen = 0;
}
mdr.pbMDData = (unsigned char *)g_aIISClasses[i].bstrMandatoryProperties;
hr = pAdminBase->SetData(root, g_aIISClasses[i].bstrName, &mdr);
BAIL_ON_FAILURE(hr);
mdr.dwMDIdentifier = MD_SCHEMA_CLASS_OPT_PROPERTIES;
mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = STRING_METADATA;
if (g_aIISClasses[i].bstrOptionalProperties) {
mdr.dwMDDataLen = (wcslen((LPWSTR)g_aIISClasses[i].bstrOptionalProperties)+1)*2;
}
else {
mdr.dwMDDataLen = 0;
}
mdr.pbMDData = (unsigned char *)g_aIISClasses[i].bstrOptionalProperties;
hr = pAdminBase->SetData(root, g_aIISClasses[i].bstrName, &mdr);
BAIL_ON_FAILURE(hr);
}
root.close();
hr = pAdminBase->SaveData();
BAIL_ON_FAILURE(hr);
hr = SetAdminACL(pAdminBase);
error:
root.close();
if (pAdminBase)
pAdminBase->Release();
return hr;
}
HRESULT SetAdminACL(
IMSAdminBase * pAdminBase
)
{
BOOL b = FALSE;
DWORD dwLength = 0;
PSECURITY_DESCRIPTOR pSD = NULL;
PSECURITY_DESCRIPTOR outpSD = NULL;
DWORD cboutpSD = 0;
PACL pACLNew = NULL;
DWORD cbACL = 0;
PSID pAdminsSID = NULL, pEveryoneSID = NULL;
BOOL bWellKnownSID = FALSE;
MetaHandle root(NULL);
METADATA_RECORD mdr;
HRESULT hr = NO_ERROR;
DWORD dwStartMetaId = IIS_MD_ADSI_METAID_BEGIN;
// Initialize a new security descriptor
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!pSD) {hr = E_OUTOFMEMORY;}
BAIL_ON_FAILURE(hr);
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
// Get Local Admins Sid
GetPrincipalSID (_T("Administrators"), &pAdminsSID, &bWellKnownSID);
// Get everyone Sid
GetPrincipalSID (_T("Everyone"), &pEveryoneSID, &bWellKnownSID);
// Initialize a new ACL, which only contains 2 aaace
cbACL = sizeof(ACL) +
(sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pAdminsSID) - sizeof(DWORD)) +
(sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pEveryoneSID) - sizeof(DWORD)) ;
pACLNew = (PACL) LocalAlloc(LPTR, cbACL);
if (!pACLNew) {hr = E_OUTOFMEMORY;}
BAIL_ON_FAILURE(hr);
InitializeAcl(pACLNew, cbACL, ACL_REVISION);
AddAccessAllowedAce(
pACLNew,
ACL_REVISION,
FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE,
pAdminsSID);
AddAccessAllowedAce(
pACLNew,
ACL_REVISION,
FILE_GENERIC_READ,
pEveryoneSID);
// Add the ACL to the security descriptor
b = SetSecurityDescriptorDacl(pSD, TRUE, pACLNew, FALSE);
b = SetSecurityDescriptorOwner(pSD, pAdminsSID, TRUE);
b = SetSecurityDescriptorGroup(pSD, pAdminsSID, TRUE);
// Security descriptor blob must be self relative
b = MakeSelfRelativeSD(pSD, outpSD, &cboutpSD);
outpSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GPTR, cboutpSD);
if (!outpSD) {hr = E_OUTOFMEMORY;}
BAIL_ON_FAILURE(hr);
b = MakeSelfRelativeSD( pSD, outpSD, &cboutpSD );
// below this modify pSD to outpSD
// Apply the new security descriptor to the file
dwLength = GetSecurityDescriptorLength(outpSD);
// Apply the new security descriptor to the file
hr = pAdminBase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
L"/Schema",
METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE,
DEFAULT_TIMEOUT_VALUE,
root);
BAIL_ON_FAILURE(hr);
mdr.dwMDIdentifier = MD_ADMIN_ACL;
mdr.dwMDAttributes = METADATA_INHERIT | METADATA_REFERENCE | METADATA_SECURE;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = BINARY_METADATA;
mdr.dwMDDataLen = dwLength;
mdr.pbMDData = (LPBYTE)outpSD;
hr = pAdminBase->SetData(root, L"", &mdr);
BAIL_ON_FAILURE(hr);
//
// set the start count for meta id
//
mdr.dwMDIdentifier = MD_SCHEMA_METAID;
mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
mdr.dwMDUserType = IIS_MD_UT_SERVER;
mdr.dwMDDataType = DWORD_METADATA;
mdr.dwMDDataLen = sizeof(DWORD);
mdr.pbMDData = (LPBYTE)&dwStartMetaId;
hr = pAdminBase->SetData(root, L"", &mdr);
BAIL_ON_FAILURE(hr);
root.close();
error :
//Cleanup:
// both of Administrators and Everyone are well-known SIDs, use FreeSid() to free them.
if (outpSD)
GlobalFree(outpSD);
if (pAdminsSID)
FreeSid(pAdminsSID);
if (pEveryoneSID)
FreeSid(pEveryoneSID);
if (pSD)
LocalFree((HLOCAL) pSD);
if (pACLNew)
LocalFree((HLOCAL) pACLNew);
return (hr);
}
DWORD
GetPrincipalSID (
LPTSTR Principal,
PSID *Sid,
BOOL *pbWellKnownSID
)
{
SID_IDENTIFIER_AUTHORITY SidIdentifierNTAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SidIdentifierWORLDAuthority = SECURITY_WORLD_SID_AUTHORITY;
PSID_IDENTIFIER_AUTHORITY pSidIdentifierAuthority;
BYTE Count;
DWORD dwRID[8];
*pbWellKnownSID = TRUE;
memset(&(dwRID[0]), 0, 8 * sizeof(DWORD));
if ( wcscmp(Principal,_T("Administrators")) == 0 ) {
// Administrators group
pSidIdentifierAuthority = &SidIdentifierNTAuthority;
Count = 2;
dwRID[0] = SECURITY_BUILTIN_DOMAIN_RID;
dwRID[1] = DOMAIN_ALIAS_RID_ADMINS;
} else if ( wcscmp(Principal,_T("System")) == 0) {
// SYSTEM
pSidIdentifierAuthority = &SidIdentifierNTAuthority;
Count = 1;
dwRID[0] = SECURITY_LOCAL_SYSTEM_RID;
} else if ( wcscmp(Principal,_T("Interactive")) == 0) {
// INTERACTIVE
pSidIdentifierAuthority = &SidIdentifierNTAuthority;
Count = 1;
dwRID[0] = SECURITY_INTERACTIVE_RID;
} else if ( wcscmp(Principal,_T("Everyone")) == 0) {
// Everyone
pSidIdentifierAuthority = &SidIdentifierWORLDAuthority;
Count = 1;
dwRID[0] = SECURITY_WORLD_RID;
} else {
*pbWellKnownSID = FALSE;
}
if (*pbWellKnownSID) {
if ( !AllocateAndInitializeSid(pSidIdentifierAuthority,
(BYTE)Count,
dwRID[0],
dwRID[1],
dwRID[2],
dwRID[3],
dwRID[4],
dwRID[5],
dwRID[6],
dwRID[7],
Sid) )
return GetLastError();
} else {
// get regular account sid
DWORD sidSize;
TCHAR refDomain [256];
DWORD refDomainSize;
DWORD returnValue;
SID_NAME_USE snu;
sidSize = 0;
refDomainSize = 255;
LookupAccountName (NULL,
Principal,
*Sid,
&sidSize,
refDomain,
&refDomainSize,
&snu);
returnValue = GetLastError();
if (returnValue != ERROR_INSUFFICIENT_BUFFER)
return returnValue;
*Sid = (PSID) malloc (sidSize);
refDomainSize = 255;
if (!LookupAccountName (NULL,
Principal,
*Sid,
&sidSize,
refDomain,
&refDomainSize,
&snu))
{
return GetLastError();
}
}
return ERROR_SUCCESS;
}