291 lines
6.1 KiB
C++
291 lines
6.1 KiB
C++
|
#include "fundsrm.h"
|
||
|
#include "fundsrmp.h"
|
||
|
|
||
|
#define FirstAce(Acl) ((PVOID)((PUCHAR)(Acl) + sizeof(ACL)))
|
||
|
|
||
|
|
||
|
FundsRM::FundsRM(DWORD dwFundsAvailable) {
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
The constructor for the Funds resource manager.
|
||
|
It initializes an instance of an Authz Resource Manager, providing it
|
||
|
with the appropriate callback functions.
|
||
|
It also creates a security descriptor for the fund, allowing only
|
||
|
corporate and transfer expenditures, not personal. Additional logic
|
||
|
could be added to allow VPs to override these restrictions, etc.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
DWORD dwFundsAvailable - The amount of money in the fund managed by this
|
||
|
resource manager
|
||
|
|
||
|
Return Value
|
||
|
None.
|
||
|
--*/
|
||
|
|
||
|
//
|
||
|
// The amount of money in the fund
|
||
|
//
|
||
|
|
||
|
_dwFundsAvailable = dwFundsAvailable;
|
||
|
|
||
|
//
|
||
|
// Initialize the fund's resource manager
|
||
|
//
|
||
|
|
||
|
AuthzInitializeResourceManager(
|
||
|
FundsAccessCheck,
|
||
|
FundsComputeDynamicGroups,
|
||
|
FundsFreeDynamicGroups,
|
||
|
NULL, // no auditing
|
||
|
0, // no flags
|
||
|
&_hRM
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Create the fund's security descriptor
|
||
|
//
|
||
|
|
||
|
InitializeSecurityDescriptor(&_SD, SECURITY_DESCRIPTOR_REVISION);
|
||
|
SetSecurityDescriptorGroup(&_SD, NULL, FALSE);
|
||
|
SetSecurityDescriptorSacl(&_SD, FALSE, NULL, FALSE);
|
||
|
SetSecurityDescriptorOwner(&_SD, NULL, FALSE);
|
||
|
|
||
|
//
|
||
|
// Initialize the DACL for the fund
|
||
|
//
|
||
|
|
||
|
PACL pDaclFund = (PACL)malloc(1024);
|
||
|
InitializeAcl(pDaclFund, 1024, ACL_REVISION_DS);
|
||
|
|
||
|
//
|
||
|
// Add an access-allowed ACE for Everyone
|
||
|
// Only company spending and transfers are allowed for this fund
|
||
|
//
|
||
|
|
||
|
AddAccessAllowedAce(pDaclFund,
|
||
|
ACL_REVISION_DS,
|
||
|
ACCESS_FUND_CORPORATE | ACCESS_FUND_TRANSFER,
|
||
|
EveryoneSid);
|
||
|
|
||
|
//
|
||
|
// Now set that ACE to a callback ACE
|
||
|
//
|
||
|
|
||
|
((PACE_HEADER)FirstAce(pDaclFund))->AceType =
|
||
|
ACCESS_ALLOWED_CALLBACK_ACE_TYPE;
|
||
|
|
||
|
//
|
||
|
// Add that ACL as the security descriptor's DACL
|
||
|
//
|
||
|
|
||
|
SetSecurityDescriptorDacl(&_SD, TRUE, pDaclFund, FALSE);
|
||
|
}
|
||
|
|
||
|
FundsRM::~FundsRM() {
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
The destructor for the Funds resource manager.
|
||
|
Frees any dynamically allocated memory used.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value
|
||
|
None.
|
||
|
--*/
|
||
|
|
||
|
//
|
||
|
// Deallocate the DACL in the security descriptor
|
||
|
//
|
||
|
|
||
|
PACL pDaclFund = NULL;
|
||
|
BOOL fDaclPresent;
|
||
|
BOOL fDaclDefaulted;
|
||
|
GetSecurityDescriptorDacl(&_SD,
|
||
|
&fDaclPresent,
|
||
|
&pDaclFund,
|
||
|
&fDaclDefaulted);
|
||
|
|
||
|
if( pDaclFund != NULL )
|
||
|
{
|
||
|
free(pDaclFund);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Deallocate the resource manager
|
||
|
//
|
||
|
|
||
|
AuthzFreeResourceManager(_hRM);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL FundsRM::Authorize(LPTSTR szwUsername,
|
||
|
DWORD dwRequestAmount,
|
||
|
DWORD dwSpendingType) {
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
This function is called by a user who needs approval of a given amount
|
||
|
of spending in a given spending type. Internally, this uses the
|
||
|
AuthzAccessCheck function to determine whether the given user
|
||
|
should be allowed the requested spending.
|
||
|
If the spending is approved, it is deducted from the fund's total.
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
LPTSTR szwUsername - The name of the user, currently limited to
|
||
|
Bob, Martha, or Joe
|
||
|
|
||
|
DWORD dwRequestAmount - The amount of spending requested, in cents
|
||
|
|
||
|
DWORD dwSpendingType - The type of spending, ACCESS_FUND_PERSONAL,
|
||
|
ACCESS_FUND_TRANSFER, or ACCESS_FUND_CORPORATE
|
||
|
|
||
|
Return Value
|
||
|
BOOL - True if the spending was approved, FALSE otherwise
|
||
|
--*/
|
||
|
|
||
|
|
||
|
//
|
||
|
// No need to check access if not enough money in fund
|
||
|
//
|
||
|
|
||
|
if( dwRequestAmount > _dwFundsAvailable )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This would normally impersonate the RPC user and create the
|
||
|
// client context from the token. However, we can just use strings for now.
|
||
|
//
|
||
|
|
||
|
PSID pUserSid = NULL;
|
||
|
|
||
|
if( wcscmp(szwUsername, L"Bob") == 0 )
|
||
|
{
|
||
|
pUserSid = BobSid;
|
||
|
}
|
||
|
else if( wcscmp(szwUsername, L"Martha") == 0 )
|
||
|
{
|
||
|
pUserSid = MarthaSid;
|
||
|
}
|
||
|
else if( wcscmp(szwUsername, L"Joe") == 0 )
|
||
|
{
|
||
|
pUserSid = JoeSid;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Only the above usernames are supported
|
||
|
//
|
||
|
|
||
|
if( pUserSid == NULL ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Now we create a client context from the SID
|
||
|
//
|
||
|
|
||
|
AUTHZ_CLIENT_CONTEXT_HANDLE hCC = NULL;
|
||
|
LUID ZeroLuid = { 0, 0};
|
||
|
|
||
|
AuthzInitializeContextFromSid(pUserSid,
|
||
|
NULL, // this is local, no need for server
|
||
|
_hRM, // Using the Fund resource manager
|
||
|
NULL, // no expiration
|
||
|
ZeroLuid, // no need for unique luid
|
||
|
0, // no flags,
|
||
|
NULL, // no args for ComputeDynamicGroups
|
||
|
&hCC);
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Initialize the access check result structure
|
||
|
//
|
||
|
|
||
|
DWORD dwGrantedAccessMask = 0;
|
||
|
DWORD dwErr = ERROR_ACCESS_DENIED; // default to deny
|
||
|
AUTHZ_ACCESS_REPLY AccessReply = {0};
|
||
|
|
||
|
AccessReply.ResultListLength = 1;
|
||
|
AccessReply.GrantedAccessMask = &dwGrantedAccessMask;
|
||
|
AccessReply.Error = &dwErr;
|
||
|
|
||
|
//
|
||
|
// Initialize the access check request
|
||
|
//
|
||
|
|
||
|
AUTHZ_ACCESS_REQUEST AccessRequest = {0};
|
||
|
|
||
|
AccessRequest.DesiredAccess = dwSpendingType;
|
||
|
AccessRequest.PrincipalSelfSid = NULL;
|
||
|
AccessRequest.ObjectTypeList = NULL;
|
||
|
AccessRequest.ObjectTypeListLength = 0;
|
||
|
AccessRequest.OptionalArguments = &dwRequestAmount;
|
||
|
|
||
|
AuthzAccessCheck(hCC, // Bob is requesting the transfer
|
||
|
&AccessRequest,
|
||
|
NULL, // no auditing
|
||
|
&_SD,
|
||
|
NULL, // only one SD and one object
|
||
|
0, // no additional SDs
|
||
|
&AccessReply,
|
||
|
NULL // no need to cache the access check
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Now free the client context
|
||
|
//
|
||
|
|
||
|
AuthzFreeContext(hCC);
|
||
|
|
||
|
//
|
||
|
// AuthzAccessCheck sets ERROR_SUCCESS if all acces bits are granted
|
||
|
//
|
||
|
|
||
|
if( dwErr == ERROR_SUCCESS )
|
||
|
{
|
||
|
|
||
|
_dwFundsAvailable -= dwRequestAmount;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
DWORD FundsRM::FundsAvailable() {
|
||
|
/*++
|
||
|
|
||
|
Routine Description
|
||
|
|
||
|
Accessor for the funds available
|
||
|
|
||
|
Arguments
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value
|
||
|
DWORD - The amount of money available in the fund
|
||
|
--*/
|
||
|
|
||
|
return _dwFundsAvailable;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|