#include "stdafx.h"
#include <ole2.h>
#include <aclapi.h>
#include "iadmw.h"
#include "iiscnfg.h"
#include "log.h"
#include "mdkey.h"
#include "dcomperm.h"
#include "other.h"
#include "mdacl.h"
#include <sddl.h>       // ConvertSidToStringSid

extern int g_GlobalDebugCrypto;

#ifndef _CHICAGO_

BOOL CleanAdminACL(SECURITY_DESCRIPTOR *pSD)
{
    // iisDebugOut((LOG_TYPE_TRACE, _T("CleanAdminACL(): Start.\n")));
    BOOL fSetData = FALSE;
    BOOL b= FALSE, bDaclPresent = FALSE, bDaclDefaulted = FALSE;;
    PACL pDacl = NULL;
    LPVOID pAce = NULL;
    int i = 0;
    ACE_HEADER *pAceHeader;
    ACCESS_MASK dwOldMask, dwNewMask,  dwExtraMask, dwMask;

    dwMask = (MD_ACR_READ |
            MD_ACR_WRITE |
            MD_ACR_RESTRICTED_WRITE |
            MD_ACR_UNSECURE_PROPS_READ |
            MD_ACR_ENUM_KEYS |
            MD_ACR_WRITE_DAC);

    b = GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pDacl, &bDaclDefaulted);
    if (NULL == pDacl)
    {
        return FALSE;
    }
    if (b) {
        //iisDebugOut((LOG_TYPE_TRACE, _T("CleanAdminACL:ACE count: %d\n"), (int)pDacl->AceCount));
        for (i=0; i<(int)pDacl->AceCount; i++) {
            b = GetAce(pDacl, i, &pAce);
            if (b) {
                pAceHeader = (ACE_HEADER *)pAce;
                switch (pAceHeader->AceType) {
                case ACCESS_ALLOWED_ACE_TYPE:
                    dwOldMask = ((ACCESS_ALLOWED_ACE *)pAce)->Mask;
                    dwExtraMask = dwOldMask & (~dwMask);
                    if (dwExtraMask) {
                        fSetData = TRUE;
                        dwNewMask = dwOldMask & dwMask;
                        ((ACCESS_ALLOWED_ACE *)pAce)->Mask = dwNewMask;
                    }
                    break;
                case ACCESS_DENIED_ACE_TYPE:
                    dwOldMask = ((ACCESS_DENIED_ACE *)pAce)->Mask;
                    dwExtraMask = dwOldMask & (~dwMask);
                    if (dwExtraMask) {
                        fSetData = TRUE;
                        dwNewMask = dwOldMask & dwMask;
                        ((ACCESS_DENIED_ACE *)pAce)->Mask = dwNewMask;
                    }
                    break;
                case SYSTEM_AUDIT_ACE_TYPE:
                    dwOldMask = ((SYSTEM_AUDIT_ACE *)pAce)->Mask;
                    dwExtraMask = dwOldMask & (~dwMask);
                    if (dwExtraMask) {
                        fSetData = TRUE;
                        dwNewMask = dwOldMask & dwMask;
                        ((SYSTEM_AUDIT_ACE *)pAce)->Mask = dwNewMask;
                    }
                    break;
                default:
                    break;
                }
            } else {
                //iisDebugOut((LOG_TYPE_TRACE, _T("CleanAdminACL:GetAce:err=%x\n"), GetLastError()));
            }
        }
    } else {
        //iisDebugOut((LOG_TYPE_TRACE, _T("CleanAdminACL:GetSecurityDescriptorDacl:err=%x\n"), GetLastError()));
    }

    //iisDebugOut_End(_T("CleanAdminACL"),LOG_TYPE_TRACE);
    return (fSetData);
}

void FixAdminACL(LPTSTR szKeyPath)
{
    // iisDebugOutSafeParams((LOG_TYPE_TRACE, _T("FixAdminACL Path=%1!s!. Start.\n"), szKeyPath));
    BOOL bFound = FALSE, b = FALSE;
    DWORD attr, uType, dType, cbLen;
    CMDKey cmdKey;
    BUFFER bufData;
    LPTSTR p, rest, token;
    CString csName, csValue;
    PBYTE pData;
    int BufSize;
    SECURITY_DESCRIPTOR *pSD;

    cmdKey.OpenNode(szKeyPath);
    if ( (METADATA_HANDLE)cmdKey )
    {
        pData = (PBYTE)(bufData.QueryPtr());
        BufSize = bufData.QuerySize();
        cbLen = 0;
        bFound = cmdKey.GetData(MD_ADMIN_ACL, &attr, &uType, &dType, &cbLen, pData, BufSize);
        if (!bFound && (cbLen > 0))
        {
            if ( ! (bufData.Resize(cbLen)) )
            {
                cmdKey.Close();
                return;  // insufficient memory
            }
            else
            {
                pData = (PBYTE)(bufData.QueryPtr());
                BufSize = cbLen;
                cbLen = 0;
                bFound = cmdKey.GetData(MD_ADMIN_ACL, &attr, &uType, &dType, &cbLen, pData, BufSize);
            }
        }
        cmdKey.Close();

        if (bFound && (dType == BINARY_METADATA))
        {
            pSD = (SECURITY_DESCRIPTOR *)pData;

            b = CleanAdminACL(pSD);
            if (b)
            {
                // need to reset the data
                DWORD dwLength = GetSecurityDescriptorLength(pSD);
                cmdKey.OpenNode(szKeyPath);
                if ( (METADATA_HANDLE)cmdKey )
                {
                    cmdKey.SetData(MD_ADMIN_ACL,METADATA_INHERIT | METADATA_REFERENCE | METADATA_SECURE,IIS_MD_UT_SERVER,BINARY_METADATA,dwLength,(LPBYTE)pSD);
                    cmdKey.Close();
                }
            }
        }
    }

    //iisDebugOut_End1(_T("FixAdminACL"),szKeyPath,LOG_TYPE_TRACE);
    return;
}

#endif //_CHICAGO_

#ifndef _CHICAGO_
DWORD SetAdminACL(LPCTSTR szKeyPath, DWORD dwAccessForEveryoneAccount)
{
    iisDebugOut_Start1(_T("SetAdminACL"), szKeyPath, LOG_TYPE_TRACE);

    int iErr=0;
    DWORD dwErr=0;

    DWORD dwRetCode = ERROR_SUCCESS;
    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;

    // Initialize a new security descriptor
    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
    if (!pSD)
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:LocalAlloc FAILED.out of memory. GetLastError()= 0x%x\n"), ERROR_NOT_ENOUGH_MEMORY));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }
    iErr = InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
    if (iErr == 0)
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:InitializeSecurityDescriptor FAILED.  GetLastError()= 0x%x\n"), GetLastError() ));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    // Get Local Admins Sid
    dwErr = GetPrincipalSID (_T("Administrators"), &pAdminsSID, &bWellKnownSID);
    if (dwErr != ERROR_SUCCESS)
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:GetPrincipalSID(Administrators) FAILED.  Return Code = 0x%x\n"), dwErr));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    // Get everyone Sid
    dwErr = GetPrincipalSID (_T("Everyone"), &pEveryoneSID, &bWellKnownSID);
    if (dwErr != ERROR_SUCCESS)
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:GetPrincipalSID(Everyone) FAILED.  Return Code = 0x%x\n"), dwErr));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    // 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 )
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:pACLNew LocalAlloc(LPTR,  FAILED. size = %u GetLastError()= 0x%x\n"), cbACL, GetLastError()));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    if (!InitializeAcl(pACLNew, cbACL, ACL_REVISION))
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:InitializeAcl FAILED.  GetLastError()= 0x%x\n"), GetLastError));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    if (!AddAccessAllowedAce(pACLNew,ACL_REVISION,(MD_ACR_READ |MD_ACR_WRITE |MD_ACR_RESTRICTED_WRITE |MD_ACR_UNSECURE_PROPS_READ |MD_ACR_ENUM_KEYS |MD_ACR_WRITE_DAC),pAdminsSID))
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:AddAccessAllowedAce(pAdminsSID) FAILED.  GetLastError()= 0x%x\n"), GetLastError));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }
    if (!AddAccessAllowedAce(pACLNew,ACL_REVISION,dwAccessForEveryoneAccount,pEveryoneSID))
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:AddAccessAllowedAce(pEveryoneSID) FAILED.  GetLastError()= 0x%x\n"), GetLastError()));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    // Add the ACL to the security descriptor
    b = SetSecurityDescriptorDacl(pSD, TRUE, pACLNew, FALSE);
    if (!b)
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:SetSecurityDescriptorDacl(pACLNew) FAILED.  GetLastError()= 0x%x\n"), GetLastError()));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    b = SetSecurityDescriptorOwner(pSD, pAdminsSID, TRUE);
    if (!b)
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:SetSecurityDescriptorOwner(pAdminsSID) FAILED.  GetLastError()= 0x%x\n"), GetLastError()));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    b = SetSecurityDescriptorGroup(pSD, pAdminsSID, TRUE);
    if (!b)
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:SetSecurityDescriptorGroup(pAdminsSID) FAILED.  GetLastError()= 0x%x\n"), GetLastError()));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    // Security descriptor blob must be self relative
    b = MakeSelfRelativeSD(pSD, outpSD, &cboutpSD);
    outpSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GPTR, cboutpSD);
    if ( !outpSD )
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:GlobalAlloc FAILED. cboutpSD = %u  GetLastError()= 0x%x\n"), cboutpSD, GetLastError()));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    b = MakeSelfRelativeSD( pSD, outpSD, &cboutpSD );
    if (!b)
    {
        iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:MakeSelfRelativeSD() FAILED. cboutpSD = %u GetLastError()= 0x%x\n"),cboutpSD, GetLastError()));
        dwRetCode = E_FAIL;
        goto Cleanup;
    }

    if (outpSD)
    {
        if (IsValidSecurityDescriptor(outpSD))
        {
            // Apply the new security descriptor to the metabase
            iisDebugOut_Start(_T("SetAdminACL:Write the new security descriptor to the Metabase"),LOG_TYPE_TRACE);
            iisDebugOut((LOG_TYPE_TRACE, _T("SetAdminACL:  At this point we have already been able to write basic entries to the metabase, so...")));
            iisDebugOut((LOG_TYPE_TRACE, _T("SetAdminACL:  If this has a problem then there is a problem with setting up encryption for the metabase (Crypto).")));
            //DoesAdminACLExist(szKeyPath);

            if (g_GlobalDebugCrypto == 2)
            {
                // if we want to call this over and over...
                do
                {
                    dwRetCode = WriteSDtoMetaBase(outpSD, szKeyPath);
                    if (FAILED(dwRetCode))
                    {
                        OutputDebugString(_T("\nCalling WriteSDtoMetaBase again...Set iis!g_GlobalDebugCrypto to 0 to stop looping on failure."));
                        OutputDebugString(_T("\nSet iis!g_GlobalDebugCrypto to 0 to stop looping on crypto failure.\n"));
                    }
                } while (FAILED(dwRetCode) && g_GlobalDebugCrypto == 2);
            }
            else
            {
                dwRetCode = WriteSDtoMetaBase(outpSD, szKeyPath);
            }
            //DoesAdminACLExist(szKeyPath);
            iisDebugOut_End(_T("SetAdminACL:Write the new security descriptor to the Metabase"),LOG_TYPE_TRACE);
        }
        else
        {
            iisDebugOut((LOG_TYPE_ERROR, _T("SetAdminACL:IsValidSecurityDescriptor.4.SelfRelative(%u) FAILED!"),outpSD));
        }
    }

    if (outpSD){GlobalFree(outpSD);outpSD=NULL;}
  

Cleanup:
  // both of Administrators and Everyone are well-known SIDs, use FreeSid() to free them.
  if (pAdminsSID){FreeSid(pAdminsSID);}
  if (pEveryoneSID){FreeSid(pEveryoneSID);}
  if (pSD){LocalFree((HLOCAL) pSD);}
  if (pACLNew){LocalFree((HLOCAL) pACLNew);}
  iisDebugOut_End1(_T("SetAdminACL"),szKeyPath,LOG_TYPE_TRACE);
  return (dwRetCode);
}


DWORD SetAdminACL_wrap(LPCTSTR szKeyPath, DWORD dwAccessForEveryoneAccount, BOOL bDisplayMsgOnErrFlag)
{
	int bFinishedFlag = FALSE;
	UINT iMsg = NULL;
	DWORD dwReturn = ERROR_SUCCESS;
    LogHeapState(FALSE, __FILE__, __LINE__);

	do
	{
		dwReturn = SetAdminACL(szKeyPath, dwAccessForEveryoneAccount);
        LogHeapState(FALSE, __FILE__, __LINE__);
		if (FAILED(dwReturn))
		{
			if (bDisplayMsgOnErrFlag == TRUE)
			{
                iMsg = MyMessageBox( NULL, IDS_RETRY, MB_ABORTRETRYIGNORE | MB_SETFOREGROUND );
				switch ( iMsg )
				{
				case IDIGNORE:
					dwReturn = ERROR_SUCCESS;
					goto SetAdminACL_wrap_Exit;
				case IDABORT:
					dwReturn = ERROR_OPERATION_ABORTED;
					goto SetAdminACL_wrap_Exit;
				case IDRETRY:
					break;
				default:
					break;
				}
			}
			else
			{
				// return whatever err happened
				goto SetAdminACL_wrap_Exit;
			}
		}
                                    else
                                    {
                                                      break;
                                    } 
	} while ( FAILED(dwReturn) );

SetAdminACL_wrap_Exit:
	return dwReturn;
}

#endif


#ifndef _CHICAGO_
DWORD WriteSDtoMetaBase(PSECURITY_DESCRIPTOR outpSD, LPCTSTR szKeyPath)
{
    iisDebugOut_Start(_T("WriteSDtoMetaBase"), LOG_TYPE_TRACE);
    DWORD dwReturn = E_FAIL;
    DWORD dwLength = 0;
    DWORD dwMDFlags = 0;
    CMDKey cmdKey;
    HRESULT hReturn = E_FAIL;
    int iSavedFlag = 0;
        
    dwMDFlags = METADATA_INHERIT | METADATA_REFERENCE | METADATA_SECURE,IIS_MD_UT_SERVER,BINARY_METADATA;
    iSavedFlag = g_GlobalDebugCrypto;

    if (!outpSD)
    {
        dwReturn = ERROR_INVALID_SECURITY_DESCR;
        goto WriteSDtoMetaBase_Exit;
    }

    // Apply the new security descriptor to the metabase
    dwLength = GetSecurityDescriptorLength(outpSD);

    // open the metabase
    // stick it into the metabase.  warning those hoses a lot because
    // it uses encryption.  rsabase.dll

    // Check for special debug flag in metabase to break right before this call!
    if (g_GlobalDebugCrypto != 0)
    {
        // special flag to say... hey "stop setup so that the crypto team can debug they're stuff"
        iisDebugOut((LOG_TYPE_TRACE, _T("Breakpoint enabled thru setup (to debug crypto api). look at debugoutput.")));
        OutputDebugString(_T("\n\nBreakpoint enabled thru setup (to debug crypto api)"));
        OutputDebugString(_T("\n1.in this process:"));
        OutputDebugString(_T("\n  set breakpoint on admwprox!IcpGetContainerHelper"));
        OutputDebugString(_T("\n  set breakpoint on advapi32!CryptAcquireContextW"));
        OutputDebugString(_T("\n  IcpGetKeyHelper will call CryptAcquireContext and try to open an existing key container,"));
        OutputDebugString(_T("\n  if it doesn't exist it will return NTE_BAD_KEYSET, and IcpGetContainerHelper will try to create the container."));
        OutputDebugString(_T("\n2.in the inetinfo process:"));
        OutputDebugString(_T("\n  set breakpoint on admwprox!IcpGetContainerHelper"));
        OutputDebugString(_T("\n  set breakpoint on advapi32!CryptAcquireContextW\n"));
    }

    hReturn = cmdKey.CreateNode(METADATA_MASTER_ROOT_HANDLE, szKeyPath);
    if ( (METADATA_HANDLE)cmdKey ) 
    {
        TCHAR szErrorString[50];
        iisDebugOut((LOG_TYPE_TRACE, _T("WriteSDtoMetaBase:cmdKey():SetData(MD_ADMIN_ACL), dwdata = %d; outpSD = %x, Start\n"), dwLength, (DWORD_PTR) outpSD ));
        if (g_GlobalDebugCrypto != 0)
        {
            OutputDebugString(_T("\nCalling SetData....\n"));
            DebugBreak();
        }
        dwReturn = cmdKey.SetData(MD_ADMIN_ACL,dwMDFlags,IIS_MD_UT_SERVER,BINARY_METADATA,dwLength,(LPBYTE)outpSD);
        if (FAILED(dwReturn))
        {
           iisDebugOut((LOG_TYPE_ERROR, _T("WriteSDtoMetaBase:cmdKey():SetData(MD_ADMIN_ACL), FAILED. Code=0x%x.End.\n"), dwReturn));
           if (g_GlobalDebugCrypto != 0)
            {
               _stprintf(szErrorString, _T("\r\nSetData Failed. code=0x%x\r\n\r\n"), dwReturn);
               OutputDebugString(szErrorString);
            }
 
        }
        else
        {
            dwReturn = ERROR_SUCCESS;
            iisDebugOut((LOG_TYPE_TRACE, _T("WriteSDtoMetaBase:cmdKey():SetData(MD_ADMIN_ACL), Success.End.\n")));
            if (g_GlobalDebugCrypto != 0)
            {
               _stprintf(szErrorString, _T("\r\nSetData Succeeded. code=0x%x\r\n\r\n"), dwReturn);
               OutputDebugString(szErrorString);
            }
        }
        cmdKey.Close();
    }
    else
    {
        dwReturn = hReturn;
    }
   
WriteSDtoMetaBase_Exit:
    g_GlobalDebugCrypto = iSavedFlag;
    iisDebugOut((LOG_TYPE_TRACE, _T("WriteSDtoMetaBase:End.  Return=0x%x"), dwReturn));
    return dwReturn;
}

DWORD WriteSessiontoMetaBase(LPCTSTR szKeyPath)
{
    iisDebugOut_Start(_T("WriteSessiontoMetaBase"), LOG_TYPE_TRACE);
    DWORD dwReturn = E_FAIL;
    CMDKey cmdKey;
    HRESULT hReturn = E_FAIL;
    
    hReturn = cmdKey.CreateNode(METADATA_MASTER_ROOT_HANDLE, szKeyPath);
    if ( (METADATA_HANDLE)cmdKey ) 
    {
        dwReturn = cmdKey.SetData(9999,METADATA_NO_ATTRIBUTES,IIS_MD_UT_SERVER,BINARY_METADATA,0,(LPBYTE)"");
        if (FAILED(dwReturn))
        {
            iisDebugOut((LOG_TYPE_ERROR, _T("WriteSessiontoMetaBase:cmdKey():SetData(), FAILED. Code=0x%x.End.\n"), dwReturn));
        }
        else
        {
            dwReturn = ERROR_SUCCESS;
            iisDebugOut((LOG_TYPE_TRACE, _T("WriteSessiontoMetaBase:cmdKey():SetData(), Success.End.\n")));
        }
        cmdKey.Close();
    }
    else
    {
        dwReturn = hReturn;
    }
   
    iisDebugOut((LOG_TYPE_TRACE, _T("WriteSessiontoMetaBase:End.  Return=0x%x"), dwReturn));
    return dwReturn;
}
#endif

//----------------------------------------------------------------------------
// Test if the given account name is an account on the local machine or not.
//----------------------------------------------------------------------------
BOOL IsLocalAccount(LPCTSTR pAccnt, DWORD *dwErr )
    {
    BOOL        fIsLocalAccount = FALSE;
    CString     csDomain, csComputer;
    DWORD       cbDomain = 0;

    PSID         pSid = NULL;
    DWORD        cbSid = 0;
    SID_NAME_USE snu;

    // get the computer name
    cbDomain = _MAX_PATH;
    GetComputerName(
        csComputer.GetBuffer( cbDomain ), // address of name buffer
        &cbDomain                         // address of size of name buffer
        );
    csComputer.ReleaseBuffer();
    cbDomain = 0;

    // have security look up the account name and get the domain name. We dont' care about
    // the other stuff it can return, so pass in nulls
    BOOL fLookup = LookupAccountName(
        NULL,                       // address of string for system name
        pAccnt,                     // address of string for account name
        NULL,                       // address of security identifier
        &cbSid,                     // address of size of security identifier
        NULL,// address of string for referenced domain
        &cbDomain,                  // address of size of domain string
        &snu                        // address of SID-type indicator
        );

    // check the error - it should be insufficient buffer
    *dwErr = GetLastError();
    if (*dwErr != ERROR_INSUFFICIENT_BUFFER)
        return FALSE;

    // allocate the sid
    pSid = (PSID) malloc (cbSid);
    if (!pSid )
        {
        *dwErr = GetLastError();
        return FALSE;
        }

    // do the real lookup
    fLookup = LookupAccountName (NULL,pAccnt,pSid,&cbSid,csDomain.GetBuffer(cbDomain+2),&cbDomain,&snu);
    csDomain.ReleaseBuffer();

    // free the pSid we allocated above and set the final error code
    *dwErr = GetLastError();
    free( pSid );
    pSid = NULL;

    // compare the domain to the machine name, if it is the same, then set the sub auth
    if ( fLookup && (csDomain.CompareNoCase(csComputer) == 0) )
        fIsLocalAccount = TRUE;

    // return the answer
    return fIsLocalAccount;
    }


// pDomainUserName can be one of the following:
//
// domainname\username       <-- this function returns true
// computername\username     <-- this function returns false
// username                  <-- this function returns false
//
int IsDomainSpecifiedOtherThanLocalMachine(LPCTSTR pDomainUserName)
{
    int iReturn = TRUE;
    TCHAR szTempDomainUserName[_MAX_PATH];
    iisDebugOut_Start1(_T("IsDomainSpecifiedOtherThanLocalMachine"),pDomainUserName);

    CString     csComputer;
    DWORD       cbDomain = 0;

    // Make a copy to be sure not to move the pointer around.
    _tcscpy(szTempDomainUserName, pDomainUserName);
    
    // Check if there is a "\" in there.
    LPTSTR pch = NULL;
    pch = _tcschr(szTempDomainUserName, _T('\\'));
    if (!pch) 
        {
        // no '\' found so, they must be specifying only the username, return false
        iReturn = FALSE;
        goto IsDomainSpecifiedOtherThanLocalMachine_Exit;
        }

    // We have at least a '\' in there, so set default return to true.
    // let's check if the name is the local computername!

    // get the computer name
    cbDomain = _MAX_PATH;
    if (0 == GetComputerName(csComputer.GetBuffer( cbDomain ),&cbDomain) )
    {
        // failed to get computername so, let's bail
        iReturn = TRUE;
        csComputer.ReleaseBuffer();
        goto IsDomainSpecifiedOtherThanLocalMachine_Exit;
    }
    csComputer.ReleaseBuffer();
    cbDomain = 0;

    // trim off the '\' character to leave just the domain\computername so we can check against it.
    *pch = _T('\0');
    
    // Compare the domainname with the computername
    // if they match then it's the local system account.
    iReturn = TRUE;
    iisDebugOut((LOG_TYPE_TRACE, _T("IsDomainSpecifiedOtherThanLocalMachine(): %s -- %s.\n"), szTempDomainUserName, csComputer));
    if (  0 == csComputer.CompareNoCase(szTempDomainUserName) )
    {
        // The domain name and the computername are the same.
        // it is the same place.
        iReturn = FALSE;
    }

IsDomainSpecifiedOtherThanLocalMachine_Exit:
    iisDebugOut((LOG_TYPE_TRACE, _T("IsDomainSpecifiedOtherThanLocalMachine():%s.End.Ret=%d.\n"), pDomainUserName,iReturn));
    return iReturn;
}



#ifndef _CHICAGO_
void DumpAdminACL(HANDLE hFile,PSECURITY_DESCRIPTOR pSD)
{
    BOOL b= FALSE, bDaclPresent = FALSE, bDaclDefaulted = FALSE;;
    PACL pDacl = NULL;
    ACCESS_ALLOWED_ACE* pAce;
    ACCESS_MASK dwOldMask, dwNewMask,  dwExtraMask, dwMask;

    iisDebugOut((LOG_TYPE_TRACE, _T("DumpAdminACL:Start\n")));

    b = GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pDacl, &bDaclDefaulted);
    if (NULL == pDacl)
    {
        iisDebugOut((LOG_TYPE_TRACE, _T("DumpAdminACL:No Security.\n")));
        return;
    }
    if (b) 
    {
        iisDebugOut((LOG_TYPE_TRACE, _T("DumpAdminACL:ACE count: %d\n"), (int)pDacl->AceCount));

        // get dacl length  
        DWORD cbDacl = pDacl->AclSize;
        // now check if SID's ACE is there  
        for (int i = 0; i < pDacl->AceCount; i++)  
        {
            if (!GetAce(pDacl, i, (LPVOID *) &pAce))
            {
                iisDebugOut((LOG_TYPE_TRACE, _T("DumpAdminACL:GetAce failed with 0x%x\n"),GetLastError()));
            }

		    if (IsValidSid(   (PSID) &(pAce->SidStart)   ) )
		    {
			    LPTSTR pszSid;

                LPCTSTR ServerName = NULL; // local machine
                DWORD cbName = UNLEN+1;
                TCHAR ReferencedDomainName[200];
                DWORD cbReferencedDomainName = sizeof(ReferencedDomainName);
                SID_NAME_USE sidNameUse = SidTypeUser;
                TCHAR szUserName[UNLEN + 1];

                // dump out the sid in string format
			    if (ConvertSidToStringSid(  (PSID) &(pAce->SidStart)  , &pszSid))
			    {
                    _tcscpy(szUserName, _T("(unknown...)"));
                    if (LookupAccountSid(ServerName, (PSID) &(pAce->SidStart), szUserName, &cbName, ReferencedDomainName, &cbReferencedDomainName, &sidNameUse))
                    {
                        // Get the rights for this user.
                        // pAce->Mask
                        DWORD dwBytesWritten = 0;
                        TCHAR szBuf[UNLEN+1 + 20 + 20];
                        memset(szBuf, 0, _tcslen(szBuf) * sizeof(TCHAR));

                        /*
                        typedef struct _ACCESS_ALLOWED_ACE {
                            ACE_HEADER Header;
                            ACCESS_MASK Mask;
                            ULONG SidStart;
                        } ACCESS_ALLOWED_ACE;

                        typedef struct _ACE_HEADER {
                            UCHAR AceType;
                            UCHAR AceFlags;
                            USHORT AceSize;
                        } ACE_HEADER;
                        typedef ACE_HEADER *PACE_HEADER;

                          typedef ULONG ACCESS_MASK;
                        */
                        _stprintf(szBuf, _T("%s,0x%x,0x%x,0x%x,0x%x\r\n"), 
                            szUserName,
                            pAce->Header.AceType,
                            pAce->Header.AceFlags,
                            pAce->Header.AceSize,
                            pAce->Mask
                            );

                        if (hFile != NULL && hFile != INVALID_HANDLE_VALUE)
                        {
                            if (WriteFile(hFile, szBuf, _tcslen(szBuf) * sizeof(TCHAR), &dwBytesWritten, NULL ) == FALSE )
                                {iisDebugOut((LOG_TYPE_WARN, _T("WriteFile Failed=0x%x.\n"), GetLastError()));}
                        }
                        else
                        {
                            // echo to logfile
                            iisDebugOut((LOG_TYPE_TRACE, _T("DumpAdminACL:Sid[%i]=%s,%s,0x%x,0x%x,0x%x,0x%x\n"),i,
                                pszSid,
                                szUserName,
                                pAce->Header.AceType,
                                pAce->Header.AceFlags,
                                pAce->Header.AceSize,
                                pAce->Mask
                                ));
                        }
                    }
                    else
                    {
                        iisDebugOut((LOG_TYPE_TRACE, _T("DumpAdminACL:Sid[%i]=%s='%s'\n"),i,pszSid,szUserName));
                    }

                    
				    LocalFree(LocalHandle(pszSid));
			    }
		    }
            else
            {
                iisDebugOut((LOG_TYPE_TRACE, _T("DumpAdminACL:IsVAlidSid failed with 0x%x\n"),GetLastError()));
            }
        }
    }

    iisDebugOut((LOG_TYPE_TRACE, _T("DumpAdminACL:End\n")));
    return;
}
#endif

DWORD MDDumpAdminACL(CString csKeyPath)
{
    DWORD dwReturn = E_FAIL;

    BOOL bFound = FALSE;
    DWORD attr, uType, dType, cbLen;
    CMDKey cmdKey;
    BUFFER bufData;
    PBYTE pData;
    int BufSize;

    PSECURITY_DESCRIPTOR pOldSd = NULL;

    cmdKey.OpenNode(csKeyPath);
    if ( (METADATA_HANDLE) cmdKey )
    {
        pData = (PBYTE)(bufData.QueryPtr());
        BufSize = bufData.QuerySize();
        cbLen = 0;
        bFound = cmdKey.GetData(MD_ADMIN_ACL, &attr, &uType, &dType, &cbLen, pData, BufSize);
        if (!bFound)
        {
            if (cbLen > 0)
            {
                if ( ! (bufData.Resize(cbLen)) )
                {
                    iisDebugOut((LOG_TYPE_ERROR, _T("MDDumpAdminACL():  cmdKey.GetData.  failed to resize to %d.!\n"), cbLen));
                }
                else
                {
                    pData = (PBYTE)(bufData.QueryPtr());
                    BufSize = cbLen;
                    cbLen = 0;
                    bFound = cmdKey.GetData(MD_ADMIN_ACL, &attr, &uType, &dType, &cbLen, pData, BufSize);
                }
            }
        }
        cmdKey.Close();

        if (bFound)
        {
            // dump out the info
            // We've got the acl
            pOldSd = (PSECURITY_DESCRIPTOR) pData;
            if (IsValidSecurityDescriptor(pOldSd))
            {
#ifndef _CHICAGO_
                DumpAdminACL(INVALID_HANDLE_VALUE,pOldSd);
                dwReturn = ERROR_SUCCESS;
#endif
            }
        }
        else
        {
            // there was no acl to be found.
        }
    }
    return dwReturn;
}

DWORD AddUserToMetabaseACL(CString csKeyPath, LPTSTR szUserToAdd)
{
    DWORD dwReturn = E_FAIL;

    BOOL bFound = FALSE;
    DWORD attr, uType, dType, cbLen;
    CMDKey cmdKey;
    BUFFER bufData;
    PBYTE pData;
    int BufSize;

    PSECURITY_DESCRIPTOR pOldSd = NULL;
    PSECURITY_DESCRIPTOR pNewSd = NULL;

    cmdKey.OpenNode(csKeyPath);
    if ( (METADATA_HANDLE) cmdKey )
    {
        pData = (PBYTE)(bufData.QueryPtr());
        BufSize = bufData.QuerySize();
        cbLen = 0;
        bFound = cmdKey.GetData(MD_ADMIN_ACL, &attr, &uType, &dType, &cbLen, pData, BufSize);
        if (!bFound)
        {
            if (cbLen > 0)
            {
                if ( ! (bufData.Resize(cbLen)) )
                {
                    iisDebugOut((LOG_TYPE_ERROR, _T("AddUserToMetabaseACL():  cmdKey.GetData.  failed to resize to %d.!\n"), cbLen));
                }
                else
                {
                    pData = (PBYTE)(bufData.QueryPtr());
                    BufSize = cbLen;
                    cbLen = 0;
                    bFound = cmdKey.GetData(MD_ADMIN_ACL, &attr, &uType, &dType, &cbLen, pData, BufSize);
                }
            }
        }

        cmdKey.Close();

        if (bFound)
        {
            // We've got the acl
            // so now we want to add a user to it.
            pOldSd = (PSECURITY_DESCRIPTOR) pData;
            if (IsValidSecurityDescriptor(pOldSd))
            {
                DWORD AccessMask = (MD_ACR_READ |MD_ACR_WRITE |MD_ACR_RESTRICTED_WRITE |MD_ACR_UNSECURE_PROPS_READ |MD_ACR_ENUM_KEYS |MD_ACR_WRITE_DAC);
                PSID principalSID = NULL;
                BOOL bWellKnownSID = FALSE;

                // Get the SID for the certain string (administrator or everyone or whoever)
                dwReturn = GetPrincipalSID(szUserToAdd, &principalSID, &bWellKnownSID);
                if (dwReturn != ERROR_SUCCESS)
                    {
                    iisDebugOut((LOG_TYPE_WARN, _T("AddUserToMetabaseACL:GetPrincipalSID(%s) FAILED.  Error()= 0x%x\n"), szUserToAdd, dwReturn));
                    return dwReturn;
                    }

#ifndef _CHICAGO_
                if (FALSE == AddUserAccessToSD(pOldSd,principalSID,AccessMask,ACCESS_ALLOWED_ACE_TYPE,&pNewSd))
                {
                    iisDebugOut((LOG_TYPE_ERROR, _T("AddUserToMetabaseACL:AddUserAccessToSD FAILED\n")));
                    return dwReturn;
                }
                if (pNewSd)
                {
                    // We have a new self relative SD
                    // lets write it to the metabase.
                    if (IsValidSecurityDescriptor(pNewSd))
                    {
                       dwReturn = WriteSDtoMetaBase(pNewSd, csKeyPath);
                    }
                }
#endif
            }
        }
        else
        {
            // there was no acl to be found.

        }

    }

    if (pNewSd){GlobalFree(pNewSd);}
    iisDebugOut((LOG_TYPE_TRACE, _T("AddUserToMetabaseACL():End.  Return=0x%x.\n"), dwReturn));
    return dwReturn;
}




DWORD DoesAdminACLExist(CString csKeyPath)
{
    DWORD dwReturn = FALSE;

    BOOL bFound = FALSE;
    DWORD attr, uType, dType, cbLen;
    CMDKey cmdKey;
    BUFFER bufData;
    PBYTE pData;
    int BufSize;

    cmdKey.OpenNode(csKeyPath);
    if ( (METADATA_HANDLE) cmdKey )
    {
        pData = (PBYTE)(bufData.QueryPtr());
        BufSize = bufData.QuerySize();
        cbLen = 0;
        bFound = cmdKey.GetData(MD_ADMIN_ACL, &attr, &uType, &dType, &cbLen, pData, BufSize);
        if (bFound)
        {
            dwReturn = TRUE;
        }
        else
        {
            if (cbLen > 0)
            {
                if ( ! (bufData.Resize(cbLen)) )
                {
                    iisDebugOut((LOG_TYPE_ERROR, _T("DoesAdminACLExist():  cmdKey.GetData.  failed to resize to %d.!\n"), cbLen));
                }
                else
                {
                    pData = (PBYTE)(bufData.QueryPtr());
                    BufSize = cbLen;
                    cbLen = 0;
                    bFound = cmdKey.GetData(MD_ADMIN_ACL, &attr, &uType, &dType, &cbLen, pData, BufSize);
                    if (bFound)
                    {
                        dwReturn = TRUE;
                    }
                }
            }
        }

        cmdKey.Close();
    }

    if (dwReturn != TRUE)
    {
        //No the acl Does not exist
    }

    iisDebugOut((LOG_TYPE_TRACE, _T("DoesAdminACLExist():End.  Return=0x%x.\n"), dwReturn));
    return dwReturn;
}