|
|
#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; }
|