|
|
/*++ BUILD Version: 0000 // Increment this if a change has global effects
Copyright (c) 2000 - 2002 Microsoft Corporation
Module Name:
dspub.cpp
Abstract:
Src module for tapi server DS publishing
Author:
Xiaohai Zhang (xzhang) 10-March-2000
Revision History:
--*/ #include "windows.h"
#include "objbase.h"
#include "winbase.h"
#include "sddl.h"
#include "iads.h"
#include "activeds.h"
#include "tapi.h"
#include "tspi.h"
#include "utils.h"
#include "client.h"
#include "server.h"
#include "private.h"
#include "tchar.h"
#define SECURITY_WIN32
#include "sspi.h"
#include "secext.h"
#include "psapi.h"
extern "C" {
extern const TCHAR gszRegKeyTelephony[]; extern DWORD gdwTapiSCPTTL; extern const TCHAR gszRegTapisrvSCPGuid[];
}
const TCHAR gszTapisrvBindingInfo[] = TEXT("E{\\pipe\\tapsrv}P{ncacn_np}C{%s}A{%s}S{%s}TTL{%s}");
const TCHAR gszVenderMS[] = TEXT("Microsoft"); const TCHAR gszMSGuid[] = TEXT("937924B8-AA44-11d2-81F1-00C04FB9624E");
const WCHAR gwszTapisrvRDN[] = L"CN=Telephony Service"; const TCHAR gszTapisrvProdName[] = TEXT("Telephony Service"); // gszTapisrvGuid needs to be consistant with remotesp\dslookup.cpp
const TCHAR gszTapisrvGuid[] = TEXT("B1A37774-E3F7-488E-ADBFD4DB8A4AB2E5"); const TCHAR gwszProxyRDN[] = L"cn=TAPI Proxy Server"; const TCHAR gszProxyProdName[] = TEXT("TAPI Proxy Server"); const TCHAR gszProxyGuid[] = TEXT("A2657445-3E27-400B-851A-456C41666E37"); const TCHAR gszRegProxySCPGuid[] = TEXT("PROXYSCPGUID");
typedef struct _PROXY_SCP_ENTRY { // A valid CLSID requires 38 chars
TCHAR szClsid[40];
// A binding GUID is of format
// LDAP://<GUID={B1A37774-E3F7-488E-ADBFD4DB8A4AB2E5}>
// required size is 38+14=52 chars
TCHAR szObjGuid[56];
// Ref count for this entry
DWORD dwRefCount; } PROXY_SCP_ENTRY, *PPROXY_SCP_ENTRY;
typedef struct _PROXY_SCPS { DWORD dwTotalEntries; DWORD dwUsedEntries; PROXY_SCP_ENTRY * aEntries; } PROXY_SCPS, *PPROXY_SCPS;
PROXY_SCPS gProxyScps;
#define MAX_SD 2048
//
// GetTokenUser
//
// Based on hAccessToken, call GetTokenInformation
// to retrieve TokenUser info
//
HRESULT GetTokenUser (HANDLE hAccessToken, PTOKEN_USER * ppUser) { HRESULT hr = S_OK; DWORD dwInfoSize = 0; PTOKEN_USER ptuUser = NULL; DWORD ntsResult;
if (!GetTokenInformation( hAccessToken, TokenUser, NULL, 0, &dwInfoSize )) { ntsResult = GetLastError(); if (ntsResult != ERROR_INSUFFICIENT_BUFFER) { hr = HRESULT_FROM_WIN32 (ntsResult); goto ExitHere; } } ptuUser = (PTOKEN_USER) ServerAlloc (dwInfoSize); if (ptuUser == NULL) { hr = LINEERR_NOMEM; goto ExitHere; } if (!GetTokenInformation( hAccessToken, TokenUser, ptuUser, dwInfoSize, &dwInfoSize )) { ServerFree (ptuUser); hr = HRESULT_FROM_WIN32 (GetLastError()); goto ExitHere; }
*ppUser = ptuUser;
ExitHere: return hr; }
//
// IsLocalSystem
//
// This function makes the determination if the given process token
// is running as LocalSystem or LocalService or NetworkService
// Returns S_OK if it is, S_FALSE if it is not LocalSystem.
//
HRESULT IsLocalSystem(HANDLE hAccessToken) { HRESULT hr = S_OK; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID pLocalSid = NULL; PSID pLocalServiceSid = NULL; PSID pNetworkServiceSid = NULL; PTOKEN_USER ptuUser = NULL;
hr = GetTokenUser (hAccessToken, &ptuUser); if (FAILED(hr)) { goto ExitHere; }
if (!AllocateAndInitializeSid ( &NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pLocalSid) || !AllocateAndInitializeSid ( &NtAuthority, 1, SECURITY_LOCAL_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &pLocalServiceSid) || !AllocateAndInitializeSid ( &NtAuthority, 1, SECURITY_NETWORK_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &pNetworkServiceSid) ) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; }
if (!EqualSid(pLocalSid, ptuUser->User.Sid) && !EqualSid(pLocalServiceSid, ptuUser->User.Sid) && !EqualSid(pNetworkServiceSid, ptuUser->User.Sid)) { hr = S_FALSE; }
ExitHere:
if (NULL != ptuUser) { ServerFree (ptuUser); }
if (NULL != pLocalSid) { FreeSid(pLocalSid); } if (NULL != pLocalServiceSid) { FreeSid (pLocalServiceSid); } if (NULL != pNetworkServiceSid) { FreeSid (pNetworkServiceSid); }
return hr; }
//
// IsCurrentLocalSystem
//
// IsCurrentLocalSystem checks to see if current thread/process
// runs in LocalSystem account
//
HRESULT IsCurrentLocalSystem () { HRESULT hr = S_OK; HANDLE hToken = NULL;
if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)) { if(!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } }
hr = IsLocalSystem (hToken); CloseHandle (hToken);
ExitHere: return hr; }
HRESULT SetPrivilege( HANDLE hToken, // token handle
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
) { HRESULT hr = S_OK; TOKEN_PRIVILEGES tp; LUID luid; TOKEN_PRIVILEGES tpPrevious; DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES); DWORD dwErr;
if(!LookupPrivilegeValue( NULL, Privilege, &luid )) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; }
//
// first pass. get current privilege setting
//
tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious ); dwErr = GetLastError (); if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32 (dwErr); goto ExitHere; }
//
// second pass. set privilege based on previous setting
//
tpPrevious.PrivilegeCount = 1; tpPrevious.Privileges[0].Luid = luid;
if(bEnablePrivilege) { tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); } else { tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); }
AdjustTokenPrivileges( hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL ); dwErr = GetLastError (); if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32 (dwErr); goto ExitHere; }
ExitHere: return hr; }
HRESULT SetCurrentPrivilege ( LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
) { HRESULT hr = S_OK; HANDLE hToken = NULL;
if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken)) { if(!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } }
hr = SetPrivilege(hToken, Privilege, bEnablePrivilege);
ExitHere: if (hToken) { CloseHandle(hToken); } return hr; }
//
// SetSidOnAcl
//
BOOL SetSidOnAcl( PSID pSid, PACL pAclSource, PACL *pAclDestination, DWORD AccessMask, BYTE AceFlags, BOOL bAddSid ) { HRESULT hr = S_OK; ACL_SIZE_INFORMATION AclInfo; DWORD dwNewAclSize, dwErr; LPVOID pAce; DWORD AceCounter;
//
// If we were given a NULL Acl, just provide a NULL Acl
//
*pAclDestination = NULL; if(pAclSource == NULL || !IsValidSid(pSid)) { hr = E_INVALIDARG; goto ExitHere; }
if(!GetAclInformation( pAclSource, &AclInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation )) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; }
//
// compute size for new Acl, based on addition or subtraction of Ace
//
if(bAddSid) { dwNewAclSize=AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD) ; } else { dwNewAclSize=AclInfo.AclBytesInUse - sizeof(ACCESS_ALLOWED_ACE) - GetLengthSid(pSid) + sizeof(DWORD) ; }
*pAclDestination = (PACL)ServerAlloc(dwNewAclSize);
if(*pAclDestination == NULL) { hr = LINEERR_NOMEM; goto ExitHere; } //
// initialize new Acl
//
if(!InitializeAcl( *pAclDestination, dwNewAclSize, ACL_REVISION )) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; }
//
// if appropriate, add ace representing pSid
//
if(bAddSid) { PACCESS_ALLOWED_ACE pNewAce;
if(!AddAccessAllowedAce( *pAclDestination, ACL_REVISION, AccessMask, pSid )) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; }
//
// get pointer to ace we just added, so we can change the AceFlags
//
if(!GetAce( *pAclDestination, 0, // this is the first ace in the Acl
(void**) &pNewAce )) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; }
pNewAce->Header.AceFlags = AceFlags; }
//
// copy existing aces to new Acl
//
for(AceCounter = 0 ; AceCounter < AclInfo.AceCount ; AceCounter++) { //
// fetch existing ace
//
if(!GetAce(pAclSource, AceCounter, &pAce)) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; } //
// check to see if we are removing the Ace
//
if(!bAddSid) { //
// we only care about ACCESS_ALLOWED aces
//
if((((PACE_HEADER)pAce)->AceType) == ACCESS_ALLOWED_ACE_TYPE) { PSID pTempSid=(PSID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart; //
// if the Sid matches, skip adding this Sid
//
if(EqualSid(pSid, pTempSid)) { continue; } } }
//
// append ace to Acl
//
if(!AddAce( *pAclDestination, ACL_REVISION, MAXDWORD, // maintain Ace order
pAce, ((PACE_HEADER)pAce)->AceSize )) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; } }
ExitHere:
//
// free memory if an error occurred
//
if(hr) { if(*pAclDestination != NULL) { ServerFree(*pAclDestination); } }
return hr; }
//
// AddSIDToKernelObject()
//
// This function takes a given SID and dwAccess and adds it to a given token.
//
// ** Be sure to restore old kernel object
// ** using call to GetKernelObjectSecurity()
//
HRESULT AddSIDToKernelObjectDacl( PSID pSid, DWORD dwAccess, HANDLE OriginalToken, PSECURITY_DESCRIPTOR* ppSDOld) { HRESULT hr = S_OK; PSECURITY_DESCRIPTOR pSD = NULL; SECURITY_DESCRIPTOR sdNew; DWORD cbByte = MAX_SD, cbNeeded = 0, dwErr = 0; PACL pOldDacl = NULL, pNewDacl = NULL; BOOL fDaclPresent, fDaclDefaulted, fRet = FALSE; pSD = (PSECURITY_DESCRIPTOR) ServerAlloc(cbByte); if (NULL == pSD) { hr = LINEERR_NOMEM; goto ExitHere; }
if (!InitializeSecurityDescriptor( &sdNew, SECURITY_DESCRIPTOR_REVISION )) { hr = HRESULT_FROM_WIN32 (GetLastError()); goto ExitHere; }
if (!GetKernelObjectSecurity( OriginalToken, DACL_SECURITY_INFORMATION, pSD, cbByte, &cbNeeded )) { dwErr = GetLastError(); if (cbNeeded > MAX_SD && dwErr == ERROR_MORE_DATA) { ServerFree(pSD); pSD = (PSECURITY_DESCRIPTOR) ServerAlloc(cbNeeded); if (NULL == pSD) { hr = LINEERR_NOMEM; goto ExitHere; } if (!GetKernelObjectSecurity( OriginalToken, DACL_SECURITY_INFORMATION, pSD, cbNeeded, &cbNeeded )) { hr = HRESULT_FROM_WIN32 (GetLastError()); goto ExitHere; } dwErr = 0; } if (dwErr != 0) { hr = HRESULT_FROM_WIN32 (dwErr); goto ExitHere; } } if (!GetSecurityDescriptorDacl( pSD, &fDaclPresent, &pOldDacl, &fDaclDefaulted )) { hr = HRESULT_FROM_WIN32 (GetLastError()); goto ExitHere; } hr = SetSidOnAcl( pSid, pOldDacl, &pNewDacl, dwAccess, 0, TRUE ); if (hr) { goto ExitHere; } if (!SetSecurityDescriptorDacl( &sdNew, TRUE, pNewDacl, FALSE )) { hr = HRESULT_FROM_WIN32 (GetLastError()); goto ExitHere; } if (!SetKernelObjectSecurity( OriginalToken, DACL_SECURITY_INFORMATION, &sdNew )) { hr = HRESULT_FROM_WIN32 (GetLastError()); goto ExitHere; } *ppSDOld = pSD;
ExitHere:
if (NULL != pNewDacl) { ServerFree(pNewDacl); }
if (hr) { if (NULL != pSD) { ServerFree(pSD); *ppSDOld = NULL; } } return hr; }
//
// SetTokenDefaultDacl
//
// This function makes pSidUser and LocalSystem account
// have full access in the default DACL of the access token
// this is necessary for CreateThread to succeed without
// an assert in checked build
//
HRESULT SetTokenDefaultDacl(HANDLE hAccessToken, PSID pSidUser) { HRESULT hr = S_OK; SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY; PSID pLocalSid = NULL; TOKEN_DEFAULT_DACL defDACL = {0}; DWORD cbDACL;
if (!AllocateAndInitializeSid( &IDAuthorityNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0,0,0,0,0,0,0, &pLocalSid )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; }
cbDACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid (pLocalSid) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid (pSidUser); defDACL.DefaultDacl = (PACL) ServerAlloc (cbDACL); if (defDACL.DefaultDacl == NULL) { hr = LINEERR_NOMEM; goto ExitHere; } if (!InitializeAcl ( defDACL.DefaultDacl, cbDACL, ACL_REVISION )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } if (!AddAccessAllowedAce ( defDACL.DefaultDacl, ACL_REVISION, GENERIC_ALL, pLocalSid ) || !AddAccessAllowedAce ( defDACL.DefaultDacl, ACL_REVISION, GENERIC_ALL, pSidUser )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } if (!SetTokenInformation ( hAccessToken, TokenDefaultDacl, &defDACL, sizeof(TOKEN_DEFAULT_DACL) )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; }
ExitHere:
if (NULL != pLocalSid) { FreeSid(pLocalSid); }
if (defDACL.DefaultDacl != NULL) { ServerFree (defDACL.DefaultDacl); }
return hr; }
//
// GetLocalSystemToken
//
// This function grabs a process token from a LocalSystem process and uses it
// to impersonate when ncessary
//
HRESULT GetLocalSystemToken(HANDLE* phRet) { HRESULT hr = S_OK;
DWORD rgDefPIDs[128]; DWORD * rgPIDs = rgDefPIDs; DWORD cbPIDs = sizeof(rgDefPIDs), cbNeeded;
DWORD i; HANDLE hProcess = NULL; HANDLE hPToken = NULL, hPDupToken = NULL, hPTokenNew = NULL; HANDLE hToken;
PTOKEN_USER ptuUser = NULL; BOOL fSet = FALSE; PSECURITY_DESCRIPTOR pSD = NULL;
//
// Set up necessary privilege for follow-on security operation
//
if(hr = SetCurrentPrivilege(SE_DEBUG_NAME, TRUE)) { goto ExitHere; } if(hr = SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE)) { goto ExitHere; }
//
// Get the current thread/process token user info
//
if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken)) { if(!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } } hr = GetTokenUser (hToken, &ptuUser); CloseHandle (hToken); if (hr) { goto ExitHere; }
//
// Get the list of process IDs in the system
//
while (1) { if (!EnumProcesses ( rgPIDs, cbPIDs, &cbNeeded )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } // Break out if we have large enough buf
if (cbNeeded < cbPIDs) { break; } // Otherwise, alloc larger buffer
if (rgPIDs != rgDefPIDs) { ServerFree (rgPIDs); } cbPIDs += 256; rgPIDs = (DWORD *)ServerAlloc (cbPIDs); if (rgPIDs == NULL) { hr = LINEERR_NOMEM; goto ExitHere; } }
//
// Walk processes until we find one that's running as
// local system
//
for (i = 1; i < (cbNeeded / sizeof(DWORD)); i++) { hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, rgPIDs[i] ); if (NULL == hProcess) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } if (!OpenProcessToken( hProcess, READ_CONTROL | WRITE_DAC, &hPToken )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; }
//
// We have got the process token, but in general
// we do not have TOKEN_DUPLICATE access. So we
// go ahead and whack the DACL of the object to
// grant us the access right.
// IMPORTANT: need to restore the original SD
//
if (hr = AddSIDToKernelObjectDacl( ptuUser->User.Sid, TOKEN_DUPLICATE, hPToken, &pSD )) { goto ExitHere; } fSet = TRUE; if (!OpenProcessToken( hProcess, TOKEN_DUPLICATE, &hPTokenNew )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } //
// Duplicate the token
//
if (!DuplicateTokenEx( hPTokenNew, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hPDupToken )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; }
if (IsLocalSystem (hPDupToken) == S_OK && SetTokenDefaultDacl ( hPDupToken, ptuUser->User.Sid) == S_OK) { break; }
//
// Loop cleanup
//
if (!SetKernelObjectSecurity( hPToken, DACL_SECURITY_INFORMATION, pSD )) { hr = HRESULT_FROM_WIN32(GetLastError()); goto ExitHere; } fSet = FALSE;
if (hPDupToken) { CloseHandle (hPDupToken); hPDupToken = NULL; } if (hPTokenNew) { CloseHandle (hPTokenNew); hPTokenNew = NULL; } if (pSD != NULL) { ServerFree (pSD); pSD = NULL; } if (hPToken) { CloseHandle (hPToken); hPToken = NULL; } if (hProcess) { CloseHandle (hProcess); hProcess = NULL; } } if (i >= cbNeeded / sizeof(DWORD)) { hr = S_FALSE; }
ExitHere: if (fSet) { if (!SetKernelObjectSecurity( hPToken, DACL_SECURITY_INFORMATION, pSD )) { hr = HRESULT_FROM_WIN32(GetLastError()); } } if (hPTokenNew) { CloseHandle (hPTokenNew); } if (hPToken) { CloseHandle (hPToken); } if (pSD != NULL) { ServerFree (pSD); } if (hProcess) { CloseHandle (hProcess); } if (rgPIDs != rgDefPIDs) { ServerFree (rgPIDs); } if (ptuUser) { ServerFree (ptuUser); }
if (hr) { *phRet = NULL; if (hPDupToken) { CloseHandle (hPDupToken); } } else { *phRet = hPDupToken; } return hr; }
//
// ImpersonateLocalSystem
//
HRESULT ImpersonateLocalSystem () { HRESULT hr = S_OK; HANDLE hTokenLocalSys;
hr = GetLocalSystemToken (&hTokenLocalSys); if (FAILED (hr)) { goto ExitHere; }
if (!ImpersonateLoggedOnUser( hTokenLocalSys )) { hr = HRESULT_FROM_WIN32 (GetLastError ()); goto ExitHere; }
ExitHere: if (hTokenLocalSys) { CloseHandle (hTokenLocalSys); } return hr; }
//
// RevertLocalSystemImp
//
// Revert the LocalSystem account impersonation
//
HRESULT RevertLocalSystemImp () { HRESULT hr;
if (!RevertToSelf()) { hr = HRESULT_FROM_WIN32 (GetLastError ()); } else { hr = S_OK; }
return hr; }
//
// AllowAccessToScpProperties
//
// The ACEs grant read/write access to the computer account
// under which the TAPI service instance will be running
//
HRESULT AllowAccessToScpProperties( IADs *pSCPObject // IADs pointer to the SCP object.
) { HRESULT hr = S_OK;
VARIANT varSD; LPOLESTR szAttribute = L"nTSecurityDescriptor"; DWORD dwLen; IADsSecurityDescriptor *pSD = NULL; IADsAccessControlList *pACL = NULL; IDispatch *pDisp = NULL; IADsAccessControlEntry *pACE1 = NULL; IADsAccessControlEntry *pACE2 = NULL; IDispatch *pDispACE = NULL; long lFlags = 0L;
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY; PSID pSid = NULL; LPOLESTR szTrustee = NULL; SID_IDENTIFIER_AUTHORITY siaAll = SECURITY_WORLD_SID_AUTHORITY; PSID pSidAll = NULL; LPOLESTR szTrusteeAll = NULL;
//
// Give tapi server service logon account full control
//
if(!AllocateAndInitializeSid( &sia, 1, SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &pSid ) || !ConvertSidToStringSidW (pSid, &szTrustee)) { hr = HRESULT_FROM_NT(GetLastError()); goto ExitHere; }
//
// Give everyone read access
//
if(!AllocateAndInitializeSid( &siaAll, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSidAll ) || !ConvertSidToStringSidW (pSidAll, &szTrusteeAll)) { hr = HRESULT_FROM_NT(GetLastError()); goto ExitHere; }
//
// Now get the nTSecurityDescriptor
//
VariantClear(&varSD); hr = pSCPObject->Get(szAttribute, &varSD); if (FAILED(hr) || (varSD.vt!=VT_DISPATCH)) { LOG((TL_ERROR, "Get nTSecurityDescriptor failed: 0x%x\n", hr)); goto ExitHere; }
//
// Use the V_DISPATCH macro to get the IDispatch pointer from VARIANT
// structure and QueryInterface for an IADsSecurityDescriptor pointer.
//
hr = V_DISPATCH( &varSD )->QueryInterface( IID_IADsSecurityDescriptor, (void**)&pSD ); if (FAILED(hr)) { LOG((TL_ERROR, "Couldn't get IADsSecurityDescriptor: 0x%x\n", hr)); goto ExitHere; } // Get an IADsAccessControlList pointer to the security descriptor's DACL.
hr = pSD->get_DiscretionaryAcl(&pDisp); if (SUCCEEDED(hr)) hr = pDisp->QueryInterface(IID_IADsAccessControlList,(void**)&pACL); if (FAILED(hr)) { LOG((TL_ERROR, "Couldn't get DACL: 0x%x\n", hr)); goto ExitHere; } // Create the COM object for the first ACE.
hr = CoCreateInstance( CLSID_AccessControlEntry, NULL, CLSCTX_INPROC_SERVER, IID_IADsAccessControlEntry, (void **)&pACE1 ); // Create the COM object for the second ACE.
if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_AccessControlEntry, NULL, CLSCTX_INPROC_SERVER, IID_IADsAccessControlEntry, (void **)&pACE2 ); } if (FAILED(hr)) { LOG((TL_ERROR, "Couldn't create ACEs: 0x%x\n", hr)); goto ExitHere; }
//
// Set the properties of the two ACEs.
//
// Set the trustee
hr = pACE1->put_Trustee( szTrustee ); hr = pACE2->put_Trustee( szTrusteeAll );
//
// Set the access rights
//
// Full access for service logon account
hr = pACE1->put_AccessMask( ADS_RIGHT_DELETE | ADS_RIGHT_READ_CONTROL | ADS_RIGHT_WRITE_DAC | ADS_RIGHT_WRITE_OWNER | ADS_RIGHT_SYNCHRONIZE | ADS_RIGHT_ACCESS_SYSTEM_SECURITY | ADS_RIGHT_GENERIC_READ | ADS_RIGHT_GENERIC_WRITE | ADS_RIGHT_GENERIC_EXECUTE | ADS_RIGHT_GENERIC_ALL | ADS_RIGHT_DS_CREATE_CHILD | ADS_RIGHT_DS_DELETE_CHILD | ADS_RIGHT_ACTRL_DS_LIST | ADS_RIGHT_DS_SELF | ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_DS_WRITE_PROP | ADS_RIGHT_DS_DELETE_TREE | ADS_RIGHT_DS_LIST_OBJECT | ADS_RIGHT_DS_CONTROL_ACCESS ); // Read access for everyone
hr = pACE2->put_AccessMask( ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_READ_CONTROL | ADS_RIGHT_GENERIC_READ | ADS_RIGHT_ACTRL_DS_LIST | ADS_RIGHT_DS_LIST_OBJECT ); // Set the ACE type.
hr = pACE1->put_AceType( ADS_ACETYPE_ACCESS_ALLOWED_OBJECT ); hr = pACE2->put_AceType( ADS_ACETYPE_ACCESS_ALLOWED_OBJECT );
// Set AceFlags to zero because ACE is not inheritable.
hr = pACE1->put_AceFlags( 0 ); hr = pACE2->put_AceFlags( 0 ); // Set Flags to indicate an ACE that protects a specified object.
hr = pACE1->put_Flags( 0 ); hr = pACE2->put_Flags( 0 ); // Set ObjectType to the schemaIDGUID of the attribute.
hr = pACE1->put_ObjectType( NULL ); hr = pACE2->put_ObjectType( NULL );
// Add the ACEs to the DACL. Need an IDispatch pointer for each ACE
// to pass to the AddAce method.
hr = pACE1->QueryInterface(IID_IDispatch,(void**)&pDispACE); if (SUCCEEDED(hr)) { hr = pACL->AddAce(pDispACE); } if (FAILED(hr)) { LOG((TL_ERROR, "Couldn't add first ACE: 0x%x\n", hr)); goto ExitHere; } else { if (pDispACE) pDispACE->Release(); pDispACE = NULL; } // Do it again for the second ACE.
hr = pACE2->QueryInterface(IID_IDispatch, (void**)&pDispACE); if (SUCCEEDED(hr)) { hr = pACL->AddAce(pDispACE); } if (FAILED(hr)) { LOG((TL_ERROR, "Couldn't add second ACE: 0x%x\n", hr)); goto ExitHere; } // Write the modified DACL back to the security descriptor.
hr = pSD->put_DiscretionaryAcl(pDisp); if (SUCCEEDED(hr)) { // Write the ntSecurityDescriptor property to the property cache.
hr = pSCPObject->Put(szAttribute, varSD); if (SUCCEEDED(hr)) { // SetInfo updates the SCP object in the directory.
hr = pSCPObject->SetInfo(); } } ExitHere: if (pDispACE) pDispACE->Release(); if (pACE1) pACE1->Release(); if (pACE2) pACE2->Release(); if (pACL) pACL->Release(); if (pDisp) pDisp->Release(); if (pSD) pSD->Release();
if (szTrustee) LocalFree (szTrustee);
if (pSid) FreeSid (pSid); if (szTrusteeAll) LocalFree (szTrusteeAll);
if (pSidAll) FreeSid (pSidAll); VariantClear(&varSD); return hr; }
/**********************************************************
* SCP Creation *********************************************************/ //
// CreateSCP
//
// Creates a server Service Connection Point object
// under the local host computer object
//
// Parameters:
// wszRDN - RDN
// szProductName - A member of "keywords" property
// szProductGuid - A member of "keywords" property
// szExtraKey - An extra member of "keywords" property
// szBindingInfo - value of property "serviceBindingInformation"
// szObjGuidVlueName
// - The value name to store the SCP object GUID
// under HKLM\Software\Microsoft\Windows\ // CurrentVersion\Telephony\ // if this value is NULL, we don't cache it in registry
// ppBindByGuidStr - For returning the SCP object GUID in the
// format of LPTSTR, if this is NULL, the GUID is
// not returned
//
HRESULT CreateSCP ( LPWSTR wszRDN, LPTSTR szProductName, LPTSTR szProductGuid, LPTSTR szExtraKey, LPTSTR szBindingInfo, LPTSTR szObjGuidValueName, LPTSTR * ppBindByGuidStr ) { DWORD dwStat, dwAttr, dwLen; HRESULT hr = S_OK; IDispatch *pDisp = NULL; // returned dispinterface of new object
IDirectoryObject *pComp = NULL; // Computer object; parent of SCP
IADs *pIADsSCP = NULL; // IADs interface on new object
BOOL bCoInited = FALSE; BOOL bRevert = FALSE;
//
// Values for SCPs keywords attribute. Tapisrv product GUID is defined
// in server.h, vendor GUID is from MSDN
//
DWORD dwNumKeywords = 4; TCHAR *KwVal[5]={ (LPTSTR) gszMSGuid, // Vendor GUID
(LPTSTR) szProductGuid, // Product GUID
(LPTSTR) gszVenderMS, // Vendor Name
(LPTSTR) szProductName, // Product Name
NULL };
if (szExtraKey != NULL && szExtraKey[0] != 0) { KwVal[4] = szExtraKey; ++dwNumKeywords; }
TCHAR szServer[MAX_PATH]; TCHAR szBinding[128]; TCHAR szDn[MAX_PATH]; TCHAR szAdsPath[MAX_PATH];
HKEY hReg = NULL; DWORD dwDisp;
ADSVALUE cn,objclass,keywords[4],binding, classname,dnsname,nametype;
//
// SCP attributes to set during creation of SCP.
//
ADS_ATTR_INFO ScpAttribs[] = { {TEXT("cn"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &cn, 1}, {TEXT("objectClass"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &objclass, 1}, {TEXT("keywords"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, keywords, dwNumKeywords}, {TEXT("serviceDNSName"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &dnsname, 1}, {TEXT("serviceDNSNameType"), ADS_ATTR_UPDATE,ADSTYPE_CASE_IGNORE_STRING, &nametype, 1}, {TEXT("serviceClassName"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &classname, 1}, {TEXT("serviceBindingInformation"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &binding, 1}, };
// A binding GUID is of format
// LDAP:<GUID=B1A37774-E3F7-488E-ADBFD4DB8A4AB2E5>
BSTR bstrGuid = NULL; TCHAR szBindByGuidStr[64];
//
// Do CoInitializeEx
//
hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); if (FAILED (hr)) { goto ExitHere; } bCoInited = TRUE;
//
// Do all the operation in LocalSystem account
//
if (IsCurrentLocalSystem () != S_OK) { hr = ImpersonateLocalSystem (); if (hr) { goto ExitHere; } bRevert = TRUE; }
//
// Get the DNS name of the local computer
//
dwLen = sizeof(szServer); if (!GetComputerNameEx( ComputerNameDnsFullyQualified, szServer, &dwLen )) { hr = HRESULT_FROM_NT(GetLastError()); LOG((TL_ERROR, "GetComputerNameEx: %s\n", szServer)); goto ExitHere; }
//
// Fill in the attribute values to be stored in the SCP.
//
cn.dwType = ADSTYPE_CASE_IGNORE_STRING; cn.CaseIgnoreString = wszRDN + 3; // 3 is the size of "CN="
objclass.dwType = ADSTYPE_CASE_IGNORE_STRING; objclass.CaseIgnoreString = TEXT("serviceConnectionPoint");
keywords[0].dwType = ADSTYPE_CASE_IGNORE_STRING; keywords[1].dwType = ADSTYPE_CASE_IGNORE_STRING; keywords[2].dwType = ADSTYPE_CASE_IGNORE_STRING; keywords[3].dwType = ADSTYPE_CASE_IGNORE_STRING; keywords[4].dwType = ADSTYPE_CASE_IGNORE_STRING;
keywords[0].CaseIgnoreString=KwVal[0]; keywords[1].CaseIgnoreString=KwVal[1]; keywords[2].CaseIgnoreString=KwVal[2]; keywords[3].CaseIgnoreString=KwVal[3]; keywords[4].CaseIgnoreString=KwVal[4];
dnsname.dwType = ADSTYPE_CASE_IGNORE_STRING; dnsname.CaseIgnoreString = szServer; nametype.dwType = ADSTYPE_CASE_IGNORE_STRING; nametype.CaseIgnoreString = TEXT("A"); classname.dwType = ADSTYPE_CASE_IGNORE_STRING; classname.CaseIgnoreString = szProductName;
binding.dwType = ADSTYPE_CASE_IGNORE_STRING; binding.CaseIgnoreString = szBindingInfo;
//
// Get the distinguished name of the computer object for the local computer
//
dwLen = sizeof(szDn); if (!GetComputerObjectName(NameFullyQualifiedDN, szDn, &dwLen)) { hr = HRESULT_FROM_NT(GetLastError()); LOG((TL_ERROR, "GetComputerObjectName: %s\n", szDn)); goto ExitHere; }
//
// Compose the ADSpath and bind to the computer object for the local computer
//
_tcscpy(szAdsPath,TEXT("LDAP://")); _tcscat(szAdsPath,szDn); hr = ADsGetObject(szAdsPath, IID_IDirectoryObject, (void **)&pComp); if (FAILED(hr)) { LOG((TL_ERROR, "Failed to bind Computer Object.",hr)); goto ExitHere; }
//*******************************************************************
// Publish the SCP as a child of the computer object
//*******************************************************************
// Figure out attribute count.
dwAttr = sizeof(ScpAttribs)/sizeof(ADS_ATTR_INFO);
// Do the Deed!
hr = pComp->CreateDSObject( wszRDN, ScpAttribs, dwAttr, &pDisp ); if (FAILED(hr)) { LOG((TL_ERROR, "Failed to create SCP: 0x%x\n", hr)); if (HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS) { hr = HRESULT_FROM_NT (TAPIERR_SCP_ALREADY_EXISTS); } goto ExitHere; }
// Query for an IADs pointer on the SCP object.
hr = pDisp->QueryInterface(IID_IADs,(void **)&pIADsSCP); if (FAILED(hr)) { LOG((TL_ERROR, "Failed to QI for IADs: 0x%x\n",hr)); goto ExitHere; }
// Set ACEs on SCP so service can modify it.
hr = AllowAccessToScpProperties( pIADsSCP // IADs pointer to the SCP object.
); if (FAILED(hr)) { LOG((TL_ERROR, "Failed to set ACEs on SCP DACL: 0x%x\n", hr)); goto ExitHere; }
// Retrieve the SCP's objectGUID in format suitable for binding.
hr = pIADsSCP->get_GUID(&bstrGuid); if (FAILED(hr)) { LOG((TL_ERROR, "Failed to get GUID: 0x%x\n", hr)); goto ExitHere; }
// Build a string for binding to the object by GUID
_tcscpy(szBindByGuidStr, TEXT("LDAP://<GUID=")); _tcscat(szBindByGuidStr, bstrGuid); _tcscat(szBindByGuidStr, TEXT(">")); LOG((TL_INFO, "GUID binding string: %s\n", szBindByGuidStr));
// Set the returning BindByGuidStr if any
if (ppBindByGuidStr) { *ppBindByGuidStr = (LPTSTR) ServerAlloc ( (_tcslen (szBindByGuidStr) + 1) * sizeof(TCHAR) ); if (*ppBindByGuidStr == NULL) { hr = LINEERR_NOMEM; goto ExitHere; } _tcscpy (*ppBindByGuidStr, szBindByGuidStr); }
// Create a registry key under
// HKEY_LOCAL_MACHINE\SOFTWARE\Vendor\Product.
if (szObjGuidValueName) { dwStat = RegCreateKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hReg, &dwDisp); if (dwStat != NO_ERROR) { hr = HRESULT_FROM_NT(GetLastError()); LOG((TL_ERROR, "RegCreateKeyEx failed: 0x%x\n", hr)); return hr; }
// Cache the GUID binding string under the registry key.
dwStat = RegSetValueEx( hReg, szObjGuidValueName, 0, REG_SZ, (const BYTE *)szBindByGuidStr, sizeof(TCHAR)*(_tcslen(szBindByGuidStr)) ); if (dwStat != NO_ERROR) { hr = HRESULT_FROM_NT(GetLastError()); LOG((TL_ERROR, "RegSetValueEx failed: 0x%x\n", hr)); // goto ExitHere;
} }
ExitHere: if (pDisp) { pDisp->Release(); } if (pIADsSCP) { pIADsSCP->Release(); } if (hReg) { RegCloseKey(hReg); } if (bstrGuid) { SysFreeString (bstrGuid); } if (pComp) { if (FAILED(hr)) { pComp->DeleteDSObject (wszRDN); } pComp->Release(); }
if (bRevert) { RevertLocalSystemImp (); }
if (bCoInited) { CoUninitialize (); }
return hr; }
//
// CreateTapiSCP
//
// Creates the TAPI server Service Connection Point object
// under the local host computer object
//
// Parameters:
// pGuidAssoc - GUID of the line/user association objecct GUID
// currently NULL
// pGuidCluster - The cluster object GUID this server belonging to
//
HRESULT CreateTapiSCP ( GUID * pGuidAssoc, GUID * pGuidCluster ) { DWORD dwStat, dwAttr, dwLen; HRESULT hr = S_OK;
TCHAR szGUIDCluster[40]; TCHAR szGUIDAssoc[40]; TCHAR szBinding[128];
// Construct the binding information
if (pGuidCluster != NULL) { StringFromGUID2 ( *pGuidCluster, szGUIDCluster, sizeof(szGUIDCluster) / sizeof(TCHAR) ); } else { szGUIDCluster[0] = 0; } if (pGuidAssoc != NULL) { StringFromGUID2 ( *pGuidAssoc, szGUIDAssoc, sizeof(szGUIDAssoc) / sizeof(TCHAR) ); } else { szGUIDAssoc[0] = 0; }
wsprintf( szBinding, gszTapisrvBindingInfo, szGUIDCluster, szGUIDAssoc, TEXT("Inactive"), TEXT("") );
hr = CreateSCP ( (LPWSTR) gwszTapisrvRDN, (LPTSTR) gszTapisrvProdName, (LPTSTR) gszTapisrvGuid, (pGuidCluster == NULL) ? NULL : ((LPTSTR)szGUIDCluster), (LPTSTR) szBinding, (LPTSTR) gszRegTapisrvSCPGuid, NULL );
return hr; }
//
// CreateProxySCP
//
// Creates the TAPI proxy server Service Connection Point object
// under the local host computer object
//
// Parameters:
// szClsid - class ID of the proxy server object for DCOM invokation
// ppBindByGuidStr
// - where to return the BindByGuid string pointer
//
HRESULT CreateProxySCP ( LPTSTR szClsid, LPTSTR * ppBindByGuidStr ) { HRESULT hr = S_OK; // RDN size include "cn=TAPI Proxy Server" + szClsid(38ch)
WCHAR wszRDN[128]; WCHAR *psz;
wcscpy (wszRDN, gwszProxyRDN); wcscat (wszRDN, L"{"); psz = wszRDN + wcslen(wszRDN); #ifndef UNICODE
if (MultiByteToWideChar ( CP_ACP, MB_PRECOMPOSED, szClsid, -1, psz, (sizeof(wszRDN) - sizeof(gwszProxyRDN)) / sizeof(WCHAR) - 3 // 3 is to compensate for the two brace
) == 0) { hr = HRESULT_FROM_NT(GetLastError()); goto ExitHere; } #else
wcscat (wszRDN, szClsid); #endif
wcscat (wszRDN, L"}"); hr = CreateSCP ( (LPWSTR) wszRDN, (LPTSTR) gszProxyProdName, (LPTSTR) gszProxyGuid, NULL, (LPTSTR) szClsid, NULL, ppBindByGuidStr );
return hr; }
/**********************************************************
* SCP Update *********************************************************/ //
// UpdateSCP
//
// Update a general SCP properties when necessary to keep every
// piece ofthe information up to date. The following will be checked:
// 1. Check the serviceDNSName property against current computer
// DNS name to ensure consistancy
// 2. Check the binding information with the information given
//
// Parameters:
// szAdsPath - The ADs path of the SCP object
// szBinding - The binding information to compare with
//
HRESULT UpdateSCP ( LPTSTR szAdsPath, LPTSTR szBinding ) { HRESULT hr = S_OK; DWORD dwAttrs; int i; ADSVALUE dnsname,binding;
DWORD dwLen; BOOL bUpdate=FALSE; BOOL bCoInited = FALSE; BOOL bRevert = FALSE;
IDirectoryObject *pObj = NULL; PADS_ATTR_INFO pAttribs = NULL;
TCHAR szServer[MAX_PATH];
TCHAR *pszAttrs[]={ TEXT("serviceDNSName"), TEXT("serviceBindingInformation") };
ADS_ATTR_INFO Attribs[]={ {TEXT("serviceDNSName"),ADS_ATTR_UPDATE,ADSTYPE_CASE_IGNORE_STRING,& dnsname,1}, {TEXT("serviceBindingInformation"),ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING,&binding,1}, };
//
// Do CoInitializeEx
//
hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); if (FAILED (hr)) { goto ExitHere; } bCoInited = TRUE;
//
// Do all the operation in LocalSystem account
//
if (IsCurrentLocalSystem() != S_OK) { hr = ImpersonateLocalSystem (); if (hr) { goto ExitHere; } bRevert = TRUE; } // Get the DNS name of the host server.
dwLen = sizeof(szServer)/sizeof(TCHAR); if (!GetComputerNameEx(ComputerNameDnsFullyQualified, szServer, &dwLen)) { hr = HRESULT_FROM_NT(GetLastError()); goto ExitHere; }
// Bind to the SCP.
hr = ADsGetObject(szAdsPath, IID_IDirectoryObject, (void **)&pObj); if (FAILED(hr)) { LOG((TL_ERROR, "ADsGetObject failed to bind to GUID (bind string: %S): ", szAdsPath )); goto ExitHere; }
// Retrieve attributes from the SCP.
hr = pObj->GetObjectAttributes(pszAttrs, 2, &pAttribs, &dwAttrs); if (FAILED(hr)) { LOG((TL_ERROR, "GetObjectAttributes failed")); goto ExitHere; }
// Check if we got the correct attribute type
if (pAttribs->dwADsType != ADSTYPE_CASE_IGNORE_STRING || (pAttribs+1)->dwADsType != ADSTYPE_CASE_IGNORE_STRING) { LOG((TL_ERROR, "GetObjectAttributes returned dwADsType (%d,%d) instead of CASE_IGNORE_STRING", pAttribs->dwADsType, (pAttribs+1)->dwADsType )); goto ExitHere; }
// Compare the current DNS name and port to the values retrieved from
// the SCP. Update the SCP only if something has changed.
for (i=0; i<(LONG)dwAttrs; i++) { if (_tcsicmp(TEXT("serviceDNSName"), pAttribs[i].pszAttrName)==0) { if (_tcsicmp(szServer, pAttribs[i].pADsValues->CaseIgnoreString) != 0) { LOG((TL_ERROR, "serviceDNSName being updated", 0)); bUpdate = TRUE; } else { LOG((TL_ERROR, "serviceDNSName okay", 0)); } } else if (_tcsicmp( TEXT("serviceBindingInformation"), pAttribs[i].pszAttrName )==0) { if (_tcsicmp(szBinding, pAttribs[i].pADsValues->CaseIgnoreString) != 0) { LOG((TL_ERROR, "serviceBindingInformation being updated", 0)); bUpdate = TRUE; } else { LOG((TL_ERROR, "serviceBindingInformation okay")); } } }
// The binding information or server name have changed,
// so update the SCP values.
if (bUpdate) { dnsname.dwType = ADSTYPE_CASE_IGNORE_STRING; dnsname.CaseIgnoreString = szServer; binding.dwType = ADSTYPE_CASE_IGNORE_STRING; binding.CaseIgnoreString = szBinding; hr = pObj->SetObjectAttributes(Attribs, 2, &dwAttrs); if (FAILED(hr)) { LOG((TL_ERROR, "ScpUpdate: Failed to set SCP values.", hr)); goto ExitHere; } }
ExitHere: if (pAttribs) { FreeADsMem(pAttribs); } if (pObj) { pObj->Release(); }
if (bRevert) { RevertLocalSystemImp (); }
if (bCoInited) { CoUninitialize (); }
return hr; }
//
// UpdateTapiSCP
//
// Update TAPI server SCP properties when necessary to keep every
// piece ofthe information up to date. The following will be checked:
//
// Parameters:
// pGuidAssoc - The line/user association guid
// pGuidCluster - The cluster GUID
//
HRESULT UpdateTapiSCP ( BOOL bActive, GUID * pGuidAssoc, GUID * pGuidCluster ) { HRESULT hr = S_OK; TCHAR szGUIDCluster[40]; TCHAR szGUIDAssoc[40]; TCHAR szBinding[128];
DWORD dwStat, dwType, dwLen; HKEY hReg = NULL; TCHAR szAdsPath[MAX_PATH];
// Open the service's registry key.
dwStat = RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_QUERY_VALUE, &hReg ); if (dwStat != NO_ERROR) { // Probably because the SCP never published, CreateTapiSCP
LOG((TL_ERROR, "RegOpenKeyEx failed", dwStat)); hr = HRESULT_FROM_NT(dwStat); goto ExitHere; }
// Get the GUID binding string used to bind to the service's SCP.
dwLen = sizeof(szAdsPath); dwStat = RegQueryValueEx( hReg, gszRegTapisrvSCPGuid, 0, &dwType, (LPBYTE)szAdsPath, &dwLen ); if (dwStat != NO_ERROR) { LOG((TL_ERROR, "RegQueryValueEx failed", dwStat)); if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER) { if (FAILED(hr = CreateTapiSCP (pGuidAssoc, pGuidCluster))) { LOG((TL_ERROR, "UpdateTapiSCP: CreateTapiSCP failed")); goto ExitHere; }
// CreateTapiSCP succeeded, need to read the guid
dwLen = sizeof(szAdsPath); dwStat = RegQueryValueEx( hReg, gszRegTapisrvSCPGuid, 0, &dwType, (LPBYTE)szAdsPath, &dwLen ); if (dwStat != NO_ERROR) { LOG((TL_ERROR, "UpdateTapiSCP: CreateTapiSCP succeeded but cannot read the guid")); hr = HRESULT_FROM_NT(dwStat); goto ExitHere; } } else { hr = HRESULT_FROM_NT(dwStat); goto ExitHere; } }
// Format to generate desired binding information
if (pGuidCluster != NULL) { StringFromGUID2 ( *pGuidCluster, szGUIDCluster, sizeof(szGUIDCluster) / sizeof(TCHAR) ); } else { szGUIDCluster[0] = 0; } if (pGuidAssoc != NULL) { StringFromGUID2 ( *pGuidAssoc, szGUIDAssoc, sizeof(szGUIDAssoc) / sizeof(TCHAR) ); } else { szGUIDAssoc[0] = 0; }
//
// Now construct the serviceBindingInformation based on the
// service status
//
if (bActive) { TCHAR szTTL[64]; FILETIME ftCur; ULONGLONG ullInc, ullTime; SYSTEMTIME stExp;
// Get current time
GetSystemTimeAsFileTime (&ftCur); CopyMemory (&ullTime, &ftCur, sizeof(ULONGLONG));
// Get the time increment for gdwTapiSCPTTL minutes
// FILETIME is in the unit of 100 nanoseconds
ullInc = ((ULONGLONG)gdwTapiSCPTTL) * 60 * 10000000;
// Get the record expiration time
ullTime += ullInc; CopyMemory (&ftCur, &ullTime, sizeof(FILETIME));
//
// Convert the expiration time to system time and
// format the string
//
// The current TTL string is the concatenation of
// Year, Month, Date, Hour, Minute, Second, Milliseconds
// There are 5 digits allocated for year, 3 digits for
// milliseconds, and 2 digits fro the remaining fields
// all the numbers are zero padded to fill the extra space
//
// Format here needs to be consistant with \ // sp\remotesp\dslookup.cpp
//
FileTimeToSystemTime (&ftCur, &stExp); wsprintf ( szTTL, TEXT("%05d%02d%02d%02d%02d%02d%03d"), stExp.wYear, stExp.wMonth, stExp.wDay, stExp.wHour, stExp.wMinute, stExp.wSecond, stExp.wMilliseconds ); wsprintf( szBinding, gszTapisrvBindingInfo, szGUIDCluster, szGUIDAssoc, TEXT("Active"), szTTL ); } else { wsprintf( szBinding, gszTapisrvBindingInfo, szGUIDCluster, szGUIDAssoc, TEXT("Inactive"), TEXT("") ); } hr = UpdateSCP ( szAdsPath, szBinding );
ExitHere: if (hReg) { RegCloseKey (hReg); } return hr; }
//
// Proxy server exists only if TAPI server are alive
// the DS information not likely to change when TAPI server is
// alive, so no SCP updating routine for Proxy server
//
/**********************************************************
* SCP Removal *********************************************************/ //
// RemoveSCP
//
// Removes a Service Connection Point object from the
// local host computer object.
//
// Parameters:
// wszRDN - the RDN of the SCP to delete
// szRegNameToDel
// - The registery value name to be deleted
// If this value is NULL, no registry del
//
HRESULT RemoveSCP ( LPWSTR wszRDN, LPTSTR szRegNameToDel ) { HRESULT hr = S_OK; TCHAR szServer[MAX_PATH]; TCHAR szAdsPath[MAX_PATH]; DWORD dwLen, dwStat; HKEY hReg; IDirectoryObject * pComp = NULL; BOOL bCoInited = FALSE; BOOL bRevert = FALSE;
//
// Do CoInitializeEx
//
hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); if (FAILED (hr)) { goto ExitHere; } bCoInited = TRUE;
//
// Do all the operation in LocalSystem account
//
if (IsCurrentLocalSystem() != S_OK) { hr = ImpersonateLocalSystem (); if (hr) { goto ExitHere; } bRevert = TRUE; } // Get the DNS name of the host server.
dwLen = sizeof(szServer); if (!GetComputerObjectName(NameFullyQualifiedDN, szServer, &dwLen)) { hr = HRESULT_FROM_NT(GetLastError()); goto ExitHere; } //
// Compose the ADSpath and bind to the computer object for the local computer
//
_tcscpy(szAdsPath,TEXT("LDAP://")); _tcscat(szAdsPath,szServer); hr = ADsGetObject(szAdsPath, IID_IDirectoryObject, (void **)&pComp); if (FAILED(hr)) { LOG((TL_ERROR, "Failed (%x) to bind Computer Object.",hr)); goto ExitHere; }
hr = pComp->DeleteDSObject (wszRDN); if (FAILED (hr)) { LOG((TL_ERROR, "Failed (%x) to Delete Tapisrv Object.",hr)); if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT) { hr = HRESULT_FROM_NT (TAPIERR_SCP_DOES_NOT_EXIST); } goto ExitHere; } // Open the service's registry key.
if (szRegNameToDel) { dwStat = RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyTelephony, 0, KEY_QUERY_VALUE | KEY_WRITE, &hReg); if (dwStat == NO_ERROR) { RegDeleteValue ( hReg, szRegNameToDel ); RegCloseKey (hReg); } else { LOG((TL_ERROR, "RegOpenKeyEx failed", dwStat)); hr = HRESULT_FROM_NT(GetLastError()); // goto ExitHere;
} }
ExitHere: if (pComp) pComp->Release(); if (bRevert) { RevertLocalSystemImp (); } if (bCoInited) { CoUninitialize (); } return hr; }
//
// RemoveTapiSCP
//
// Removes the TAPI server Service Connection Point object from the
// local host computer object. This happens if a TAPI server machine
// retires from service.
//
HRESULT RemoveTapiSCP ( ) { return RemoveSCP ( (LPWSTR) gwszTapisrvRDN, (LPTSTR) gszRegTapisrvSCPGuid ); }
//
// RemoveProxySCP
//
// Removes the proxy server Service Connection Point object from the
// local host computer object. This happens if the last line is closed
// from a certain proxy server (CLSID)
//
HRESULT RemoveProxySCP ( LPTSTR szClsid ) { HRESULT hr = S_OK;
// Construct the RDN
// RDN size include "cn=TAPI Proxy Server" + szClsid(38ch)
WCHAR wszRDN[128]; WCHAR *psz;
wcscpy (wszRDN, gwszProxyRDN); wcscat (wszRDN, L"{"); psz = wszRDN + wcslen(wszRDN); #ifndef UNICODE
if (MultiByteToWideChar ( CP_ACP, MB_PRECOMPOSED, szClsid, -1, psz, (sizeof(wszRDN) - sizeof(gwszProxyRDN)) / sizeof(WCHAR) - 3 // 3 is to compensate for the two brace
) == 0) { hr = HRESULT_FROM_NT(GetLastError()); goto ExitHere; } #else
wcscat (wszRDN, szClsid); #endif
wcscat (wszRDN, L"}");
// Call RemoveSCP
hr = RemoveSCP ( wszRDN, NULL );
//ExitHere:
return hr; }
/**********************************************************
* Proxy Server SCP management *********************************************************/
//
// The Rules:
// 1. An array of created SCP objects and their corresponding CLSID
// is maintained in a global data structure PROXY_SCPS
// 2. ServerInit calls OnProxySCPInit & ServerShutdown calls
// OnProxySCPShutdown
// 3. Every LOpen with proxy privilege will call OnProxyLineOpen with
// the proxy server CLSID as the input parameter.
// An SCP object will be created for a new CLSID, subsequent LOpen
// with the same CLSID will only increment the ref count
// 4. Every LClose with on a line (opened with proxy privilege) will call
// OnProxyLineClose with the proxy server CLSID as the input parameter
// The ref count is decemented every time for the SCP with the CLSID,
// if the ref count goes to zero, the SCP object will be deleted.
//
HRESULT OnProxySCPInit ( ) { TapiEnterCriticalSection (&TapiGlobals.CritSec); ZeroMemory (&gProxyScps, sizeof(gProxyScps)); TapiLeaveCriticalSection (&TapiGlobals.CritSec); return S_OK; }
HRESULT OnProxySCPShutdown ( ) { DWORD i;
TapiEnterCriticalSection (&TapiGlobals.CritSec); for (i = 0; i < gProxyScps.dwUsedEntries; ++i) { RemoveProxySCP (gProxyScps.aEntries[i].szClsid); } if (gProxyScps.aEntries != NULL) { ServerFree (gProxyScps.aEntries); } ZeroMemory (&gProxyScps, sizeof(gProxyScps)); TapiLeaveCriticalSection (&TapiGlobals.CritSec); return S_OK; }
HRESULT OnProxyLineOpen ( LPTSTR szClsid ) { HRESULT hr = S_OK; BOOL fExists = FALSE; DWORD i;
// Skip beginning/trailing white space
while (*szClsid == TEXT(' ') || *szClsid == TEXT('\t')) ++ szClsid; // A valid CLSID string should only contain 38 chars
if (_tcslen (szClsid) > 40) { hr = E_INVALIDARG; goto ExitHere; }
TapiEnterCriticalSection (&TapiGlobals.CritSec); // Is SCP for this szClsid already created (in array)?
for (i = 0; i < gProxyScps.dwUsedEntries; ++i) { if (_tcsicmp ( gProxyScps.aEntries[i].szClsid, szClsid ) == 0) { fExists = TRUE; break; } }
// If already exists, inc the ref count
if (fExists) { gProxyScps.aEntries[i].dwRefCount++; } // If not exists, create the new SCP and cache it
else { LPTSTR pBindByGuidStr; hr = CreateProxySCP (szClsid, &pBindByGuidStr); if (FAILED (hr)) { TapiLeaveCriticalSection (&TapiGlobals.CritSec); goto ExitHere; }
if (gProxyScps.dwUsedEntries >= gProxyScps.dwTotalEntries) { // Increase the size
PROXY_SCP_ENTRY * pNew;
pNew = (PPROXY_SCP_ENTRY) ServerAlloc ( sizeof(PROXY_SCP_ENTRY) * (gProxyScps.dwTotalEntries + 16) ); if (pNew == NULL) { hr = LINEERR_NOMEM; ServerFree (pBindByGuidStr); TapiLeaveCriticalSection (&TapiGlobals.CritSec); goto ExitHere; } CopyMemory ( pNew, gProxyScps.aEntries, sizeof(PROXY_SCP_ENTRY) * gProxyScps.dwTotalEntries ); ServerFree (gProxyScps.aEntries); gProxyScps.aEntries = pNew; gProxyScps.dwTotalEntries += 16; } i = gProxyScps.dwUsedEntries++; _tcscpy (gProxyScps.aEntries[i].szClsid, szClsid); _tcscpy (gProxyScps.aEntries[i].szObjGuid, pBindByGuidStr); gProxyScps.aEntries[i].dwRefCount = 1; ServerFree (pBindByGuidStr); } TapiLeaveCriticalSection (&TapiGlobals.CritSec);
ExitHere: return hr; }
HRESULT OnProxyLineClose ( LPTSTR szClsid ) { HRESULT hr = S_OK; BOOL fExists = FALSE; DWORD i;
// Skip beginning/trailing white space
while (*szClsid == TEXT(' ') || *szClsid == TEXT('\t')) ++ szClsid; // A valid CLSID string should only contain 38 chars
if (_tcslen (szClsid) > 40) { hr = E_INVALIDARG; goto ExitHere; }
TapiEnterCriticalSection (&TapiGlobals.CritSec); // Is SCP for this szClsid already created (in array)?
for (i = 0; i < gProxyScps.dwUsedEntries; ++i) { if (_tcsicmp ( gProxyScps.aEntries[i].szClsid, szClsid ) == 0) { fExists = TRUE; break; } }
if (fExists) { --gProxyScps.aEntries[i].dwRefCount; // If ref count goes to zero, remove the SCP
if (gProxyScps.aEntries[i].dwRefCount == 0) { hr = RemoveProxySCP (gProxyScps.aEntries[i].szClsid); if (i < gProxyScps.dwUsedEntries - 1) { MoveMemory ( gProxyScps.aEntries + i, gProxyScps.aEntries + i + 1, sizeof(PROXY_SCP_ENTRY) * (gProxyScps.dwUsedEntries - 1 - i) ); } --gProxyScps.dwUsedEntries; } } TapiLeaveCriticalSection (&TapiGlobals.CritSec);
ExitHere: return hr; }
|