/*++ 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 #define ATLASSERT Assert #include #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(&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(&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(&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(&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; }