Windows-Server-2003/printscan/faxsrv/service/server/security.c

1535 lines
40 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
security.c
Abstract:
This module provides security for the service.
Author:
Oded Sacher (OdedS) 13-Feb-2000
Revision History:
--*/
#include "faxsvc.h"
#include <aclapi.h>
#define ATLASSERT Assert
#include <smartptr.h>
#pragma hdrstop
//
// defined in ntrtl.h.
// do this to avoid dragging in ntrtl.h since we already include some stuff
// from ntrtl.h
//
extern "C"
NTSYSAPI
BOOLEAN
NTAPI
RtlValidRelativeSecurityDescriptor (
IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
IN ULONG SecurityDescriptorLength,
IN SECURITY_INFORMATION RequiredInformation
);
//
// Global Fax Service Security Descriptor
//
PSECURITY_DESCRIPTOR g_pFaxSD;
CFaxCriticalSection g_CsSecurity;
const GENERIC_MAPPING gc_FaxGenericMapping =
{
(STANDARD_RIGHTS_READ | FAX_GENERIC_READ),
(STANDARD_RIGHTS_WRITE | FAX_GENERIC_WRITE),
(STANDARD_RIGHTS_EXECUTE | FAX_GENERIC_EXECUTE),
(READ_CONTROL | WRITE_DAC | WRITE_OWNER | FAX_GENERIC_ALL)
};
DWORD
FaxSvcAccessCheck(
IN ACCESS_MASK DesiredAccess,
OUT BOOL* lpbAccessStatus,
OUT LPDWORD lpdwGrantedAccess
)
/*++
Routine name : FaxSvcAccessCheck
Routine description:
Performs an access check against the fax service security descriptor
Author:
Oded Sacher (OdedS), Feb, 2000
Arguments:
DesiredAccess [in ] - Desired access
lpbAccessStatus [out ] - Address of a BOOL to receive the access check result (TRUE is access allowed)
lpdwGrantedAccess [out ] - Optional., Address of a DWORD to receive the maximum access allowed. Desired Access should be MAXIMUM_ALLOWED
Return Value:
Standard Win32 error code
--*/
{
DWORD rc;
DWORD GrantedAccess;
DWORD dwRes;
BOOL fGenerateOnClose;
DEBUG_FUNCTION_NAME(TEXT("FaxSvcAccessCheck"));
Assert (lpbAccessStatus);
//
// Impersonate the client.
//
if ((rc = RpcImpersonateClient(NULL)) != RPC_S_OK)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcImpersonateClient() failed. (ec: %ld)"),
rc);
goto exit;
}
EnterCriticalSection( &g_CsSecurity );
//
// purify the access mask - get rid of generic access bits
//
MapGenericMask( &DesiredAccess, const_cast<PGENERIC_MAPPING>(&gc_FaxGenericMapping) );
//
// Check if the client has the required access.
//
if (!AccessCheckAndAuditAlarm(
FAX_SERVICE_NAME, // subsystem name
NULL, // handle to object
NULL, // type of object
NULL, // name of object
g_pFaxSD, // SD
DesiredAccess, // requested access rights
const_cast<PGENERIC_MAPPING>(&gc_FaxGenericMapping), // mapping
FALSE, // creation status
&GrantedAccess, // granted access rights
lpbAccessStatus, // result of access check
&fGenerateOnClose // audit generation option
))
{
rc = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("AccessCheck() failed. (ec: %ld)"),
rc);
LeaveCriticalSection( &g_CsSecurity );
goto exit;
}
if (lpdwGrantedAccess)
{
*lpdwGrantedAccess = GrantedAccess;
}
LeaveCriticalSection( &g_CsSecurity );
Assert (ERROR_SUCCESS == rc);
exit:
dwRes=RpcRevertToSelf();
if (RPC_S_OK != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcRevertToSelf() failed (ec: %ld)"),
dwRes);
Assert(FALSE);
}
return rc;
}
DWORD
SaveSecurityDescriptor(
PSECURITY_DESCRIPTOR pSD
)
/*++
Routine name : SaveSecurityDescriptor
Routine description:
Saves the Fax Service SD to the registry
Author:
Oded Sacher (OdedS), Feb, 2000
Arguments:
pSD [in ] - Pointer to a SD to be saved
Return Value:
DWORD
--*/
{
DWORD rc = ERROR_SUCCESS;
DWORD dwSize;
PSECURITY_DESCRIPTOR pSDSelfRelative = NULL;
HKEY hKey = NULL;
DWORD Disposition;
SECURITY_DESCRIPTOR_CONTROL Control = SE_SELF_RELATIVE;
DWORD dwRevision;
DEBUG_FUNCTION_NAME(TEXT("SaveSecurityDescriptor"));
Assert (pSD);
rc = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
REGKEY_FAX_SECURITY,
0,
TEXT(""),
0,
KEY_WRITE,
NULL,
&hKey,
&Disposition
);
if (rc != ERROR_SUCCESS)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RegCreateKeyEx() failed (ec: %ld)"),
rc);
return rc;
}
if (!IsValidSecurityDescriptor(pSD))
{
rc = ERROR_INVALID_SECURITY_DESCR;
DebugPrintEx(
DEBUG_ERR,
TEXT("IsValidSecurityDescriptor() failed."));
goto exit;
}
//
// Check if the security descriptor is absolute or self relative.
//
if (!GetSecurityDescriptorControl( pSD, &Control, &dwRevision))
{
rc = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("GetSecurityDescriptorControl() failed (ec: %ld)"),
rc);
goto exit;
}
//
// store the security descriptor in the registry
//
dwSize = GetSecurityDescriptorLength( pSD );
if (SE_SELF_RELATIVE & Control)
{
//
// store the security descriptor in the registry use absolute SD
//
rc = RegSetValueEx(
hKey,
REGVAL_DESCRIPTOR,
0,
REG_BINARY,
(LPBYTE) pSD,
dwSize
);
if (ERROR_SUCCESS != rc)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RegSetValueEx() failed (ec: %ld)"),
rc);
goto exit;
}
}
else
{
//
// Convert the absolute SD to self relative
//
pSDSelfRelative = (PSECURITY_DESCRIPTOR) MemAlloc( dwSize );
if (NULL == pSDSelfRelative)
{
rc = ERROR_NOT_ENOUGH_MEMORY;
DebugPrintEx(
DEBUG_ERR,
TEXT("Error Allocating security descriptor"));
goto exit;
}
//
// make the security descriptor self relative
//
if (!MakeSelfRelativeSD( pSD, pSDSelfRelative, &dwSize))
{
rc = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("MakeSelfRelativeSD() failed (ec: %ld)"),
rc);
goto exit;
}
//
// store the security descriptor in the registry use self relative SD
//
rc = RegSetValueEx(
hKey,
REGVAL_DESCRIPTOR,
0,
REG_BINARY,
(LPBYTE) pSDSelfRelative,
dwSize
);
if (ERROR_SUCCESS != rc)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RegSetValueEx() failed (ec: %ld)"),
rc);
goto exit;
}
}
Assert (ERROR_SUCCESS == rc);
exit:
if (NULL != hKey)
{
RegCloseKey (hKey);
}
if (NULL != pSDSelfRelative)
{
MemFree (pSDSelfRelative);
}
return rc;
}
#define FAX_OWNER_SID TEXT("O:NS") // Owner sid : Network Service
#define FAX_GROUP_SID TEXT("G:NS") // Group sid : Network Service
#define FAX_DACL TEXT("D:")
#define FAX_BA_ALLOW_ACE TEXT("(A;;0xe07ff;;;BA)") // Allow Built-in administrators (BA) -
// Access mask : 0xe07ff == FAX_GENERIC_ALL |
// WRITE_OWNER |
// WRITE_DAC |
// READ_CONTROL
#define FAX_WD_ALLOW_ACE TEXT("(A;;0x20003;;;WD)") // Allow Everyone (WD) -
// Access mask : 0x20003 == FAX_ACCESS_SUBMIT |
// FAX_ACCESS_SUBMIT_NORMAL |
// READ_CONTROL
#define FAX_IU_ALLOW_ACE TEXT("(A;;0x202BF;;;IU)") // Allow Interactive users (IU) -
// Access mask : 0x202BF == FAX_ACCESS_SUBMIT |
// FAX_ACCESS_SUBMIT_NORMAL |
// FAX_ACCESS_SUBMIT_HIGH |
// FAX_ACCESS_QUERY_JOBS |
// FAX_ACCESS_MANAGE_JOBS |
// FAX_ACCESS_QUERY_CONFIG |
// FAX_ACCESS_QUERY_OUT_ARCHIVE |
// FAX_ACCESS_QUERY_IN_ARCHIVE |
// READ_CONTROL
#define FAX_DESKTOP_SKU_SD (FAX_OWNER_SID FAX_GROUP_SID FAX_DACL FAX_BA_ALLOW_ACE FAX_WD_ALLOW_ACE FAX_IU_ALLOW_ACE) // SD for per/pro SKU
#define FAX_SERVER_SKU_SD (FAX_OWNER_SID FAX_GROUP_SID FAX_DACL FAX_BA_ALLOW_ACE FAX_WD_ALLOW_ACE) // SD for server SKU
DWORD
CreateDefaultSecurityDescriptor(
VOID
)
/*++
Routine name : CreateDefaultSecurityDescriptor
Routine description:
Creates the default security descriptor
Author:
Oded Sacher (OdedS), Feb, 2000
Caliv Nir (t-nicali) Mar, 2002 - changed to use SDDL, while moving Fax service
to run under "Network service"
Arguments:
None.
Return Value:
Standard Win32 error code.
--*/
{
DWORD dwRet = ERROR_SUCCESS;
BOOL bRet;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
PSECURITY_DESCRIPTOR pPrivateObjectSD = NULL;
ULONG SecurityDescriptorSize = 0;
HANDLE hFaxServiceToken = NULL;
BOOL bDesktopSKU = FALSE;
TCHAR* ptstrSD = NULL;
DEBUG_FUNCTION_NAME(TEXT("CreateDefaultSecurityDescriptor"));
//
// If this is PERSONAL SKU, then add Interactive Users SID
//
bDesktopSKU = IsDesktopSKU();
ptstrSD = bDesktopSKU ? FAX_DESKTOP_SKU_SD : FAX_SERVER_SKU_SD;
bRet = ConvertStringSecurityDescriptorToSecurityDescriptor(
ptstrSD, // security descriptor string
SDDL_REVISION_1, // revision level
&pSecurityDescriptor, // SD
&SecurityDescriptorSize // SD size
);
if(!bRet)
{
dwRet = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("ConvertStringSecurityDescriptorToSecurityDescriptor() failed (ec: %lu)"),
dwRet);
goto exit;
}
//
// Get the Fax Service Token
//
if (!OpenProcessToken( GetCurrentProcess(), // handle to process
TOKEN_QUERY, // desired access to process
&hFaxServiceToken // handle to open access token
))
{
dwRet = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("OpenThreadToken failed. (ec: %ld)"),
dwRet);
goto exit;
}
//
// Create a private object SD
//
if (!CreatePrivateObjectSecurity( NULL, // parent directory SD
pSecurityDescriptor, // creator SD
&pPrivateObjectSD, // new SD
FALSE, // container
hFaxServiceToken, // handle to access token
const_cast<PGENERIC_MAPPING>(&gc_FaxGenericMapping) // mapping
))
{
dwRet = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("CreatePrivateObjectSecurity() failed (ec: %ld)"),
dwRet);
goto exit;
}
//
// store the security descriptor in the registry
//
dwRet = SaveSecurityDescriptor (pPrivateObjectSD);
if (ERROR_SUCCESS != dwRet)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("SaveSecurityDescriptor() failed (ec: %ld)"),
dwRet);
goto exit;
}
//
// All done! Set the global fax service security descriptor
//
g_pFaxSD = pPrivateObjectSD;
pPrivateObjectSD = NULL;
Assert (ERROR_SUCCESS == dwRet);
exit:
if(NULL != pSecurityDescriptor)
{
LocalFree(pSecurityDescriptor);
}
if (NULL != hFaxServiceToken)
{
if (!CloseHandle(hFaxServiceToken))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CloseHandle() failed. (ec: %ld)"),
GetLastError());
}
}
if (NULL != pPrivateObjectSD)
{
//
// in case of failure in creating the SD destroy the private object SD.
//
if (!DestroyPrivateObjectSecurity (&pPrivateObjectSD))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("DestroyPrivateObjectSecurity() failed. (ec: %ld)"),
GetLastError());
}
}
return dwRet;
} // CreateDefaultSecurityDescriptor
DWORD
LoadSecurityDescriptor(
VOID
)
/*++
Routine name : LoadSecurityDescriptor
Routine description:
Loads the Fax Service security descriptor from the registry
Author:
Oded Sacher (OdedS), Feb, 2000
Arguments:
None
Return Value:
Standard Win32 error code
--*/
{
DWORD rc = ERROR_SUCCESS;
DWORD dwSize;
HKEY hKey = NULL;
DWORD Disposition;
DWORD dwType;
PSECURITY_DESCRIPTOR pRelativeSD = NULL;
DEBUG_FUNCTION_NAME(TEXT("LoadSecurityDescriptor"));
rc = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
REGKEY_FAX_SECURITY,
0,
TEXT(""),
0,
KEY_READ,
NULL,
&hKey,
&Disposition
);
if (rc != ERROR_SUCCESS)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RegCreateKeyEx() failed (ec: %ld)"),
rc);
goto exit;
}
rc = RegQueryValueEx(
hKey,
REGVAL_DESCRIPTOR,
NULL,
&dwType,
NULL,
&dwSize
);
if (ERROR_SUCCESS != rc)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RegQueryValueEx failed with %ld"),
rc);
goto exit;
}
//
// We opened an existing registry value
//
if (REG_BINARY != dwType ||
0 == dwSize)
{
//
// We expect only binary data here
//
DebugPrintEx(
DEBUG_ERR,
TEXT("Error reading security descriptor from the registry, not a binary type, or size is 0"));
rc = ERROR_BADDB; // The configuration registry database is corrupt.
goto exit;
}
//
// Allocate required buffer
// The buffer must be allocated using HeapAlloc (GetProcessHeap()...) because this is the way CreatePrivateObjectSecurity() allocates memory
// This is a result of a bad design of private object security APIs, see Windows Bugs #324906.
//
pRelativeSD = (PSECURITY_DESCRIPTOR) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize );
if (!pRelativeSD)
{
rc = ERROR_NOT_ENOUGH_MEMORY;
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to allocate security descriptor buffer"));
goto exit;
}
//
// Read the data
//
rc = RegQueryValueEx(
hKey,
REGVAL_DESCRIPTOR,
NULL,
&dwType,
(LPBYTE)pRelativeSD,
&dwSize
);
if (ERROR_SUCCESS != rc)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RegQueryValueEx failed with %ld"),
rc);
goto exit;
}
if (!IsValidSecurityDescriptor(pRelativeSD))
{
rc = ERROR_INVALID_SECURITY_DESCR;
DebugPrintEx(
DEBUG_ERR,
TEXT("IsValidSecurityDescriptor() failed."));
goto exit;
}
g_pFaxSD = pRelativeSD;
pRelativeSD = NULL;
Assert (ERROR_SUCCESS == rc);
exit:
if (hKey)
{
RegCloseKey( hKey );
}
if (NULL != pRelativeSD)
{
if (!HeapFree(GetProcessHeap(), 0, pRelativeSD))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("pRelativeSD() failed. (ec: %ld)"),
GetLastError());
}
}
return rc;
}
DWORD
InitializeServerSecurity(
VOID
)
/*++
Routine name : InitializeServerSecurity
Routine description:
Initializes the Fax Service security
Author:
Oded Sacher (OdedS), Feb, 2000
Arguments:
None
Return Value:
Standard Win32 error code
--*/
{
DWORD rc = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("InitializeServerSecurity"));
rc = LoadSecurityDescriptor();
if (ERROR_SUCCESS != rc)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("LoadSecurityDescriptor() failed (ec: %ld), Create default security descriptor"),
rc);
}
else
{
//success
return rc;
}
//
// We failed to load the security descriptor
//
if (ERROR_NOT_ENOUGH_MEMORY == rc)
{
//
// Do not let the service start
//
return rc;
}
//
// The registry is corrupted - create the default security descriptor
//
rc = CreateDefaultSecurityDescriptor();
if (ERROR_SUCCESS != rc)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CreateDefaultSecurityDescriptor() failed (ec: %ld)"),
rc);
}
return rc;
}
//*********************************************************************************
//* Name:GetClientUserName()
//* Author: Ronen Barenboim
//* Date: May 02, 1999
//*********************************************************************************
//* DESCRIPTION:
//* Returns the OS User Name of the connected RPC client.
//* PARAMETERS:
//* None.
//* RETURN VALUE:
//* A pointer to a newly allocated string holding the user name.
//* The caller must free this string using MemFree().
//* Returns NULL if an error occures.
//* To get extended error information, call GetLastError.
//*********************************************************************************
LPWSTR
GetClientUserName(
VOID
)
{
RPC_STATUS dwRes;
LPWSTR lpwstrUserName = NULL;
HANDLE hToken = NULL;
PSID pUserSid;
WCHAR szShortUserName[64];
WCHAR szShortDomainName[64];
DWORD dwUserNameLen = sizeof(szShortUserName) / sizeof(WCHAR);
DWORD dwDomainNameLen = sizeof(szShortDomainName) / sizeof(WCHAR);
LPWSTR szUserName = szShortUserName; // first point to short on stack buffers
LPWSTR szDomainName = szShortDomainName;
SID_NAME_USE SidNameUse;
LPWSTR szLongUserName = NULL;
LPWSTR szLongDomainName = NULL;
DEBUG_FUNCTION_NAME(TEXT("GetClientUserName"));
//
// Impersonate the user.
//
dwRes=RpcImpersonateClient(NULL);
if (dwRes != RPC_S_OK)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcImpersonateClient(NULL) failed. (ec: %ld)"),
dwRes);
SetLastError (dwRes);
return NULL;
}
//
// Open the thread token. We're in an RPC thread, not the main thread.
//
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken))
{
dwRes = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("OpenThreadToken failed. (ec: %ld)"),
dwRes);
goto exit;
}
//
// Get the user's SID. A 128 byte long buffer should always suffice since
// a SID length is limited to +/- 80 bytes at most.
//
BYTE abTokenUser[128];
DWORD dwReqSize;
if (!GetTokenInformation(hToken,
TokenUser,
(LPVOID)abTokenUser,
sizeof(abTokenUser),
&dwReqSize))
{
dwRes = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("GetTokenInformation failed. (ec: %ld)"),
dwRes);
goto exit;
}
//
// Get the user name and domain.
//
pUserSid = ((TOKEN_USER *)abTokenUser)->User.Sid;
//
// Try to get account Sid - with small on stack buffers
//
if (!LookupAccountSid(NULL,
pUserSid,
szShortUserName,
&dwUserNameLen,
szShortDomainName,
&dwDomainNameLen,
&SidNameUse))
{
dwRes = GetLastError();
if (dwRes == ERROR_INSUFFICIENT_BUFFER)
{
//
// At least one of buffer were too small.
//
if (dwUserNameLen > sizeof(szShortUserName) / sizeof(WCHAR))
{
//
// Allocate a buffer for the user name.
//
szLongUserName = new (std::nothrow) WCHAR[dwUserNameLen];
if (!szLongUserName)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to allocate user name buffer (%d bytes)"),
dwUserNameLen);
dwRes = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
//
// Update szUserName to point to longer buffers
//
szUserName = szLongUserName;
}
if (dwDomainNameLen > sizeof(szShortDomainName) / sizeof(WCHAR))
{
//
// Allocate a buffer for the domain name.
//
szLongDomainName = new (std::nothrow) WCHAR[dwDomainNameLen];
if (!szLongDomainName)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to allocate domain name buffer (%d bytes)"),
dwDomainNameLen);
dwRes = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
//
// Update szDomainName to point to longer buffers
//
szDomainName = szLongDomainName;
}
}
else
{
DebugPrintEx(
DEBUG_ERR,
TEXT("LookupAccountSid(1) failed. (ec: %ld)"),
dwRes);
goto exit;
}
//
// Try now with larger buffers.
//
if (!LookupAccountSid(NULL,
pUserSid,
szUserName,
&dwUserNameLen,
szDomainName,
&dwDomainNameLen,
&SidNameUse))
{
dwRes = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("LookupAccountSid(2) failed. (ec: %ld)"),
dwRes);
goto exit;
}
}
//
// Allocate a buffer for the combined string - domain\user
//
dwUserNameLen = wcslen(szUserName);
dwDomainNameLen = wcslen(szDomainName);
lpwstrUserName = (LPWSTR)MemAlloc(sizeof(WCHAR) * (dwUserNameLen + dwDomainNameLen + 2));
if (!lpwstrUserName)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to allocate user and domain name buffer (%d bytes)"),
sizeof(WCHAR) * (dwUserNameLen + dwDomainNameLen + 2));
dwRes = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
//
// Construct the combined string
//
memcpy(lpwstrUserName,
szDomainName,
sizeof(WCHAR) * dwDomainNameLen);
lpwstrUserName[dwDomainNameLen] = L'\\';
memcpy(lpwstrUserName + dwDomainNameLen + 1,
szUserName,
sizeof(WCHAR) * (dwUserNameLen + 1));
exit:
DWORD dwErr = RpcRevertToSelf();
if (RPC_S_OK != dwErr)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcRevertToSelf() failed. (ec: %ld)"),
dwRes);
Assert(dwErr == RPC_S_OK); // Assert(FALSE)
}
if (NULL != szLongUserName)
{
delete[] szLongUserName;
}
if (NULL != szLongDomainName)
{
delete[] szLongDomainName;
}
if (hToken)
{
CloseHandle(hToken);
}
if (dwRes != ERROR_SUCCESS)
{
Assert (NULL == lpwstrUserName);
SetLastError (dwRes);
}
return lpwstrUserName;
}
error_status_t
FAX_SetSecurity (
IN handle_t hFaxHandle,
IN SECURITY_INFORMATION SecurityInformation,
IN const LPBYTE lpBuffer,
IN DWORD dwBufferSize
)
/*++
Routine name : FAX_SetSecurity
Routine description:
RPC implementation of FaxSetSecurity
Author:
Eran Yariv (EranY), Nov, 1999
Arguments:
hFaxHandle [in] - Unused
SecurityInformation [in] - Defines the valid entries in the security descriptor (Bit wise OR )
lpBuffer [in] - Pointer to new security descriptor
dwBufferSize [in] - Buffer size
Return Value:
Standard RPC error codes
--*/
{
DWORD rVal = ERROR_SUCCESS;
DWORD rVal2;
BOOL fAccess;
ACCESS_MASK AccessMask = 0;
HANDLE hClientToken = NULL;
DEBUG_FUNCTION_NAME(TEXT("FAX_SetSecurity"));
Assert (g_pFaxSD);
Assert (IsValidSecurityDescriptor(g_pFaxSD));
if (!lpBuffer || !dwBufferSize)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("'Error Null buffer"));
return ERROR_INVALID_PARAMETER;
}
//
// Must validate the RPC blob before calling IsValidSecurityDescriptor();
//
if (!RtlValidRelativeSecurityDescriptor( (PSECURITY_DESCRIPTOR)lpBuffer,
dwBufferSize,
SecurityInformation))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RtlValidRelativeSecurityDescriptor failed"));
return ERROR_INVALID_DATA;
}
//
// Access check
//
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
{
AccessMask |= WRITE_OWNER;
}
if (SecurityInformation & (GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION) )
{
AccessMask |= WRITE_DAC;
}
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
AccessMask |= ACCESS_SYSTEM_SECURITY;
}
//
// Block other threads from changing the SD
//
EnterCriticalSection (&g_CsSecurity);
rVal = FaxSvcAccessCheck (AccessMask, &fAccess, NULL);
if (ERROR_SUCCESS != rVal)
{
DebugPrintEx(DEBUG_ERR,
TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
rVal);
goto exit;
}
if (FALSE == fAccess)
{
DebugPrintEx(DEBUG_ERR,
TEXT("The user does not have the needed rights to change the security descriptor"));
rVal = ERROR_ACCESS_DENIED;
goto exit;
}
//
// Get the calling client access token
//
// Impersonate the user.
//
rVal = RpcImpersonateClient(NULL);
if (rVal != RPC_S_OK)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcImpersonateClient(NULL) failed. (ec: %ld)"),
rVal);
goto exit;
}
//
// Open the thread token. We're in an RPC thread, not the main thread.
//
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hClientToken))
{
rVal = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("OpenThreadToken failed. (ec: %ld)"),
rVal);
DWORD dwErr = RpcRevertToSelf();
if (RPC_S_OK != dwErr)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcRevertToSelf() failed. (ec: %ld)"),
dwErr);
}
goto exit;
}
//
// The calling process (SetPrivateObjectSecurity()) must not impersonate the client
//
rVal = RpcRevertToSelf();
if (RPC_S_OK != rVal)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcRevertToSelf() failed. (ec: %ld)"),
rVal);
goto exit;
}
//
// Get a new (Mereged) Fax service private object SD
//
if (!SetPrivateObjectSecurity ( SecurityInformation,
(PSECURITY_DESCRIPTOR)lpBuffer,
&g_pFaxSD,
const_cast<PGENERIC_MAPPING>(&gc_FaxGenericMapping),
hClientToken))
{
rVal = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("SetPrivateObjectSecurity failed. (ec: %ld)"),
rVal);
goto exit;
}
Assert (IsValidSecurityDescriptor(g_pFaxSD));
//
// Save the new SD
//
rVal = SaveSecurityDescriptor(g_pFaxSD);
if (rVal != ERROR_SUCCESS)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Error in SaveSecurityDescriptor (%ld)"),
rVal);
rVal = ERROR_REGISTRY_CORRUPT;
goto exit;
}
rVal2 = CreateConfigEvent (FAX_CONFIG_TYPE_SECURITY);
if (ERROR_SUCCESS != rVal2)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_SECURITY) (ec: %lc)"),
rVal2);
}
Assert (ERROR_SUCCESS == rVal);
exit:
LeaveCriticalSection (&g_CsSecurity);
if (NULL != hClientToken)
{
if (!CloseHandle(hClientToken))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CloseHandle() failed. (ec: %ld)"),
GetLastError());
}
}
return GetServerErrorCode(rVal);
UNREFERENCED_PARAMETER (hFaxHandle);
} // FAX_SetSecurity
error_status_t
FAX_GetSecurityEx(
IN handle_t hFaxHandle,
IN SECURITY_INFORMATION SecurityInformation,
OUT LPBYTE *lpBuffer,
OUT LPDWORD lpdwBufferSize
)
/*++
Routine Description:
Retrieves the FAX security descriptor from the FAX server.
Arguments:
hFaxHandle - FAX handle obtained from FaxConnectFaxServer.
SecurityInformation - Defines the desired entries in the security descriptor (Bit wise OR )
lpBuffer - Pointer to a SECURITY_DESCRIPTOR structure.
lpdwBufferSize - Size of lpBuffer
Return Value:
TRUE - Success
FALSE - Failure, call GetLastError() for more error information.
--*/
{
error_status_t rVal = ERROR_SUCCESS;
DWORD dwDescLength = 0;
DEBUG_FUNCTION_NAME(TEXT("FAX_GetSecurityEx"));
BOOL fAccess;
ACCESS_MASK AccessMask = 0;
PSECURITY_DESCRIPTOR pSDPrivateObject = NULL;
Assert (g_pFaxSD);
Assert (IsValidSecurityDescriptor(g_pFaxSD));
Assert (lpdwBufferSize); // ref pointer in idl
if (!lpBuffer) // unique pointer in idl
{
return ERROR_INVALID_PARAMETER;
}
*lpBuffer = NULL;
*lpdwBufferSize = 0;
//
// Block other threads from changing the SD
//
EnterCriticalSection (&g_CsSecurity);
//
// Access check
//
if (SecurityInformation & (GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION |
OWNER_SECURITY_INFORMATION) )
{
AccessMask |= READ_CONTROL;
}
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
AccessMask |= ACCESS_SYSTEM_SECURITY;
}
rVal = FaxSvcAccessCheck (AccessMask, &fAccess, NULL);
if (ERROR_SUCCESS != rVal)
{
DebugPrintEx(DEBUG_ERR,
TEXT("FaxSvcAccessCheck Failed, Error : %ld"),
rVal);
goto exit;
}
if (FALSE == fAccess)
{
DebugPrintEx(DEBUG_ERR,
TEXT("The user does not have the READ_CONTROL or ACCESS_SYSTEM_SECURITY"));
rVal = ERROR_ACCESS_DENIED;;
goto exit;
}
if (!IsValidSecurityDescriptor( g_pFaxSD ))
{
rVal = ERROR_INVALID_SECURITY_DESCR;
DebugPrintEx(
DEBUG_ERR,
TEXT("IsValidSecurityDescriptor() failed. Got invalid SD"));
ASSERT_FALSE;
goto exit;
}
//
// Get the required buffer size
//
GetPrivateObjectSecurity( g_pFaxSD, // SD
SecurityInformation, // requested info type
NULL, // requested SD info
0, // size of SD buffer
&dwDescLength // required buffer size
);
//
// Allocate returned security descriptor buffer
//
Assert(dwDescLength);
*lpBuffer = (LPBYTE)MemAlloc(dwDescLength);
if (NULL == *lpBuffer)
{
rVal = ERROR_NOT_ENOUGH_MEMORY;
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to allocate SD"));
goto exit;
}
if (!GetPrivateObjectSecurity( g_pFaxSD, // SD
SecurityInformation, // requested info type
(PSECURITY_DESCRIPTOR)*lpBuffer, // requested SD info
dwDescLength, // size of SD buffer
&dwDescLength // required buffer size
))
{
rVal = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("GetPrivateObjectSecurity() failed. (ec: %ld)"),
rVal);
goto exit;
}
*lpdwBufferSize = dwDescLength;
Assert (ERROR_SUCCESS == rVal);
exit:
LeaveCriticalSection (&g_CsSecurity);
if (ERROR_SUCCESS != rVal)
{
MemFree (*lpBuffer);
*lpBuffer = NULL;
*lpdwBufferSize = 0;
}
return GetServerErrorCode(rVal);
UNREFERENCED_PARAMETER (hFaxHandle);
} // FAX_GetSecurityEx
error_status_t
FAX_GetSecurity(
IN handle_t hFaxHandle,
OUT LPBYTE *lpBuffer,
OUT LPDWORD lpdwBufferSize
)
/*++
Routine Description:
Retrieves the FAX security descriptor from the FAX server.
Arguments:
hFaxHandle - FAX handle obtained from FaxConnectFaxServer.
lpBuffer - Pointer to a SECURITY_DESCRIPTOR structure.
lpdwBufferSize - Size of lpBuffer
Return Value:
TRUE - Success
FALSE - Failure, call GetLastError() for more error information.
--*/
{
error_status_t rVal = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("FAX_GetSecurity"));
rVal = FAX_GetSecurityEx (hFaxHandle,
DACL_SECURITY_INFORMATION | // Read DACL
GROUP_SECURITY_INFORMATION | // Read group
OWNER_SECURITY_INFORMATION | // Read owner
SACL_SECURITY_INFORMATION, // Read SACL
lpBuffer,
lpdwBufferSize);
if (ERROR_ACCESS_DENIED == rVal)
{
//
// Let's try without the SACL
//
rVal = FAX_GetSecurityEx (hFaxHandle,
DACL_SECURITY_INFORMATION | // Read DACL
GROUP_SECURITY_INFORMATION | // Read group
OWNER_SECURITY_INFORMATION, // Read owner
lpBuffer,
lpdwBufferSize);
}
return rVal;
} // FAX_GetSecurity
error_status_t
FAX_AccessCheck(
IN handle_t hBinding,
IN DWORD dwAccessMask,
OUT BOOL* pfAccess,
OUT LPDWORD lpdwRights
)
/*++
Routine name : FAX_AccessCheck
Routine description:
Performs an access check against the fax service security descriptor
Author:
Oded Sacher (OdedS), Feb, 2000
Arguments:
hBinding [in ] - Handle to the Fax Server obtained from FaxConnectFaxServer()
dwAccessMask [in ] - Desired access
pfAccess [out] - Address of a BOOL to receive the access check return value (TRUE - access allowed).
lpdwRights [out] - Optional, Address of a DWORD to receive the access rights bit wise OR.
To get the access rights, set dwAccessMask to MAXIMUM_ALLOWED
Return Value:
Standard Win32 error code.
--*/
{
error_status_t Rval = ERROR_SUCCESS;
DEBUG_FUNCTION_NAME(TEXT("FAX_AccessCheck"));
if (!pfAccess)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("fAccess is NULL "));
return ERROR_INVALID_PARAMETER;
}
Rval = FaxSvcAccessCheck (dwAccessMask, pfAccess, lpdwRights);
if (ERROR_SUCCESS != Rval)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("FaxSvcAccessCheck failed with error (%ld)"),
Rval);
}
return GetServerErrorCode(Rval);
} // FAX_AccessCheck
//*********************************************************************************
//* Name:GetClientUserSID()
//* Author: Oded Sacher
//* Date: Oct 26, 1999
//*********************************************************************************
//* DESCRIPTION:
//* Returns the SID of the connected RPC client.
//* PARAMETERS:
//* None.
//* RETURN VALUE:
//* A pointer to a newly allocated SID buffer.
//* The caller must free this buffer using MemFree().
//* Returns NULL if an error occures.
//* To get extended error information, call GetLastError.
//*********************************************************************************
PSID
GetClientUserSID(
VOID
)
{
RPC_STATUS dwRes;
PSID pUserSid;
DEBUG_FUNCTION_NAME(TEXT("GetClientUserSID"));
//
// Impersonate the user.
//
dwRes=RpcImpersonateClient(NULL);
if (dwRes != RPC_S_OK)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcImpersonateClient(NULL) failed. (ec: %ld)"),
dwRes);
SetLastError( dwRes);
return NULL;
}
//
// Get SID of (impersonated) thread
//
pUserSid = GetCurrentThreadSID ();
if (!pUserSid)
{
dwRes = GetLastError ();
DebugPrintEx(
DEBUG_ERR,
TEXT("GetCurrentThreadSID failed. (ec: %ld)"),
dwRes);
}
dwRes = RpcRevertToSelf();
if (RPC_S_OK != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("RpcRevertToSelf() failed. (ec: %ld)"),
dwRes);
ASSERT_FALSE;
//
// Free SID (if exists)
MemFree (pUserSid);
SetLastError (dwRes);
return NULL;
}
return pUserSid;
}