/*++ 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 , 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; }