2025-04-27 07:49:33 -04:00

504 lines
12 KiB
C++

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
ACE.CPP
Abstract:
Security Test Tool
History:
--*/
#include "precomp.h"
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <wbemidl.h>
#include <cominit.h>
#include <bstring.h>
#include <corepol.h>
#include <winntsec.h>
SCODE sc;
CNtSecurityDescriptor gSD;
WCHAR wPath[MAX_PATH];
class ReleaseMe
{
protected:
IUnknown* m_pUnk;
public:
ReleaseMe(IUnknown* pUnk) : m_pUnk(pUnk){}
~ReleaseMe() {if(m_pUnk) m_pUnk->Release();}
};
bool MoveVariantIntoGlobalSD(VARIANT * pvar)
{
if(pvar->vt != (VT_ARRAY | VT_UI1))
return false;
SAFEARRAY * psa = pvar->parray;
PSECURITY_DESCRIPTOR pSD;
sc = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pSD);
if(sc != 0)
return false;
CNtSecurityDescriptor temp(pSD);
gSD = temp;
SafeArrayUnaccessData(psa);
return true;
}
bool LoadSD(IWbemServices * pServices)
{
bool bRet = false;
CBString InstPath(L"__systemsecurity=@");
CBString MethName(L"GetSD");
IWbemClassObject * pOutParams = NULL;
sc = pServices->ExecMethod(InstPath.GetString(),
MethName.GetString(),
0,
NULL, NULL,
&pOutParams, NULL);
if(sc == S_OK)
{
CBString prop(L"sd");
VARIANT var;
VariantInit(&var);
sc = pOutParams->Get(prop.GetString(), 0, &var, NULL, NULL);
if(sc == S_OK)
{
MoveVariantIntoGlobalSD(&var);
VariantClear(&var);
bRet = true;
}
}
return bRet;
}
bool StoreSD(IWbemServices * pSession)
{
bool bRet = false;
// Get the class object
IWbemClassObject * pClass = NULL;
CBString InstPath(L"__systemsecurity=@");
CBString ClassPath(L"__systemsecurity");
sc = pSession->GetObject(ClassPath.GetString(), 0, NULL, &pClass, NULL);
if(sc != S_OK)
return false;
ReleaseMe c(pClass);
// Get the input parameter class
CBString MethName(L"SetSD");
IWbemClassObject * pInClassSig = NULL;
sc = pClass->GetMethod(MethName.GetString(),0, &pInClassSig, NULL);
if(sc != S_OK)
return false;
ReleaseMe d(pInClassSig);
// spawn an instance of the input parameter class
IWbemClassObject * pInArg = NULL;
pInClassSig->SpawnInstance(0, &pInArg);
if(sc != S_OK)
return false;
ReleaseMe e(pInArg);
// move the SD into a variant.
SAFEARRAY FAR* psa;
SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0;
long lSize = gSD.GetSize();
rgsabound[0].cElements = lSize;
psa = SafeArrayCreate( VT_UI1, 1 , rgsabound );
if(psa == NULL)
return false;
char * pData = NULL;
sc = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pData);
if(sc != S_OK)
return false;
memcpy(pData, gSD.GetPtr(), lSize);
SafeArrayUnaccessData(psa);
VARIANT var;
var.vt = VT_I4|VT_ARRAY;
var.parray = psa;
// put the property
sc = pInArg->Put(L"SD" , 0, &var, 0);
VariantClear(&var);
if(sc != S_OK)
return false;
// Execute the method
IWbemClassObject * pOutParams = NULL;
sc = pSession->ExecMethod(InstPath.GetString(),
MethName.GetString(),
0,
NULL, pInArg,
NULL, NULL);
if(FAILED(sc))
printf("\nPut failed, returned 0x%x",sc);
return bRet;
}
bool AddNTAce(IWbemServices * pSession, WCHAR * wUser, WCHAR * wDomain,
WCHAR * wNamespace, long lMask, long lFlags, long lType)
{
WCHAR wFullName[MAX_PATH];
wFullName[0] = 0;
if(wcslen(wDomain) > 1 ||
(wcslen(wDomain) == 1 && wDomain[0] != L'.'))
{
wcscpy(wFullName, wDomain);
wcscat(wFullName, L"\\");
}
wcscat(wFullName, wUser);
// Read the security descriptor
if(!LoadSD(pSession))
return false;
// Add an ace
CNtAce Ace(
lMask,
lType,
lFlags,
wFullName,
0
);
if(Ace.GetStatus() != 0)
{
printf("\nFAILED!!!!\n");
return false;
}
CNtAcl Acl;
gSD.GetDacl(Acl);
Acl.AddAce(&Ace);
gSD.SetDacl(&Acl);
// write the security descriptor back
return StoreSD(pSession);
}
bool Add9XAce(IWbemServices * pSession, WCHAR * wUser, WCHAR * wDomain,
WCHAR * wNamespace, long lMask, long lFlags, long lType)
{
// Read the ntlm user list
CBString InstPath(L"__systemsecurity=@");
CBString GetMethName(L"Get9XUserList");
CBString SetMethName(L"Set9XUserList");
CBString ClassName(L"__ntlmuser9x");
CBString MethClassName(L"__systemsecurity");
IWbemClassObject * pOutParams = NULL;
SCODE sc = pSession->ExecMethod(InstPath.GetString(),
GetMethName.GetString(),
0,
NULL, NULL,
&pOutParams, NULL);
if(sc != S_OK)
{
printf("\nfailed executing the Get9XUserList method");
return false;
}
// Get the __ntlmuser9x class and spawn an instance
IWbemClassObject * pClassObj = NULL;
IWbemClassObject * pUserInst = NULL;
sc = pSession->GetObject(ClassName.GetString(), 0, NULL, &pClassObj, NULL);
if(sc != S_OK)
return false;
pClassObj->SpawnInstance(0, &pUserInst);
pClassObj->Release();
// Set the arugments
VARIANT var;
var.vt = VT_BSTR;
var.bstrVal = SysAllocString(wDomain);
pUserInst->Put(L"Authority", 0, &var, 0);
SysFreeString(var.bstrVal);
var.bstrVal = SysAllocString(wUser);
pUserInst->Put(L"name", 0, &var, 0);
VariantClear(&var);
var.vt = VT_I4;
var.lVal = lType;
pUserInst->Put(L"Type", 0, &var, 0);
var.lVal = lFlags;
pUserInst->Put(L"Flags", 0, &var, 0);
var.vt = VT_I4;
var.lVal = lMask;
pUserInst->Put(L"Mask", 0, &var, 0);
// Add the new user to the list
pOutParams->Get(L"ul", 0, &var, NULL, NULL);
SAFEARRAYBOUND sb;
SAFEARRAY * psa = var.parray;
long lLBound, lUBound;
SafeArrayGetLBound(psa, 1, &lLBound);
SafeArrayGetUBound(psa, 1, &lUBound);
sb.cElements = lUBound - lLBound + 2;
sb.lLbound = 0;
sc = SafeArrayRedim( psa, &sb);
long lNew = lLBound + sb.cElements -1;
sc = SafeArrayPutElement(psa,&lNew, pUserInst);
// Get the parameters class and spawn an instance
IWbemClassObject * pMethClass = NULL;
pClassObj = NULL;
IWbemClassObject * pArgInstObj = NULL;
sc = pSession->GetObject(MethClassName.GetString(), 0, NULL, &pMethClass, NULL);
pMethClass->GetMethod(L"Set9XUserList", 0, &pClassObj, NULL);
pMethClass->Release();
pClassObj->SpawnInstance(0, &pArgInstObj);
pClassObj->Release();
var.vt = VT_ARRAY | VT_UNKNOWN;
var.parray = psa;
pArgInstObj->Put(L"ul", 0, &var, NULL);
// write the list back
sc = pSession->ExecMethod(InstPath.GetString(),
SetMethName.GetString(),
0,
NULL, pArgInstObj,
NULL, NULL);
if(FAILED(sc))
printf("\nPut failed, returned 0x%x",sc);
return true;
}
bool AddAnyAce(IWbemLocator * pLocator,WCHAR * wUser, WCHAR * wDomain,
WCHAR * wNamespace, long lMask, long lFlags, long lType)
{
bool bRet;
// Connect up to the namespace
IWbemServices * pSession = NULL;
SCODE sc = pLocator->ConnectServer(wNamespace, NULL, NULL,0,0,NULL,NULL,&pSession);
if(sc != S_OK)
return false;
ReleaseMe r(pSession);
// Determine if the pc is 9x or nt
bool bIsNT = false;
CBString InstPath(L"__systemsecurity=@");
CBString MethName(L"GetSD");
IWbemClassObject * pOutParams = NULL;
sc = pSession->ExecMethod(InstPath.GetString(),
MethName.GetString(),
0,
NULL, NULL,
&pOutParams, NULL);
if(sc == S_OK)
{
bIsNT = true;
pOutParams->Release();
}
// Add the ace
if(bIsNT)
bRet = AddNTAce(pSession, wUser, wDomain, wNamespace, lMask, lFlags, lType);
else
{
if((lMask & WBEM_REMOTE_ACCESS) == 0)
printf("\nWarning, win9X ACEs require remote access");
bRet = Add9XAce(pSession, wUser, wDomain, wNamespace, lMask, lFlags, lType);
}
return bRet;
}
void PrintUsage()
{
printf("\nUsage, c:>ace /namespace:root /user:name /domain:redmond /mask:0x3 /flags:2 /type:0\n"
"where mask 1=enable, 2=methods, 4=full, 8=partial rep, 0x10=provider,\n"
"0x20=remote access 0x40000=write DACL, 0x20000=read DACL\n"
"\nFor optional flags, 2 = container inherit\n"
"For type, 0 = allow (default), 1 = deny");
}
bool GetString(WCHAR * wOut, char * pArg)
{
// find the ':' in the arugment
for(;*pArg && *pArg != ':'; pArg++); // intentional!
if(*pArg == 0)
return false;
pArg++;
mbstowcs(wOut, pArg, MAX_PATH);
return true;
}
//***************************************************************************
//
// main
//
// Purpose: Initialized Ole, calls some test code, cleans up and exits.
//
//***************************************************************************
int __cdecl main(int argc, char ** argv)
{
bool bOK = true;
long lType = 0;
long lFlags = 0;
long lMask = 0;
WCHAR wUser[MAX_PATH];
WCHAR wDomain[MAX_PATH];
WCHAR wNamespace[MAX_PATH];
wUser[0] = 0;
wDomain[0] = 0;
wNamespace[0] = 0;
if(argc < 2)
{
PrintUsage();
return 1;
}
// Initialize com and get the locator pointer
HRESULT hr = InitializeCom();
if(hr != S_OK)
return 1;
IWbemLocator *pLocator = 0;
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLocator);
if(hr != S_OK)
{
printf("\nCCI failed, error is 0x%x", hr);
return 1;
}
// Get the options
for(int i = 1; bOK && i < argc; i++)
{
char *pcCurrArg = argv[i] + 1;
if(argv[i][0] != '-' && argv[i][0] != '/')
{
PrintUsage();
return 1;
}
else if(!_strnicmp(pcCurrArg, "namespace:", 10))
{
bOK = GetString(wNamespace, pcCurrArg);
}
else if(!_strnicmp(pcCurrArg, "domain:", 7))
{
bOK = GetString(wDomain, pcCurrArg);
}
else if(!_strnicmp(pcCurrArg, "user:", 5))
{
bOK = GetString(wUser, pcCurrArg);
}
else if(!_strnicmp(pcCurrArg, "mask:", 5))
{
if(0 == sscanf(pcCurrArg+5, "%x", &lMask))
bOK = false;
}
else if(!_strnicmp(pcCurrArg, "flags:", 6))
{
if(0 == sscanf(pcCurrArg+6, "%x", &lFlags))
bOK = false;
}
else if(!_strnicmp(pcCurrArg, "type:", 5))
{
if(0 == sscanf(pcCurrArg+5, "%x", &lType))
bOK = false;
}
else
{
bOK = false;
}
}
// Check the choices
if(lMask & WBEM_FULL_WRITE_REP && ((lMask & WBEM_PARTIAL_WRITE_REP) == 0 ||
(lMask & WBEM_WRITE_PROVIDER) == 0))
{
printf("\nSpecifying full repository write(0x4) requires both \npartial repository write(0x8)"
" and write provider(0x10) rights.");
return 1;
}
if(!bOK)
{
printf("\nInvalid argument");
PrintUsage();
return 1;
}
// Add the Ace
AddAnyAce(pLocator, wUser, wDomain, wNamespace, lMask, lFlags, lType);
pLocator->Release();
CoUninitialize();
printf("Terminating normally\n");
return 0;
}