|
|
/*++ BUILD Version: 0000 // Increment this if a change has global effects
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
tapimmc.c
Abstract:
Src module for tapi server mmc-support funcs
Author:
Dan Knudson (DanKn) 10-Dec-1997
Revision History:
--*/
#include "windows.h"
#include "stdio.h"
#include "stdlib.h"
#include "assert.h"
#include "tapi.h"
#include "utils.h"
#include "tapiclnt.h"
#include "tspi.h"
#include "client.h"
#include "server.h"
#include "tapimmc.h"
#include "private.h"
#include "Sddl.h"
typedef struct _USERNAME_TUPLE { LPWSTR pDomainUserNames;
LPWSTR pFriendlyUserNames;
} USERNAME_TUPLE, *LPUSERNAME_TUPLE;
typedef struct _MMCGETAVAILABLEPROVIDERS_PARAMS { union { OUT LONG lResult; };
DWORD dwUnused;
union { IN HLINEAPP hLineApp; };
union { IN DWORD dwProviderListTotalSize; // size of client buffer
OUT DWORD dwProviderListOffset; // valid offset on success
};
} MMCGETAVAILABLEPROVIDERS_PARAMS, *PMMCGETAVAILABLEPROVIDERS_PARAMS;
typedef struct _MMCGETDEVICEINFO_PARAMS { union { OUT LONG lResult; };
DWORD dwUnused;
union { IN HLINEAPP hLineApp; };
union { IN DWORD dwDeviceInfoListTotalSize; // size of client buffer
OUT DWORD dwDeviceInfoListOffset; // valid offset on success
};
} MMCGETDEVICEINFO_PARAMS, *PMMCGETDEVICEINFO_PARAMS;
typedef struct _MMCGETSERVERCONFIG_PARAMS { union { OUT LONG lResult; };
DWORD dwUnused;
union { IN HLINEAPP hLineApp; };
union { IN DWORD dwServerConfigTotalSize; // size of client buffer
OUT DWORD dwServerConfigOffset; // valid offset on success
} ;
} MMCGETSERVERCONFIG_PARAMS, *PMMCGETSERVERCONFIG_PARAMS;
typedef struct _MMCSETDEVICEINFO_PARAMS { union { OUT LONG lResult; };
DWORD dwUnused;
union { IN HLINEAPP hLineApp; };
union { IN DWORD dwDeviceInfoListOffset; // valid offset
};
} MMCSETDEVICEINFO_PARAMS, *PMMCSETDEVICEINFO_PARAMS;
typedef struct _MMCSETSERVERCONFIG_PARAMS { union { OUT LONG lResult; };
DWORD dwUnused;
union { IN HLINEAPP hLineApp; };
union { IN DWORD dwServerConfigOffset; // valid offset
};
} MMCSETSERVERCONFIG_PARAMS, *PMMCSETSERVERCONFIG_PARAMS;
typedef struct _MMCGETDEVICEFLAGS_PARAMS {
OUT LONG lResult; DWORD dwUnused;
IN HLINEAPP hLineApp;
IN DWORD fLine;
IN DWORD dwProviderID; IN DWORD dwPermanentDeviceID;
OUT DWORD dwFlags;
OUT DWORD dwDeviceID; } MMCGETDEVICEFLAGS_PARAM, *PMMCGETDEVICEFLAGS_PARAMS;
LPDEVICEINFOLIST gpLineInfoList = NULL; LPDEVICEINFOLIST gpPhoneInfoList = NULL; LPDWORD gpLineDevFlags = NULL; DWORD gdwNumFlags = 0; BOOL gbLockMMCWrite = FALSE;
//
// the last ftLastWriteTime of tsec.ini when we build the
// gpLineInfoList or gpPhoneInfoList, we will rebuild the
// *InfList if tsec.ini has been updated since then
//
FILETIME gftLineLastWrite = {0}; FILETIME gftPhoneLastWrite = {0}; CRITICAL_SECTION gMgmtCritSec;
WCHAR gszLines[] = L"Lines"; WCHAR gszPhones[] = L"Phones"; WCHAR gszFileName[] = L"..\\TAPI\\tsec.ini"; WCHAR gszEmptyString[] = L""; WCHAR gszFriendlyUserName[] = L"FriendlyUserName"; WCHAR gszTapiAdministrators[] = L"TapiAdministrators";
//
// The following are the length of the constant strings
// defined above (excluding the terminating zero). The above
// string should not be changed normally. If for some
// reason the above strings need to be changed, the following
// CCH_constants need to be changed accordingly.
//
#define CCH_LINES 5
#define CCH_PHONES 6
#define CCH_FRIENDLYUSERNAME 16
#define CCH_TAPIADMINISTRATORS 18
extern TAPIGLOBALS TapiGlobals;
extern TCHAR gszProductType[]; extern TCHAR gszProductTypeServer[]; extern TCHAR gszProductTypeLanmanNt[]; extern TCHAR gszRegKeyNTServer[];
extern HANDLE ghEventService;
PTLINELOOKUPENTRY GetLineLookupEntry( DWORD dwDeviceID );
PTPHONELOOKUPENTRY GetPhoneLookupEntry( DWORD dwDeviceID );
BOOL InitTapiStruct( LPVOID pTapiStruct, DWORD dwTotalSize, DWORD dwFixedSize, BOOL bZeroInit );
DWORD GetDeviceIDFromPermanentID( TAPIPERMANENTID ID, BOOL bLine );
DWORD GetProviderFriendlyName( WCHAR *pFileNameBuf, WCHAR **ppFriendlyNameBuf );
BOOL IsBadStructParam( DWORD dwParamsBufferSize, LPBYTE pDataBuf, DWORD dwXxxOffset );
LONG PASCAL GetClientList( BOOL bAdminOnly, PTPOINTERLIST *ppList );
extern CRITICAL_SECTION *gLockTable; extern DWORD gdwPointerToLockTableIndexBits;
#define POINTERTOTABLEINDEX(p) \
((((ULONG_PTR) p) >> 4) & gdwPointerToLockTableIndexBits)
PTCLIENT PASCAL WaitForExclusiveClientAccess( PTCLIENT ptClient ); #define UNLOCKTCLIENT(p) \
LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)]) #define UNLOCKTLINECLIENT(p) \
LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)]) #define UNLOCKTPHONECLIENT(p) \
LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
BOOL PASCAL WaitForExclusivetLineAccess( PTLINE ptLine, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout );
BOOL PASCAL WaitForExclusiveLineClientAccess( PTLINECLIENT ptLineClient );
BOOL PASCAL WaitForExclusivetPhoneAccess( PTPHONE ptPhone, HANDLE *phMutex, BOOL *pbDupedMutex, DWORD dwTimeout );
BOOL PASCAL WaitForExclusivePhoneClientAccess( PTPHONECLIENT ptPhoneClient );
void DestroytPhoneClient( HPHONE hPhone );
void PASCAL DestroytLineClient( HLINE hLine );
LONG PASCAL GetLineAppListFromClient( PTCLIENT ptClient, PTPOINTERLIST *ppList );
LONG PASCAL GetPhoneAppListFromClient( PTCLIENT ptClient, PTPOINTERLIST *ppList ); void WINAPI MGetAvailableProviders( PTCLIENT ptClient, PMMCGETAVAILABLEPROVIDERS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { WCHAR szPath[MAX_PATH+8], *pFileNameBuf, *pFriendlyNameBuf, *p, *p2; DWORD dwFileNameBufTotalSize, dwFileNameBufUsedSize, dwFriendlyNameBufTotalSize, dwFriendlyNameBufUsedSize, dwNumProviders, dwSize, i; HANDLE hFind; WIN32_FIND_DATAW findData; LPAVAILABLEPROVIDERLIST pList = (LPAVAILABLEPROVIDERLIST) pDataBuf;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwProviderListTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; }
if (pParams->dwProviderListTotalSize < sizeof (AVAILABLEPROVIDERLIST)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; return; }
pList->dwTotalSize = pParams->dwProviderListTotalSize; pList->dwNeededSize = pList->dwUsedSize = sizeof (*pList); pList->dwNumProviderListEntries = pList->dwProviderListSize = pList->dwProviderListOffset = 0;
pParams->dwProviderListOffset = 0;
//
// Find all the files in the system directory with the extenion .TSP
//
GetSystemDirectoryW (szPath, MAX_PATH);
wcscat (szPath, L"\\*.TSP");
if ((hFind = FindFirstFileW (szPath, &findData)) == INVALID_HANDLE_VALUE) { LOG((TL_ERROR, "MGetAvailableProviders: FindFirstFile err=%d", GetLastError() ));
goto done; }
dwNumProviders = dwFileNameBufTotalSize = dwFileNameBufUsedSize = 0;
do { LOG((TL_INFO, "MGetAvailableProviders: found '%ws'", findData.cFileName ));
dwSize = (wcslen (findData.cFileName) + 1) * sizeof (WCHAR);
if ((dwSize + dwFileNameBufUsedSize) > dwFileNameBufTotalSize) { if (!(p = ServerAlloc (dwFileNameBufTotalSize += 512))) { FindClose (hFind); pParams->lResult = LINEERR_NOMEM; return; }
if (dwFileNameBufUsedSize) { CopyMemory (p, pFileNameBuf, dwFileNameBufUsedSize);
ServerFree (pFileNameBuf); }
pFileNameBuf = p; }
CopyMemory( ((LPBYTE) pFileNameBuf) + dwFileNameBufUsedSize, findData.cFileName, dwSize );
dwFileNameBufUsedSize += dwSize;
dwNumProviders++;
} while (FindNextFileW (hFind, &findData));
FindClose (hFind);
//
// For each of the files we found above get their "friendly" name
// (use the module name if there's no friendly name)
//
RpcImpersonateClient (0); dwFriendlyNameBufUsedSize = GetProviderFriendlyName (pFileNameBuf, &pFriendlyNameBuf); RpcRevertToSelf();
if (0 == dwFriendlyNameBufUsedSize) { pFriendlyNameBuf = pFileNameBuf;
dwFriendlyNameBufUsedSize = dwFileNameBufUsedSize; }
pList->dwNeededSize += (dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY)) + dwFileNameBufUsedSize + dwFriendlyNameBufUsedSize;
//
// Now if there's enough room in the buffer for everything then
// pack it all in there
//
if (pList->dwNeededSize <= pList->dwTotalSize) { DWORD dwNumAvailProviders; LPAVAILABLEPROVIDERENTRY pEntry = (LPAVAILABLEPROVIDERENTRY) (pList + 1);
pList->dwUsedSize += dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY);
p = pFileNameBuf; p2 = pFriendlyNameBuf;
for (i = dwNumAvailProviders = 0; i < dwNumProviders; i++) { HANDLE hTsp;
if (!(hTsp = LoadLibraryW (p))) { //
// If we can't even load the tsp then ignore it
//
p += wcslen (p) + 1; p2 += wcslen (p2) + 1; continue; } if (GetProcAddress (hTsp, "TSPI_providerInstall")) { pEntry->dwOptions = AVAILABLEPROVIDER_INSTALLABLE; } else { pEntry->dwOptions = 0; }
if (GetProcAddress (hTsp, "TSPI_providerConfig") || GetProcAddress (hTsp, "TUISPI_providerConfig")) { pEntry->dwOptions |= AVAILABLEPROVIDER_CONFIGURABLE; }
if (GetProcAddress (hTsp, "TSPI_providerRemove")) { pEntry->dwOptions |= AVAILABLEPROVIDER_REMOVABLE; }
FreeLibrary (hTsp);
pEntry->dwFileNameSize = (wcslen (p) + 1) * sizeof (WCHAR); pEntry->dwFileNameOffset = pList->dwUsedSize;
CopyMemory( ((LPBYTE) pList) + pEntry->dwFileNameOffset, p, pEntry->dwFileNameSize );
pList->dwUsedSize += pEntry->dwFileNameSize;
p += pEntry->dwFileNameSize / sizeof (WCHAR);
pEntry->dwFriendlyNameSize = (wcslen (p2) + 1) * sizeof (WCHAR); pEntry->dwFriendlyNameOffset = pList->dwUsedSize;
CopyMemory( ((LPBYTE) pList) + pEntry->dwFriendlyNameOffset, p2, pEntry->dwFriendlyNameSize );
pList->dwUsedSize += pEntry->dwFriendlyNameSize;
p2 += pEntry->dwFriendlyNameSize / sizeof (WCHAR);
dwNumAvailProviders++; pEntry++; }
pList->dwNumProviderListEntries = dwNumAvailProviders; pList->dwProviderListSize = dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY); pList->dwProviderListOffset = sizeof (*pList); }
ServerFree (pFileNameBuf);
if (pFriendlyNameBuf != pFileNameBuf) { ServerFree (pFriendlyNameBuf); }
done:
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pList->dwUsedSize;
pParams->lResult = 0; }
DWORD PASCAL MyGetPrivateProfileString( LPCWSTR pszSection, LPCWSTR pszKey, LPCWSTR pszDefault, LPWSTR *ppBuf, LPDWORD pdwBufSize ) { DWORD dwResult;
while (1) { dwResult = GetPrivateProfileStringW( pszSection, pszKey, pszDefault, *ppBuf, *pdwBufSize / sizeof (WCHAR), gszFileName );
if (dwResult < ((*pdwBufSize) / sizeof(WCHAR) - 2)) { return 0; }
ServerFree (*ppBuf);
*pdwBufSize *= 2;
if (!(*ppBuf = ServerAlloc (*pdwBufSize))) { break; } }
return LINEERR_NOMEM; }
DWORD PASCAL InsertInfoListString( LPDEVICEINFOLIST *ppInfoList, DWORD dwInfoIndex, DWORD dwXxxSizeFieldOffset, LPWSTR psz, DWORD dwLength, BOOL bAppendNull ) { LPDWORD pdwXxxSize; LPDEVICEINFO pInfo; LPDEVICEINFOLIST pInfoList = *ppInfoList;
if (!dwLength) { return 0; }
//
// If the existing buffer is too small the alloc a larger one
//
if ((pInfoList->dwUsedSize + dwLength + sizeof (WCHAR)) > pInfoList->dwTotalSize) { DWORD dwTotalSize = (*ppInfoList)->dwTotalSize + dwLength + 4096;
if (!(pInfoList = ServerAlloc (dwTotalSize))) { return LINEERR_NOMEM; }
CopyMemory (pInfoList, *ppInfoList, (*ppInfoList)->dwUsedSize);
pInfoList->dwTotalSize = dwTotalSize;;
ServerFree (*ppInfoList);
*ppInfoList = pInfoList; }
CopyMemory (((LPBYTE) pInfoList) + pInfoList->dwUsedSize, psz, dwLength);
pInfo = ((LPDEVICEINFO)(pInfoList + 1)) + dwInfoIndex;
pdwXxxSize = (LPDWORD) (((LPBYTE) pInfo) + dwXxxSizeFieldOffset);
if ((*pdwXxxSize += dwLength) == dwLength) { *(pdwXxxSize + 1) = pInfoList->dwUsedSize; }
pInfoList->dwUsedSize += dwLength;
if (bAppendNull) { *((WCHAR *)(((LPBYTE) pInfoList) + pInfoList->dwUsedSize)) = L'\0';
pInfoList->dwUsedSize += sizeof (WCHAR);
*pdwXxxSize += sizeof (WCHAR); }
return 0; }
DWORD PASCAL GrowCapsBuf( LPDWORD *ppXxxCaps, LPDWORD pdwBufSize ) { DWORD dwTotalSize = **ppXxxCaps + 256, *pXxxCapsTmp;
if (!(pXxxCapsTmp = ServerAlloc (dwTotalSize))) { return LINEERR_NOMEM; }
*pdwBufSize = *pXxxCapsTmp = dwTotalSize;
ServerFree (*ppXxxCaps);
*ppXxxCaps = pXxxCapsTmp;
return 0; }
DWORD PASCAL ChangeDeviceUserAssociation( LPWSTR pDomainUserName, LPWSTR pFriendlyUserName, DWORD dwProviderID, DWORD dwPermanentDeviceID, BOOL bLine ) { DWORD dwSize = 64 * sizeof (WCHAR), dwLength, dwNeededSize; WCHAR *p, *p2, *p3, buf[32]; BOOL bAlreadyIn; WCHAR *pSub;
if (!(p = ServerAlloc (dwSize))) { return LINEERR_NOMEM; }
if (MyGetPrivateProfileString( pDomainUserName, (bLine ? gszLines : gszPhones), gszEmptyString, &p, &dwSize )) { ServerFree (p); return LINEERR_NOMEM; }
dwLength = wsprintfW (buf, L"%d,%d", dwProviderID, dwPermanentDeviceID);
//
// Check if the specified Device/User assocation is already there
// if so bAlreadyIn is set to be true and pSub points to the
// (dwProviderID, dwPermanentDeviceID) pair
//
bAlreadyIn = FALSE; pSub = p; while (*pSub) { if ((wcsncmp(pSub, buf, dwLength) == 0) && (*(pSub + dwLength) == L',' || *(pSub + dwLength) == L'\0')) { bAlreadyIn = TRUE; break; }
//
// Skip the next two delimiting ','
//
if (!(pSub = wcschr (pSub, L','))) { break; } pSub++; if (!(pSub = wcschr (pSub, L','))) { break; } pSub++; }
if (pFriendlyUserName) // Add device/user association
{ // Always write the friendly name which could be different
WritePrivateProfileStringW( pDomainUserName, gszFriendlyUserName, pFriendlyUserName, gszFileName );
if ( !bAlreadyIn) { dwNeededSize = (dwLength + wcslen (p) + 2) * sizeof (WCHAR);
if (dwNeededSize > dwSize) { if (!(p2 = ServerAlloc (dwNeededSize))) { return LINEERR_NOMEM; }
wcscpy (p2, p); ServerFree (p); p = p2; }
if (*p == L'\0') { wcscpy (p, buf); } else { wcscat (p, L","); wcscat (p, buf); } } } else // Remove device/user association
{ p2 = pSub;
if (bAlreadyIn) { if (*(p2 + dwLength) == L',') // not last item in list, so copy
{ for( p3 = p2 + dwLength + 1; (*p2 = *p3) != L'\0'; p2++, p3++ ); } else if (*(p2 + dwLength) == L'\0') { if (p2 == p) // only item in list, so list == ""
{ *p2 = L'\0'; } else // last item in list, so nuke preceding ','
{ *(p2 - 1) = L'\0'; } } }
if (*p == L'\0') { } }
if (bLine && *p == 0) { WritePrivateProfileStringW( pDomainUserName, NULL, NULL, gszFileName ); } else { WritePrivateProfileStringW( pDomainUserName, (bLine ? gszLines : gszPhones), p, gszFileName ); }
ServerFree (p);
return 0; }
//
// UpdateLastWriteTime
// It reads the ftLastWriteTime of the tsec.ini into gftLineLastWrite or
// gftPhoneLastWrite, it also returns S_FALSE, if the timestamp is newer
//
LONG UpdateLastWriteTime ( BOOL bLine ) { LONG lResult = S_OK; WCHAR szFilePath[MAX_PATH + 16]; // include space for "tsec.ini"
WIN32_FILE_ATTRIBUTE_DATA fad; FILETIME * pft; DWORD dwError; if (GetSystemWindowsDirectoryW(szFilePath, MAX_PATH) == 0) { lResult = LINEERR_OPERATIONFAILED; goto ExitHere; }
wcscat (szFilePath, L"\\"); wcscat (szFilePath, gszFileName); pft = bLine ? &gftLineLastWrite : &gftPhoneLastWrite;
if (GetFileAttributesExW ( szFilePath, GetFileExInfoStandard, &fad) == 0 ) { dwError = GetLastError(); if (dwError == ERROR_FILE_NOT_FOUND || dwError == ERROR_PATH_NOT_FOUND) { ZeroMemory (pft, sizeof(FILETIME)); lResult = S_FALSE; } else { lResult = LINEERR_OPERATIONFAILED; } goto ExitHere; }
if (fad.ftLastWriteTime.dwHighDateTime > pft->dwHighDateTime || fad.ftLastWriteTime.dwLowDateTime > pft->dwLowDateTime) { pft->dwHighDateTime = fad.ftLastWriteTime.dwHighDateTime; pft->dwLowDateTime = fad.ftLastWriteTime.dwLowDateTime; lResult = S_FALSE; }
ExitHere: return lResult; }
//
// InsertDevNameAddrInfo
// Utlity to fill
// DEVICEINFO.dwDeviceNameSize
// DEVICEINFO.dwDeviceNameOffset
// DEVICEINFO.dwAddressSize
// DEVICEINFO.dwAddressOffset
// dwDeviceID is the device ID to retrieve information while
// dwEntry is the DEVICEINFO entry index in the deviceinfo list
//
//
LONG InsertDevNameAddrInfo ( BOOL bLine, LPDEVICEINFOLIST *ppList, LPDWORD pdwDevFlags, DWORD dwDeviceID, DWORD dwEntry ) { LPDEVICEINFO pInfo = ((LPDEVICEINFO)((*ppList) + 1)) + dwEntry; PTLINELOOKUPENTRY pLLE; PTPHONELOOKUPENTRY pPLE; LONG lResult = S_OK; DWORD k; LINEDEVCAPS devCaps[3]; LPLINEDEVCAPS pDevCaps = devCaps; DWORD dwDevCapsTotalSize = sizeof(devCaps); LINEADDRESSCAPS addrCaps[3]; LPLINEADDRESSCAPS pAddrCaps = addrCaps; DWORD dwAddrCapsTotalSize = sizeof(addrCaps);
TapiEnterCriticalSection(&TapiGlobals.CritSec); if (bLine) { pLLE = GetLineLookupEntry (dwDeviceID);
if (!pLLE || pLLE->bRemoved) { lResult = S_FALSE; goto ExitHere; }
pInfo->dwProviderID = pLLE->ptProvider->dwPermanentProviderID; } else { pPLE = GetPhoneLookupEntry (dwDeviceID);
if (!pPLE || pPLE->bRemoved) { lResult = S_FALSE; goto ExitHere; } pInfo->dwProviderID = pPLE->ptProvider->dwPermanentProviderID; }
//
// Retrieve device name from TSPI_xxGetCaps
//
get_dev_caps:
InitTapiStruct( pDevCaps, dwDevCapsTotalSize, sizeof (LINEDEVCAPS), TRUE );
if (bLine) { lResult = CallSP4( pLLE->ptProvider->apfn[SP_LINEGETDEVCAPS], "lineGetDevCaps", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) pLLE->dwSPIVersion, (DWORD) 0, (ULONG_PTR) pDevCaps ); } else { lResult = CallSP4( pPLE->ptProvider->apfn[SP_PHONEGETDEVCAPS], "phoneGetDevCaps", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) pPLE->dwSPIVersion, (DWORD) 0, (ULONG_PTR) pDevCaps ); } if (lResult != 0) { //
// We can't get the name or the PermDevID, so ignore this device
//
goto ExitHere; } else if (pDevCaps->dwNeededSize <= pDevCaps->dwTotalSize) { DWORD dwXxxSize; LPWSTR pwszXxxName; const WCHAR szUnknown[] = L"Unknown";
if (bLine) { pInfo->dwPermanentDeviceID = pDevCaps->dwPermanentLineID;
if (pdwDevFlags) { *pdwDevFlags = pDevCaps->dwDevCapFlags; }
dwXxxSize = pDevCaps->dwLineNameSize;
pwszXxxName = (WCHAR *) (((LPBYTE) pDevCaps) + pDevCaps->dwLineNameOffset);
} else { LPPHONECAPS pPhoneCaps = (LPPHONECAPS) pDevCaps;
pInfo->dwPermanentDeviceID = pPhoneCaps->dwPermanentPhoneID;
dwXxxSize = pPhoneCaps->dwPhoneNameSize;
pwszXxxName = (WCHAR *) (((LPBYTE) pPhoneCaps) + pPhoneCaps->dwPhoneNameOffset); }
if (dwXxxSize == 0 || *pwszXxxName == L'\0') { dwXxxSize = 8 * sizeof (WCHAR);
pwszXxxName = (LPWSTR) szUnknown; }
if (InsertInfoListString( ppList, dwEntry, (DWORD) (((LPBYTE) &pInfo->dwDeviceNameSize) - ((LPBYTE) pInfo)), pwszXxxName, dwXxxSize, FALSE )) { lResult = LINEERR_NOMEM; goto ExitHere; } } //
// if the pDevCaps is not large enough, increase the size
// by 256 and try again.
//
else { LPLINEDEVCAPS pNewDevCaps; dwDevCapsTotalSize += 256; pNewDevCaps = ServerAlloc (dwDevCapsTotalSize); if (pNewDevCaps == NULL) { lResult = LINEERR_NOMEM; goto ExitHere; } if (pDevCaps != devCaps) { ServerFree (pDevCaps); } pDevCaps = pNewDevCaps; goto get_dev_caps; }
if (bLine) { //
// for each address on this line retrieve the address "name"
// by calling TSPI_lineGetAddressCaps. Terminate the last
// address name in the list with an extra Null character.
//
for (k = 0; k < pDevCaps->dwNumAddresses; k++) {
get_addr_caps: InitTapiStruct( pAddrCaps, dwAddrCapsTotalSize, sizeof (LINEADDRESSCAPS), TRUE );
if ((lResult = CallSP5( pLLE->ptProvider->apfn[SP_LINEGETADDRESSCAPS], "lineGetAddressCaps", SP_FUNC_SYNC, (DWORD) dwDeviceID, (DWORD) k, (DWORD) pLLE->dwSPIVersion, (DWORD) 0, (ULONG_PTR) pAddrCaps )) == 0) { if (pAddrCaps->dwNeededSize <= pAddrCaps->dwTotalSize) { if (InsertInfoListString( ppList, dwEntry, (DWORD) (((LPBYTE) &pInfo->dwAddressesSize) - ((LPBYTE) pInfo)), (LPWSTR) (((LPBYTE) pAddrCaps) + pAddrCaps->dwAddressOffset), pAddrCaps->dwAddressSize, (k < (pDevCaps->dwNumAddresses - 1) ? FALSE : TRUE) )) { lResult = LINEERR_NOMEM; goto ExitHere; } } //
// if the pAddrCaps is not large enough, increase the size
// by 256 and try again.
//
else { LPLINEADDRESSCAPS pNewAddrCaps; dwAddrCapsTotalSize += 256; pNewAddrCaps = ServerAlloc (dwAddrCapsTotalSize); if (pNewAddrCaps == NULL) { goto ExitHere; } if (pAddrCaps != addrCaps) { ServerFree (pAddrCaps); } pAddrCaps = pNewAddrCaps; goto get_addr_caps; } } else { // no addr name (will default to blank, not bad)
} } }
ExitHere: if (pDevCaps != devCaps) { ServerFree (pDevCaps); } if (pAddrCaps != addrCaps) { ServerFree (pAddrCaps); } TapiLeaveCriticalSection(&TapiGlobals.CritSec); return lResult; }
//
// AppendNewDeviceInfo
// This function insert a newly created device identified by
// dwDeviceID into the cached gpLineInfoList or gpPhoneInfoList in
// response to LINE/PHONE_CREATE message
//
LONG AppendNewDeviceInfo ( BOOL bLine, DWORD dwDeviceID ) { LONG lResult = S_OK; LPDEVICEINFOLIST pXxxList; DWORD dwXxxDevices; DWORD dwTotalSize; DWORD dwSize, dw;
EnterCriticalSection (&gMgmtCritSec);
pXxxList = bLine? gpLineInfoList : gpPhoneInfoList; dwXxxDevices = bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones;
if (pXxxList == NULL) { goto ExitHere; }
//
// make sure we have enough space to accomodate the new device flags
if (bLine && gpLineDevFlags && gdwNumFlags < dwXxxDevices) { LPDWORD pNewLineDevFlags;
pNewLineDevFlags = ServerAlloc (dwXxxDevices * sizeof(DWORD)); if (pNewLineDevFlags == NULL) { goto ExitHere; } CopyMemory ( pNewLineDevFlags, gpLineDevFlags, gdwNumFlags * sizeof(DWORD) ); ServerFree (gpLineDevFlags); gpLineDevFlags = pNewLineDevFlags; gdwNumFlags = dwXxxDevices; }
//
// make sure we have enough space for the new DEVICEINFO entry
// An estimate is done for the new DEVICEINFO entry
// the estimation includes:
// 1. Fixed size of DEVICEINFO structure
// 2. 20 bytes each for DeviceName, Addresses, DomainUserName
// and FriendlyUserName
//
dwTotalSize = pXxxList->dwUsedSize + sizeof(DEVICEINFO) + (20 + 20 + 20 + 20) * sizeof(WCHAR); if (dwTotalSize > pXxxList->dwTotalSize) { LPDEVICEINFOLIST pNewList;
pNewList = ServerAlloc (dwTotalSize); if (pNewList == NULL) { lResult = (bLine ? LINEERR_NOMEM : PHONEERR_NOMEM); goto ExitHere; } CopyMemory (pNewList, pXxxList, pXxxList->dwUsedSize); pNewList->dwTotalSize = dwTotalSize; pXxxList = pNewList; if (bLine) { ServerFree (gpLineInfoList); gpLineInfoList = pXxxList; } else { ServerFree (gpPhoneInfoList); gpPhoneInfoList = pXxxList; } }
// Now make space for the new DEVICEINFO entry
if (pXxxList->dwUsedSize > pXxxList->dwDeviceInfoSize + sizeof(*pXxxList)) { LPBYTE pbVar = (LPBYTE) pXxxList + pXxxList->dwDeviceInfoSize + sizeof(*pXxxList); LPDEVICEINFO pInfo = (LPDEVICEINFO)(((LPBYTE)pXxxList) + sizeof(*pXxxList)); dwSize = pXxxList->dwUsedSize - pXxxList->dwDeviceInfoSize - sizeof(*pXxxList); MoveMemory ( pbVar + sizeof(DEVICEINFO), pbVar, dwSize); ZeroMemory (pbVar, sizeof(DEVICEINFO)); for (dw = 0; dw < pXxxList->dwNumDeviceInfoEntries; ++dw ) { if (pInfo->dwDeviceNameOffset != 0) { pInfo->dwDeviceNameOffset += sizeof(DEVICEINFO); } if (pInfo->dwAddressesOffset != 0) { pInfo->dwAddressesOffset += sizeof(DEVICEINFO); } if (pInfo->dwDomainUserNamesOffset != 0) { pInfo->dwDomainUserNamesOffset += sizeof(DEVICEINFO); } if (pInfo->dwFriendlyUserNamesOffset != 0) { pInfo->dwFriendlyUserNamesOffset += sizeof(DEVICEINFO); } ++pInfo; } } pXxxList->dwUsedSize += sizeof(DEVICEINFO); pXxxList->dwNeededSize = pXxxList->dwUsedSize;
// Now add the new entry
lResult = InsertDevNameAddrInfo ( bLine, (bLine ? (&gpLineInfoList) : (&gpPhoneInfoList)), (bLine && dwDeviceID < gdwNumFlags) ? (gpLineDevFlags + dwDeviceID) : NULL, dwDeviceID, pXxxList->dwNumDeviceInfoEntries ); if (lResult == 0) { pXxxList = bLine? gpLineInfoList : gpPhoneInfoList; pXxxList->dwDeviceInfoSize += sizeof(DEVICEINFO); ++pXxxList->dwNumDeviceInfoEntries; pXxxList->dwNeededSize = pXxxList->dwUsedSize; }
ExitHere: LeaveCriticalSection (&gMgmtCritSec);
return lResult; }
//
// RemoveDeviceInfoEntry
// // This function removes a device info entry from the gpLineInfoList
// or gpPhoneInfoList identified by dwDevice in response to LINE/PHONE_REMOVE
// message
//
LONG RemoveDeviceInfoEntry ( BOOL bLine, DWORD dwDeviceID ) { LPDEVICEINFOLIST pXxxList; LPDEVICEINFO pInfo; int iIndex, cItems; LPBYTE pb;
EnterCriticalSection (&gMgmtCritSec);
pXxxList = bLine ? gpLineInfoList : gpPhoneInfoList; if (pXxxList == NULL) { goto ExitHere; } pInfo = (LPDEVICEINFO)(pXxxList + 1);
cItems = (int)pXxxList->dwNumDeviceInfoEntries; iIndex = dwDeviceID; if ((int)dwDeviceID >= cItems) { iIndex = cItems - 1; } pInfo += iIndex; while (iIndex >= 0) { TAPIPERMANENTID tpid;
tpid.dwDeviceID = pInfo->dwPermanentDeviceID; tpid.dwProviderID = pInfo->dwProviderID;
if (dwDeviceID == GetDeviceIDFromPermanentID(tpid, bLine)) { break; } --pInfo; --iIndex; } if (iIndex < 0) { goto ExitHere; }
// With the entry pointed to by iIndex found, move down
// all the DEVICEINFO entry above it
if (iIndex < cItems - 1) { pb = (LPBYTE)((LPDEVICEINFO)(pXxxList + 1) + iIndex); MoveMemory ( pb, pb + sizeof(DEVICEINFO), (cItems - 1 - iIndex) * sizeof(DEVICEINFO) ); } pXxxList->dwDeviceInfoSize -= sizeof(DEVICEINFO); --pXxxList->dwNumDeviceInfoEntries;
ExitHere: LeaveCriticalSection (&gMgmtCritSec); return 0; }
//
// BuildDeviceInfoList
// Private function called by GetDeviceInfo to build the DEVICEINFOLIST
// if not already created, the list is saved in gpLineInfoList or
// gpPhoneInfoList
//
LONG BuildDeviceInfoList( BOOL bLine ) { LONG lResult = S_OK; DWORD dwNumDevices, dwListTotalSize, dwFriendlyNameSize, dwDomainUserNameSize, dwFriendlyUserNameSize; DWORD i, j; LPDEVICEINFOLIST pList = NULL; LPUSERNAME_TUPLE pUserNames= NULL; LPWSTR lpszFriendlyName = NULL; LPDEVICEINFO pInfo; HANDLE hIniFile = 0; HANDLE hFileMap = NULL; char * lpszFileBuf = NULL; char* lpszLineAnsiBuf = NULL; LPWSTR lpszLineWcharBuf = NULL; DWORD dwAnsiLineBufSize, dwWcharLineBufSize; DWORD dwTotalFileSize; DWORD dwFilePtr; LPWSTR lpszDomainUser = NULL; DWORD cbDomainUser; LPDWORD lpdwDevFlags = NULL; WCHAR *p;
//
// Alloc a buffer to use for the device info list. Size includes
// the list header, list entries for each existing device,
// and space wide unicode strings for device name, (address,)
// domain\user name(s), and friendly user name(s) (each est to 20 char).
//
// Also alloc buffers to use for retrieving device & address caps,
// and a buffer to temporarily store pointers to user name
// strings (which are associated with each line)
//
TapiEnterCriticalSection(&TapiGlobals.CritSec); dwNumDevices = (bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones); TapiLeaveCriticalSection(&TapiGlobals.CritSec);
dwAnsiLineBufSize = 256 * sizeof(WCHAR); dwWcharLineBufSize = 256 * sizeof(WCHAR); dwFriendlyNameSize = 64 * sizeof (WCHAR); cbDomainUser = 128; dwListTotalSize = sizeof (DEVICEINFOLIST) + (dwNumDevices * sizeof (DEVICEINFO)) + (dwNumDevices * (20 + 20 + 20 + 20) * sizeof (WCHAR));
if (!(pList = ServerAlloc (dwListTotalSize)) || !(pUserNames = ServerAlloc (dwNumDevices * sizeof (USERNAME_TUPLE))) || !(lpszFriendlyName = ServerAlloc (dwFriendlyNameSize)) || !(lpszLineAnsiBuf = ServerAlloc (dwAnsiLineBufSize)) || !(lpszLineWcharBuf = ServerAlloc (dwWcharLineBufSize)) || !(lpszDomainUser = ServerAlloc (cbDomainUser))) { lResult = LINEERR_NOMEM; goto ExitHere; }
if (bLine && !(lpdwDevFlags = ServerAlloc (dwNumDevices * sizeof (DWORD)))) { lResult = LINEERR_NOMEM; goto ExitHere; }
pList->dwTotalSize = dwListTotalSize; pList->dwUsedSize = sizeof (*pList) + dwNumDevices * sizeof (DEVICEINFO); pList->dwDeviceInfoSize = dwNumDevices * sizeof (DEVICEINFO); pList->dwDeviceInfoOffset = sizeof (*pList);
//
// Get info for all the lines, including:
//
// Provider ID
// Permanent Device ID
// Device Name
// (Addresses)
//
// ... and pack this info in the list sequentially
//
LOG((TL_INFO, "GetDeviceInfo: getting names (addrs) for %ld %ws", dwNumDevices, (bLine ? gszLines : gszPhones) ));
for (i = j = 0; i < dwNumDevices; i++) { if (WaitForSingleObject ( ghEventService, 0 ) == WAIT_OBJECT_0) { lResult = LINEERR_OPERATIONFAILED; goto ExitHere; } lResult = InsertDevNameAddrInfo ( bLine, &pList, bLine ? lpdwDevFlags + i : NULL, i, j ); if (lResult) { lResult = 0; continue; } ++j; }
dwNumDevices = pList->dwNumDeviceInfoEntries = j; // the number of devices in the list
//
// Now enumerate all the known users & figure out what devices they
// have access to. Since each device can be seen by zero, one, or
// many users, we allocate separate user name buffers in this loop
// rather than try to pack them into the existing device info list.
//
//
// Open %windir%\tsec.ini file and map it into memory
//
{ TCHAR szFilePath[MAX_PATH + 16]; // include space for "tsec.ini"
OFSTRUCT ofs; if (GetCurrentDirectory(MAX_PATH, szFilePath) == 0) { lResult = LINEERR_OPERATIONFAILED; goto ExitHere; }
wcscat (szFilePath, L"\\"); wcscat (szFilePath, gszFileName);
hIniFile = CreateFile ( szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hIniFile == INVALID_HANDLE_VALUE) { DWORD dwError; dwError = GetLastError(); if (dwError != ERROR_FILE_NOT_FOUND && dwError != ERROR_PATH_NOT_FOUND) { lResult = LINEERR_OPERATIONFAILED; goto ExitHere; } } if (hIniFile != INVALID_HANDLE_VALUE) { dwTotalFileSize = GetFileSize(hIniFile, NULL); } else { dwTotalFileSize = 0; } if (dwTotalFileSize > 0) { hFileMap = CreateFileMapping ( hIniFile, NULL, PAGE_READONLY, 0, 0, NULL ); if (hFileMap == NULL) { lResult = LINEERR_OPERATIONFAILED; goto ExitHere; } lpszFileBuf = MapViewOfFile ( hFileMap, FILE_MAP_READ, 0, 0, 0 ); if (lpszFileBuf == NULL) { lResult = LINEERR_OPERATIONFAILED; goto ExitHere; } } }
pInfo = (LPDEVICEINFO)(pList + 1);
dwFilePtr = 0; while (dwFilePtr < dwTotalFileSize) { WCHAR wch; DWORD cch, cb; WCHAR * lpwsz; if (WaitForSingleObject ( ghEventService, 0 ) == WAIT_OBJECT_0) { lResult = LINEERR_OPERATIONFAILED; goto ExitHere; } ASSERT (lpszFileBuf != NULL);
// Read one line from the file
cch = 0; wch = 0; cb = 0; while (wch != L'\n' && wch != L'\r' && dwFilePtr < dwTotalFileSize) { // Not enough line buffer? if so enlarge
if (cb >= dwAnsiLineBufSize) { char * lpszNewAnsi; if (!(lpszNewAnsi = ServerAlloc (dwAnsiLineBufSize + 256))) { lResult = LINEERR_NOMEM; goto ExitHere; } CopyMemory (lpszNewAnsi, lpszLineAnsiBuf, cb); ServerFree (lpszLineAnsiBuf); lpszLineAnsiBuf = lpszNewAnsi; dwAnsiLineBufSize += 256; } wch = lpszLineAnsiBuf[cb++] = lpszFileBuf[dwFilePtr++]; if (IsDBCSLeadByte((BYTE)wch)) { lpszLineAnsiBuf[cb] = lpszFileBuf[dwFilePtr++]; wch = (wch << 8) + lpszLineAnsiBuf[cb]; ++cb; } ++cch; }
// skip the \r & \n
if (wch == L'\r' || wch == L'\n') { lpszLineAnsiBuf[cb - 1] = 0; if (dwFilePtr < dwTotalFileSize && ((lpszFileBuf[dwFilePtr] == L'\n') || (lpszFileBuf[dwFilePtr] == L'\r'))) { ++dwFilePtr; } }
// Now convert the ANSI string to Wide char
// enough wchar line buffer size?
if (dwWcharLineBufSize <= (cch + 1) * sizeof(WCHAR)) { ServerFree (lpszLineWcharBuf); dwWcharLineBufSize = (cch + 256) * sizeof(WCHAR); if (!(lpszLineWcharBuf = ServerAlloc (dwWcharLineBufSize))) { lResult = LINEERR_NOMEM; goto ExitHere; } }
if ((cch = MultiByteToWideChar ( CP_ACP, MB_PRECOMPOSED, lpszLineAnsiBuf, cb, lpszLineWcharBuf, dwWcharLineBufSize / sizeof(WCHAR) )) == 0) { lResult = LINEERR_OPERATIONFAILED; goto ExitHere; } ASSERT (cch < dwWcharLineBufSize / sizeof(WCHAR)); lpszLineWcharBuf[cch] = 0;
lpwsz = lpszLineWcharBuf; // Skip white space
while (*lpwsz && ((*lpwsz == L' ') || (*lpwsz == L'\t'))) { ++lpwsz; }
// Got a bracket, this might be the starting of a new NT
// domain user or the section of [TapiAdministators]
if (*lpwsz == L'[') { *lpszFriendlyName = 0; // reset friendly name
++lpwsz; if (_wcsnicmp ( lpwsz, gszTapiAdministrators, CCH_TAPIADMINISTRATORS ) == 0 && lpwsz[CCH_TAPIADMINISTRATORS] == L']') { // Got [TapiAdministrators], not any domain user
// to process, reset the lpszDomainUser to empty
*lpszDomainUser = 0; continue; } else { // might be a valid NT domain user like [ndev\jonsmith]
// copy the domain user string over
cch = 0; while (*lpwsz && *lpwsz != L']') { if (((cch + 1) * sizeof(WCHAR)) >= cbDomainUser) { LPTSTR lpszNew;
if (!(lpszNew = ServerAlloc (cbDomainUser + 128))) { lResult = LINEERR_NOMEM; goto ExitHere; } CopyMemory (lpszNew, lpszDomainUser, cb); ServerFree (lpszDomainUser); lpszDomainUser = lpszNew; cbDomainUser += 128; } lpszDomainUser[cch++] = *lpwsz++; } lpszDomainUser[cch] = 0; if (*lpwsz == 0) { // did not find a closing ']', ignore this section
*lpszDomainUser = 0; continue; } } } //
// Now it might be some ntdev\jonsmith=1 in [TapiAdministrators] or
// Lines=1,1000 under section of [ntdev\jonsmith].
// for the first case, we just ignore this line, for the second case
// we need to have *lpszDomainUser != 0
//
else if (*lpszDomainUser) { if (_wcsnicmp ( lpwsz, gszFriendlyUserName, CCH_FRIENDLYUSERNAME ) == 0) { // The tsec.ini friendly name is the following format
// FriendlyName=Jon Smith
// skip over the '='
while (*lpwsz && *lpwsz != L'=') { ++lpwsz; } if (*lpwsz == 0) { continue; } else { ++lpwsz; } if (dwFriendlyNameSize < (1 + wcslen (lpwsz)) * sizeof(WCHAR)) { ServerFree (lpszFriendlyName); dwFriendlyNameSize = (64 + wcslen (lpwsz)) * sizeof(WCHAR); if (!(lpszFriendlyName = ServerAlloc (dwFriendlyNameSize))) { lResult = LINEERR_NOMEM; goto ExitHere; } } wcscpy (lpszFriendlyName, lpwsz); continue; } else if (_wcsnicmp ( lpwsz, gszLines, CCH_LINES ) == 0 && bLine || _wcsnicmp ( lpwsz, gszPhones, CCH_PHONES ) == 0 && (!bLine)) { // Here it is either Lines=1,100 or Phones=1,100
DWORD dwXxxSize, dwDeviceID; WCHAR *pXxxNames, *pNewXxxNames, * p; TAPIPERMANENTID tpid;
// first skip over the '=' sign
while (*lpwsz && *lpwsz != L'=') { ++lpwsz; } if (*lpwsz == 0) { continue; } ++lpwsz;
p = lpwsz; while (*p) { if ((tpid.dwProviderID = _wtol (p)) == 0) { //
// ProviderID's are never 0, so list must be corrupt.
//
break; } for (; ((*p != L'\0') && (*p != L',')); p++); if (*p == L'\0') { //
// Couldn't find a trailing ',' so list must be corrupt.
//
break; }
p++; // skip the ','
tpid.dwDeviceID = _wtol (p);
while (*p != L',' && *p != L'\0') { p++; }
if (*p == L',') { if (*(p + 1) == L'\0') { //
// The ',' is followed by a NULL, so nuke the ','
//
*p = L'\0'; } else { p++; } } dwDeviceID = GetDeviceIDFromPermanentID (tpid, bLine);
if (dwDeviceID == 0xffffffff) { //
// This <ppid>,<plid> pair is bad. Skip it.
//
continue; }
//
// At this point dwDeviceID is the zero-based index
// of a fully populated info list (no missing entries).
//
// If the list is not fully-populated (due to failed
// dev caps, or removed devices, etc) we need to
// recompute the index by walking the list & comparing
// permanent XXX id's.
//
if (dwNumDevices < (bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones)) { BOOL bContinue = FALSE;
for (i = dwDeviceID;; i--) { LPDEVICEINFO pInfoTmp = ((LPDEVICEINFO) (pList + 1)) +i;
if (pInfoTmp->dwPermanentDeviceID == tpid.dwDeviceID && pInfoTmp->dwProviderID == tpid.dwProviderID) { dwDeviceID = i; break; }
if (i == 0) { bContinue = TRUE; break; } }
if (bContinue) { continue; } }
//
//
//
dwDomainUserNameSize = (wcslen(lpszDomainUser) + 1) * sizeof(WCHAR); dwXxxSize = pInfo[dwDeviceID].dwDomainUserNamesOffset; pXxxNames = pUserNames[dwDeviceID].pDomainUserNames;
if (!(pNewXxxNames = ServerAlloc( dwXxxSize + dwDomainUserNameSize ))) { lResult = LINEERR_NOMEM; goto ExitHere; }
CopyMemory (pNewXxxNames, lpszDomainUser, dwDomainUserNameSize);
if (dwXxxSize) { CopyMemory( ((LPBYTE) pNewXxxNames) + dwDomainUserNameSize, pXxxNames, dwXxxSize );
ServerFree (pXxxNames); }
pInfo[dwDeviceID].dwDomainUserNamesOffset += dwDomainUserNameSize; pUserNames[dwDeviceID].pDomainUserNames = pNewXxxNames;
//
//
//
// If there is no friendly name specified in tsec.ini
// which happens in NT/SP4 upgrade case, we use the
// DomainUserName for display
//
if (*lpszFriendlyName == 0) { wcsncpy(lpszFriendlyName, lpszDomainUser, dwFriendlyNameSize / sizeof(WCHAR)); lpszFriendlyName[(dwFriendlyNameSize / sizeof(WCHAR)) - 1] = 0; } dwFriendlyUserNameSize = (wcslen(lpszFriendlyName) + 1) * sizeof(WCHAR); dwXxxSize = pInfo[dwDeviceID].dwFriendlyUserNamesOffset; pXxxNames = pUserNames[dwDeviceID].pFriendlyUserNames;
if (!(pNewXxxNames = ServerAlloc( dwXxxSize + dwFriendlyUserNameSize ))) { lResult = LINEERR_NOMEM; goto ExitHere; }
CopyMemory( pNewXxxNames, lpszFriendlyName, dwFriendlyUserNameSize );
if (dwXxxSize) { CopyMemory( ((LPBYTE) pNewXxxNames) + dwFriendlyUserNameSize, pXxxNames, dwXxxSize );
ServerFree (pXxxNames); }
pInfo[dwDeviceID].dwFriendlyUserNamesOffset += dwFriendlyUserNameSize; pUserNames[dwDeviceID].pFriendlyUserNames = pNewXxxNames; } } } }
//
//
//
LOG((TL_INFO, "GetDeviceInfo: matching users to %ws", (bLine ? gszLines : gszPhones) ));
for (i = 0; i < dwNumDevices; i++) { pInfo = ((LPDEVICEINFO)(pList + 1)) + i;
if (InsertInfoListString( &pList, i, (DWORD) (((LPBYTE) &pInfo->dwDomainUserNamesSize) - ((LPBYTE) pInfo)), pUserNames[i].pDomainUserNames, pInfo->dwDomainUserNamesOffset, TRUE )) { lResult = LINEERR_NOMEM; goto ExitHere; }
pInfo = ((LPDEVICEINFO)(pList + 1)) + i;
if (InsertInfoListString( &pList, i, (DWORD) (((LPBYTE) &pInfo->dwFriendlyUserNamesSize) - ((LPBYTE) pInfo)), pUserNames[i].pFriendlyUserNames, pInfo->dwFriendlyUserNamesOffset, TRUE )) { lResult = LINEERR_NOMEM; goto ExitHere; } }
//
// If here we successfully built the list
//
pList->dwNeededSize = pList->dwUsedSize;
if (bLine) { gpLineInfoList = pList; gpLineDevFlags = lpdwDevFlags; gdwNumFlags = dwNumDevices; } else { gpPhoneInfoList = pList; }
ExitHere:
if (pUserNames != NULL) { for (i = 0; i < dwNumDevices; i++) { ServerFree (pUserNames[i].pDomainUserNames); ServerFree (pUserNames[i].pFriendlyUserNames); } }
ServerFree (lpszDomainUser); ServerFree (lpszLineAnsiBuf); ServerFree (lpszLineWcharBuf); ServerFree (lpszFriendlyName); ServerFree (pUserNames); if (lResult) { ServerFree (pList); if (bLine) { ServerFree (lpdwDevFlags); gdwNumFlags = 0; } }
if (hFileMap) { UnmapViewOfFile(lpszFileBuf); CloseHandle (hFileMap); } if (hIniFile != INVALID_HANDLE_VALUE) { CloseHandle (hIniFile); }
return lResult; }
void GetDeviceInfo( PMMCGETDEVICEINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned, BOOL bLine ) { LONG lResult = LINEERR_NOMEM; LPDEVICEINFOLIST pXxxList, pInfoListApp;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwDeviceInfoListTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; goto ExitHere; }
if (pParams->dwDeviceInfoListTotalSize < sizeof (*pXxxList)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; goto ExitHere; }
//
// If there's not an existing device info list then & build a
// new one or
// if tsec.ini has been updated outsize, rebuild the DeviceInfoList
//
pInfoListApp = (LPDEVICEINFOLIST) pDataBuf;
EnterCriticalSection(&gMgmtCritSec);
pXxxList = (bLine ? gpLineInfoList : gpPhoneInfoList);
if (UpdateLastWriteTime(bLine) == S_FALSE || pXxxList == NULL) {
// First free old infoList if any (if updated outside)
if (bLine) { if (gpLineInfoList) { ServerFree (gpLineInfoList); gpLineInfoList = NULL; ServerFree (gpLineDevFlags); gpLineDevFlags = NULL; gdwNumFlags = 0; } } else { if (gpPhoneInfoList) { ServerFree (gpPhoneInfoList); gpPhoneInfoList = NULL; } }
// Create new info list, BuildDeviceInfoList is a long process
pParams->lResult = BuildDeviceInfoList(bLine); if (pParams->lResult != S_OK) { LeaveCriticalSection(&gMgmtCritSec); goto ExitHere; } }
//
// Return the device info list we have in memory
//
pXxxList = (bLine ? gpLineInfoList : gpPhoneInfoList); ASSERT (pXxxList != NULL); if (pParams->dwDeviceInfoListTotalSize < pXxxList->dwNeededSize) { pInfoListApp->dwNeededSize = pXxxList->dwNeededSize; pInfoListApp->dwUsedSize = sizeof (*pInfoListApp); pInfoListApp->dwNumDeviceInfoEntries = pInfoListApp->dwDeviceInfoSize = pInfoListApp->dwDeviceInfoOffset = 0; } else { CopyMemory( pInfoListApp, pXxxList, pXxxList->dwNeededSize ); }
pInfoListApp->dwTotalSize = pParams->dwDeviceInfoListTotalSize;
pParams->dwDeviceInfoListOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pInfoListApp->dwUsedSize;
pParams->lResult = 0;
LeaveCriticalSection(&gMgmtCritSec);
ExitHere: return; }
void WINAPI MGetLineInfo( PTCLIENT ptClient, PMMCGETDEVICEINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { GetDeviceInfo( pParams, dwParamsBufferSize, pDataBuf, pdwNumBytesReturned, TRUE ); }
void WINAPI MGetPhoneInfo( PTCLIENT ptClient, PMMCGETDEVICEINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { GetDeviceInfo( pParams, dwParamsBufferSize, pDataBuf, pdwNumBytesReturned, FALSE ); }
void SetDeviceInfo( PMMCSETDEVICEINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned, BOOL bLine ) { DWORD i; WCHAR *pDomainUserName, *pDomainUserNames, *pFriendlyUserName, *pFriendlyUserNames; LPDEVICEINFO pOldInfo, pNewInfo; LPDEVICEINFOLIST pNewInfoList = (LPDEVICEINFOLIST) (pDataBuf + pParams->dwDeviceInfoListOffset), *ppXxxList = (bLine ? &gpLineInfoList : &gpPhoneInfoList);
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwDeviceInfoListOffset )) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
//
// Serialize access to global line info list
//
if (!(*ppXxxList)) { pParams->lResult = LINEERR_OPERATIONFAILED; goto exit; }
//
// Update the global list & ini file by diff'ing old & new settings
//
pNewInfo = (LPDEVICEINFO) (((LPBYTE) pNewInfoList) + pNewInfoList->dwDeviceInfoOffset);
for (i = 0; i < pNewInfoList->dwNumDeviceInfoEntries; i++, pNewInfo++) { DWORD dwDeviceID; DWORD dwIndex; TAPIPERMANENTID tpid;
tpid.dwProviderID = pNewInfo->dwProviderID; tpid.dwDeviceID = pNewInfo->dwPermanentDeviceID;
dwDeviceID = GetDeviceIDFromPermanentID (tpid, bLine);
if (dwDeviceID == 0xffffffff) { LOG((TL_ERROR, "SetDeviceInfo: bad provider/device IDs (x%x/x%x)", pNewInfo->dwProviderID, pNewInfo->dwPermanentDeviceID ));
continue; }
pOldInfo = dwDeviceID + ((LPDEVICEINFO) (*ppXxxList + 1));
//
// Due to device removal, it is possible pOldInfo is not the entry
// desired, we need to search back to find the one we want
//
dwIndex = dwDeviceID; if ((dwDeviceID >= (*ppXxxList)->dwNumDeviceInfoEntries) || (pOldInfo->dwProviderID != tpid.dwProviderID) || (pOldInfo->dwPermanentDeviceID != tpid.dwDeviceID)) { LPDEVICEINFO pInfoFirst = (LPDEVICEINFO)(*ppXxxList + 1); DWORD dwLastSchDevice = ((*ppXxxList)->dwNumDeviceInfoEntries <= dwDeviceID)? ((*ppXxxList)->dwNumDeviceInfoEntries - 1) : (dwDeviceID - 1); LPDEVICEINFO pInfo = pInfoFirst + dwLastSchDevice; while (pInfo >= pInfoFirst && ((pInfo->dwProviderID != tpid.dwProviderID) || (pInfo->dwPermanentDeviceID != tpid.dwDeviceID))) { --pInfo; } if (pInfo < pInfoFirst) { LOG((TL_ERROR, "SetDeviceInfo: bad provider/device IDs (x%x/x%x)", pNewInfo->dwProviderID, pNewInfo->dwPermanentDeviceID ));
continue; } pOldInfo = pInfo; dwIndex = (DWORD)(ULONG_PTR)(pInfo - pInfoFirst); }
//
// Remove all the old users from this device
//
if (pOldInfo->dwDomainUserNamesSize) { pDomainUserName = (WCHAR *) (((LPBYTE) *ppXxxList) + pOldInfo->dwDomainUserNamesOffset);
while (*pDomainUserName != L'\0') { ChangeDeviceUserAssociation( pDomainUserName, NULL, pOldInfo->dwProviderID, pOldInfo->dwPermanentDeviceID, bLine );
pDomainUserName += wcslen (pDomainUserName) + 1; }
pOldInfo->dwDomainUserNamesSize = 0; pOldInfo->dwFriendlyUserNamesSize = 0; }
//
// Add all the new users to this device
//
if (pNewInfo->dwDomainUserNamesSize) { pDomainUserName = pDomainUserNames = (WCHAR *) (((LPBYTE) pNewInfoList) + pNewInfo->dwDomainUserNamesOffset);
pFriendlyUserName = pFriendlyUserNames = (WCHAR *) (((LPBYTE) pNewInfoList) + pNewInfo->dwFriendlyUserNamesOffset);
while (*pDomainUserName != L'\0') { ChangeDeviceUserAssociation( pDomainUserName, pFriendlyUserName, pOldInfo->dwProviderID, pOldInfo->dwPermanentDeviceID, bLine );
pDomainUserName += wcslen (pDomainUserName) + 1; pFriendlyUserName += wcslen (pFriendlyUserName) + 1; }
if (InsertInfoListString( ppXxxList, dwIndex, (DWORD) (((LPBYTE) &pNewInfo->dwDomainUserNamesSize) - ((LPBYTE) pNewInfo)), pDomainUserNames, pNewInfo->dwDomainUserNamesSize, FALSE )) { }
if (InsertInfoListString( ppXxxList, dwIndex, (DWORD) (((LPBYTE) &pNewInfo->dwFriendlyUserNamesSize) - ((LPBYTE) pNewInfo)), pFriendlyUserNames, pNewInfo->dwFriendlyUserNamesSize, FALSE )) { } }
//
// Update the device access(phone/line mapping) for the client users
// send LINE/PHONE_REMOVE if the domain/user lose the access
// send LINE/PHONE_CREATE if the domain/user gained the access
//
{ TPOINTERLIST clientList = {0}, *pClientList = &clientList; DWORD i, j;
//
// Walk throught the client list
//
GetClientList (FALSE, &pClientList); for (i = 0; i < pClientList->dwNumUsedEntries; i++) { PTCLIENT ptClient; BOOL bHaveAccess = FALSE; BOOL bGainAccess = FALSE; BOOL bLoseAccess = FALSE; BOOL bSendMessage = FALSE; WCHAR * pwsz = NULL; WCHAR wszBuf[255]; DWORD dw, dwNewDeviceID;
ptClient = (PTCLIENT) pClientList->aEntries[i];
//
// Should this client have access to this device?
//
if (WaitForExclusiveClientAccess(ptClient)) { if (IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR) || ptClient->pszDomainName == NULL || ptClient->pszUserName == NULL) { UNLOCKTCLIENT (ptClient); continue; } dw = wcslen (ptClient->pszDomainName) + wcslen (ptClient->pszUserName) + 2; dw *= sizeof(WCHAR); if (dw > sizeof (wszBuf)) { pwsz = ServerAlloc (dw); if (pwsz == NULL) { UNLOCKTCLIENT (ptClient); continue; } } else { pwsz = wszBuf; } wcscpy (pwsz, ptClient->pszDomainName); wcscat (pwsz, L"\\"); wcscat (pwsz, ptClient->pszUserName); UNLOCKTCLIENT (ptClient); } else { continue; } pDomainUserName = (WCHAR *) (((LPBYTE) pNewInfoList) + pNewInfo->dwDomainUserNamesOffset); while (*pDomainUserName != L'\0') { if (lstrcmpiW (pwsz, pDomainUserName) == 0) { bHaveAccess = TRUE; break; } pDomainUserName += wcslen (pDomainUserName) + 1; } if (pwsz != wszBuf) { ServerFree (pwsz); }
//
// Does the client lose/gain the access to this device
// if any changes happen, modify the mapping
//
if (WaitForExclusiveClientAccess(ptClient)) { LPDWORD lpXxxDevices; LPTAPIPERMANENTID lpXxxMap; DWORD dwNumDev;
if (bLine) { dwNumDev = ptClient->dwLineDevices; lpXxxMap = ptClient->pLineMap; lpXxxDevices = ptClient->pLineDevices; } else { dwNumDev = ptClient->dwPhoneDevices; lpXxxMap = ptClient->pPhoneMap; lpXxxDevices = ptClient->pPhoneDevices; }
for (j = 0; j < dwNumDev; ++ j) { if (lpXxxDevices[j] == dwDeviceID) { bLoseAccess = (!bHaveAccess); break; } } if (j == dwNumDev) { bGainAccess = bHaveAccess; }
if (bLoseAccess) { lpXxxDevices[j] = 0xffffffff; lpXxxMap[j].dwDeviceID = 0xffffff; dwNewDeviceID = j; }
if (bGainAccess) { LPTAPIPERMANENTID lpNewXxxMap; LPDWORD lpNewDevices = NULL;
if (lpNewXxxMap = ServerAlloc ( sizeof(TAPIPERMANENTID) * (dwNumDev + 1))) { if (lpNewDevices = ServerAlloc ( sizeof(DWORD) * (dwNumDev + 1))) { if (dwNumDev != 0) { memcpy ( lpNewXxxMap, lpXxxMap, sizeof (TAPIPERMANENTID) * dwNumDev ); memcpy ( lpNewDevices, lpXxxDevices, sizeof (DWORD) * dwNumDev ); } lpNewDevices[dwNumDev] = dwDeviceID; lpNewXxxMap[dwNumDev] = tpid; ++ dwNumDev; } else { ServerFree (lpNewXxxMap); UNLOCKTCLIENT (ptClient); continue; } } else { UNLOCKTCLIENT(ptClient); continue; } if (bLine) { ptClient->dwLineDevices = dwNumDev; ServerFree (ptClient->pLineDevices); ptClient->pLineDevices = lpNewDevices; ServerFree (ptClient->pLineMap); ptClient->pLineMap = lpNewXxxMap; } else { ptClient->dwPhoneDevices = dwNumDev; ServerFree (ptClient->pPhoneDevices); ptClient->pPhoneDevices = lpNewDevices; ServerFree (ptClient->pPhoneMap); ptClient->pPhoneMap = lpNewXxxMap; }
dwNewDeviceID = dwNumDev - 1; } //
// Need to send messsage if there is
// any line/phoneInitialize(Ex)
//
if ((ptClient->ptLineApps && bLine) || (ptClient->ptPhoneApps && (!bLine))) { if (bLoseAccess || bGainAccess) { bSendMessage = TRUE; } } UNLOCKTCLIENT (ptClient); } else { continue; } if (bSendMessage) { ASYNCEVENTMSG msg; TPOINTERLIST xxxAppList = {0}, *pXxxAppList = &xxxAppList;
msg.TotalSize = sizeof (ASYNCEVENTMSG); msg.fnPostProcessProcHandle = 0; msg.Msg = (bLine ? (bLoseAccess? LINE_REMOVE : LINE_CREATE) : (bLoseAccess? PHONE_REMOVE: PHONE_CREATE)); msg.Param1 = dwNewDeviceID;
if (bLine) { GetLineAppListFromClient (ptClient, &pXxxAppList); } else { GetPhoneAppListFromClient (ptClient, &pXxxAppList); }
for (i = 0; i < pXxxAppList->dwNumUsedEntries; ++i) { BOOL b;
try { if (bLine) { PTLINEAPP ptLineApp = (PTLINEAPP) pXxxAppList->aEntries[i];
b = FMsgDisabled ( ptLineApp->dwAPIVersion, ptLineApp->adwEventSubMasks, (DWORD) msg.Msg, (DWORD) msg.Param1 ); msg.InitContext = ptLineApp->InitContext; } else { PTPHONEAPP ptPhoneApp = (PTPHONEAPP) pXxxAppList->aEntries[i];
b = FMsgDisabled ( ptPhoneApp->dwAPIVersion, ptPhoneApp->adwEventSubMasks, (DWORD) msg.Msg, (DWORD) msg.Param1 ); msg.InitContext = ptPhoneApp->InitContext; } } myexcept { continue; } if (b) { continue; } WriteEventBuffer (ptClient, &msg); }
if (pXxxAppList != &xxxAppList) { ServerFree (pXxxAppList); } } //
// If the user loses the device access, anything
// opened about the device needs to be closed
//
if (bLoseAccess) { //
// Walk throught all its TLINEAPP
//
if (bLine) { PTLINELOOKUPENTRY ptLineLookup; PTLINE ptLine; PTLINECLIENT ptLineClient, pNextLineClient; HANDLE hMutex; BOOL bDupedMutex; ptLineLookup = GetLineLookupEntry(dwDeviceID); if (!ptLineLookup || !(ptLine = ptLineLookup->ptLine)); { continue; } if (!WaitForExclusivetLineAccess( ptLine, &hMutex, &bDupedMutex, INFINITE )) { continue; } ptLineClient = ptLine->ptLineClients; while (ptLineClient) { if (WaitForExclusiveLineClientAccess(ptLineClient)) { pNextLineClient = ptLineClient->pNextSametLine; if (ptLineClient->ptClient == ptClient) { HLINE hLine = ptLineClient->hLine; UNLOCKTLINECLIENT (ptLineClient); DestroytLineClient(ptLineClient->hLine); } else { UNLOCKTLINECLIENT (ptLineClient); }
ptLineClient = pNextLineClient; } else { break; } } MyReleaseMutex(hMutex, bDupedMutex); }
//
// Walk throught all its TPHONEAPP
//
else { PTPHONELOOKUPENTRY ptPhoneLookup; PTPHONE ptPhone; PTPHONECLIENT ptPhoneClient, pNextPhoneClient; HANDLE hMutex; BOOL bDupedMutex; ptPhoneLookup = GetPhoneLookupEntry(dwDeviceID); if (!ptPhoneLookup || !(ptPhone = ptPhoneLookup->ptPhone)); { continue; } if (!WaitForExclusivetPhoneAccess( ptPhone, &hMutex, &bDupedMutex, INFINITE )) { continue; } ptPhoneClient = ptPhone->ptPhoneClients; while (ptPhoneClient) { if (WaitForExclusivePhoneClientAccess(ptPhoneClient)) { pNextPhoneClient = ptPhoneClient->pNextSametPhone; if (ptPhoneClient->ptClient == ptClient) { HPHONE hPhone = ptPhoneClient->hPhone; UNLOCKTPHONECLIENT (ptPhoneClient); DestroytPhoneClient(ptPhoneClient->hPhone); } else { UNLOCKTPHONECLIENT (ptPhoneClient); }
ptPhoneClient = pNextPhoneClient; } else { break; } } MyReleaseMutex (hMutex, bDupedMutex); } } } if (pClientList != &clientList) { ServerFree (pClientList); } } }
//
// Reset the dwNeededSize field since it might have grown adding
// users to devices
//
(*ppXxxList)->dwNeededSize = (*ppXxxList)->dwUsedSize;
exit:
return; }
void WINAPI MSetLineInfo( PTCLIENT ptClient, PMMCSETDEVICEINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bDidLock;
if (WaitForExclusiveClientAccess(ptClient)) { bDidLock = IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE); UNLOCKTCLIENT (ptClient); } else { bDidLock = FALSE; }
EnterCriticalSection (&gMgmtCritSec);
if (gbLockMMCWrite && !bDidLock) { pParams->lResult = TAPIERR_MMCWRITELOCKED; } else { SetDeviceInfo( pParams, dwParamsBufferSize, pDataBuf, pdwNumBytesReturned, TRUE ); UpdateLastWriteTime(TRUE); }
LeaveCriticalSection (&gMgmtCritSec);
}
void WINAPI MSetPhoneInfo( PTCLIENT ptClient, PMMCSETDEVICEINFO_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { BOOL bDidLock;
if (WaitForExclusiveClientAccess(ptClient)) { bDidLock = IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE); UNLOCKTCLIENT (ptClient); } else { bDidLock = FALSE; }
EnterCriticalSection (&gMgmtCritSec);
if (gbLockMMCWrite && !bDidLock) { pParams->lResult = TAPIERR_MMCWRITELOCKED; } else { SetDeviceInfo( pParams, dwParamsBufferSize, pDataBuf, pdwNumBytesReturned, FALSE ); UpdateLastWriteTime(FALSE); }
LeaveCriticalSection (&gMgmtCritSec); }
VOID PASCAL InsertString( LPVOID pStruct, LPDWORD pdwXxxSize, LPWSTR pString ) { DWORD dwSize = (wcslen (pString) + 1) * sizeof (WCHAR);
CopyMemory( ((LPBYTE) pStruct) + ((LPVARSTRING) pStruct)->dwUsedSize, pString, dwSize );
if (*pdwXxxSize == 0) // if dwXxxSize == 0 set dwXxxOffset
{ *(pdwXxxSize + 1) = ((LPVARSTRING) pStruct)->dwUsedSize; }
((LPVARSTRING) pStruct)->dwUsedSize += dwSize;
*pdwXxxSize += dwSize; }
LONG PASCAL GetDomainAndUserNames( WCHAR **ppDomainName, WCHAR **ppUserName ) { LONG lResult = LINEERR_OPERATIONFAILED; DWORD dwInfoBufferSize, dwSize, dwAccountNameSize, dwDomainNameSize; HANDLE hAccessToken; LPWSTR InfoBuffer, lpszAccountName, lpszDomainName; PTOKEN_USER ptuUser; SID_NAME_USE use;
if (!OpenProcessToken (GetCurrentProcess(), TOKEN_READ, &hAccessToken)) { LOG((TL_ERROR, "GetAccountInfo: OpenThreadToken failed, error=%d", GetLastError() ));
goto GetDomainAndUserNames_return; }
dwSize = 1000; dwInfoBufferSize = 0; InfoBuffer = (LPWSTR) ServerAlloc (dwSize); if (!InfoBuffer) { CloseHandle (hAccessToken); return LINEERR_NOMEM; }
ptuUser = (PTOKEN_USER) InfoBuffer;
if (!GetTokenInformation( hAccessToken, TokenUser, InfoBuffer, dwSize, &dwInfoBufferSize )) { LOG((TL_ERROR, "GetAccountInfo: GetTokenInformation failed, error=%d", GetLastError() ));
goto close_AccessToken; }
if (!(lpszAccountName = ServerAlloc (200))) { lResult = LINEERR_NOMEM; goto free_InfoBuffer; }
if (!(lpszDomainName = ServerAlloc (200))) { lResult = LINEERR_NOMEM; goto free_AccountName; }
dwAccountNameSize = dwDomainNameSize = 200;
if (!LookupAccountSidW( NULL, ptuUser->User.Sid, lpszAccountName, &dwAccountNameSize, lpszDomainName, &dwDomainNameSize, &use )) { LOG((TL_ERROR, "GetAccountInfo: LookupAccountSidW failed, error=%d", GetLastError() )); } else { LOG((TL_INFO, "GetAccountInfo: User name %ls Domain name %ls", lpszAccountName, lpszDomainName ));
lResult = 0;
*ppDomainName = lpszDomainName; *ppUserName = lpszAccountName;
goto free_InfoBuffer; }
ServerFree (lpszDomainName);
free_AccountName:
ServerFree (lpszAccountName);
free_InfoBuffer:
ServerFree (InfoBuffer);
close_AccessToken:
CloseHandle (hAccessToken);
GetDomainAndUserNames_return:
return lResult; }
BOOL IsNTServer( void ) { BOOL bResult = FALSE; TCHAR szProductType[64]; HKEY hKey; DWORD dwDataSize; DWORD dwDataType;
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszRegKeyNTServer, 0, KEY_QUERY_VALUE, &hKey
) == ERROR_SUCCESS) { dwDataSize = 64*sizeof(TCHAR);
if (RegQueryValueEx( hKey, gszProductType, 0, &dwDataType, (LPBYTE) szProductType, &dwDataSize
) == ERROR_SUCCESS)
if ((!lstrcmpi (szProductType, gszProductTypeServer)) || (!lstrcmpi (szProductType, gszProductTypeLanmanNt))) { bResult = TRUE; }
RegCloseKey (hKey); }
return bResult; }
BOOL IsSharingEnabled( void ) { HKEY hKey; BOOL bResult = FALSE; DWORD dwType, dwDisableSharing;
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Server"), 0, KEY_ALL_ACCESS, &hKey
) == ERROR_SUCCESS) { DWORD dwSize = sizeof (dwDisableSharing);
dwDisableSharing = 1; // default is sharing == disabled
if (RegQueryValueEx( hKey, TEXT("DisableSharing"), 0, &dwType, (LPBYTE) &dwDisableSharing, &dwSize
) == ERROR_SUCCESS) { bResult = (dwDisableSharing ? FALSE : TRUE); }
RegCloseKey (hKey); }
return bResult; }
void WINAPI MGetServerConfig( PTCLIENT ptClient, PMMCGETSERVERCONFIG_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LONG lResult; DWORD dwDomainNameSize, dwUserNameSize, dwValuesSize, dwResult, dwNeededSize; WCHAR *pValues = NULL, *pValue; LPWSTR pDomainName, pUserName; LPTAPISERVERCONFIG pServerConfig = (LPTAPISERVERCONFIG) pDataBuf;
//
// Verify size/offset/string params given our input buffer/size
//
if (pParams->dwServerConfigTotalSize > dwParamsBufferSize) { pParams->lResult = LINEERR_OPERATIONFAILED; return; }
//
// Make sure the buffer is >= fixed size of the structure
//
if (pParams->dwServerConfigTotalSize < sizeof (*pServerConfig)) { pParams->lResult = LINEERR_STRUCTURETOOSMALL; return; }
pServerConfig->dwTotalSize = pParams->dwServerConfigTotalSize;
//
// If this is not an NT server then just set the needed/used size
// fields & jump to done
//
if (!IsNTServer()) { pServerConfig->dwNeededSize = pServerConfig->dwUsedSize = sizeof (*pServerConfig);
goto MGetServerConfig_done; }
//
// Retrieve domain & user name strings, & calc their length in bytes
//
if ((lResult = GetDomainAndUserNames (&pDomainName, &pUserName))) { pParams->lResult = lResult; return; }
dwDomainNameSize = (wcslen (pDomainName) + 1) * sizeof (WCHAR); dwUserNameSize = (wcslen (pUserName) + 1) * sizeof (WCHAR);
//
// Retrieve the list of tapi administrators
//
do { if (pValues) { ServerFree (pValues);
dwValuesSize *= 2; } else { dwValuesSize = 256; }
if (!(pValues = ServerAlloc (dwValuesSize * sizeof (WCHAR)))) { pParams->lResult = LINEERR_NOMEM; goto MGetServerConfig_freeNames; }
pValues[0] = L'\0';
dwResult = GetPrivateProfileSectionW( gszTapiAdministrators, pValues, dwValuesSize, gszFileName );
} while (dwResult >= (dwValuesSize - 2));
dwNeededSize = dwDomainNameSize + dwUserNameSize + dwValuesSize;
//
// Fill in the server config structure
//
ZeroMemory( &pServerConfig->dwFlags, sizeof (*pServerConfig) - (3 * sizeof (DWORD)) );
pServerConfig->dwFlags |= TAPISERVERCONFIGFLAGS_ISSERVER;
if (IsSharingEnabled()) { pServerConfig->dwFlags |= TAPISERVERCONFIGFLAGS_ENABLESERVER; }
if (pServerConfig->dwTotalSize < dwNeededSize) { pServerConfig->dwNeededSize = dwNeededSize; pServerConfig->dwUsedSize = sizeof (*pServerConfig); } else { pServerConfig->dwUsedSize = sizeof (*pServerConfig);
InsertString( pServerConfig, &pServerConfig->dwDomainNameSize, pDomainName );
InsertString( pServerConfig, &pServerConfig->dwUserNameSize, pUserName );
pValue = pValues;
while (*pValue != L'\0') { //
// The string looks like "Domain\User=1", and we want
// the "Domain\User" part.
//
//
// Walk the string until we find a '=' char, or ' ' space
// (which might result from user editing ini file manually),
// or a NULL char (implying corruption).
//
WCHAR *p;
for (p = pValue; *p != L'\0' && *p != L'=' && *p != L' '; p++);
//
// If we found a '=' or ' ' char then we're good to go.
//
// A more robust check would be to see that the following
// string looks like "=1" or "1" (possibly with some spaces
// thrown in) to make sure.
//
if (*p != L'\0') { *p = L'\0';
InsertString( pServerConfig, &pServerConfig->dwAdministratorsSize, pValue );
//
// Skip the NULL we set above & look for the next NULL
//
for (++p; *p != L'\0'; p++); }
//
// Skip the NULL
//
pValue = p + 1; }
if (pServerConfig->dwAdministratorsSize) { InsertString( pServerConfig, &pServerConfig->dwAdministratorsSize, gszEmptyString ); }
pServerConfig->dwNeededSize = pServerConfig->dwUsedSize; }
ServerFree (pValues);
MGetServerConfig_freeNames:
ServerFree (pDomainName); ServerFree (pUserName);
MGetServerConfig_done:
if (pParams->lResult == 0) { pParams->dwServerConfigOffset = 0;
*pdwNumBytesReturned = sizeof (TAPI32_MSG) + pServerConfig->dwUsedSize; } }
LONG PASCAL WriteRegistryKeys( LPTSTR lpszMapper, LPTSTR lpszDlls, DWORD dwDisableSharing ) { LONG lResult = LINEERR_OPERATIONFAILED; HKEY hKeyTelephony, hKey; DWORD dw;
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony"), 0, KEY_ALL_ACCESS, &hKeyTelephony
) == ERROR_SUCCESS) { if (RegCreateKeyEx( hKeyTelephony, TEXT("Server"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dw
) == ERROR_SUCCESS) { if (RegSetValueEx( hKey, TEXT("DisableSharing"), 0, REG_DWORD, (LPBYTE) &dwDisableSharing, sizeof (dwDisableSharing)
) == ERROR_SUCCESS &&
RegSetValueEx( hKey, TEXT("MapperDll"), 0, REG_SZ, (LPBYTE) TEXT ("TSEC.DLL"), (lstrlen (TEXT ("TSEC.DLL")) + 1) * sizeof (TCHAR)
) == ERROR_SUCCESS) { lResult = 0; }
RegCloseKey (hKeyTelephony); }
RegCloseKey (hKey); }
return lResult; }
LONG PASCAL WriteServiceConfig( LPWSTR pDomainName, LPWSTR pUserName, LPWSTR pPassword, BOOL bServer ) { LONG lResult = LINEERR_OPERATIONFAILED; SC_HANDLE sch, sc_tapisrv;
if ((sch = OpenSCManager (NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE))) { if ((sc_tapisrv = OpenService( sch, TEXT("TAPISRV"), SERVICE_CHANGE_CONFIG ))) { DWORD dwSize; WCHAR *pDomainUserName;
dwSize = (wcslen (pDomainName) + wcslen (pUserName) + 2) *\ sizeof (WCHAR);
if ((pDomainUserName = ServerAlloc (dwSize))) { wcscpy (pDomainUserName, pDomainName); wcscat (pDomainUserName, L"\\"); wcscat (pDomainUserName, pUserName);
if ((ChangeServiceConfigW( sc_tapisrv, SERVICE_WIN32_OWN_PROCESS, bServer ? SERVICE_AUTO_START : SERVICE_DEMAND_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, pDomainUserName, pPassword, NULL ))) { lResult = 0; } else { LOG((TL_ERROR, "WriteServiceConfig: ChangeServiceConfig " \ "failed, err=%ld", GetLastError() )); }
ServerFree (pDomainUserName); } else { lResult = LINEERR_NOMEM; }
CloseServiceHandle(sc_tapisrv); }
CloseServiceHandle(sch); }
return lResult; }
void WINAPI MSetServerConfig( PTCLIENT ptClient, PMMCSETSERVERCONFIG_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { LONG lResult; BOOL bIsSharingEnabled; LPTAPISERVERCONFIG pServerConfig = (LPTAPISERVERCONFIG) (pDataBuf + pParams->dwServerConfigOffset);
pParams->lResult = 0;
//
// Verify size/offset/string params given our input buffer/size
//
if (IsBadStructParam( dwParamsBufferSize, pDataBuf, pParams->dwServerConfigOffset )) { pParams->lResult = PHONEERR_OPERATIONFAILED; return; }
if (!IsNTServer()) { pParams->lResult = LINEERR_OPERATIONFAILED; return; }
bIsSharingEnabled = IsSharingEnabled();
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_LOCKMMCWRITE) { EnterCriticalSection (&gMgmtCritSec); if (gbLockMMCWrite) { pParams->lResult = TAPIERR_MMCWRITELOCKED; } else { gbLockMMCWrite = TRUE; } LeaveCriticalSection (&gMgmtCritSec); if (pParams->lResult) { return; } else if (WaitForExclusiveClientAccess (ptClient)) { SET_FLAG (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE); UNLOCKTCLIENT (ptClient); } }
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_UNLOCKMMCWRITE && WaitForExclusiveClientAccess (ptClient)) { BOOL bToUnlock;
bToUnlock = IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE); RESET_FLAG (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE); UNLOCKTCLIENT (ptClient);
if (bToUnlock) { EnterCriticalSection (&gMgmtCritSec); gbLockMMCWrite = FALSE; LeaveCriticalSection (&gMgmtCritSec); } }
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_SETACCOUNT) { HANDLE hToken; LPWSTR pUserName, pDomainName, pPassword;
pUserName = (LPWSTR) (((LPBYTE) pServerConfig) + pServerConfig->dwUserNameOffset);
pDomainName = (LPWSTR) (((LPBYTE) pServerConfig) + pServerConfig->dwDomainNameOffset);
pPassword = (LPWSTR) (((LPBYTE) pServerConfig) + pServerConfig->dwPasswordOffset);
//
// Make sure the new name/domain/password are valid
//
if (!LogonUserW( pUserName, pDomainName, pPassword, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hToken )) { LOG((TL_ERROR, "MSetServerConfig: LogonUser failed, err=%ld", GetLastError() ));
pParams->lResult = ERROR_LOGON_FAILURE; return; }
CloseHandle (hToken);
//
//
//
if ((lResult = WriteServiceConfig( pDomainName, pUserName, pPassword, (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER) ))) { LOG((TL_ERROR, "MSetServerConfig: WriteServiceConfig failed, err=%ld", lResult ));
pParams->lResult = lResult; return; } }
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER && !bIsSharingEnabled) { if ((pParams->lResult = CreateTapiSCP (NULL, NULL)) != 0) { LOG((TL_ERROR, "MSetServerConfig: CreateTapiSCP failed, err=%ld", pParams->lResult )); return; } } else if (!(pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER) && bIsSharingEnabled) { if ((pParams->lResult = RemoveTapiSCP ()) != 0) { LOG((TL_ERROR, "MSetServerConfig: RemoveTapiSCP failed, err=%ld", pParams->lResult )); return; } else { // This is not a Telephony server anymore, so reset the flag
TapiGlobals.dwFlags = TapiGlobals.dwFlags & ~TAPIGLOBALS_SERVER; } } if ((lResult = WriteRegistryKeys( NULL, NULL, (DWORD) ((pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER) ? 0 : 1) ))) { LOG((TL_ERROR, "MSetServerConfig: WriteRegistryKeys failed, err=%ld", lResult )); pParams->lResult = LINEERR_OPERATIONFAILED; return; }
if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_SETTAPIADMINISTRATORS) { WCHAR *pAdmin, buf[16]; DWORD i;
//
// Reset the TapiAdministrators section
//
if (WritePrivateProfileSectionW( gszTapiAdministrators, L"\0", gszFileName) == 0) { pParams->lResult = LINEERR_OPERATIONFAILED; return; }
pAdmin = (WCHAR *) (((LPBYTE) pServerConfig) + pServerConfig->dwAdministratorsOffset);
//
// For each admin in the list write out a "Domain\User=1"
// value to the TapiAdministrators section
//
for (i = 0; *pAdmin != L'\0'; i++) { if (WritePrivateProfileStringW( gszTapiAdministrators, pAdmin, L"1", gszFileName ) == 0) { pParams->lResult = LINEERR_OPERATIONFAILED; return; }
pAdmin += (wcslen (pAdmin) + 1); } } }
typedef BOOL ( APIENTRY GETFILEVERSIONINFO( LPWSTR lptstrFilename, // pointer to filename string
DWORD dwHandle, // ignored
DWORD dwLen, // size of buffer
LPVOID lpData // pointer to buffer to receive file-version info.
)); typedef DWORD ( APIENTRY GETFILEVERSIONINFOSIZE( LPWSTR lptstrFilename, // pointer to filename string
LPDWORD lpdwHandle // pointer to variable to receive zero
)); typedef BOOL ( APIENTRY VERQUERYVALUE( const LPVOID pBlock, // address of buffer for version resource
LPWSTR lpSubBlock, // address of value to retrieve
LPVOID *lplpBuffer, // address of buffer for version pointer
PUINT puLen // address of version-value length buffer
));
static WCHAR gszVarFileInfo[] = L"\\VarFileInfo\\Translation"; static WCHAR gszStringFileInfo[] = L"\\StringFileInfo\\%04x%04x\\FileDescription";
//
// EmanP
// Given a multisz of file names,
// allocates a multisz of friendly names.
// Returns the number of bytes in the frienly name multisz
//
//
DWORD GetProviderFriendlyName( /*IN */ WCHAR *pFileNameBuf, /*OUT*/ WCHAR **ppFriendlyNameBuf ) { DWORD dwBufTotalSize = 0, dwBufUsedSize = 0, dwVerSize = 0, dwSize, dwVerHandle; UINT uItemSize; HINSTANCE hVerDll; GETFILEVERSIONINFO *pGetFileVersionInfo; GETFILEVERSIONINFOSIZE *pGetFileVersionInfoSize; VERQUERYVALUE *pVerQueryValue; WCHAR *pFileName = pFileNameBuf, *pszBuffer, *pFriendlyNameBuf = NULL, *p; BYTE *pbVerData = NULL; WCHAR szItem[1024]; WORD wLangID; WORD wUserLangID; WORD wCodePage; DWORD dwIdx;
if (NULL == pFileName || NULL == ppFriendlyNameBuf) { return 0; }
//
// First, load VERSION.DLL
//
hVerDll = LoadLibrary( TEXT("Version.dll") );
if ( NULL == hVerDll ) { LOG((TL_ERROR, "LoadLibrary('VERSION.DLL') failed! err=0x%08lx", GetLastError() ));
return 0; }
//
// Now, get the needed entry points into VERSION.DLL.
// Use only UNICODE versions.
//
pGetFileVersionInfo = (GETFILEVERSIONINFO*) GetProcAddress( hVerDll, "GetFileVersionInfoW" );
if ( NULL == pGetFileVersionInfo ) { LOG((TL_ERROR, "GetProcAddress('VERSION.DLL', 'GetFileVersionInfoW') " \ "failed! err=0x%08lx", GetLastError() ));
goto _Return; }
pGetFileVersionInfoSize = (GETFILEVERSIONINFOSIZE *) GetProcAddress( hVerDll, "GetFileVersionInfoSizeW" );
if ( NULL == pGetFileVersionInfoSize ) { LOG((TL_ERROR, "GetProcAddress('VERSION.DLL', 'GetFileVersionInfoSizeW') " \ "failed! err=0x%08lx", GetLastError() ));
goto _Return; }
pVerQueryValue = (VERQUERYVALUE *) GetProcAddress( hVerDll, "VerQueryValueW" );
if ( NULL == pVerQueryValue ) { LOG((TL_ERROR, "GetProcAddress('VERSION.DLL', 'VerQueryValueW') " \ "failed! err=0x%08lx", GetLastError() ));
goto _Return; }
//
// Get the current UI language ( this is needed if MUI is enabled )
//
wUserLangID = GetUserDefaultUILanguage ();
//
// For each filename in the input multisz,
// try to get it's friendly name. If anything fails,
// make the friendly name the same as the file name.
//
for (; 0 != *pFileName; pFileName += lstrlenW(pFileName)+1) { pszBuffer = NULL;
//
// 1. Get the size needed for the verion resource
//
if ((dwSize = pGetFileVersionInfoSize( pFileName, &dwVerHandle )) == 0) { LOG((TL_ERROR, "GetFileVersionInfoSize failure for %S", pFileName )); goto _UseFileName; }
//
// 2. If our current buffer is smaller than needed, reallocate it.
//
if (dwSize > dwVerSize) { if (NULL != pbVerData) { ServerFree (pbVerData); }
dwVerSize = dwSize + 16; pbVerData = ServerAlloc( dwVerSize ); if ( pbVerData == NULL ) { dwVerSize = 0; goto _UseFileName; } }
//
// 3. Now, get the version information for the file.
//
if (pGetFileVersionInfo( pFileName, dwVerHandle, dwVerSize, pbVerData
) == FALSE ) { LOG((TL_ERROR, "GetFileVersionInfo failure for %S", pFileName )); goto _UseFileName; }
//
// 4. Get the Language/Code page translation
//
// NOTE: bug in VerQueryValue, can't handle static CS based str
//
lstrcpyW ( szItem, gszVarFileInfo );
if ((pVerQueryValue( pbVerData, szItem, &pszBuffer, (LPUINT) &uItemSize
) == FALSE) ||
(uItemSize == 0)) { LOG((TL_ERROR, "ERROR: VerQueryValue failure for %S on file %S", szItem, pFileName ));
pszBuffer = NULL; goto _UseFileName; }
wCodePage = 0; wLangID = wUserLangID;
//
// lookup the current user UI language ID in the file version info
//
if (0 != wLangID) { for( dwIdx=0; dwIdx < uItemSize/sizeof(DWORD); dwIdx++ ) { if ( *(WORD*)((DWORD*)pszBuffer + dwIdx) == wLangID ) { wCodePage = *( (WORD*)((DWORD*)pszBuffer + dwIdx) + 1); break; } } if( dwIdx == uItemSize/sizeof(DWORD) ) { wLangID = 0; } }
//
// if GetUserDefaultUILanguage() failed,
// or the current user UI language doesn't show up in the file version info
// just use the first language in the file version
//
if (0 == wLangID) { wLangID = *(LPWORD)pszBuffer; wCodePage = *(((LPWORD)pszBuffer)+1); }
//
// 5. Get the FileDescription in the language obtained above.
// (We use the FileDescription as friendly name).
//
wsprintfW( szItem, gszStringFileInfo, wLangID, wCodePage );
if ((pVerQueryValue( pbVerData, szItem, &pszBuffer, (LPUINT) &uItemSize
) == FALSE) ||
(uItemSize == 0)) { LOG((TL_ERROR, "ERROR: VerQueryValue failure for %S on file %S", szItem, pFileName ));
pszBuffer = NULL; goto _UseFileName; }
_UseFileName:
if (NULL == pszBuffer) { //
// Something went wrong and we couldn't get
// the file description. Use the file name
// instead.
//
pszBuffer = pFileName; }
//
// At this point, pszBuffer points to a (UNICODE) string
// containing what we deem to be the friendly name.
// Let's append it to the OUT multisz.
//
dwSize = (lstrlenW (pszBuffer) + 1) * sizeof (WCHAR);
if ((dwSize + dwBufUsedSize) > dwBufTotalSize) { if (!(p = ServerAlloc (dwBufTotalSize += 512))) { //
// We don't have enough memory.
// Release what we allocated until now, and return 0.
//
if (NULL != pFriendlyNameBuf) { ServerFree (pFriendlyNameBuf); }
dwBufUsedSize = 0; break; }
if (dwBufUsedSize) { CopyMemory (p, pFriendlyNameBuf, dwBufUsedSize);
ServerFree (pFriendlyNameBuf); }
pFriendlyNameBuf = p; }
CopyMemory( ((LPBYTE) pFriendlyNameBuf) + dwBufUsedSize, pszBuffer, dwSize );
dwBufUsedSize += dwSize; }
_Return:
//
// We don't need the library anymore.
// We don't need the version buffer either.
//
FreeLibrary (hVerDll);
if (NULL != pbVerData) { ServerFree (pbVerData); }
if (0 != dwBufUsedSize) { *ppFriendlyNameBuf = pFriendlyNameBuf; }
return dwBufUsedSize; }
void WINAPI MGetDeviceFlags ( PTCLIENT ptClient, PMMCGETDEVICEFLAGS_PARAMS pParams, DWORD dwParamsBufferSize, LPBYTE pDataBuf, LPDWORD pdwNumBytesReturned ) { DWORD dwDeviceID; TAPIPERMANENTID ID;
*pdwNumBytesReturned = sizeof (TAPI32_MSG); // Support calls on line device only for now
if (!pParams->fLine) { pParams->lResult = LINEERR_OPERATIONUNAVAIL; return; }
ID.dwDeviceID = pParams->dwPermanentDeviceID; ID.dwProviderID = pParams->dwProviderID;
EnterCriticalSection(&gMgmtCritSec);
if (gpLineDevFlags == NULL) { pParams->lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; }
dwDeviceID = GetDeviceIDFromPermanentID (ID, pParams->fLine);
if (dwDeviceID == 0xffffffff || dwDeviceID >= gdwNumFlags) { pParams->lResult = LINEERR_OPERATIONUNAVAIL; goto ExitHere; }
pParams->dwDeviceID = dwDeviceID; pParams->dwFlags = gpLineDevFlags[dwDeviceID];
ExitHere: LeaveCriticalSection (&gMgmtCritSec); return; }
|