windows-nt/Source/XPSP1/NT/ds/security/authz/test/mailrm/mailrm.cpp
2020-09-26 16:20:57 +08:00

1308 lines
32 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
mailrm.cpp
Abstract:
The implementation of the Mail resource manager
Author:
t-eugenz - August 2000
Environment:
User mode only.
Revision History:
Created - August 2000
--*/
#include "pch.h"
#include "mailrm.h"
#include "mailrmp.h"
#include <time.h>
MailRM::MailRM()
/*++
Routine Description
The constructor for the Mail 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 mail RM, with a
SACL and DACL.
Arguments
None.
Return Value
None.
--*/
{
//
// Initialize the audit information
//
AUTHZ_RM_AUDIT_INFO_HANDLE hRMAuditInfo;
if( FALSE == AuthzInitializeRMAuditInfo(&hRMAuditInfo,
0,
0,
0,
L"MailRM") )
{
throw (DWORD)ERROR_INTERNAL_ERROR;
}
if( FALSE == AuthzInitializeResourceManager(
MailRM::AccessCheck,
MailRM::ComputeDynamicGroups,
MailRM::FreeDynamicGroups,
hRMAuditInfo,
0, // no flags
&_hRM
) )
{
AuthzFreeRMAuditInfo(hRMAuditInfo);
throw (DWORD)ERROR_INTERNAL_ERROR;
}
//
// Create the security descriptor
//
try {
InitializeMailSecurityDescriptor();
}
catch(...)
{
AuthzFreeRMAuditInfo(hRMAuditInfo);
AuthzFreeResourceManager(_hRM);
throw;
}
}
MailRM::~MailRM()
/*++
Routine Description
The destructor for the Mail resource manager.
Frees any dynamically allocated memory used, including
deleting any registered mailboxes.
Arguments
None.
Return Value
None.
--*/
{
//
// Deallocate the DACL and SACL in the security descriptor
//
PACL pAclMail = NULL;
BOOL fPresent;
BOOL fDefaulted;
DWORD dwTmp;
AUTHZ_RM_AUDIT_INFO_HANDLE hAuditInfo;
if( FALSE != AuthzGetInformationFromResourceManager(
_hRM,
AuthzRMInfoRMAuditInfo,
&hAuditInfo,
sizeof(AUTHZ_RM_AUDIT_INFO_HANDLE),
&dwTmp
) )
{
AuthzFreeRMAuditInfo(hAuditInfo);
}
GetSecurityDescriptorDacl(&_sd,
&fPresent,
&pAclMail,
&fDefaulted);
if( pAclMail != NULL )
{
delete[] (PBYTE)pAclMail;
pAclMail = NULL;
}
GetSecurityDescriptorSacl(&_sd,
&fPresent,
&pAclMail,
&fDefaulted);
if( pAclMail != NULL )
{
delete[] (PBYTE)pAclMail;
}
//
// Deallocate the resource manager
//
AuthzFreeResourceManager(_hRM);
//
// Delete the mailboxes
//
while( ! _mapSidMailbox.empty() )
{
delete (*(_mapSidMailbox.begin())).second;
_mapSidMailbox.erase(_mapSidMailbox.begin());
}
//
// Free the AuthZ client contexts
//
while( ! _mapSidContext.empty() )
{
AuthzFreeContext((*(_mapSidContext.begin())).second);
_mapSidContext.erase(_mapSidContext.begin());
}
}
void MailRM::InitializeMailSecurityDescriptor()
/*++
Routine Description
This private method initializes the MailRM's security descriptor.
It should be called exactly once, and only by the constructor.
It creates a security descriptor with the following DACL:
CallbackDeny READ Insecure 11pm-5am OR Sensitive
Allow READ, WRITE PrincipalSelf
Allow READ, WRITE, ADMIN MailAdmins
And the following SACL
CallbackAudit READ Insecure 11pm-5am OR Sensitive
(audit on both success and failure)
Arguments
None.
Return Value
None.
--*/
{
DWORD dwAclSize = sizeof(ACL);
DWORD dwAceSize = 0;
PMAILRM_OPTIONAL_DATA pOptionalData = NULL;
//
// Initialize the security descriptor
// No need for owner or group
//
InitializeSecurityDescriptor(&_sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorGroup(&_sd, NULL, FALSE);
SetSecurityDescriptorOwner(&_sd, MailAdminsSid, FALSE);
//
// Callback deny ace RWA for Insecure group SID
// Optional data: Sensitive mailbox OR 11pm-5am
// Any users coming in over an insecure connection between 11pm and 5am
// should be denied read access.
// Also any users coming in over insecure connections to sensitive mailboxes
// should be denied read access.
//
PACCESS_DENIED_CALLBACK_ACE pDenyAce = NULL;
//
// This audit ACE has the same conditions as the above deny ACE. It audits
// any successful (should not happen with the above deny) or failed
// authentications which fit the callback parameters.
//
PSYSTEM_AUDIT_CALLBACK_ACE pAuditAce = NULL;
//
// DACL for the security descriptor
//
PACL pDacl = NULL;
//
// SACL for the security descriptor
//
PACL pSacl = NULL;
//
// We allocate and initialize the callback deny ACE
//
//
// Size of the callback access denied ACE with the optional data
//
dwAceSize = sizeof(ACCESS_DENIED_CALLBACK_ACE) // ACE and 1 DWORD of SID
- sizeof(DWORD) // minus the dword
+ GetLengthSid(InsecureSid) // length of the SID
+ sizeof(MAILRM_OPTIONAL_DATA); // size of optional data
pDenyAce = (PACCESS_DENIED_CALLBACK_ACE)new BYTE[dwAceSize];
if( pDenyAce == NULL )
{
throw (DWORD)ERROR_OUTOFMEMORY;
}
//
// Manually initialize the ACE structure
//
pDenyAce->Header.AceFlags = 0;
pDenyAce->Header.AceSize = dwAceSize;
pDenyAce->Header.AceType = ACCESS_DENIED_CALLBACK_ACE_TYPE;
pDenyAce->Mask = ACCESS_MAIL_READ;
//
// Copy the Insecure SID into the ACE
//
memcpy(&(pDenyAce->SidStart), InsecureSid, GetLengthSid(InsecureSid));
//
// Our optional data is at the end of the ACE
//
pOptionalData = (PMAILRM_OPTIONAL_DATA)( (PBYTE)pDenyAce
+ dwAceSize
- sizeof(MAILRM_OPTIONAL_DATA) );
//
// Initialize the optional data as described above
//
pOptionalData->bIsSensitive = MAILRM_SENSITIVE;
pOptionalData->bLogicType = MAILRM_USE_OR;
pOptionalData->bStartHour = MAILRM_DEFAULT_START_TIME;
pOptionalData->bEndHour = MAILRM_DEFAULT_END_TIME;
//
// Add the size of the callback ACE to the expected ACL size
//
dwAclSize += dwAceSize;
//
// We also need to add non-callback ACEs
//
dwAclSize += ( sizeof(ACCESS_ALLOWED_ACE)
- sizeof(DWORD)
+ GetLengthSid(PrincipalSelfSid) );
dwAclSize += ( sizeof(ACCESS_ALLOWED_ACE)
- sizeof(DWORD)
+ GetLengthSid(MailAdminsSid) );
//
// Now we can allocate the DACL
//
pDacl = (PACL) (new BYTE[dwAclSize]);
if( pDacl == NULL )
{
delete[] (PBYTE)pDenyAce;
throw (DWORD)ERROR_OUTOFMEMORY;
}
//
// Finally, initialize the ACL and copy the ACEs into it
//
InitializeAcl(pDacl, dwAclSize, ACL_REVISION_DS);
//
// Copy the ACE into the ACL
//
AddAce(pDacl,
ACL_REVISION_DS,
0xFFFFFFFF, // Add to end
pDenyAce,
dwAceSize);
delete[] (PBYTE)pDenyAce;
//
// Add a PRINCIPAL_SELF_SID allow read and write ace
//
AddAccessAllowedAce(pDacl,
ACL_REVISION_DS,
ACCESS_MAIL_READ | ACCESS_MAIL_WRITE,
PrincipalSelfSid);
//
// Add an allow mail administrators group full access
//
AddAccessAllowedAce(pDacl,
ACL_REVISION_DS,
ACCESS_MAIL_READ | ACCESS_MAIL_WRITE | ACCESS_MAIL_ADMIN,
MailAdminsSid);
//
// Now create the SACL, which will onlye have a single callback ACE
//
dwAclSize = sizeof(ACL);
dwAceSize = sizeof(SYSTEM_AUDIT_CALLBACK_ACE) // ACE and 1 DWORD of SID
- sizeof(DWORD) // minus the dword
+ GetLengthSid(InsecureSid) // length of the SID
+ sizeof(MAILRM_OPTIONAL_DATA); // size of optional data
//
// Allocate the callback audit ACE
//
pAuditAce = (PSYSTEM_AUDIT_CALLBACK_ACE)new BYTE[dwAceSize];
if( pAuditAce == NULL )
{
delete[] (PBYTE)pDacl;
throw (DWORD)ERROR_OUTOFMEMORY;
}
//
// Initialize the ACE structure
//
pAuditAce->Header.AceFlags = FAILED_ACCESS_ACE_FLAG
| SUCCESSFUL_ACCESS_ACE_FLAG;
pAuditAce->Header.AceSize = dwAceSize;
pAuditAce->Header.AceType = SYSTEM_AUDIT_CALLBACK_ACE_TYPE;
pAuditAce->Mask = ACCESS_MAIL_READ;
//
// Copy the Insecure SID into the ACE
//
memcpy(&(pAuditAce->SidStart), InsecureSid, GetLengthSid(InsecureSid));
pOptionalData = (PMAILRM_OPTIONAL_DATA)( (PBYTE)pAuditAce
+ dwAceSize
- sizeof(MAILRM_OPTIONAL_DATA) );
//
// Initialize the optional data as described above
//
pOptionalData->bIsSensitive = MAILRM_SENSITIVE;
pOptionalData->bLogicType = MAILRM_USE_OR;
pOptionalData->bStartHour = MAILRM_DEFAULT_START_TIME;
pOptionalData->bEndHour = MAILRM_DEFAULT_END_TIME;
dwAclSize += dwAceSize;
//
// Allocate the SACL
//
pSacl = (PACL)new BYTE[dwAclSize];
if( pSacl == NULL )
{
delete[] (PBYTE)pDacl;
throw (DWORD)ERROR_OUTOFMEMORY;
}
InitializeAcl(pSacl, dwAclSize, ACL_REVISION_DS);
//
// Now add the audit ACE to the SACL
//
AddAce(pSacl,
ACL_REVISION_DS,
0xFFFFFFFF, // Add to end
pAuditAce,
dwAceSize);
delete[] (PBYTE)pAuditAce;
//
// We now have the DACL and the SACL, set them
// in the security descriptor
//
SetSecurityDescriptorDacl(&_sd, TRUE, pDacl, FALSE);
SetSecurityDescriptorSacl(&_sd, TRUE, pSacl, FALSE);
}
void MailRM::AddMailbox(Mailbox *pMailbox)
/*++
Routine Description
Registers a mailbox (and its user) with the resource manager.
Arguments
pMailbox - Pointer to an allocated and initialized mailbox
Return Value
None.
--*/
{
_mapSidMailbox[pMailbox->GetOwnerSid()] = pMailbox;
}
Mailbox * MailRM::GetMailboxAccess(
const PSID psMailbox,
const PSID psUser,
DWORD dwIncomingIp,
ACCESS_MASK amAccessRequested
)
/*++
Routine Description
This routine checks whether the user with SID psUser should
be allowed access to the mailbox of user psMailbox. psUser
is coming from dwIncomingIp, and desires amAccessRequested
access mask.
Arguments
psMailbox - PSID of the user whose mailbox will be accessed
psUser - PSID of the user accessing the mailbox
dwIncomingIp- IP address of the user accessing the mailbox
amAccessRequested - Requested access type to the mailbox
Return Value
Non-NULL Mailbox * if access is granted.
NULL if mailbox does not exist or access is denied.
--*/
{
AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClient;
AUTHZ_ACCESS_REQUEST AuthzAccessRequest;
AUTHZ_ACCESS_REPLY AuthzAccessReply;
AUTHZ_AUDIT_INFO_HANDLE hAuthzAuditInfo = NULL;
PAUDIT_EVENT_INFO pAuditEventInfo = NULL;
wstring wsAccessType;
DWORD dwErr = ERROR_SUCCESS;
ACCESS_MASK amAccessGranted = 0;
WCHAR szIP[20];
//
// Find the correct mailbox
//
Mailbox *pMbx = _mapSidMailbox[psMailbox];
//
// Initialize the auditing info for a Generic object
//
if( FALSE == AuthzInitializeAuditEvent( &pAuditEventInfo,
AUTHZ_INIT_GENERIC_AUDIT_EVENT,
0,
0,
0) )
{
throw (DWORD)ERROR_INTERNAL_ERROR;
}
try {
if( amAccessRequested & ACCESS_MAIL_READ )
{
wsAccessType.append(L"Read ");
}
if( amAccessRequested & ACCESS_MAIL_WRITE )
{
wsAccessType.append(L"Write ");
}
if( amAccessRequested & ACCESS_MAIL_ADMIN )
{
wsAccessType.append(L"Administer");
}
}
catch(...)
{
throw (DWORD)ERROR_INTERNAL_ERROR;
}
wsprintf(szIP, L"IP: %d.%d.%d.%d", (dwIncomingIp >> 24) & 0x000000FF,
(dwIncomingIp >> 16) & 0x000000FF,
(dwIncomingIp >> 8 ) & 0x000000FF,
(dwIncomingIp ) & 0x000000FF );
if( NULL == AuthzInitializeAuditInfo(
&hAuthzAuditInfo,
0,
pAuditEventInfo,
NULL,
INFINITE,
wsAccessType.c_str(),
L"Mailbox",
pMbx->GetOwnerName(),
szIP) )
{
AuthzFreeAuditEvent(pAuditEventInfo);
throw (DWORD)ERROR_INTERNAL_ERROR;
}
//
// The audit event info is only needed for the above call, we can
// deallocate it immediately after
//
AuthzFreeAuditEvent(pAuditEventInfo);
//
// Set up the Authz access request
//
AuthzAccessRequest.DesiredAccess = amAccessRequested;
AuthzAccessRequest.ObjectTypeList = NULL;
AuthzAccessRequest.ObjectTypeListLength = 0;
AuthzAccessRequest.OptionalArguments = pMbx;
//
// The PrincipalSelf SID is the SID of the mailbox owner
// This way, the PRINCIPAL_SELF_SID allow ACE grants access
// only to the owner. PrincipalSelfSid in the ACE will be replaced
// by this value for access check purposes. The owner of this mailbox
// will have the same SID in his context. Therefore, the two SIDs will
// match if there is a PrincipalSelfSid ACE in the ACL.
//
AuthzAccessRequest.PrincipalSelfSid = pMbx->GetOwnerSid();
//
// Prepare the reply structure
//
AuthzAccessReply.Error = &dwErr;
AuthzAccessReply.GrantedAccessMask = &amAccessGranted;
AuthzAccessReply.ResultListLength = 1;
//
// Create or retrieve the client context
//
if( _mapSidContext.find(pair<PSID, DWORD>(psUser, dwIncomingIp))
== _mapSidContext.end())
{
//
// No context available, initialize
//
LUID lIdentifier = {0L, 0L};
//
// Since we are using SIDs which are not generated by NT,
// it would be pointless to resolve group memberships, since
// the SIDs will not be recognized by any machine in the domain,
// and none of our ACLs use actual NT account SIDs. Therefore,
// we use the SKIP_LOCAL_GROUPS and SKIP_TOKEN_GROUPS flags,
// the LOCAL prevents a check for groups on the local machine,
// and TOKEN prevents a search on the domain
//
if( FALSE == AuthzInitializeContextFromSid(
psUser,
NULL,
_hRM,
NULL,
lIdentifier,
AUTHZ_SKIP_LOCAL_GROUPS | AUTHZ_SKIP_TOKEN_GROUPS,
&dwIncomingIp,
&hAuthzClient) )
{
AuthzFreeAuditInfo(hAuthzAuditInfo, _hRM);
throw (DWORD)ERROR_INTERNAL_ERROR;
}
_mapSidContext[pair<PSID, DWORD>(psUser, dwIncomingIp)] =
hAuthzClient;
}
else
{
//
// Use existing context
//
hAuthzClient = _mapSidContext[pair<PSID, DWORD>(psUser, dwIncomingIp)];
}
BOOL bTmp;
//
// Perform the access check
//
bTmp = AuthzAccessCheck(
hAuthzClient,
&AuthzAccessRequest,
hAuthzAuditInfo,
&_sd,
NULL,
0,
&AuthzAccessReply,
NULL
);
AuthzFreeAuditInfo(hAuthzAuditInfo, _hRM);
//
// Determine whether to grant access
// On AccessCheck error, deny access
//
if( dwErr == ERROR_SUCCESS && bTmp != FALSE)
{
return pMbx;
}
else
{
return NULL;
}
}
BOOL MailRM::GetMultipleMailboxAccess(
IN const PMAILRM_MULTI_REQUEST pRequest,
IN OUT PMAILRM_MULTI_REPLY pReply
)
/*++
Routine Description
This routine performs a set of cached access checks in order to request
access to a set of mailboxes for a single user (for example, mail admin
sending out a message to all users).
No need to audit, since this type of access would be only done by an
administrator, and multiple audits would most likely flood the mailbox.
Something like this would be use, for example, to send out a message
to all users.
The cached access check first assumes all callback deny ACEs which match
SIDs in the user's context apply, and no allow callback ACEs apply.
Therefore, the cached access check may initially deny access when it
should be granted. If a cached access check results
in access denied, a regular access check is performed automatically
by AuthZ. As a result, the cached access check is guaranteed to have
the same results as a normal access check, though it will take
significantly more time if many denies are encountered than if most
access requests succeed.
Arguments
pRequest - Request structure describing the user and the mailboxes
pReply - Reply structure returning mailbox pointers and granted
access masks. If the access check fails, a NULL pointer
is returned for the given mailbox. This is allocated
by the caller, and should have the same number of
elements as the request.
Return Value
TRUE on success
FALSE on failure. If failure, pReply may not be completely filled
--*/
{
AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClient;
AUTHZ_ACCESS_REQUEST AuthzAccessRequest;
AUTHZ_ACCESS_REPLY AuthzAccessReply;
DWORD dwErr = ERROR_SUCCESS;
ACCESS_MASK amAccessGranted = 0;
AUTHZ_HANDLE hAuthzCached;
//
// Set up the Authz access request
// Only the DesiredAccess and PrincipalSelfSid parameters will change
// per mailbox. Initial access check is MAXIMUM_ALLOWED.
//
AuthzAccessRequest.ObjectTypeList = NULL;
AuthzAccessRequest.ObjectTypeListLength = 0;
//
// Initial access check will be caching, therefore optional parameters
// will not be used
//
AuthzAccessRequest.OptionalArguments = NULL;
//
// The PrincipalSelf SID is the SID of the mailbox owner
// This way, the PRINCIPAL_SELF_SID allow ACE grants access
// only to the owner
//
AuthzAccessRequest.PrincipalSelfSid = NULL;
//
// Initially ask for MAXIMUM_ALLOWED access
//
AuthzAccessRequest.DesiredAccess = MAXIMUM_ALLOWED;
//
// Prepare the reply structure
//
AuthzAccessReply.Error = &dwErr;
AuthzAccessReply.GrantedAccessMask = &amAccessGranted;
AuthzAccessReply.ResultListLength = 1;
//
// Create or retrieve the client context
//
if( _mapSidContext.find(
pair<PSID, DWORD>(pRequest->psUser , pRequest->dwIp))
== _mapSidContext.end())
{
//
// No context available, initialize
//
LUID lIdentifier = {0L, 0L};
//
// The SIDs are not real, therefore do not attempt to resolve
// local or domain group memberships for the token
//
AuthzInitializeContextFromSid(
pRequest->psUser,
NULL,
_hRM,
NULL,
lIdentifier,
AUTHZ_SKIP_LOCAL_GROUPS | AUTHZ_SKIP_TOKEN_GROUPS,
&(pRequest->dwIp),
&hAuthzClient);
_mapSidContext[pair<PSID, DWORD>(pRequest->psUser,
pRequest->dwIp)] = hAuthzClient;
}
else
{
//
// Use existing context
//
hAuthzClient = _mapSidContext[pair<PSID, DWORD>(pRequest->psUser,
pRequest->dwIp)];
}
//
// Perform a single AuthZ access check to get the cached handle
//
if( FALSE == AuthzAccessCheck(
hAuthzClient,
&AuthzAccessRequest,
NULL,
&_sd,
NULL,
0,
&AuthzAccessReply,
&hAuthzCached
))
{
return FALSE;
}
//
// Now use the cached access check for all of the access requests
//
DWORD i;
Mailbox * mbx;
for( i = 0; i < pRequest->dwNumElems; i++ )
{
mbx = _mapSidMailbox[pRequest->pRequestElem[i].psMailbox];
AuthzAccessRequest.DesiredAccess =
pRequest->pRequestElem[i].amAccessRequested;
AuthzAccessRequest.PrincipalSelfSid = mbx->GetOwnerSid();
AuthzAccessRequest.OptionalArguments = mbx;
if( FALSE == AuthzCachedAccessCheck(
hAuthzCached,
&AuthzAccessRequest,
NULL,
&AuthzAccessReply
))
{
return FALSE;
}
//
// Access check done, now fill in the access array element
//
if( dwErr == ERROR_SUCCESS )
{
pReply[i].pMailbox = mbx;
pReply[i].amAccessGranted = amAccessGranted;
}
else
{
pReply[i].pMailbox = NULL;
pReply[i].amAccessGranted = 0;
}
}
return TRUE;
}
BOOL CALLBACK MailRM::AccessCheck(
IN AUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext,
IN PACE_HEADER pAce,
IN PVOID pArgs OPTIONAL,
IN OUT PBOOL pbAceApplicable
)
/*++
Routine Description
This is the Authz callback access check for the mail resource manager.
It determines whether the given callback ACE applies based on whether
the mailbox contains sensitive information and the current time.
Arguments
pAuthzClientContext - the AuthZ client context of the user accessing
the mailbox, with dynamic groups already
computed
pAce - Pointer to the start of the callback ACE
The optional ACE data is in the last 4
bytes of the ACE
pArgs - The optional argument passed to the
AuthzAccessCheck, pointer to the Mailbox
being accessed
pbAceApplicable - Set to TRUE iff the ACE should be used in the
access check.
Return Value
TRUE on success
FALSE on failure
--*/
{
BOOL bTimeApplies;
BOOL bSensitiveApplies;
//
// If pArgs are not present, ACE is never applicable
//
if( pArgs == NULL )
{
*pbAceApplicable = FALSE;
return TRUE;
}
//
// Offset of the optional data, last 4 bytes of the callback ACE
//
PMAILRM_OPTIONAL_DATA pOptData = (PMAILRM_OPTIONAL_DATA) (
(PBYTE)pAce
+ pAce->AceSize
- sizeof(MAILRM_OPTIONAL_DATA));
//
// Get current time and check if the ACE time restriction applies
//
time_t tTime;
struct tm * tStruct;
time(&tTime);
tStruct = localtime(&tTime);
if( WITHIN_TIMERANGE(tStruct->tm_hour,
pOptData->bStartHour,
pOptData->bEndHour) )
{
bTimeApplies = TRUE;
}
else
{
bTimeApplies = FALSE;
}
//
// Check whether the mailbox is sensitive and the ACE applies to sensitive
// mailboxes
//
if( ((Mailbox *)pArgs)->IsSensitive()
&& pOptData->bIsSensitive == MAILRM_SENSITIVE )
{
bSensitiveApplies = TRUE;
}
else
{
bSensitiveApplies = FALSE;
}
//
// Make the final decision based on whether the optional argument
// calls for an AND or OR condition
//
if( pOptData->bLogicType == MAILRM_USE_AND )
{
*pbAceApplicable = bSensitiveApplies && bTimeApplies;
}
else
{
*pbAceApplicable = bSensitiveApplies || bTimeApplies;
}
//
// AccessCheck succeeded
//
return TRUE;
}
BOOL CALLBACK MailRM::ComputeDynamicGroups(
IN AUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext,
IN PVOID Args,
OUT PSID_AND_ATTRIBUTES *pSidAttrArray,
OUT PDWORD pSidCount,
OUT PSID_AND_ATTRIBUTES *pRestrictedSidAttrArray,
OUT PDWORD pRestrictedSidCount
)
/*++
Routine Description
This is the Authz callback which computes additional dynamic groups
for the user context.
If the user is originating at an IP address outside the company lan
(company lan assumed to be 192.*), the InsecureSid SID is added
to the client's context, signifying that the connection is not
secure. This enables callback ACEs which prohibit sensitive
information from being sent over insecure connections.
Arguments
pAuthzClientContext - the AuthZ client context of the user
pArgs - The optional argument passed to the
AuthzCreateContext, pointer to a DWORD
containing the user's IP address
pSidAttrArray * - The additional SIDs, if any are assigned,
are returned here.
pSidCount - Number of entries in pSidAttrArray
pRestrictedSidAttrArray * - The additional restricted SIDs, if any
are assigned, are returned here.
pRestrictedSidCount - Number of entries in pSidAttrArray
Return Value
TRUE on success
FALSE on failure
--*/
{
//
// No restrict-only groups used
//
*pRestrictedSidCount = 0;
*pRestrictedSidAttrArray = NULL;
//
// Internal company network (secure) is 192.*, anything else is insecure
//
if( *( (DWORD *) Args) >= 0xC0000000 && *( (DWORD *) Args) < 0xC1000000 )
{
//
// Secure, within the company IP range, no restricted groups
//
*pSidCount = 0;
*pSidAttrArray = NULL;
}
else
{
//
// Insecure external connection, add the Insecure group SID
//
*pSidCount = 1;
*pSidAttrArray =
(PSID_AND_ATTRIBUTES)malloc( sizeof(SID_AND_ATTRIBUTES) );
if( pSidAttrArray == NULL )
{
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
(*pSidAttrArray)[0].Attributes = SE_GROUP_ENABLED;
(*pSidAttrArray)[0].Sid = InsecureSid;
}
return TRUE;
}
VOID CALLBACK MailRM::FreeDynamicGroups (
IN PSID_AND_ATTRIBUTES pSidAttrArray
)
/*++
Routine Description
This routine frees any memory allocated by ComputeDynamicGroups
Arguments
pSidAttrArray - Pointer to the memory to be freed
Return Value
None
--*/
{
free(pSidAttrArray);
}
bool CompareSidStruct::operator()(const PSID pSid1, const PSID pSid2) const
/*++
Routine Description
This is a less-than function which places a complete ordering on
a set of PSIDs by value, NULL PSIDs are valid. This is used by the
STL map.
Since the number of subauthorities appears before the subauthorities
themselves, that difference will be noticed for two SIDs of different
size before the memcmp tries to access the nonexistant subauthority
in the shorter SID, therefore an access violation will not occur.
Arguments
pSid1 - The first PSID
pSid2 - The second PSID
Return Value
true IFF pSid1 < pSid2
--*/
{
//
// If both are NULL, false should be returned for complete ordering
//
if(pSid2 == NULL)
{
return false;
}
if(pSid1 == NULL)
{
return true;
}
if( memcmp(pSid1, pSid2, GetLengthSid(pSid1)) < 0 )
{
return true;
}
else
{
return false;
}
}
bool CompareSidPairStruct::operator()(const pair<PSID, DWORD > pair1,
const pair<PSID, DWORD > pair2) const
/*++
Routine Description
This is a less-than function which places a complete ordering on
a set of <PSID, DWORD> pairs by value, NULL PSIDs are valid. This
is used by the STL map
Arguments
pair1 - The first pair
pair2 - The second pair
Return Value
true IFF pSid1 < pSid2 OR (pSid1 = pSid2 AND DWORD1 < DWORD2)
--*/
{
CompareSidStruct SidComp;
if( pair1.second < pair2.second )
{
return true;
}
if( pair1.second > pair2.second )
{
return false;
}
return SidComp.operator()(pair1.first, pair2.first);
}