Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4271 lines
112 KiB

  1. /*++ BUILD Version: 0000 // Increment this if a change has global effects
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. tapimmc.c
  5. Abstract:
  6. Src module for tapi server mmc-support funcs
  7. Author:
  8. Dan Knudson (DanKn) 10-Dec-1997
  9. Revision History:
  10. --*/
  11. #include "windows.h"
  12. #include "stdio.h"
  13. #include "stdlib.h"
  14. #include "assert.h"
  15. #include "tapi.h"
  16. #include "utils.h"
  17. #include "tapiclnt.h"
  18. #include "tspi.h"
  19. #include "client.h"
  20. #include "server.h"
  21. #include "tapimmc.h"
  22. #include "private.h"
  23. #include "Sddl.h"
  24. typedef struct _USERNAME_TUPLE
  25. {
  26. LPWSTR pDomainUserNames;
  27. LPWSTR pFriendlyUserNames;
  28. } USERNAME_TUPLE, *LPUSERNAME_TUPLE;
  29. typedef struct _MMCGETAVAILABLEPROVIDERS_PARAMS
  30. {
  31. union
  32. {
  33. OUT LONG lResult;
  34. };
  35. DWORD dwUnused;
  36. union
  37. {
  38. IN HLINEAPP hLineApp;
  39. };
  40. union
  41. {
  42. IN DWORD dwProviderListTotalSize; // size of client buffer
  43. OUT DWORD dwProviderListOffset; // valid offset on success
  44. };
  45. } MMCGETAVAILABLEPROVIDERS_PARAMS, *PMMCGETAVAILABLEPROVIDERS_PARAMS;
  46. typedef struct _MMCGETDEVICEINFO_PARAMS
  47. {
  48. union
  49. {
  50. OUT LONG lResult;
  51. };
  52. DWORD dwUnused;
  53. union
  54. {
  55. IN HLINEAPP hLineApp;
  56. };
  57. union
  58. {
  59. IN DWORD dwDeviceInfoListTotalSize; // size of client buffer
  60. OUT DWORD dwDeviceInfoListOffset; // valid offset on success
  61. };
  62. } MMCGETDEVICEINFO_PARAMS, *PMMCGETDEVICEINFO_PARAMS;
  63. typedef struct _MMCGETSERVERCONFIG_PARAMS
  64. {
  65. union
  66. {
  67. OUT LONG lResult;
  68. };
  69. DWORD dwUnused;
  70. union
  71. {
  72. IN HLINEAPP hLineApp;
  73. };
  74. union
  75. {
  76. IN DWORD dwServerConfigTotalSize; // size of client buffer
  77. OUT DWORD dwServerConfigOffset; // valid offset on success
  78. } ;
  79. } MMCGETSERVERCONFIG_PARAMS, *PMMCGETSERVERCONFIG_PARAMS;
  80. typedef struct _MMCSETDEVICEINFO_PARAMS
  81. {
  82. union
  83. {
  84. OUT LONG lResult;
  85. };
  86. DWORD dwUnused;
  87. union
  88. {
  89. IN HLINEAPP hLineApp;
  90. };
  91. union
  92. {
  93. IN DWORD dwDeviceInfoListOffset; // valid offset
  94. };
  95. } MMCSETDEVICEINFO_PARAMS, *PMMCSETDEVICEINFO_PARAMS;
  96. typedef struct _MMCSETSERVERCONFIG_PARAMS
  97. {
  98. union
  99. {
  100. OUT LONG lResult;
  101. };
  102. DWORD dwUnused;
  103. union
  104. {
  105. IN HLINEAPP hLineApp;
  106. };
  107. union
  108. {
  109. IN DWORD dwServerConfigOffset; // valid offset
  110. };
  111. } MMCSETSERVERCONFIG_PARAMS, *PMMCSETSERVERCONFIG_PARAMS;
  112. typedef struct _MMCGETDEVICEFLAGS_PARAMS
  113. {
  114. OUT LONG lResult;
  115. DWORD dwUnused;
  116. IN HLINEAPP hLineApp;
  117. IN DWORD fLine;
  118. IN DWORD dwProviderID;
  119. IN DWORD dwPermanentDeviceID;
  120. OUT DWORD dwFlags;
  121. OUT DWORD dwDeviceID;
  122. } MMCGETDEVICEFLAGS_PARAM, *PMMCGETDEVICEFLAGS_PARAMS;
  123. LPDEVICEINFOLIST gpLineInfoList = NULL;
  124. LPDEVICEINFOLIST gpPhoneInfoList = NULL;
  125. LPDWORD gpLineDevFlags = NULL;
  126. DWORD gdwNumFlags = 0;
  127. BOOL gbLockMMCWrite = FALSE;
  128. //
  129. // the last ftLastWriteTime of tsec.ini when we build the
  130. // gpLineInfoList or gpPhoneInfoList, we will rebuild the
  131. // *InfList if tsec.ini has been updated since then
  132. //
  133. FILETIME gftLineLastWrite = {0};
  134. FILETIME gftPhoneLastWrite = {0};
  135. CRITICAL_SECTION gMgmtCritSec;
  136. WCHAR gszLines[] = L"Lines";
  137. WCHAR gszPhones[] = L"Phones";
  138. WCHAR gszFileName[] = L"..\\TAPI\\tsec.ini";
  139. WCHAR gszEmptyString[] = L"";
  140. WCHAR gszFriendlyUserName[] = L"FriendlyUserName";
  141. WCHAR gszTapiAdministrators[] = L"TapiAdministrators";
  142. //
  143. // The following are the length of the constant strings
  144. // defined above (excluding the terminating zero). The above
  145. // string should not be changed normally. If for some
  146. // reason the above strings need to be changed, the following
  147. // CCH_constants need to be changed accordingly.
  148. //
  149. #define CCH_LINES 5
  150. #define CCH_PHONES 6
  151. #define CCH_FRIENDLYUSERNAME 16
  152. #define CCH_TAPIADMINISTRATORS 18
  153. extern TAPIGLOBALS TapiGlobals;
  154. extern TCHAR gszProductType[];
  155. extern TCHAR gszProductTypeServer[];
  156. extern TCHAR gszProductTypeLanmanNt[];
  157. extern TCHAR gszRegKeyNTServer[];
  158. extern HANDLE ghEventService;
  159. PTLINELOOKUPENTRY
  160. GetLineLookupEntry(
  161. DWORD dwDeviceID
  162. );
  163. PTPHONELOOKUPENTRY
  164. GetPhoneLookupEntry(
  165. DWORD dwDeviceID
  166. );
  167. BOOL
  168. InitTapiStruct(
  169. LPVOID pTapiStruct,
  170. DWORD dwTotalSize,
  171. DWORD dwFixedSize,
  172. BOOL bZeroInit
  173. );
  174. DWORD
  175. GetDeviceIDFromPermanentID(
  176. TAPIPERMANENTID ID,
  177. BOOL bLine
  178. );
  179. DWORD
  180. GetProviderFriendlyName(
  181. WCHAR *pFileNameBuf,
  182. WCHAR **ppFriendlyNameBuf
  183. );
  184. BOOL
  185. IsBadStructParam(
  186. DWORD dwParamsBufferSize,
  187. LPBYTE pDataBuf,
  188. DWORD dwXxxOffset
  189. );
  190. LONG
  191. PASCAL
  192. GetClientList(
  193. BOOL bAdminOnly,
  194. PTPOINTERLIST *ppList
  195. );
  196. extern CRITICAL_SECTION *gLockTable;
  197. extern DWORD gdwPointerToLockTableIndexBits;
  198. #define POINTERTOTABLEINDEX(p) \
  199. ((((ULONG_PTR) p) >> 4) & gdwPointerToLockTableIndexBits)
  200. PTCLIENT
  201. PASCAL
  202. WaitForExclusiveClientAccess(
  203. PTCLIENT ptClient
  204. );
  205. #define UNLOCKTCLIENT(p) \
  206. LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
  207. #define UNLOCKTLINECLIENT(p) \
  208. LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
  209. #define UNLOCKTPHONECLIENT(p) \
  210. LeaveCriticalSection(&gLockTable[POINTERTOTABLEINDEX(p)])
  211. BOOL
  212. PASCAL
  213. WaitForExclusivetLineAccess(
  214. PTLINE ptLine,
  215. HANDLE *phMutex,
  216. BOOL *pbDupedMutex,
  217. DWORD dwTimeout
  218. );
  219. BOOL
  220. PASCAL
  221. WaitForExclusiveLineClientAccess(
  222. PTLINECLIENT ptLineClient
  223. );
  224. BOOL
  225. PASCAL
  226. WaitForExclusivetPhoneAccess(
  227. PTPHONE ptPhone,
  228. HANDLE *phMutex,
  229. BOOL *pbDupedMutex,
  230. DWORD dwTimeout
  231. );
  232. BOOL
  233. PASCAL
  234. WaitForExclusivePhoneClientAccess(
  235. PTPHONECLIENT ptPhoneClient
  236. );
  237. void
  238. DestroytPhoneClient(
  239. HPHONE hPhone
  240. );
  241. void
  242. PASCAL
  243. DestroytLineClient(
  244. HLINE hLine
  245. );
  246. LONG
  247. PASCAL
  248. GetLineAppListFromClient(
  249. PTCLIENT ptClient,
  250. PTPOINTERLIST *ppList
  251. );
  252. LONG
  253. PASCAL
  254. GetPhoneAppListFromClient(
  255. PTCLIENT ptClient,
  256. PTPOINTERLIST *ppList
  257. );
  258. void
  259. WINAPI
  260. MGetAvailableProviders(
  261. PTCLIENT ptClient,
  262. PMMCGETAVAILABLEPROVIDERS_PARAMS pParams,
  263. DWORD dwParamsBufferSize,
  264. LPBYTE pDataBuf,
  265. LPDWORD pdwNumBytesReturned
  266. )
  267. {
  268. WCHAR szPath[MAX_PATH+8], *pFileNameBuf,
  269. *pFriendlyNameBuf, *p, *p2;
  270. DWORD dwFileNameBufTotalSize, dwFileNameBufUsedSize,
  271. dwFriendlyNameBufTotalSize,
  272. dwFriendlyNameBufUsedSize,
  273. dwNumProviders, dwSize, i;
  274. HANDLE hFind;
  275. WIN32_FIND_DATAW findData;
  276. LPAVAILABLEPROVIDERLIST pList = (LPAVAILABLEPROVIDERLIST) pDataBuf;
  277. //
  278. // Verify size/offset/string params given our input buffer/size
  279. //
  280. if (pParams->dwProviderListTotalSize > dwParamsBufferSize)
  281. {
  282. pParams->lResult = LINEERR_OPERATIONFAILED;
  283. return;
  284. }
  285. if (pParams->dwProviderListTotalSize < sizeof (AVAILABLEPROVIDERLIST))
  286. {
  287. pParams->lResult = LINEERR_STRUCTURETOOSMALL;
  288. return;
  289. }
  290. pList->dwTotalSize = pParams->dwProviderListTotalSize;
  291. pList->dwNeededSize =
  292. pList->dwUsedSize = sizeof (*pList);
  293. pList->dwNumProviderListEntries =
  294. pList->dwProviderListSize =
  295. pList->dwProviderListOffset = 0;
  296. pParams->dwProviderListOffset = 0;
  297. //
  298. // Find all the files in the system directory with the extenion .TSP
  299. //
  300. GetSystemDirectoryW (szPath, MAX_PATH);
  301. wcscat (szPath, L"\\*.TSP");
  302. if ((hFind = FindFirstFileW (szPath, &findData)) == INVALID_HANDLE_VALUE)
  303. {
  304. LOG((TL_ERROR,
  305. "MGetAvailableProviders: FindFirstFile err=%d",
  306. GetLastError()
  307. ));
  308. goto done;
  309. }
  310. dwNumProviders =
  311. dwFileNameBufTotalSize =
  312. dwFileNameBufUsedSize = 0;
  313. do
  314. {
  315. LOG((TL_INFO,
  316. "MGetAvailableProviders: found '%ws'",
  317. findData.cFileName
  318. ));
  319. dwSize = (wcslen (findData.cFileName) + 1) * sizeof (WCHAR);
  320. if ((dwSize + dwFileNameBufUsedSize) > dwFileNameBufTotalSize)
  321. {
  322. if (!(p = ServerAlloc (dwFileNameBufTotalSize += 512)))
  323. {
  324. FindClose (hFind);
  325. pParams->lResult = LINEERR_NOMEM;
  326. return;
  327. }
  328. if (dwFileNameBufUsedSize)
  329. {
  330. CopyMemory (p, pFileNameBuf, dwFileNameBufUsedSize);
  331. ServerFree (pFileNameBuf);
  332. }
  333. pFileNameBuf = p;
  334. }
  335. CopyMemory(
  336. ((LPBYTE) pFileNameBuf) + dwFileNameBufUsedSize,
  337. findData.cFileName,
  338. dwSize
  339. );
  340. dwFileNameBufUsedSize += dwSize;
  341. dwNumProviders++;
  342. } while (FindNextFileW (hFind, &findData));
  343. FindClose (hFind);
  344. //
  345. // For each of the files we found above get their "friendly" name
  346. // (use the module name if there's no friendly name)
  347. //
  348. RpcImpersonateClient (0);
  349. dwFriendlyNameBufUsedSize = GetProviderFriendlyName (pFileNameBuf, &pFriendlyNameBuf);
  350. RpcRevertToSelf();
  351. if (0 == dwFriendlyNameBufUsedSize)
  352. {
  353. pFriendlyNameBuf = pFileNameBuf;
  354. dwFriendlyNameBufUsedSize = dwFileNameBufUsedSize;
  355. }
  356. pList->dwNeededSize +=
  357. (dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY)) +
  358. dwFileNameBufUsedSize +
  359. dwFriendlyNameBufUsedSize;
  360. //
  361. // Now if there's enough room in the buffer for everything then
  362. // pack it all in there
  363. //
  364. if (pList->dwNeededSize <= pList->dwTotalSize)
  365. {
  366. DWORD dwNumAvailProviders;
  367. LPAVAILABLEPROVIDERENTRY pEntry = (LPAVAILABLEPROVIDERENTRY)
  368. (pList + 1);
  369. pList->dwUsedSize += dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY);
  370. p = pFileNameBuf;
  371. p2 = pFriendlyNameBuf;
  372. for (i = dwNumAvailProviders = 0; i < dwNumProviders; i++)
  373. {
  374. HANDLE hTsp;
  375. if (!(hTsp = LoadLibraryW (p)))
  376. {
  377. //
  378. // If we can't even load the tsp then ignore it
  379. //
  380. p += wcslen (p) + 1;
  381. p2 += wcslen (p2) + 1;
  382. continue;
  383. }
  384. if (GetProcAddress (hTsp, "TSPI_providerInstall"))
  385. {
  386. pEntry->dwOptions = AVAILABLEPROVIDER_INSTALLABLE;
  387. }
  388. else
  389. {
  390. pEntry->dwOptions = 0;
  391. }
  392. if (GetProcAddress (hTsp, "TSPI_providerConfig") ||
  393. GetProcAddress (hTsp, "TUISPI_providerConfig"))
  394. {
  395. pEntry->dwOptions |= AVAILABLEPROVIDER_CONFIGURABLE;
  396. }
  397. if (GetProcAddress (hTsp, "TSPI_providerRemove"))
  398. {
  399. pEntry->dwOptions |= AVAILABLEPROVIDER_REMOVABLE;
  400. }
  401. FreeLibrary (hTsp);
  402. pEntry->dwFileNameSize = (wcslen (p) + 1) * sizeof (WCHAR);
  403. pEntry->dwFileNameOffset = pList->dwUsedSize;
  404. CopyMemory(
  405. ((LPBYTE) pList) + pEntry->dwFileNameOffset,
  406. p,
  407. pEntry->dwFileNameSize
  408. );
  409. pList->dwUsedSize += pEntry->dwFileNameSize;
  410. p += pEntry->dwFileNameSize / sizeof (WCHAR);
  411. pEntry->dwFriendlyNameSize = (wcslen (p2) + 1) * sizeof (WCHAR);
  412. pEntry->dwFriendlyNameOffset = pList->dwUsedSize;
  413. CopyMemory(
  414. ((LPBYTE) pList) + pEntry->dwFriendlyNameOffset,
  415. p2,
  416. pEntry->dwFriendlyNameSize
  417. );
  418. pList->dwUsedSize += pEntry->dwFriendlyNameSize;
  419. p2 += pEntry->dwFriendlyNameSize / sizeof (WCHAR);
  420. dwNumAvailProviders++; pEntry++;
  421. }
  422. pList->dwNumProviderListEntries = dwNumAvailProviders;
  423. pList->dwProviderListSize =
  424. dwNumProviders * sizeof (AVAILABLEPROVIDERENTRY);
  425. pList->dwProviderListOffset = sizeof (*pList);
  426. }
  427. ServerFree (pFileNameBuf);
  428. if (pFriendlyNameBuf != pFileNameBuf)
  429. {
  430. ServerFree (pFriendlyNameBuf);
  431. }
  432. done:
  433. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pList->dwUsedSize;
  434. pParams->lResult = 0;
  435. }
  436. DWORD
  437. PASCAL
  438. MyGetPrivateProfileString(
  439. LPCWSTR pszSection,
  440. LPCWSTR pszKey,
  441. LPCWSTR pszDefault,
  442. LPWSTR *ppBuf,
  443. LPDWORD pdwBufSize
  444. )
  445. {
  446. DWORD dwResult;
  447. while (1)
  448. {
  449. dwResult = GetPrivateProfileStringW(
  450. pszSection,
  451. pszKey,
  452. pszDefault,
  453. *ppBuf,
  454. *pdwBufSize / sizeof (WCHAR),
  455. gszFileName
  456. );
  457. if (dwResult < ((*pdwBufSize) / sizeof(WCHAR) - 2))
  458. {
  459. return 0;
  460. }
  461. ServerFree (*ppBuf);
  462. *pdwBufSize *= 2;
  463. if (!(*ppBuf = ServerAlloc (*pdwBufSize)))
  464. {
  465. break;
  466. }
  467. }
  468. return LINEERR_NOMEM;
  469. }
  470. DWORD
  471. PASCAL
  472. InsertInfoListString(
  473. LPDEVICEINFOLIST *ppInfoList,
  474. DWORD dwInfoIndex,
  475. DWORD dwXxxSizeFieldOffset,
  476. LPWSTR psz,
  477. DWORD dwLength,
  478. BOOL bAppendNull
  479. )
  480. {
  481. LPDWORD pdwXxxSize;
  482. LPDEVICEINFO pInfo;
  483. LPDEVICEINFOLIST pInfoList = *ppInfoList;
  484. if (!dwLength)
  485. {
  486. return 0;
  487. }
  488. //
  489. // If the existing buffer is too small the alloc a larger one
  490. //
  491. if ((pInfoList->dwUsedSize + dwLength + sizeof (WCHAR)) >
  492. pInfoList->dwTotalSize)
  493. {
  494. DWORD dwTotalSize = (*ppInfoList)->dwTotalSize + dwLength + 4096;
  495. if (!(pInfoList = ServerAlloc (dwTotalSize)))
  496. {
  497. return LINEERR_NOMEM;
  498. }
  499. CopyMemory (pInfoList, *ppInfoList, (*ppInfoList)->dwUsedSize);
  500. pInfoList->dwTotalSize = dwTotalSize;;
  501. ServerFree (*ppInfoList);
  502. *ppInfoList = pInfoList;
  503. }
  504. CopyMemory (((LPBYTE) pInfoList) + pInfoList->dwUsedSize, psz, dwLength);
  505. pInfo = ((LPDEVICEINFO)(pInfoList + 1)) + dwInfoIndex;
  506. pdwXxxSize = (LPDWORD) (((LPBYTE) pInfo) + dwXxxSizeFieldOffset);
  507. if ((*pdwXxxSize += dwLength) == dwLength)
  508. {
  509. *(pdwXxxSize + 1) = pInfoList->dwUsedSize;
  510. }
  511. pInfoList->dwUsedSize += dwLength;
  512. if (bAppendNull)
  513. {
  514. *((WCHAR *)(((LPBYTE) pInfoList) + pInfoList->dwUsedSize)) = L'\0';
  515. pInfoList->dwUsedSize += sizeof (WCHAR);
  516. *pdwXxxSize += sizeof (WCHAR);
  517. }
  518. return 0;
  519. }
  520. DWORD
  521. PASCAL
  522. GrowCapsBuf(
  523. LPDWORD *ppXxxCaps,
  524. LPDWORD pdwBufSize
  525. )
  526. {
  527. DWORD dwTotalSize = **ppXxxCaps + 256, *pXxxCapsTmp;
  528. if (!(pXxxCapsTmp = ServerAlloc (dwTotalSize)))
  529. {
  530. return LINEERR_NOMEM;
  531. }
  532. *pdwBufSize = *pXxxCapsTmp = dwTotalSize;
  533. ServerFree (*ppXxxCaps);
  534. *ppXxxCaps = pXxxCapsTmp;
  535. return 0;
  536. }
  537. DWORD
  538. PASCAL
  539. ChangeDeviceUserAssociation(
  540. LPWSTR pDomainUserName,
  541. LPWSTR pFriendlyUserName,
  542. DWORD dwProviderID,
  543. DWORD dwPermanentDeviceID,
  544. BOOL bLine
  545. )
  546. {
  547. DWORD dwSize = 64 * sizeof (WCHAR), dwLength, dwNeededSize;
  548. WCHAR *p, *p2, *p3, buf[32];
  549. BOOL bAlreadyIn;
  550. WCHAR *pSub;
  551. if (!(p = ServerAlloc (dwSize)))
  552. {
  553. return LINEERR_NOMEM;
  554. }
  555. if (MyGetPrivateProfileString(
  556. pDomainUserName,
  557. (bLine ? gszLines : gszPhones),
  558. gszEmptyString,
  559. &p,
  560. &dwSize
  561. ))
  562. {
  563. ServerFree (p);
  564. return LINEERR_NOMEM;
  565. }
  566. dwLength = wsprintfW (buf, L"%d,%d", dwProviderID, dwPermanentDeviceID);
  567. //
  568. // Check if the specified Device/User assocation is already there
  569. // if so bAlreadyIn is set to be true and pSub points to the
  570. // (dwProviderID, dwPermanentDeviceID) pair
  571. //
  572. bAlreadyIn = FALSE;
  573. pSub = p;
  574. while (*pSub)
  575. {
  576. if ((wcsncmp(pSub, buf, dwLength) == 0) &&
  577. (*(pSub + dwLength) == L',' || *(pSub + dwLength) == L'\0'))
  578. {
  579. bAlreadyIn = TRUE;
  580. break;
  581. }
  582. //
  583. // Skip the next two delimiting ','
  584. //
  585. if (!(pSub = wcschr (pSub, L',')))
  586. {
  587. break;
  588. }
  589. pSub++;
  590. if (!(pSub = wcschr (pSub, L',')))
  591. {
  592. break;
  593. }
  594. pSub++;
  595. }
  596. if (pFriendlyUserName) // Add device/user association
  597. {
  598. // Always write the friendly name which could be different
  599. WritePrivateProfileStringW(
  600. pDomainUserName,
  601. gszFriendlyUserName,
  602. pFriendlyUserName,
  603. gszFileName
  604. );
  605. if ( !bAlreadyIn)
  606. {
  607. dwNeededSize = (dwLength + wcslen (p) + 2) * sizeof (WCHAR);
  608. if (dwNeededSize > dwSize)
  609. {
  610. if (!(p2 = ServerAlloc (dwNeededSize)))
  611. {
  612. return LINEERR_NOMEM;
  613. }
  614. wcscpy (p2, p);
  615. ServerFree (p);
  616. p = p2;
  617. }
  618. if (*p == L'\0')
  619. {
  620. wcscpy (p, buf);
  621. }
  622. else
  623. {
  624. wcscat (p, L",");
  625. wcscat (p, buf);
  626. }
  627. }
  628. }
  629. else // Remove device/user association
  630. {
  631. p2 = pSub;
  632. if (bAlreadyIn)
  633. {
  634. if (*(p2 + dwLength) == L',') // not last item in list, so copy
  635. {
  636. for(
  637. p3 = p2 + dwLength + 1;
  638. (*p2 = *p3) != L'\0';
  639. p2++, p3++
  640. );
  641. }
  642. else if (*(p2 + dwLength) == L'\0')
  643. {
  644. if (p2 == p) // only item in list, so list == ""
  645. {
  646. *p2 = L'\0';
  647. }
  648. else // last item in list, so nuke preceding ','
  649. {
  650. *(p2 - 1) = L'\0';
  651. }
  652. }
  653. }
  654. if (*p == L'\0')
  655. {
  656. }
  657. }
  658. if (bLine && *p == 0)
  659. {
  660. WritePrivateProfileStringW(
  661. pDomainUserName,
  662. NULL,
  663. NULL,
  664. gszFileName
  665. );
  666. }
  667. else
  668. {
  669. WritePrivateProfileStringW(
  670. pDomainUserName,
  671. (bLine ? gszLines : gszPhones),
  672. p,
  673. gszFileName
  674. );
  675. }
  676. ServerFree (p);
  677. return 0;
  678. }
  679. //
  680. // UpdateLastWriteTime
  681. // It reads the ftLastWriteTime of the tsec.ini into gftLineLastWrite or
  682. // gftPhoneLastWrite, it also returns S_FALSE, if the timestamp is newer
  683. //
  684. LONG
  685. UpdateLastWriteTime (
  686. BOOL bLine
  687. )
  688. {
  689. LONG lResult = S_OK;
  690. WCHAR szFilePath[MAX_PATH + 16]; // include space for "tsec.ini"
  691. WIN32_FILE_ATTRIBUTE_DATA fad;
  692. FILETIME * pft;
  693. DWORD dwError;
  694. if (GetSystemWindowsDirectoryW(szFilePath, MAX_PATH) == 0)
  695. {
  696. lResult = LINEERR_OPERATIONFAILED;
  697. goto ExitHere;
  698. }
  699. wcscat (szFilePath, L"\\");
  700. wcscat (szFilePath, gszFileName);
  701. pft = bLine ? &gftLineLastWrite : &gftPhoneLastWrite;
  702. if (GetFileAttributesExW (
  703. szFilePath,
  704. GetFileExInfoStandard,
  705. &fad) == 0
  706. )
  707. {
  708. dwError = GetLastError();
  709. if (dwError == ERROR_FILE_NOT_FOUND || dwError == ERROR_PATH_NOT_FOUND)
  710. {
  711. ZeroMemory (pft, sizeof(FILETIME));
  712. lResult = S_FALSE;
  713. }
  714. else
  715. {
  716. lResult = LINEERR_OPERATIONFAILED;
  717. }
  718. goto ExitHere;
  719. }
  720. if (fad.ftLastWriteTime.dwHighDateTime > pft->dwHighDateTime ||
  721. fad.ftLastWriteTime.dwLowDateTime > pft->dwLowDateTime)
  722. {
  723. pft->dwHighDateTime = fad.ftLastWriteTime.dwHighDateTime;
  724. pft->dwLowDateTime = fad.ftLastWriteTime.dwLowDateTime;
  725. lResult = S_FALSE;
  726. }
  727. ExitHere:
  728. return lResult;
  729. }
  730. //
  731. // InsertDevNameAddrInfo
  732. // Utlity to fill
  733. // DEVICEINFO.dwDeviceNameSize
  734. // DEVICEINFO.dwDeviceNameOffset
  735. // DEVICEINFO.dwAddressSize
  736. // DEVICEINFO.dwAddressOffset
  737. // dwDeviceID is the device ID to retrieve information while
  738. // dwEntry is the DEVICEINFO entry index in the deviceinfo list
  739. //
  740. //
  741. LONG
  742. InsertDevNameAddrInfo (
  743. BOOL bLine,
  744. LPDEVICEINFOLIST *ppList,
  745. LPDWORD pdwDevFlags,
  746. DWORD dwDeviceID,
  747. DWORD dwEntry
  748. )
  749. {
  750. LPDEVICEINFO pInfo = ((LPDEVICEINFO)((*ppList) + 1)) + dwEntry;
  751. PTLINELOOKUPENTRY pLLE;
  752. PTPHONELOOKUPENTRY pPLE;
  753. LONG lResult = S_OK;
  754. DWORD k;
  755. LINEDEVCAPS devCaps[3];
  756. LPLINEDEVCAPS pDevCaps = devCaps;
  757. DWORD dwDevCapsTotalSize = sizeof(devCaps);
  758. LINEADDRESSCAPS addrCaps[3];
  759. LPLINEADDRESSCAPS pAddrCaps = addrCaps;
  760. DWORD dwAddrCapsTotalSize = sizeof(addrCaps);
  761. TapiEnterCriticalSection(&TapiGlobals.CritSec);
  762. if (bLine)
  763. {
  764. pLLE = GetLineLookupEntry (dwDeviceID);
  765. if (!pLLE ||
  766. pLLE->bRemoved)
  767. {
  768. lResult = S_FALSE;
  769. goto ExitHere;
  770. }
  771. pInfo->dwProviderID = pLLE->ptProvider->dwPermanentProviderID;
  772. }
  773. else
  774. {
  775. pPLE = GetPhoneLookupEntry (dwDeviceID);
  776. if (!pPLE ||
  777. pPLE->bRemoved)
  778. {
  779. lResult = S_FALSE;
  780. goto ExitHere;
  781. }
  782. pInfo->dwProviderID = pPLE->ptProvider->dwPermanentProviderID;
  783. }
  784. //
  785. // Retrieve device name from TSPI_xxGetCaps
  786. //
  787. get_dev_caps:
  788. InitTapiStruct(
  789. pDevCaps,
  790. dwDevCapsTotalSize,
  791. sizeof (LINEDEVCAPS),
  792. TRUE
  793. );
  794. if (bLine)
  795. {
  796. lResult = CallSP4(
  797. pLLE->ptProvider->apfn[SP_LINEGETDEVCAPS],
  798. "lineGetDevCaps",
  799. SP_FUNC_SYNC,
  800. (DWORD) dwDeviceID,
  801. (DWORD) pLLE->dwSPIVersion,
  802. (DWORD) 0,
  803. (ULONG_PTR) pDevCaps
  804. );
  805. }
  806. else
  807. {
  808. lResult = CallSP4(
  809. pPLE->ptProvider->apfn[SP_PHONEGETDEVCAPS],
  810. "phoneGetDevCaps",
  811. SP_FUNC_SYNC,
  812. (DWORD) dwDeviceID,
  813. (DWORD) pPLE->dwSPIVersion,
  814. (DWORD) 0,
  815. (ULONG_PTR) pDevCaps
  816. );
  817. }
  818. if (lResult != 0)
  819. {
  820. //
  821. // We can't get the name or the PermDevID, so ignore this device
  822. //
  823. goto ExitHere;
  824. }
  825. else if (pDevCaps->dwNeededSize <= pDevCaps->dwTotalSize)
  826. {
  827. DWORD dwXxxSize;
  828. LPWSTR pwszXxxName;
  829. const WCHAR szUnknown[] = L"Unknown";
  830. if (bLine)
  831. {
  832. pInfo->dwPermanentDeviceID = pDevCaps->dwPermanentLineID;
  833. if (pdwDevFlags)
  834. {
  835. *pdwDevFlags = pDevCaps->dwDevCapFlags;
  836. }
  837. dwXxxSize = pDevCaps->dwLineNameSize;
  838. pwszXxxName = (WCHAR *) (((LPBYTE) pDevCaps) +
  839. pDevCaps->dwLineNameOffset);
  840. }
  841. else
  842. {
  843. LPPHONECAPS pPhoneCaps = (LPPHONECAPS) pDevCaps;
  844. pInfo->dwPermanentDeviceID = pPhoneCaps->dwPermanentPhoneID;
  845. dwXxxSize = pPhoneCaps->dwPhoneNameSize;
  846. pwszXxxName = (WCHAR *) (((LPBYTE) pPhoneCaps) +
  847. pPhoneCaps->dwPhoneNameOffset);
  848. }
  849. if (dwXxxSize == 0 || *pwszXxxName == L'\0')
  850. {
  851. dwXxxSize = 8 * sizeof (WCHAR);
  852. pwszXxxName = (LPWSTR) szUnknown;
  853. }
  854. if (InsertInfoListString(
  855. ppList,
  856. dwEntry,
  857. (DWORD) (((LPBYTE) &pInfo->dwDeviceNameSize) -
  858. ((LPBYTE) pInfo)),
  859. pwszXxxName,
  860. dwXxxSize,
  861. FALSE
  862. ))
  863. {
  864. lResult = LINEERR_NOMEM;
  865. goto ExitHere;
  866. }
  867. }
  868. //
  869. // if the pDevCaps is not large enough, increase the size
  870. // by 256 and try again.
  871. //
  872. else
  873. {
  874. LPLINEDEVCAPS pNewDevCaps;
  875. dwDevCapsTotalSize += 256;
  876. pNewDevCaps = ServerAlloc (dwDevCapsTotalSize);
  877. if (pNewDevCaps == NULL)
  878. {
  879. lResult = LINEERR_NOMEM;
  880. goto ExitHere;
  881. }
  882. if (pDevCaps != devCaps)
  883. {
  884. ServerFree (pDevCaps);
  885. }
  886. pDevCaps = pNewDevCaps;
  887. goto get_dev_caps;
  888. }
  889. if (bLine)
  890. {
  891. //
  892. // for each address on this line retrieve the address "name"
  893. // by calling TSPI_lineGetAddressCaps. Terminate the last
  894. // address name in the list with an extra Null character.
  895. //
  896. for (k = 0; k < pDevCaps->dwNumAddresses; k++)
  897. {
  898. get_addr_caps:
  899. InitTapiStruct(
  900. pAddrCaps,
  901. dwAddrCapsTotalSize,
  902. sizeof (LINEADDRESSCAPS),
  903. TRUE
  904. );
  905. if ((lResult = CallSP5(
  906. pLLE->ptProvider->apfn[SP_LINEGETADDRESSCAPS],
  907. "lineGetAddressCaps",
  908. SP_FUNC_SYNC,
  909. (DWORD) dwDeviceID,
  910. (DWORD) k,
  911. (DWORD) pLLE->dwSPIVersion,
  912. (DWORD) 0,
  913. (ULONG_PTR) pAddrCaps
  914. )) == 0)
  915. {
  916. if (pAddrCaps->dwNeededSize <= pAddrCaps->dwTotalSize)
  917. {
  918. if (InsertInfoListString(
  919. ppList,
  920. dwEntry,
  921. (DWORD) (((LPBYTE) &pInfo->dwAddressesSize) -
  922. ((LPBYTE) pInfo)),
  923. (LPWSTR) (((LPBYTE) pAddrCaps) +
  924. pAddrCaps->dwAddressOffset),
  925. pAddrCaps->dwAddressSize,
  926. (k < (pDevCaps->dwNumAddresses - 1) ?
  927. FALSE : TRUE)
  928. ))
  929. {
  930. lResult = LINEERR_NOMEM;
  931. goto ExitHere;
  932. }
  933. }
  934. //
  935. // if the pAddrCaps is not large enough, increase the size
  936. // by 256 and try again.
  937. //
  938. else
  939. {
  940. LPLINEADDRESSCAPS pNewAddrCaps;
  941. dwAddrCapsTotalSize += 256;
  942. pNewAddrCaps = ServerAlloc (dwAddrCapsTotalSize);
  943. if (pNewAddrCaps == NULL)
  944. {
  945. goto ExitHere;
  946. }
  947. if (pAddrCaps != addrCaps)
  948. {
  949. ServerFree (pAddrCaps);
  950. }
  951. pAddrCaps = pNewAddrCaps;
  952. goto get_addr_caps;
  953. }
  954. }
  955. else
  956. {
  957. // no addr name (will default to blank, not bad)
  958. }
  959. }
  960. }
  961. ExitHere:
  962. if (pDevCaps != devCaps)
  963. {
  964. ServerFree (pDevCaps);
  965. }
  966. if (pAddrCaps != addrCaps)
  967. {
  968. ServerFree (pAddrCaps);
  969. }
  970. TapiLeaveCriticalSection(&TapiGlobals.CritSec);
  971. return lResult;
  972. }
  973. //
  974. // AppendNewDeviceInfo
  975. // This function insert a newly created device identified by
  976. // dwDeviceID into the cached gpLineInfoList or gpPhoneInfoList in
  977. // response to LINE/PHONE_CREATE message
  978. //
  979. LONG
  980. AppendNewDeviceInfo (
  981. BOOL bLine,
  982. DWORD dwDeviceID
  983. )
  984. {
  985. LONG lResult = S_OK;
  986. LPDEVICEINFOLIST pXxxList;
  987. DWORD dwXxxDevices;
  988. DWORD dwTotalSize;
  989. DWORD dwSize, dw;
  990. EnterCriticalSection (&gMgmtCritSec);
  991. pXxxList = bLine? gpLineInfoList : gpPhoneInfoList;
  992. dwXxxDevices = bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones;
  993. if (pXxxList == NULL)
  994. {
  995. goto ExitHere;
  996. }
  997. //
  998. // make sure we have enough space to accomodate the new device flags
  999. if (bLine && gpLineDevFlags && gdwNumFlags < dwXxxDevices)
  1000. {
  1001. LPDWORD pNewLineDevFlags;
  1002. pNewLineDevFlags = ServerAlloc (dwXxxDevices * sizeof(DWORD));
  1003. if (pNewLineDevFlags == NULL)
  1004. {
  1005. goto ExitHere;
  1006. }
  1007. CopyMemory (
  1008. pNewLineDevFlags,
  1009. gpLineDevFlags,
  1010. gdwNumFlags * sizeof(DWORD)
  1011. );
  1012. ServerFree (gpLineDevFlags);
  1013. gpLineDevFlags = pNewLineDevFlags;
  1014. gdwNumFlags = dwXxxDevices;
  1015. }
  1016. //
  1017. // make sure we have enough space for the new DEVICEINFO entry
  1018. // An estimate is done for the new DEVICEINFO entry
  1019. // the estimation includes:
  1020. // 1. Fixed size of DEVICEINFO structure
  1021. // 2. 20 bytes each for DeviceName, Addresses, DomainUserName
  1022. // and FriendlyUserName
  1023. //
  1024. dwTotalSize = pXxxList->dwUsedSize +
  1025. sizeof(DEVICEINFO) + (20 + 20 + 20 + 20) * sizeof(WCHAR);
  1026. if (dwTotalSize > pXxxList->dwTotalSize)
  1027. {
  1028. LPDEVICEINFOLIST pNewList;
  1029. pNewList = ServerAlloc (dwTotalSize);
  1030. if (pNewList == NULL)
  1031. {
  1032. lResult = (bLine ? LINEERR_NOMEM : PHONEERR_NOMEM);
  1033. goto ExitHere;
  1034. }
  1035. CopyMemory (pNewList, pXxxList, pXxxList->dwUsedSize);
  1036. pNewList->dwTotalSize = dwTotalSize;
  1037. pXxxList = pNewList;
  1038. if (bLine)
  1039. {
  1040. ServerFree (gpLineInfoList);
  1041. gpLineInfoList = pXxxList;
  1042. }
  1043. else
  1044. {
  1045. ServerFree (gpPhoneInfoList);
  1046. gpPhoneInfoList = pXxxList;
  1047. }
  1048. }
  1049. // Now make space for the new DEVICEINFO entry
  1050. if (pXxxList->dwUsedSize >
  1051. pXxxList->dwDeviceInfoSize + sizeof(*pXxxList))
  1052. {
  1053. LPBYTE pbVar = (LPBYTE) pXxxList +
  1054. pXxxList->dwDeviceInfoSize + sizeof(*pXxxList);
  1055. LPDEVICEINFO pInfo = (LPDEVICEINFO)(((LPBYTE)pXxxList) +
  1056. sizeof(*pXxxList));
  1057. dwSize = pXxxList->dwUsedSize -
  1058. pXxxList->dwDeviceInfoSize - sizeof(*pXxxList);
  1059. MoveMemory (
  1060. pbVar + sizeof(DEVICEINFO),
  1061. pbVar,
  1062. dwSize);
  1063. ZeroMemory (pbVar, sizeof(DEVICEINFO));
  1064. for (dw = 0;
  1065. dw < pXxxList->dwNumDeviceInfoEntries;
  1066. ++dw
  1067. )
  1068. {
  1069. if (pInfo->dwDeviceNameOffset != 0)
  1070. {
  1071. pInfo->dwDeviceNameOffset += sizeof(DEVICEINFO);
  1072. }
  1073. if (pInfo->dwAddressesOffset != 0)
  1074. {
  1075. pInfo->dwAddressesOffset += sizeof(DEVICEINFO);
  1076. }
  1077. if (pInfo->dwDomainUserNamesOffset != 0)
  1078. {
  1079. pInfo->dwDomainUserNamesOffset += sizeof(DEVICEINFO);
  1080. }
  1081. if (pInfo->dwFriendlyUserNamesOffset != 0)
  1082. {
  1083. pInfo->dwFriendlyUserNamesOffset += sizeof(DEVICEINFO);
  1084. }
  1085. ++pInfo;
  1086. }
  1087. }
  1088. pXxxList->dwUsedSize += sizeof(DEVICEINFO);
  1089. pXxxList->dwNeededSize = pXxxList->dwUsedSize;
  1090. // Now add the new entry
  1091. lResult = InsertDevNameAddrInfo (
  1092. bLine,
  1093. (bLine ? (&gpLineInfoList) : (&gpPhoneInfoList)),
  1094. (bLine && dwDeviceID < gdwNumFlags) ? (gpLineDevFlags + dwDeviceID) : NULL,
  1095. dwDeviceID,
  1096. pXxxList->dwNumDeviceInfoEntries
  1097. );
  1098. if (lResult == 0)
  1099. {
  1100. pXxxList = bLine? gpLineInfoList : gpPhoneInfoList;
  1101. pXxxList->dwDeviceInfoSize += sizeof(DEVICEINFO);
  1102. ++pXxxList->dwNumDeviceInfoEntries;
  1103. pXxxList->dwNeededSize = pXxxList->dwUsedSize;
  1104. }
  1105. ExitHere:
  1106. LeaveCriticalSection (&gMgmtCritSec);
  1107. return lResult;
  1108. }
  1109. //
  1110. // RemoveDeviceInfoEntry
  1111. // // This function removes a device info entry from the gpLineInfoList
  1112. // or gpPhoneInfoList identified by dwDevice in response to LINE/PHONE_REMOVE
  1113. // message
  1114. //
  1115. LONG
  1116. RemoveDeviceInfoEntry (
  1117. BOOL bLine,
  1118. DWORD dwDeviceID
  1119. )
  1120. {
  1121. LPDEVICEINFOLIST pXxxList;
  1122. LPDEVICEINFO pInfo;
  1123. int iIndex, cItems;
  1124. LPBYTE pb;
  1125. EnterCriticalSection (&gMgmtCritSec);
  1126. pXxxList = bLine ? gpLineInfoList : gpPhoneInfoList;
  1127. if (pXxxList == NULL)
  1128. {
  1129. goto ExitHere;
  1130. }
  1131. pInfo = (LPDEVICEINFO)(pXxxList + 1);
  1132. cItems = (int)pXxxList->dwNumDeviceInfoEntries;
  1133. iIndex = dwDeviceID;
  1134. if ((int)dwDeviceID >= cItems)
  1135. {
  1136. iIndex = cItems - 1;
  1137. }
  1138. pInfo += iIndex;
  1139. while (iIndex >= 0)
  1140. {
  1141. TAPIPERMANENTID tpid;
  1142. tpid.dwDeviceID = pInfo->dwPermanentDeviceID;
  1143. tpid.dwProviderID = pInfo->dwProviderID;
  1144. if (dwDeviceID == GetDeviceIDFromPermanentID(tpid, bLine))
  1145. {
  1146. break;
  1147. }
  1148. --pInfo;
  1149. --iIndex;
  1150. }
  1151. if (iIndex < 0)
  1152. {
  1153. goto ExitHere;
  1154. }
  1155. // With the entry pointed to by iIndex found, move down
  1156. // all the DEVICEINFO entry above it
  1157. if (iIndex < cItems - 1)
  1158. {
  1159. pb = (LPBYTE)((LPDEVICEINFO)(pXxxList + 1) + iIndex);
  1160. MoveMemory (
  1161. pb,
  1162. pb + sizeof(DEVICEINFO),
  1163. (cItems - 1 - iIndex) * sizeof(DEVICEINFO)
  1164. );
  1165. }
  1166. pXxxList->dwDeviceInfoSize -= sizeof(DEVICEINFO);
  1167. --pXxxList->dwNumDeviceInfoEntries;
  1168. ExitHere:
  1169. LeaveCriticalSection (&gMgmtCritSec);
  1170. return 0;
  1171. }
  1172. //
  1173. // BuildDeviceInfoList
  1174. // Private function called by GetDeviceInfo to build the DEVICEINFOLIST
  1175. // if not already created, the list is saved in gpLineInfoList or
  1176. // gpPhoneInfoList
  1177. //
  1178. LONG
  1179. BuildDeviceInfoList(
  1180. BOOL bLine
  1181. )
  1182. {
  1183. LONG lResult = S_OK;
  1184. DWORD dwNumDevices, dwListTotalSize, dwFriendlyNameSize,
  1185. dwDomainUserNameSize, dwFriendlyUserNameSize;
  1186. DWORD i, j;
  1187. LPDEVICEINFOLIST pList = NULL;
  1188. LPUSERNAME_TUPLE pUserNames= NULL;
  1189. LPWSTR lpszFriendlyName = NULL;
  1190. LPDEVICEINFO pInfo;
  1191. HANDLE hIniFile = 0;
  1192. HANDLE hFileMap = NULL;
  1193. char * lpszFileBuf = NULL;
  1194. char* lpszLineAnsiBuf = NULL;
  1195. LPWSTR lpszLineWcharBuf = NULL;
  1196. DWORD dwAnsiLineBufSize, dwWcharLineBufSize;
  1197. DWORD dwTotalFileSize;
  1198. DWORD dwFilePtr;
  1199. LPWSTR lpszDomainUser = NULL;
  1200. DWORD cbDomainUser;
  1201. LPDWORD lpdwDevFlags = NULL;
  1202. WCHAR *p;
  1203. //
  1204. // Alloc a buffer to use for the device info list. Size includes
  1205. // the list header, list entries for each existing device,
  1206. // and space wide unicode strings for device name, (address,)
  1207. // domain\user name(s), and friendly user name(s) (each est to 20 char).
  1208. //
  1209. // Also alloc buffers to use for retrieving device & address caps,
  1210. // and a buffer to temporarily store pointers to user name
  1211. // strings (which are associated with each line)
  1212. //
  1213. TapiEnterCriticalSection(&TapiGlobals.CritSec);
  1214. dwNumDevices = (bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones);
  1215. TapiLeaveCriticalSection(&TapiGlobals.CritSec);
  1216. dwAnsiLineBufSize = 256 * sizeof(WCHAR);
  1217. dwWcharLineBufSize = 256 * sizeof(WCHAR);
  1218. dwFriendlyNameSize = 64 * sizeof (WCHAR);
  1219. cbDomainUser = 128;
  1220. dwListTotalSize =
  1221. sizeof (DEVICEINFOLIST) +
  1222. (dwNumDevices * sizeof (DEVICEINFO)) +
  1223. (dwNumDevices * (20 + 20 + 20 + 20) * sizeof (WCHAR));
  1224. if (!(pList = ServerAlloc (dwListTotalSize)) ||
  1225. !(pUserNames = ServerAlloc (dwNumDevices * sizeof (USERNAME_TUPLE))) ||
  1226. !(lpszFriendlyName = ServerAlloc (dwFriendlyNameSize)) ||
  1227. !(lpszLineAnsiBuf = ServerAlloc (dwAnsiLineBufSize)) ||
  1228. !(lpszLineWcharBuf = ServerAlloc (dwWcharLineBufSize)) ||
  1229. !(lpszDomainUser = ServerAlloc (cbDomainUser)))
  1230. {
  1231. lResult = LINEERR_NOMEM;
  1232. goto ExitHere;
  1233. }
  1234. if (bLine && !(lpdwDevFlags = ServerAlloc (dwNumDevices * sizeof (DWORD))))
  1235. {
  1236. lResult = LINEERR_NOMEM;
  1237. goto ExitHere;
  1238. }
  1239. pList->dwTotalSize = dwListTotalSize;
  1240. pList->dwUsedSize = sizeof (*pList) +
  1241. dwNumDevices * sizeof (DEVICEINFO);
  1242. pList->dwDeviceInfoSize = dwNumDevices * sizeof (DEVICEINFO);
  1243. pList->dwDeviceInfoOffset = sizeof (*pList);
  1244. //
  1245. // Get info for all the lines, including:
  1246. //
  1247. // Provider ID
  1248. // Permanent Device ID
  1249. // Device Name
  1250. // (Addresses)
  1251. //
  1252. // ... and pack this info in the list sequentially
  1253. //
  1254. LOG((TL_INFO,
  1255. "GetDeviceInfo: getting names (addrs) for %ld %ws",
  1256. dwNumDevices,
  1257. (bLine ? gszLines : gszPhones)
  1258. ));
  1259. for (i = j = 0; i < dwNumDevices; i++)
  1260. {
  1261. if (WaitForSingleObject (
  1262. ghEventService,
  1263. 0
  1264. ) == WAIT_OBJECT_0)
  1265. {
  1266. lResult = LINEERR_OPERATIONFAILED;
  1267. goto ExitHere;
  1268. }
  1269. lResult = InsertDevNameAddrInfo (
  1270. bLine,
  1271. &pList,
  1272. bLine ? lpdwDevFlags + i : NULL,
  1273. i,
  1274. j
  1275. );
  1276. if (lResult)
  1277. {
  1278. lResult = 0;
  1279. continue;
  1280. }
  1281. ++j;
  1282. }
  1283. dwNumDevices =
  1284. pList->dwNumDeviceInfoEntries = j; // the number of devices in the list
  1285. //
  1286. // Now enumerate all the known users & figure out what devices they
  1287. // have access to. Since each device can be seen by zero, one, or
  1288. // many users, we allocate separate user name buffers in this loop
  1289. // rather than try to pack them into the existing device info list.
  1290. //
  1291. //
  1292. // Open %windir%\tsec.ini file and map it into memory
  1293. //
  1294. {
  1295. TCHAR szFilePath[MAX_PATH + 16]; // include space for "tsec.ini"
  1296. OFSTRUCT ofs;
  1297. if (GetCurrentDirectory(MAX_PATH, szFilePath) == 0)
  1298. {
  1299. lResult = LINEERR_OPERATIONFAILED;
  1300. goto ExitHere;
  1301. }
  1302. wcscat (szFilePath, L"\\");
  1303. wcscat (szFilePath, gszFileName);
  1304. hIniFile = CreateFile (
  1305. szFilePath,
  1306. GENERIC_READ,
  1307. FILE_SHARE_READ,
  1308. NULL,
  1309. OPEN_EXISTING,
  1310. FILE_ATTRIBUTE_NORMAL,
  1311. NULL
  1312. );
  1313. if (hIniFile == INVALID_HANDLE_VALUE)
  1314. {
  1315. DWORD dwError;
  1316. dwError = GetLastError();
  1317. if (dwError != ERROR_FILE_NOT_FOUND
  1318. && dwError != ERROR_PATH_NOT_FOUND)
  1319. {
  1320. lResult = LINEERR_OPERATIONFAILED;
  1321. goto ExitHere;
  1322. }
  1323. }
  1324. if (hIniFile != INVALID_HANDLE_VALUE)
  1325. {
  1326. dwTotalFileSize = GetFileSize(hIniFile, NULL);
  1327. }
  1328. else
  1329. {
  1330. dwTotalFileSize = 0;
  1331. }
  1332. if (dwTotalFileSize > 0)
  1333. {
  1334. hFileMap = CreateFileMapping (
  1335. hIniFile,
  1336. NULL,
  1337. PAGE_READONLY,
  1338. 0,
  1339. 0,
  1340. NULL
  1341. );
  1342. if (hFileMap == NULL)
  1343. {
  1344. lResult = LINEERR_OPERATIONFAILED;
  1345. goto ExitHere;
  1346. }
  1347. lpszFileBuf = MapViewOfFile (
  1348. hFileMap,
  1349. FILE_MAP_READ,
  1350. 0,
  1351. 0,
  1352. 0
  1353. );
  1354. if (lpszFileBuf == NULL)
  1355. {
  1356. lResult = LINEERR_OPERATIONFAILED;
  1357. goto ExitHere;
  1358. }
  1359. }
  1360. }
  1361. pInfo = (LPDEVICEINFO)(pList + 1);
  1362. dwFilePtr = 0;
  1363. while (dwFilePtr < dwTotalFileSize)
  1364. {
  1365. WCHAR wch;
  1366. DWORD cch, cb;
  1367. WCHAR * lpwsz;
  1368. if (WaitForSingleObject (
  1369. ghEventService,
  1370. 0
  1371. ) == WAIT_OBJECT_0)
  1372. {
  1373. lResult = LINEERR_OPERATIONFAILED;
  1374. goto ExitHere;
  1375. }
  1376. ASSERT (lpszFileBuf != NULL);
  1377. // Read one line from the file
  1378. cch = 0;
  1379. wch = 0;
  1380. cb = 0;
  1381. while (wch != L'\n' && wch != L'\r' && dwFilePtr < dwTotalFileSize)
  1382. {
  1383. // Not enough line buffer? if so enlarge
  1384. if (cb >= dwAnsiLineBufSize)
  1385. {
  1386. char * lpszNewAnsi;
  1387. if (!(lpszNewAnsi = ServerAlloc (dwAnsiLineBufSize + 256)))
  1388. {
  1389. lResult = LINEERR_NOMEM;
  1390. goto ExitHere;
  1391. }
  1392. CopyMemory (lpszNewAnsi, lpszLineAnsiBuf, cb);
  1393. ServerFree (lpszLineAnsiBuf);
  1394. lpszLineAnsiBuf = lpszNewAnsi;
  1395. dwAnsiLineBufSize += 256;
  1396. }
  1397. wch = lpszLineAnsiBuf[cb++] = lpszFileBuf[dwFilePtr++];
  1398. if (IsDBCSLeadByte((BYTE)wch))
  1399. {
  1400. lpszLineAnsiBuf[cb] = lpszFileBuf[dwFilePtr++];
  1401. wch = (wch << 8) + lpszLineAnsiBuf[cb];
  1402. ++cb;
  1403. }
  1404. ++cch;
  1405. }
  1406. // skip the \r & \n
  1407. if (wch == L'\r' || wch == L'\n')
  1408. {
  1409. lpszLineAnsiBuf[cb - 1] = 0;
  1410. if (dwFilePtr < dwTotalFileSize &&
  1411. ((lpszFileBuf[dwFilePtr] == L'\n') ||
  1412. (lpszFileBuf[dwFilePtr] == L'\r')))
  1413. {
  1414. ++dwFilePtr;
  1415. }
  1416. }
  1417. // Now convert the ANSI string to Wide char
  1418. // enough wchar line buffer size?
  1419. if (dwWcharLineBufSize <= (cch + 1) * sizeof(WCHAR))
  1420. {
  1421. ServerFree (lpszLineWcharBuf);
  1422. dwWcharLineBufSize = (cch + 256) * sizeof(WCHAR);
  1423. if (!(lpszLineWcharBuf = ServerAlloc (dwWcharLineBufSize)))
  1424. {
  1425. lResult = LINEERR_NOMEM;
  1426. goto ExitHere;
  1427. }
  1428. }
  1429. if ((cch = MultiByteToWideChar (
  1430. CP_ACP,
  1431. MB_PRECOMPOSED,
  1432. lpszLineAnsiBuf,
  1433. cb,
  1434. lpszLineWcharBuf,
  1435. dwWcharLineBufSize / sizeof(WCHAR)
  1436. )) == 0)
  1437. {
  1438. lResult = LINEERR_OPERATIONFAILED;
  1439. goto ExitHere;
  1440. }
  1441. ASSERT (cch < dwWcharLineBufSize / sizeof(WCHAR));
  1442. lpszLineWcharBuf[cch] = 0;
  1443. lpwsz = lpszLineWcharBuf;
  1444. // Skip white space
  1445. while (*lpwsz && ((*lpwsz == L' ') || (*lpwsz == L'\t')))
  1446. {
  1447. ++lpwsz;
  1448. }
  1449. // Got a bracket, this might be the starting of a new NT
  1450. // domain user or the section of [TapiAdministators]
  1451. if (*lpwsz == L'[')
  1452. {
  1453. *lpszFriendlyName = 0; // reset friendly name
  1454. ++lpwsz;
  1455. if (_wcsnicmp (
  1456. lpwsz,
  1457. gszTapiAdministrators,
  1458. CCH_TAPIADMINISTRATORS
  1459. ) == 0 &&
  1460. lpwsz[CCH_TAPIADMINISTRATORS] == L']')
  1461. {
  1462. // Got [TapiAdministrators], not any domain user
  1463. // to process, reset the lpszDomainUser to empty
  1464. *lpszDomainUser = 0;
  1465. continue;
  1466. }
  1467. else
  1468. {
  1469. // might be a valid NT domain user like [ndev\jonsmith]
  1470. // copy the domain user string over
  1471. cch = 0;
  1472. while (*lpwsz && *lpwsz != L']')
  1473. {
  1474. if (((cch + 1) * sizeof(WCHAR)) >= cbDomainUser)
  1475. {
  1476. LPTSTR lpszNew;
  1477. if (!(lpszNew = ServerAlloc (cbDomainUser + 128)))
  1478. {
  1479. lResult = LINEERR_NOMEM;
  1480. goto ExitHere;
  1481. }
  1482. CopyMemory (lpszNew, lpszDomainUser, cb);
  1483. ServerFree (lpszDomainUser);
  1484. lpszDomainUser = lpszNew;
  1485. cbDomainUser += 128;
  1486. }
  1487. lpszDomainUser[cch++] = *lpwsz++;
  1488. }
  1489. lpszDomainUser[cch] = 0;
  1490. if (*lpwsz == 0)
  1491. {
  1492. // did not find a closing ']', ignore this section
  1493. *lpszDomainUser = 0;
  1494. continue;
  1495. }
  1496. }
  1497. }
  1498. //
  1499. // Now it might be some ntdev\jonsmith=1 in [TapiAdministrators] or
  1500. // Lines=1,1000 under section of [ntdev\jonsmith].
  1501. // for the first case, we just ignore this line, for the second case
  1502. // we need to have *lpszDomainUser != 0
  1503. //
  1504. else if (*lpszDomainUser)
  1505. {
  1506. if (_wcsnicmp (
  1507. lpwsz,
  1508. gszFriendlyUserName,
  1509. CCH_FRIENDLYUSERNAME
  1510. ) == 0)
  1511. {
  1512. // The tsec.ini friendly name is the following format
  1513. // FriendlyName=Jon Smith
  1514. // skip over the '='
  1515. while (*lpwsz && *lpwsz != L'=')
  1516. {
  1517. ++lpwsz;
  1518. }
  1519. if (*lpwsz == 0)
  1520. {
  1521. continue;
  1522. }
  1523. else
  1524. {
  1525. ++lpwsz;
  1526. }
  1527. if (dwFriendlyNameSize < (1 + wcslen (lpwsz)) * sizeof(WCHAR))
  1528. {
  1529. ServerFree (lpszFriendlyName);
  1530. dwFriendlyNameSize = (64 + wcslen (lpwsz)) * sizeof(WCHAR);
  1531. if (!(lpszFriendlyName = ServerAlloc (dwFriendlyNameSize)))
  1532. {
  1533. lResult = LINEERR_NOMEM;
  1534. goto ExitHere;
  1535. }
  1536. }
  1537. wcscpy (lpszFriendlyName, lpwsz);
  1538. continue;
  1539. }
  1540. else if (_wcsnicmp (
  1541. lpwsz,
  1542. gszLines,
  1543. CCH_LINES
  1544. ) == 0 && bLine ||
  1545. _wcsnicmp (
  1546. lpwsz,
  1547. gszPhones,
  1548. CCH_PHONES
  1549. ) == 0 && (!bLine))
  1550. {
  1551. // Here it is either Lines=1,100 or Phones=1,100
  1552. DWORD dwXxxSize, dwDeviceID;
  1553. WCHAR *pXxxNames, *pNewXxxNames, * p;
  1554. TAPIPERMANENTID tpid;
  1555. // first skip over the '=' sign
  1556. while (*lpwsz && *lpwsz != L'=')
  1557. {
  1558. ++lpwsz;
  1559. }
  1560. if (*lpwsz == 0)
  1561. {
  1562. continue;
  1563. }
  1564. ++lpwsz;
  1565. p = lpwsz;
  1566. while (*p)
  1567. {
  1568. if ((tpid.dwProviderID = _wtol (p)) == 0)
  1569. {
  1570. //
  1571. // ProviderID's are never 0, so list must be corrupt.
  1572. //
  1573. break;
  1574. }
  1575. for (; ((*p != L'\0') && (*p != L',')); p++);
  1576. if (*p == L'\0')
  1577. {
  1578. //
  1579. // Couldn't find a trailing ',' so list must be corrupt.
  1580. //
  1581. break;
  1582. }
  1583. p++; // skip the ','
  1584. tpid.dwDeviceID = _wtol (p);
  1585. while (*p != L',' && *p != L'\0')
  1586. {
  1587. p++;
  1588. }
  1589. if (*p == L',')
  1590. {
  1591. if (*(p + 1) == L'\0')
  1592. {
  1593. //
  1594. // The ',' is followed by a NULL, so nuke the ','
  1595. //
  1596. *p = L'\0';
  1597. }
  1598. else
  1599. {
  1600. p++;
  1601. }
  1602. }
  1603. dwDeviceID = GetDeviceIDFromPermanentID (tpid, bLine);
  1604. if (dwDeviceID == 0xffffffff)
  1605. {
  1606. //
  1607. // This <ppid>,<plid> pair is bad. Skip it.
  1608. //
  1609. continue;
  1610. }
  1611. //
  1612. // At this point dwDeviceID is the zero-based index
  1613. // of a fully populated info list (no missing entries).
  1614. //
  1615. // If the list is not fully-populated (due to failed
  1616. // dev caps, or removed devices, etc) we need to
  1617. // recompute the index by walking the list & comparing
  1618. // permanent XXX id's.
  1619. //
  1620. if (dwNumDevices <
  1621. (bLine ? TapiGlobals.dwNumLines : TapiGlobals.dwNumPhones))
  1622. {
  1623. BOOL bContinue = FALSE;
  1624. for (i = dwDeviceID;; i--)
  1625. {
  1626. LPDEVICEINFO pInfoTmp = ((LPDEVICEINFO) (pList + 1)) +i;
  1627. if (pInfoTmp->dwPermanentDeviceID == tpid.dwDeviceID &&
  1628. pInfoTmp->dwProviderID == tpid.dwProviderID)
  1629. {
  1630. dwDeviceID = i;
  1631. break;
  1632. }
  1633. if (i == 0)
  1634. {
  1635. bContinue = TRUE;
  1636. break;
  1637. }
  1638. }
  1639. if (bContinue)
  1640. {
  1641. continue;
  1642. }
  1643. }
  1644. //
  1645. //
  1646. //
  1647. dwDomainUserNameSize = (wcslen(lpszDomainUser) + 1) * sizeof(WCHAR);
  1648. dwXxxSize = pInfo[dwDeviceID].dwDomainUserNamesOffset;
  1649. pXxxNames = pUserNames[dwDeviceID].pDomainUserNames;
  1650. if (!(pNewXxxNames = ServerAlloc(
  1651. dwXxxSize + dwDomainUserNameSize
  1652. )))
  1653. {
  1654. lResult = LINEERR_NOMEM;
  1655. goto ExitHere;
  1656. }
  1657. CopyMemory (pNewXxxNames, lpszDomainUser, dwDomainUserNameSize);
  1658. if (dwXxxSize)
  1659. {
  1660. CopyMemory(
  1661. ((LPBYTE) pNewXxxNames) + dwDomainUserNameSize,
  1662. pXxxNames,
  1663. dwXxxSize
  1664. );
  1665. ServerFree (pXxxNames);
  1666. }
  1667. pInfo[dwDeviceID].dwDomainUserNamesOffset +=
  1668. dwDomainUserNameSize;
  1669. pUserNames[dwDeviceID].pDomainUserNames = pNewXxxNames;
  1670. //
  1671. //
  1672. //
  1673. // If there is no friendly name specified in tsec.ini
  1674. // which happens in NT/SP4 upgrade case, we use the
  1675. // DomainUserName for display
  1676. //
  1677. if (*lpszFriendlyName == 0)
  1678. {
  1679. wcsncpy(lpszFriendlyName, lpszDomainUser,
  1680. dwFriendlyNameSize / sizeof(WCHAR));
  1681. lpszFriendlyName[(dwFriendlyNameSize / sizeof(WCHAR)) - 1] = 0;
  1682. }
  1683. dwFriendlyUserNameSize = (wcslen(lpszFriendlyName) + 1) * sizeof(WCHAR);
  1684. dwXxxSize = pInfo[dwDeviceID].dwFriendlyUserNamesOffset;
  1685. pXxxNames = pUserNames[dwDeviceID].pFriendlyUserNames;
  1686. if (!(pNewXxxNames = ServerAlloc(
  1687. dwXxxSize + dwFriendlyUserNameSize
  1688. )))
  1689. {
  1690. lResult = LINEERR_NOMEM;
  1691. goto ExitHere;
  1692. }
  1693. CopyMemory(
  1694. pNewXxxNames,
  1695. lpszFriendlyName,
  1696. dwFriendlyUserNameSize
  1697. );
  1698. if (dwXxxSize)
  1699. {
  1700. CopyMemory(
  1701. ((LPBYTE) pNewXxxNames) + dwFriendlyUserNameSize,
  1702. pXxxNames,
  1703. dwXxxSize
  1704. );
  1705. ServerFree (pXxxNames);
  1706. }
  1707. pInfo[dwDeviceID].dwFriendlyUserNamesOffset +=
  1708. dwFriendlyUserNameSize;
  1709. pUserNames[dwDeviceID].pFriendlyUserNames = pNewXxxNames;
  1710. }
  1711. }
  1712. }
  1713. }
  1714. //
  1715. //
  1716. //
  1717. LOG((TL_INFO,
  1718. "GetDeviceInfo: matching users to %ws",
  1719. (bLine ? gszLines : gszPhones)
  1720. ));
  1721. for (i = 0; i < dwNumDevices; i++)
  1722. {
  1723. pInfo = ((LPDEVICEINFO)(pList + 1)) + i;
  1724. if (InsertInfoListString(
  1725. &pList,
  1726. i,
  1727. (DWORD) (((LPBYTE) &pInfo->dwDomainUserNamesSize) -
  1728. ((LPBYTE) pInfo)),
  1729. pUserNames[i].pDomainUserNames,
  1730. pInfo->dwDomainUserNamesOffset,
  1731. TRUE
  1732. ))
  1733. {
  1734. lResult = LINEERR_NOMEM;
  1735. goto ExitHere;
  1736. }
  1737. pInfo = ((LPDEVICEINFO)(pList + 1)) + i;
  1738. if (InsertInfoListString(
  1739. &pList,
  1740. i,
  1741. (DWORD) (((LPBYTE) &pInfo->dwFriendlyUserNamesSize) -
  1742. ((LPBYTE) pInfo)),
  1743. pUserNames[i].pFriendlyUserNames,
  1744. pInfo->dwFriendlyUserNamesOffset,
  1745. TRUE
  1746. ))
  1747. {
  1748. lResult = LINEERR_NOMEM;
  1749. goto ExitHere;
  1750. }
  1751. }
  1752. //
  1753. // If here we successfully built the list
  1754. //
  1755. pList->dwNeededSize = pList->dwUsedSize;
  1756. if (bLine)
  1757. {
  1758. gpLineInfoList = pList;
  1759. gpLineDevFlags = lpdwDevFlags;
  1760. gdwNumFlags = dwNumDevices;
  1761. }
  1762. else
  1763. {
  1764. gpPhoneInfoList = pList;
  1765. }
  1766. ExitHere:
  1767. if (pUserNames != NULL)
  1768. {
  1769. for (i = 0; i < dwNumDevices; i++)
  1770. {
  1771. ServerFree (pUserNames[i].pDomainUserNames);
  1772. ServerFree (pUserNames[i].pFriendlyUserNames);
  1773. }
  1774. }
  1775. ServerFree (lpszDomainUser);
  1776. ServerFree (lpszLineAnsiBuf);
  1777. ServerFree (lpszLineWcharBuf);
  1778. ServerFree (lpszFriendlyName);
  1779. ServerFree (pUserNames);
  1780. if (lResult)
  1781. {
  1782. ServerFree (pList);
  1783. if (bLine)
  1784. {
  1785. ServerFree (lpdwDevFlags);
  1786. gdwNumFlags = 0;
  1787. }
  1788. }
  1789. if (hFileMap)
  1790. {
  1791. UnmapViewOfFile(lpszFileBuf);
  1792. CloseHandle (hFileMap);
  1793. }
  1794. if (hIniFile != INVALID_HANDLE_VALUE)
  1795. {
  1796. CloseHandle (hIniFile);
  1797. }
  1798. return lResult;
  1799. }
  1800. void
  1801. GetDeviceInfo(
  1802. PMMCGETDEVICEINFO_PARAMS pParams,
  1803. DWORD dwParamsBufferSize,
  1804. LPBYTE pDataBuf,
  1805. LPDWORD pdwNumBytesReturned,
  1806. BOOL bLine
  1807. )
  1808. {
  1809. LONG lResult = LINEERR_NOMEM;
  1810. LPDEVICEINFOLIST pXxxList,
  1811. pInfoListApp;
  1812. //
  1813. // Verify size/offset/string params given our input buffer/size
  1814. //
  1815. if (pParams->dwDeviceInfoListTotalSize > dwParamsBufferSize)
  1816. {
  1817. pParams->lResult = LINEERR_OPERATIONFAILED;
  1818. goto ExitHere;
  1819. }
  1820. if (pParams->dwDeviceInfoListTotalSize < sizeof (*pXxxList))
  1821. {
  1822. pParams->lResult = LINEERR_STRUCTURETOOSMALL;
  1823. goto ExitHere;
  1824. }
  1825. //
  1826. // If there's not an existing device info list then & build a
  1827. // new one or
  1828. // if tsec.ini has been updated outsize, rebuild the DeviceInfoList
  1829. //
  1830. pInfoListApp = (LPDEVICEINFOLIST) pDataBuf;
  1831. EnterCriticalSection(&gMgmtCritSec);
  1832. pXxxList = (bLine ? gpLineInfoList : gpPhoneInfoList);
  1833. if (UpdateLastWriteTime(bLine) == S_FALSE || pXxxList == NULL)
  1834. {
  1835. // First free old infoList if any (if updated outside)
  1836. if (bLine)
  1837. {
  1838. if (gpLineInfoList)
  1839. {
  1840. ServerFree (gpLineInfoList);
  1841. gpLineInfoList = NULL;
  1842. ServerFree (gpLineDevFlags);
  1843. gpLineDevFlags = NULL;
  1844. gdwNumFlags = 0;
  1845. }
  1846. }
  1847. else
  1848. {
  1849. if (gpPhoneInfoList)
  1850. {
  1851. ServerFree (gpPhoneInfoList);
  1852. gpPhoneInfoList = NULL;
  1853. }
  1854. }
  1855. // Create new info list, BuildDeviceInfoList is a long process
  1856. pParams->lResult = BuildDeviceInfoList(bLine);
  1857. if (pParams->lResult != S_OK)
  1858. {
  1859. LeaveCriticalSection(&gMgmtCritSec);
  1860. goto ExitHere;
  1861. }
  1862. }
  1863. //
  1864. // Return the device info list we have in memory
  1865. //
  1866. pXxxList = (bLine ? gpLineInfoList : gpPhoneInfoList);
  1867. ASSERT (pXxxList != NULL);
  1868. if (pParams->dwDeviceInfoListTotalSize < pXxxList->dwNeededSize)
  1869. {
  1870. pInfoListApp->dwNeededSize = pXxxList->dwNeededSize;
  1871. pInfoListApp->dwUsedSize = sizeof (*pInfoListApp);
  1872. pInfoListApp->dwNumDeviceInfoEntries =
  1873. pInfoListApp->dwDeviceInfoSize =
  1874. pInfoListApp->dwDeviceInfoOffset = 0;
  1875. }
  1876. else
  1877. {
  1878. CopyMemory(
  1879. pInfoListApp,
  1880. pXxxList,
  1881. pXxxList->dwNeededSize
  1882. );
  1883. }
  1884. pInfoListApp->dwTotalSize = pParams->dwDeviceInfoListTotalSize;
  1885. pParams->dwDeviceInfoListOffset = 0;
  1886. *pdwNumBytesReturned = sizeof (TAPI32_MSG) + pInfoListApp->dwUsedSize;
  1887. pParams->lResult = 0;
  1888. LeaveCriticalSection(&gMgmtCritSec);
  1889. ExitHere:
  1890. return;
  1891. }
  1892. void
  1893. WINAPI
  1894. MGetLineInfo(
  1895. PTCLIENT ptClient,
  1896. PMMCGETDEVICEINFO_PARAMS pParams,
  1897. DWORD dwParamsBufferSize,
  1898. LPBYTE pDataBuf,
  1899. LPDWORD pdwNumBytesReturned
  1900. )
  1901. {
  1902. GetDeviceInfo(
  1903. pParams,
  1904. dwParamsBufferSize,
  1905. pDataBuf,
  1906. pdwNumBytesReturned,
  1907. TRUE
  1908. );
  1909. }
  1910. void
  1911. WINAPI
  1912. MGetPhoneInfo(
  1913. PTCLIENT ptClient,
  1914. PMMCGETDEVICEINFO_PARAMS pParams,
  1915. DWORD dwParamsBufferSize,
  1916. LPBYTE pDataBuf,
  1917. LPDWORD pdwNumBytesReturned
  1918. )
  1919. {
  1920. GetDeviceInfo(
  1921. pParams,
  1922. dwParamsBufferSize,
  1923. pDataBuf,
  1924. pdwNumBytesReturned,
  1925. FALSE
  1926. );
  1927. }
  1928. void
  1929. SetDeviceInfo(
  1930. PMMCSETDEVICEINFO_PARAMS pParams,
  1931. DWORD dwParamsBufferSize,
  1932. LPBYTE pDataBuf,
  1933. LPDWORD pdwNumBytesReturned,
  1934. BOOL bLine
  1935. )
  1936. {
  1937. DWORD i;
  1938. WCHAR *pDomainUserName, *pDomainUserNames,
  1939. *pFriendlyUserName, *pFriendlyUserNames;
  1940. LPDEVICEINFO pOldInfo, pNewInfo;
  1941. LPDEVICEINFOLIST pNewInfoList = (LPDEVICEINFOLIST) (pDataBuf +
  1942. pParams->dwDeviceInfoListOffset),
  1943. *ppXxxList = (bLine ?
  1944. &gpLineInfoList : &gpPhoneInfoList);
  1945. //
  1946. // Verify size/offset/string params given our input buffer/size
  1947. //
  1948. if (IsBadStructParam(
  1949. dwParamsBufferSize,
  1950. pDataBuf,
  1951. pParams->dwDeviceInfoListOffset
  1952. ))
  1953. {
  1954. pParams->lResult = PHONEERR_OPERATIONFAILED;
  1955. return;
  1956. }
  1957. //
  1958. // Serialize access to global line info list
  1959. //
  1960. if (!(*ppXxxList))
  1961. {
  1962. pParams->lResult = LINEERR_OPERATIONFAILED;
  1963. goto exit;
  1964. }
  1965. //
  1966. // Update the global list & ini file by diff'ing old & new settings
  1967. //
  1968. pNewInfo = (LPDEVICEINFO)
  1969. (((LPBYTE) pNewInfoList) + pNewInfoList->dwDeviceInfoOffset);
  1970. for (i = 0; i < pNewInfoList->dwNumDeviceInfoEntries; i++, pNewInfo++)
  1971. {
  1972. DWORD dwDeviceID;
  1973. DWORD dwIndex;
  1974. TAPIPERMANENTID tpid;
  1975. tpid.dwProviderID = pNewInfo->dwProviderID;
  1976. tpid.dwDeviceID = pNewInfo->dwPermanentDeviceID;
  1977. dwDeviceID = GetDeviceIDFromPermanentID (tpid, bLine);
  1978. if (dwDeviceID == 0xffffffff)
  1979. {
  1980. LOG((TL_ERROR,
  1981. "SetDeviceInfo: bad provider/device IDs (x%x/x%x)",
  1982. pNewInfo->dwProviderID,
  1983. pNewInfo->dwPermanentDeviceID
  1984. ));
  1985. continue;
  1986. }
  1987. pOldInfo = dwDeviceID + ((LPDEVICEINFO) (*ppXxxList + 1));
  1988. //
  1989. // Due to device removal, it is possible pOldInfo is not the entry
  1990. // desired, we need to search back to find the one we want
  1991. //
  1992. dwIndex = dwDeviceID;
  1993. if ((dwDeviceID >= (*ppXxxList)->dwNumDeviceInfoEntries) ||
  1994. (pOldInfo->dwProviderID != tpid.dwProviderID) ||
  1995. (pOldInfo->dwPermanentDeviceID != tpid.dwDeviceID))
  1996. {
  1997. LPDEVICEINFO pInfoFirst = (LPDEVICEINFO)(*ppXxxList + 1);
  1998. DWORD dwLastSchDevice =
  1999. ((*ppXxxList)->dwNumDeviceInfoEntries <= dwDeviceID)?
  2000. ((*ppXxxList)->dwNumDeviceInfoEntries - 1) :
  2001. (dwDeviceID - 1);
  2002. LPDEVICEINFO pInfo = pInfoFirst + dwLastSchDevice;
  2003. while (pInfo >= pInfoFirst &&
  2004. ((pInfo->dwProviderID != tpid.dwProviderID) ||
  2005. (pInfo->dwPermanentDeviceID != tpid.dwDeviceID)))
  2006. {
  2007. --pInfo;
  2008. }
  2009. if (pInfo < pInfoFirst)
  2010. {
  2011. LOG((TL_ERROR,
  2012. "SetDeviceInfo: bad provider/device IDs (x%x/x%x)",
  2013. pNewInfo->dwProviderID,
  2014. pNewInfo->dwPermanentDeviceID
  2015. ));
  2016. continue;
  2017. }
  2018. pOldInfo = pInfo;
  2019. dwIndex = (DWORD)(ULONG_PTR)(pInfo - pInfoFirst);
  2020. }
  2021. //
  2022. // Remove all the old users from this device
  2023. //
  2024. if (pOldInfo->dwDomainUserNamesSize)
  2025. {
  2026. pDomainUserName = (WCHAR *) (((LPBYTE) *ppXxxList) +
  2027. pOldInfo->dwDomainUserNamesOffset);
  2028. while (*pDomainUserName != L'\0')
  2029. {
  2030. ChangeDeviceUserAssociation(
  2031. pDomainUserName,
  2032. NULL,
  2033. pOldInfo->dwProviderID,
  2034. pOldInfo->dwPermanentDeviceID,
  2035. bLine
  2036. );
  2037. pDomainUserName += wcslen (pDomainUserName) + 1;
  2038. }
  2039. pOldInfo->dwDomainUserNamesSize = 0;
  2040. pOldInfo->dwFriendlyUserNamesSize = 0;
  2041. }
  2042. //
  2043. // Add all the new users to this device
  2044. //
  2045. if (pNewInfo->dwDomainUserNamesSize)
  2046. {
  2047. pDomainUserName =
  2048. pDomainUserNames = (WCHAR *) (((LPBYTE) pNewInfoList) +
  2049. pNewInfo->dwDomainUserNamesOffset);
  2050. pFriendlyUserName =
  2051. pFriendlyUserNames = (WCHAR *) (((LPBYTE) pNewInfoList) +
  2052. pNewInfo->dwFriendlyUserNamesOffset);
  2053. while (*pDomainUserName != L'\0')
  2054. {
  2055. ChangeDeviceUserAssociation(
  2056. pDomainUserName,
  2057. pFriendlyUserName,
  2058. pOldInfo->dwProviderID,
  2059. pOldInfo->dwPermanentDeviceID,
  2060. bLine
  2061. );
  2062. pDomainUserName += wcslen (pDomainUserName) + 1;
  2063. pFriendlyUserName += wcslen (pFriendlyUserName) + 1;
  2064. }
  2065. if (InsertInfoListString(
  2066. ppXxxList,
  2067. dwIndex,
  2068. (DWORD) (((LPBYTE) &pNewInfo->dwDomainUserNamesSize) -
  2069. ((LPBYTE) pNewInfo)),
  2070. pDomainUserNames,
  2071. pNewInfo->dwDomainUserNamesSize,
  2072. FALSE
  2073. ))
  2074. {
  2075. }
  2076. if (InsertInfoListString(
  2077. ppXxxList,
  2078. dwIndex,
  2079. (DWORD) (((LPBYTE) &pNewInfo->dwFriendlyUserNamesSize) -
  2080. ((LPBYTE) pNewInfo)),
  2081. pFriendlyUserNames,
  2082. pNewInfo->dwFriendlyUserNamesSize,
  2083. FALSE
  2084. ))
  2085. {
  2086. }
  2087. }
  2088. //
  2089. // Update the device access(phone/line mapping) for the client users
  2090. // send LINE/PHONE_REMOVE if the domain/user lose the access
  2091. // send LINE/PHONE_CREATE if the domain/user gained the access
  2092. //
  2093. {
  2094. TPOINTERLIST clientList = {0}, *pClientList = &clientList;
  2095. DWORD i, j;
  2096. //
  2097. // Walk throught the client list
  2098. //
  2099. GetClientList (FALSE, &pClientList);
  2100. for (i = 0; i < pClientList->dwNumUsedEntries; i++)
  2101. {
  2102. PTCLIENT ptClient;
  2103. BOOL bHaveAccess = FALSE;
  2104. BOOL bGainAccess = FALSE;
  2105. BOOL bLoseAccess = FALSE;
  2106. BOOL bSendMessage = FALSE;
  2107. WCHAR * pwsz = NULL;
  2108. WCHAR wszBuf[255];
  2109. DWORD dw, dwNewDeviceID;
  2110. ptClient = (PTCLIENT) pClientList->aEntries[i];
  2111. //
  2112. // Should this client have access to this device?
  2113. //
  2114. if (WaitForExclusiveClientAccess(ptClient))
  2115. {
  2116. if (IS_FLAG_SET(ptClient->dwFlags, PTCLIENT_FLAG_ADMINISTRATOR) ||
  2117. ptClient->pszDomainName == NULL ||
  2118. ptClient->pszUserName == NULL)
  2119. {
  2120. UNLOCKTCLIENT (ptClient);
  2121. continue;
  2122. }
  2123. dw = wcslen (ptClient->pszDomainName) +
  2124. wcslen (ptClient->pszUserName) + 2;
  2125. dw *= sizeof(WCHAR);
  2126. if (dw > sizeof (wszBuf))
  2127. {
  2128. pwsz = ServerAlloc (dw);
  2129. if (pwsz == NULL)
  2130. {
  2131. UNLOCKTCLIENT (ptClient);
  2132. continue;
  2133. }
  2134. }
  2135. else
  2136. {
  2137. pwsz = wszBuf;
  2138. }
  2139. wcscpy (pwsz, ptClient->pszDomainName);
  2140. wcscat (pwsz, L"\\");
  2141. wcscat (pwsz, ptClient->pszUserName);
  2142. UNLOCKTCLIENT (ptClient);
  2143. }
  2144. else
  2145. {
  2146. continue;
  2147. }
  2148. pDomainUserName = (WCHAR *) (((LPBYTE) pNewInfoList) +
  2149. pNewInfo->dwDomainUserNamesOffset);
  2150. while (*pDomainUserName != L'\0')
  2151. {
  2152. if (lstrcmpiW (pwsz, pDomainUserName) == 0)
  2153. {
  2154. bHaveAccess = TRUE;
  2155. break;
  2156. }
  2157. pDomainUserName += wcslen (pDomainUserName) + 1;
  2158. }
  2159. if (pwsz != wszBuf)
  2160. {
  2161. ServerFree (pwsz);
  2162. }
  2163. //
  2164. // Does the client lose/gain the access to this device
  2165. // if any changes happen, modify the mapping
  2166. //
  2167. if (WaitForExclusiveClientAccess(ptClient))
  2168. {
  2169. LPDWORD lpXxxDevices;
  2170. LPTAPIPERMANENTID lpXxxMap;
  2171. DWORD dwNumDev;
  2172. if (bLine)
  2173. {
  2174. dwNumDev = ptClient->dwLineDevices;
  2175. lpXxxMap = ptClient->pLineMap;
  2176. lpXxxDevices = ptClient->pLineDevices;
  2177. }
  2178. else
  2179. {
  2180. dwNumDev = ptClient->dwPhoneDevices;
  2181. lpXxxMap = ptClient->pPhoneMap;
  2182. lpXxxDevices = ptClient->pPhoneDevices;
  2183. }
  2184. for (j = 0; j < dwNumDev; ++ j)
  2185. {
  2186. if (lpXxxDevices[j] == dwDeviceID)
  2187. {
  2188. bLoseAccess = (!bHaveAccess);
  2189. break;
  2190. }
  2191. }
  2192. if (j == dwNumDev)
  2193. {
  2194. bGainAccess = bHaveAccess;
  2195. }
  2196. if (bLoseAccess)
  2197. {
  2198. lpXxxDevices[j] = 0xffffffff;
  2199. lpXxxMap[j].dwDeviceID = 0xffffff;
  2200. dwNewDeviceID = j;
  2201. }
  2202. if (bGainAccess)
  2203. {
  2204. LPTAPIPERMANENTID lpNewXxxMap;
  2205. LPDWORD lpNewDevices = NULL;
  2206. if (lpNewXxxMap = ServerAlloc (
  2207. sizeof(TAPIPERMANENTID) * (dwNumDev + 1)))
  2208. {
  2209. if (lpNewDevices = ServerAlloc (
  2210. sizeof(DWORD) * (dwNumDev + 1)))
  2211. {
  2212. if (dwNumDev != 0)
  2213. {
  2214. memcpy (
  2215. lpNewXxxMap,
  2216. lpXxxMap,
  2217. sizeof (TAPIPERMANENTID) * dwNumDev
  2218. );
  2219. memcpy (
  2220. lpNewDevices,
  2221. lpXxxDevices,
  2222. sizeof (DWORD) * dwNumDev
  2223. );
  2224. }
  2225. lpNewDevices[dwNumDev] = dwDeviceID;
  2226. lpNewXxxMap[dwNumDev] = tpid;
  2227. ++ dwNumDev;
  2228. }
  2229. else
  2230. {
  2231. ServerFree (lpNewXxxMap);
  2232. UNLOCKTCLIENT (ptClient);
  2233. continue;
  2234. }
  2235. }
  2236. else
  2237. {
  2238. UNLOCKTCLIENT(ptClient);
  2239. continue;
  2240. }
  2241. if (bLine)
  2242. {
  2243. ptClient->dwLineDevices = dwNumDev;
  2244. ServerFree (ptClient->pLineDevices);
  2245. ptClient->pLineDevices = lpNewDevices;
  2246. ServerFree (ptClient->pLineMap);
  2247. ptClient->pLineMap = lpNewXxxMap;
  2248. }
  2249. else
  2250. {
  2251. ptClient->dwPhoneDevices = dwNumDev;
  2252. ServerFree (ptClient->pPhoneDevices);
  2253. ptClient->pPhoneDevices = lpNewDevices;
  2254. ServerFree (ptClient->pPhoneMap);
  2255. ptClient->pPhoneMap = lpNewXxxMap;
  2256. }
  2257. dwNewDeviceID = dwNumDev - 1;
  2258. }
  2259. //
  2260. // Need to send messsage if there is
  2261. // any line/phoneInitialize(Ex)
  2262. //
  2263. if ((ptClient->ptLineApps && bLine) ||
  2264. (ptClient->ptPhoneApps && (!bLine)))
  2265. {
  2266. if (bLoseAccess || bGainAccess)
  2267. {
  2268. bSendMessage = TRUE;
  2269. }
  2270. }
  2271. UNLOCKTCLIENT (ptClient);
  2272. }
  2273. else
  2274. {
  2275. continue;
  2276. }
  2277. if (bSendMessage)
  2278. {
  2279. ASYNCEVENTMSG msg;
  2280. TPOINTERLIST xxxAppList = {0},
  2281. *pXxxAppList = &xxxAppList;
  2282. msg.TotalSize = sizeof (ASYNCEVENTMSG);
  2283. msg.fnPostProcessProcHandle = 0;
  2284. msg.Msg = (bLine ?
  2285. (bLoseAccess? LINE_REMOVE : LINE_CREATE) :
  2286. (bLoseAccess? PHONE_REMOVE: PHONE_CREATE));
  2287. msg.Param1 = dwNewDeviceID;
  2288. if (bLine)
  2289. {
  2290. GetLineAppListFromClient (ptClient, &pXxxAppList);
  2291. }
  2292. else
  2293. {
  2294. GetPhoneAppListFromClient (ptClient, &pXxxAppList);
  2295. }
  2296. for (i = 0; i < pXxxAppList->dwNumUsedEntries; ++i)
  2297. {
  2298. BOOL b;
  2299. try
  2300. {
  2301. if (bLine)
  2302. {
  2303. PTLINEAPP ptLineApp =
  2304. (PTLINEAPP) pXxxAppList->aEntries[i];
  2305. b = FMsgDisabled (
  2306. ptLineApp->dwAPIVersion,
  2307. ptLineApp->adwEventSubMasks,
  2308. (DWORD) msg.Msg,
  2309. (DWORD) msg.Param1
  2310. );
  2311. msg.InitContext = ptLineApp->InitContext;
  2312. }
  2313. else
  2314. {
  2315. PTPHONEAPP ptPhoneApp =
  2316. (PTPHONEAPP) pXxxAppList->aEntries[i];
  2317. b = FMsgDisabled (
  2318. ptPhoneApp->dwAPIVersion,
  2319. ptPhoneApp->adwEventSubMasks,
  2320. (DWORD) msg.Msg,
  2321. (DWORD) msg.Param1
  2322. );
  2323. msg.InitContext = ptPhoneApp->InitContext;
  2324. }
  2325. }
  2326. myexcept
  2327. {
  2328. continue;
  2329. }
  2330. if (b)
  2331. {
  2332. continue;
  2333. }
  2334. WriteEventBuffer (ptClient, &msg);
  2335. }
  2336. if (pXxxAppList != &xxxAppList)
  2337. {
  2338. ServerFree (pXxxAppList);
  2339. }
  2340. }
  2341. //
  2342. // If the user loses the device access, anything
  2343. // opened about the device needs to be closed
  2344. //
  2345. if (bLoseAccess)
  2346. {
  2347. //
  2348. // Walk throught all its TLINEAPP
  2349. //
  2350. if (bLine)
  2351. {
  2352. PTLINELOOKUPENTRY ptLineLookup;
  2353. PTLINE ptLine;
  2354. PTLINECLIENT ptLineClient, pNextLineClient;
  2355. HANDLE hMutex;
  2356. BOOL bDupedMutex;
  2357. ptLineLookup = GetLineLookupEntry(dwDeviceID);
  2358. if (!ptLineLookup || !(ptLine = ptLineLookup->ptLine));
  2359. {
  2360. continue;
  2361. }
  2362. if (!WaitForExclusivetLineAccess(
  2363. ptLine,
  2364. &hMutex,
  2365. &bDupedMutex,
  2366. INFINITE
  2367. ))
  2368. {
  2369. continue;
  2370. }
  2371. ptLineClient = ptLine->ptLineClients;
  2372. while (ptLineClient)
  2373. {
  2374. if (WaitForExclusiveLineClientAccess(ptLineClient))
  2375. {
  2376. pNextLineClient = ptLineClient->pNextSametLine;
  2377. if (ptLineClient->ptClient == ptClient)
  2378. {
  2379. HLINE hLine = ptLineClient->hLine;
  2380. UNLOCKTLINECLIENT (ptLineClient);
  2381. DestroytLineClient(ptLineClient->hLine);
  2382. }
  2383. else
  2384. {
  2385. UNLOCKTLINECLIENT (ptLineClient);
  2386. }
  2387. ptLineClient = pNextLineClient;
  2388. }
  2389. else
  2390. {
  2391. break;
  2392. }
  2393. }
  2394. MyReleaseMutex(hMutex, bDupedMutex);
  2395. }
  2396. //
  2397. // Walk throught all its TPHONEAPP
  2398. //
  2399. else
  2400. {
  2401. PTPHONELOOKUPENTRY ptPhoneLookup;
  2402. PTPHONE ptPhone;
  2403. PTPHONECLIENT ptPhoneClient, pNextPhoneClient;
  2404. HANDLE hMutex;
  2405. BOOL bDupedMutex;
  2406. ptPhoneLookup = GetPhoneLookupEntry(dwDeviceID);
  2407. if (!ptPhoneLookup || !(ptPhone = ptPhoneLookup->ptPhone));
  2408. {
  2409. continue;
  2410. }
  2411. if (!WaitForExclusivetPhoneAccess(
  2412. ptPhone,
  2413. &hMutex,
  2414. &bDupedMutex,
  2415. INFINITE
  2416. ))
  2417. {
  2418. continue;
  2419. }
  2420. ptPhoneClient = ptPhone->ptPhoneClients;
  2421. while (ptPhoneClient)
  2422. {
  2423. if (WaitForExclusivePhoneClientAccess(ptPhoneClient))
  2424. {
  2425. pNextPhoneClient = ptPhoneClient->pNextSametPhone;
  2426. if (ptPhoneClient->ptClient == ptClient)
  2427. {
  2428. HPHONE hPhone = ptPhoneClient->hPhone;
  2429. UNLOCKTPHONECLIENT (ptPhoneClient);
  2430. DestroytPhoneClient(ptPhoneClient->hPhone);
  2431. }
  2432. else
  2433. {
  2434. UNLOCKTPHONECLIENT (ptPhoneClient);
  2435. }
  2436. ptPhoneClient = pNextPhoneClient;
  2437. }
  2438. else
  2439. {
  2440. break;
  2441. }
  2442. }
  2443. MyReleaseMutex (hMutex, bDupedMutex);
  2444. }
  2445. }
  2446. }
  2447. if (pClientList != &clientList)
  2448. {
  2449. ServerFree (pClientList);
  2450. }
  2451. }
  2452. }
  2453. //
  2454. // Reset the dwNeededSize field since it might have grown adding
  2455. // users to devices
  2456. //
  2457. (*ppXxxList)->dwNeededSize = (*ppXxxList)->dwUsedSize;
  2458. exit:
  2459. return;
  2460. }
  2461. void
  2462. WINAPI
  2463. MSetLineInfo(
  2464. PTCLIENT ptClient,
  2465. PMMCSETDEVICEINFO_PARAMS pParams,
  2466. DWORD dwParamsBufferSize,
  2467. LPBYTE pDataBuf,
  2468. LPDWORD pdwNumBytesReturned
  2469. )
  2470. {
  2471. BOOL bDidLock;
  2472. if (WaitForExclusiveClientAccess(ptClient))
  2473. {
  2474. bDidLock =
  2475. IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
  2476. UNLOCKTCLIENT (ptClient);
  2477. }
  2478. else
  2479. {
  2480. bDidLock = FALSE;
  2481. }
  2482. EnterCriticalSection (&gMgmtCritSec);
  2483. if (gbLockMMCWrite && !bDidLock)
  2484. {
  2485. pParams->lResult = TAPIERR_MMCWRITELOCKED;
  2486. }
  2487. else
  2488. {
  2489. SetDeviceInfo(
  2490. pParams,
  2491. dwParamsBufferSize,
  2492. pDataBuf,
  2493. pdwNumBytesReturned,
  2494. TRUE
  2495. );
  2496. UpdateLastWriteTime(TRUE);
  2497. }
  2498. LeaveCriticalSection (&gMgmtCritSec);
  2499. }
  2500. void
  2501. WINAPI
  2502. MSetPhoneInfo(
  2503. PTCLIENT ptClient,
  2504. PMMCSETDEVICEINFO_PARAMS pParams,
  2505. DWORD dwParamsBufferSize,
  2506. LPBYTE pDataBuf,
  2507. LPDWORD pdwNumBytesReturned
  2508. )
  2509. {
  2510. BOOL bDidLock;
  2511. if (WaitForExclusiveClientAccess(ptClient))
  2512. {
  2513. bDidLock =
  2514. IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
  2515. UNLOCKTCLIENT (ptClient);
  2516. }
  2517. else
  2518. {
  2519. bDidLock = FALSE;
  2520. }
  2521. EnterCriticalSection (&gMgmtCritSec);
  2522. if (gbLockMMCWrite && !bDidLock)
  2523. {
  2524. pParams->lResult = TAPIERR_MMCWRITELOCKED;
  2525. }
  2526. else
  2527. {
  2528. SetDeviceInfo(
  2529. pParams,
  2530. dwParamsBufferSize,
  2531. pDataBuf,
  2532. pdwNumBytesReturned,
  2533. FALSE
  2534. );
  2535. UpdateLastWriteTime(FALSE);
  2536. }
  2537. LeaveCriticalSection (&gMgmtCritSec);
  2538. }
  2539. VOID
  2540. PASCAL
  2541. InsertString(
  2542. LPVOID pStruct,
  2543. LPDWORD pdwXxxSize,
  2544. LPWSTR pString
  2545. )
  2546. {
  2547. DWORD dwSize = (wcslen (pString) + 1) * sizeof (WCHAR);
  2548. CopyMemory(
  2549. ((LPBYTE) pStruct) + ((LPVARSTRING) pStruct)->dwUsedSize,
  2550. pString,
  2551. dwSize
  2552. );
  2553. if (*pdwXxxSize == 0) // if dwXxxSize == 0 set dwXxxOffset
  2554. {
  2555. *(pdwXxxSize + 1) = ((LPVARSTRING) pStruct)->dwUsedSize;
  2556. }
  2557. ((LPVARSTRING) pStruct)->dwUsedSize += dwSize;
  2558. *pdwXxxSize += dwSize;
  2559. }
  2560. LONG
  2561. PASCAL
  2562. GetDomainAndUserNames(
  2563. WCHAR **ppDomainName,
  2564. WCHAR **ppUserName
  2565. )
  2566. {
  2567. LONG lResult = LINEERR_OPERATIONFAILED;
  2568. DWORD dwInfoBufferSize, dwSize, dwAccountNameSize,
  2569. dwDomainNameSize;
  2570. HANDLE hAccessToken;
  2571. LPWSTR InfoBuffer, lpszAccountName, lpszDomainName;
  2572. PTOKEN_USER ptuUser;
  2573. SID_NAME_USE use;
  2574. if (!OpenProcessToken (GetCurrentProcess(), TOKEN_READ, &hAccessToken))
  2575. {
  2576. LOG((TL_ERROR,
  2577. "GetAccountInfo: OpenThreadToken failed, error=%d",
  2578. GetLastError()
  2579. ));
  2580. goto GetDomainAndUserNames_return;
  2581. }
  2582. dwSize = 1000;
  2583. dwInfoBufferSize = 0;
  2584. InfoBuffer = (LPWSTR) ServerAlloc (dwSize);
  2585. if (!InfoBuffer)
  2586. {
  2587. CloseHandle (hAccessToken);
  2588. return LINEERR_NOMEM;
  2589. }
  2590. ptuUser = (PTOKEN_USER) InfoBuffer;
  2591. if (!GetTokenInformation(
  2592. hAccessToken,
  2593. TokenUser,
  2594. InfoBuffer,
  2595. dwSize,
  2596. &dwInfoBufferSize
  2597. ))
  2598. {
  2599. LOG((TL_ERROR,
  2600. "GetAccountInfo: GetTokenInformation failed, error=%d",
  2601. GetLastError()
  2602. ));
  2603. goto close_AccessToken;
  2604. }
  2605. if (!(lpszAccountName = ServerAlloc (200)))
  2606. {
  2607. lResult = LINEERR_NOMEM;
  2608. goto free_InfoBuffer;
  2609. }
  2610. if (!(lpszDomainName = ServerAlloc (200)))
  2611. {
  2612. lResult = LINEERR_NOMEM;
  2613. goto free_AccountName;
  2614. }
  2615. dwAccountNameSize = dwDomainNameSize = 200;
  2616. if (!LookupAccountSidW(
  2617. NULL,
  2618. ptuUser->User.Sid,
  2619. lpszAccountName,
  2620. &dwAccountNameSize,
  2621. lpszDomainName,
  2622. &dwDomainNameSize,
  2623. &use
  2624. ))
  2625. {
  2626. LOG((TL_ERROR,
  2627. "GetAccountInfo: LookupAccountSidW failed, error=%d",
  2628. GetLastError()
  2629. ));
  2630. }
  2631. else
  2632. {
  2633. LOG((TL_INFO,
  2634. "GetAccountInfo: User name %ls Domain name %ls",
  2635. lpszAccountName,
  2636. lpszDomainName
  2637. ));
  2638. lResult = 0;
  2639. *ppDomainName = lpszDomainName;
  2640. *ppUserName = lpszAccountName;
  2641. goto free_InfoBuffer;
  2642. }
  2643. ServerFree (lpszDomainName);
  2644. free_AccountName:
  2645. ServerFree (lpszAccountName);
  2646. free_InfoBuffer:
  2647. ServerFree (InfoBuffer);
  2648. close_AccessToken:
  2649. CloseHandle (hAccessToken);
  2650. GetDomainAndUserNames_return:
  2651. return lResult;
  2652. }
  2653. BOOL
  2654. IsNTServer(
  2655. void
  2656. )
  2657. {
  2658. BOOL bResult = FALSE;
  2659. TCHAR szProductType[64];
  2660. HKEY hKey;
  2661. DWORD dwDataSize;
  2662. DWORD dwDataType;
  2663. if (RegOpenKeyEx(
  2664. HKEY_LOCAL_MACHINE,
  2665. gszRegKeyNTServer,
  2666. 0,
  2667. KEY_QUERY_VALUE,
  2668. &hKey
  2669. ) == ERROR_SUCCESS)
  2670. {
  2671. dwDataSize = 64*sizeof(TCHAR);
  2672. if (RegQueryValueEx(
  2673. hKey,
  2674. gszProductType,
  2675. 0,
  2676. &dwDataType,
  2677. (LPBYTE) szProductType,
  2678. &dwDataSize
  2679. ) == ERROR_SUCCESS)
  2680. if ((!lstrcmpi (szProductType, gszProductTypeServer)) ||
  2681. (!lstrcmpi (szProductType, gszProductTypeLanmanNt)))
  2682. {
  2683. bResult = TRUE;
  2684. }
  2685. RegCloseKey (hKey);
  2686. }
  2687. return bResult;
  2688. }
  2689. BOOL
  2690. IsSharingEnabled(
  2691. void
  2692. )
  2693. {
  2694. HKEY hKey;
  2695. BOOL bResult = FALSE;
  2696. DWORD dwType, dwDisableSharing;
  2697. if (RegOpenKeyEx(
  2698. HKEY_LOCAL_MACHINE,
  2699. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Server"),
  2700. 0,
  2701. KEY_ALL_ACCESS,
  2702. &hKey
  2703. ) == ERROR_SUCCESS)
  2704. {
  2705. DWORD dwSize = sizeof (dwDisableSharing);
  2706. dwDisableSharing = 1; // default is sharing == disabled
  2707. if (RegQueryValueEx(
  2708. hKey,
  2709. TEXT("DisableSharing"),
  2710. 0,
  2711. &dwType,
  2712. (LPBYTE) &dwDisableSharing,
  2713. &dwSize
  2714. ) == ERROR_SUCCESS)
  2715. {
  2716. bResult = (dwDisableSharing ? FALSE : TRUE);
  2717. }
  2718. RegCloseKey (hKey);
  2719. }
  2720. return bResult;
  2721. }
  2722. void
  2723. WINAPI
  2724. MGetServerConfig(
  2725. PTCLIENT ptClient,
  2726. PMMCGETSERVERCONFIG_PARAMS pParams,
  2727. DWORD dwParamsBufferSize,
  2728. LPBYTE pDataBuf,
  2729. LPDWORD pdwNumBytesReturned
  2730. )
  2731. {
  2732. LONG lResult;
  2733. DWORD dwDomainNameSize, dwUserNameSize, dwValuesSize,
  2734. dwResult, dwNeededSize;
  2735. WCHAR *pValues = NULL, *pValue;
  2736. LPWSTR pDomainName, pUserName;
  2737. LPTAPISERVERCONFIG pServerConfig = (LPTAPISERVERCONFIG) pDataBuf;
  2738. //
  2739. // Verify size/offset/string params given our input buffer/size
  2740. //
  2741. if (pParams->dwServerConfigTotalSize > dwParamsBufferSize)
  2742. {
  2743. pParams->lResult = LINEERR_OPERATIONFAILED;
  2744. return;
  2745. }
  2746. //
  2747. // Make sure the buffer is >= fixed size of the structure
  2748. //
  2749. if (pParams->dwServerConfigTotalSize < sizeof (*pServerConfig))
  2750. {
  2751. pParams->lResult = LINEERR_STRUCTURETOOSMALL;
  2752. return;
  2753. }
  2754. pServerConfig->dwTotalSize = pParams->dwServerConfigTotalSize;
  2755. //
  2756. // If this is not an NT server then just set the needed/used size
  2757. // fields & jump to done
  2758. //
  2759. if (!IsNTServer())
  2760. {
  2761. pServerConfig->dwNeededSize =
  2762. pServerConfig->dwUsedSize = sizeof (*pServerConfig);
  2763. goto MGetServerConfig_done;
  2764. }
  2765. //
  2766. // Retrieve domain & user name strings, & calc their length in bytes
  2767. //
  2768. if ((lResult = GetDomainAndUserNames (&pDomainName, &pUserName)))
  2769. {
  2770. pParams->lResult = lResult;
  2771. return;
  2772. }
  2773. dwDomainNameSize = (wcslen (pDomainName) + 1) * sizeof (WCHAR);
  2774. dwUserNameSize = (wcslen (pUserName) + 1) * sizeof (WCHAR);
  2775. //
  2776. // Retrieve the list of tapi administrators
  2777. //
  2778. do
  2779. {
  2780. if (pValues)
  2781. {
  2782. ServerFree (pValues);
  2783. dwValuesSize *= 2;
  2784. }
  2785. else
  2786. {
  2787. dwValuesSize = 256;
  2788. }
  2789. if (!(pValues = ServerAlloc (dwValuesSize * sizeof (WCHAR))))
  2790. {
  2791. pParams->lResult = LINEERR_NOMEM;
  2792. goto MGetServerConfig_freeNames;
  2793. }
  2794. pValues[0] = L'\0';
  2795. dwResult = GetPrivateProfileSectionW(
  2796. gszTapiAdministrators,
  2797. pValues,
  2798. dwValuesSize,
  2799. gszFileName
  2800. );
  2801. } while (dwResult >= (dwValuesSize - 2));
  2802. dwNeededSize = dwDomainNameSize + dwUserNameSize + dwValuesSize;
  2803. //
  2804. // Fill in the server config structure
  2805. //
  2806. ZeroMemory(
  2807. &pServerConfig->dwFlags,
  2808. sizeof (*pServerConfig) - (3 * sizeof (DWORD))
  2809. );
  2810. pServerConfig->dwFlags |= TAPISERVERCONFIGFLAGS_ISSERVER;
  2811. if (IsSharingEnabled())
  2812. {
  2813. pServerConfig->dwFlags |= TAPISERVERCONFIGFLAGS_ENABLESERVER;
  2814. }
  2815. if (pServerConfig->dwTotalSize < dwNeededSize)
  2816. {
  2817. pServerConfig->dwNeededSize = dwNeededSize;
  2818. pServerConfig->dwUsedSize = sizeof (*pServerConfig);
  2819. }
  2820. else
  2821. {
  2822. pServerConfig->dwUsedSize = sizeof (*pServerConfig);
  2823. InsertString(
  2824. pServerConfig,
  2825. &pServerConfig->dwDomainNameSize,
  2826. pDomainName
  2827. );
  2828. InsertString(
  2829. pServerConfig,
  2830. &pServerConfig->dwUserNameSize,
  2831. pUserName
  2832. );
  2833. pValue = pValues;
  2834. while (*pValue != L'\0')
  2835. {
  2836. //
  2837. // The string looks like "Domain\User=1", and we want
  2838. // the "Domain\User" part.
  2839. //
  2840. //
  2841. // Walk the string until we find a '=' char, or ' ' space
  2842. // (which might result from user editing ini file manually),
  2843. // or a NULL char (implying corruption).
  2844. //
  2845. WCHAR *p;
  2846. for (p = pValue; *p != L'\0' && *p != L'=' && *p != L' '; p++);
  2847. //
  2848. // If we found a '=' or ' ' char then we're good to go.
  2849. //
  2850. // A more robust check would be to see that the following
  2851. // string looks like "=1" or "1" (possibly with some spaces
  2852. // thrown in) to make sure.
  2853. //
  2854. if (*p != L'\0')
  2855. {
  2856. *p = L'\0';
  2857. InsertString(
  2858. pServerConfig,
  2859. &pServerConfig->dwAdministratorsSize,
  2860. pValue
  2861. );
  2862. //
  2863. // Skip the NULL we set above & look for the next NULL
  2864. //
  2865. for (++p; *p != L'\0'; p++);
  2866. }
  2867. //
  2868. // Skip the NULL
  2869. //
  2870. pValue = p + 1;
  2871. }
  2872. if (pServerConfig->dwAdministratorsSize)
  2873. {
  2874. InsertString(
  2875. pServerConfig,
  2876. &pServerConfig->dwAdministratorsSize,
  2877. gszEmptyString
  2878. );
  2879. }
  2880. pServerConfig->dwNeededSize = pServerConfig->dwUsedSize;
  2881. }
  2882. ServerFree (pValues);
  2883. MGetServerConfig_freeNames:
  2884. ServerFree (pDomainName);
  2885. ServerFree (pUserName);
  2886. MGetServerConfig_done:
  2887. if (pParams->lResult == 0)
  2888. {
  2889. pParams->dwServerConfigOffset = 0;
  2890. *pdwNumBytesReturned = sizeof (TAPI32_MSG) +
  2891. pServerConfig->dwUsedSize;
  2892. }
  2893. }
  2894. LONG
  2895. PASCAL
  2896. WriteRegistryKeys(
  2897. LPTSTR lpszMapper,
  2898. LPTSTR lpszDlls,
  2899. DWORD dwDisableSharing
  2900. )
  2901. {
  2902. LONG lResult = LINEERR_OPERATIONFAILED;
  2903. HKEY hKeyTelephony, hKey;
  2904. DWORD dw;
  2905. if (RegOpenKeyEx(
  2906. HKEY_LOCAL_MACHINE,
  2907. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Telephony"),
  2908. 0,
  2909. KEY_ALL_ACCESS,
  2910. &hKeyTelephony
  2911. ) == ERROR_SUCCESS)
  2912. {
  2913. if (RegCreateKeyEx(
  2914. hKeyTelephony,
  2915. TEXT("Server"),
  2916. 0,
  2917. NULL,
  2918. REG_OPTION_NON_VOLATILE,
  2919. KEY_ALL_ACCESS,
  2920. NULL,
  2921. &hKey,
  2922. &dw
  2923. ) == ERROR_SUCCESS)
  2924. {
  2925. if (RegSetValueEx(
  2926. hKey,
  2927. TEXT("DisableSharing"),
  2928. 0,
  2929. REG_DWORD,
  2930. (LPBYTE) &dwDisableSharing,
  2931. sizeof (dwDisableSharing)
  2932. ) == ERROR_SUCCESS &&
  2933. RegSetValueEx(
  2934. hKey,
  2935. TEXT("MapperDll"),
  2936. 0,
  2937. REG_SZ,
  2938. (LPBYTE) TEXT ("TSEC.DLL"),
  2939. (lstrlen (TEXT ("TSEC.DLL")) + 1) * sizeof (TCHAR)
  2940. ) == ERROR_SUCCESS)
  2941. {
  2942. lResult = 0;
  2943. }
  2944. RegCloseKey (hKeyTelephony);
  2945. }
  2946. RegCloseKey (hKey);
  2947. }
  2948. return lResult;
  2949. }
  2950. LONG
  2951. PASCAL
  2952. WriteServiceConfig(
  2953. LPWSTR pDomainName,
  2954. LPWSTR pUserName,
  2955. LPWSTR pPassword,
  2956. BOOL bServer
  2957. )
  2958. {
  2959. LONG lResult = LINEERR_OPERATIONFAILED;
  2960. SC_HANDLE sch, sc_tapisrv;
  2961. if ((sch = OpenSCManager (NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE)))
  2962. {
  2963. if ((sc_tapisrv = OpenService(
  2964. sch,
  2965. TEXT("TAPISRV"),
  2966. SERVICE_CHANGE_CONFIG
  2967. )))
  2968. {
  2969. DWORD dwSize;
  2970. WCHAR *pDomainUserName;
  2971. dwSize = (wcslen (pDomainName) + wcslen (pUserName) + 2) *\
  2972. sizeof (WCHAR);
  2973. if ((pDomainUserName = ServerAlloc (dwSize)))
  2974. {
  2975. wcscpy (pDomainUserName, pDomainName);
  2976. wcscat (pDomainUserName, L"\\");
  2977. wcscat (pDomainUserName, pUserName);
  2978. if ((ChangeServiceConfigW(
  2979. sc_tapisrv,
  2980. SERVICE_WIN32_OWN_PROCESS,
  2981. bServer ? SERVICE_AUTO_START : SERVICE_DEMAND_START,
  2982. SERVICE_NO_CHANGE,
  2983. NULL,
  2984. NULL,
  2985. NULL,
  2986. NULL,
  2987. pDomainUserName,
  2988. pPassword,
  2989. NULL
  2990. )))
  2991. {
  2992. lResult = 0;
  2993. }
  2994. else
  2995. {
  2996. LOG((TL_ERROR,
  2997. "WriteServiceConfig: ChangeServiceConfig " \
  2998. "failed, err=%ld",
  2999. GetLastError()
  3000. ));
  3001. }
  3002. ServerFree (pDomainUserName);
  3003. }
  3004. else
  3005. {
  3006. lResult = LINEERR_NOMEM;
  3007. }
  3008. CloseServiceHandle(sc_tapisrv);
  3009. }
  3010. CloseServiceHandle(sch);
  3011. }
  3012. return lResult;
  3013. }
  3014. void
  3015. WINAPI
  3016. MSetServerConfig(
  3017. PTCLIENT ptClient,
  3018. PMMCSETSERVERCONFIG_PARAMS pParams,
  3019. DWORD dwParamsBufferSize,
  3020. LPBYTE pDataBuf,
  3021. LPDWORD pdwNumBytesReturned
  3022. )
  3023. {
  3024. LONG lResult;
  3025. BOOL bIsSharingEnabled;
  3026. LPTAPISERVERCONFIG pServerConfig = (LPTAPISERVERCONFIG)
  3027. (pDataBuf + pParams->dwServerConfigOffset);
  3028. pParams->lResult = 0;
  3029. //
  3030. // Verify size/offset/string params given our input buffer/size
  3031. //
  3032. if (IsBadStructParam(
  3033. dwParamsBufferSize,
  3034. pDataBuf,
  3035. pParams->dwServerConfigOffset
  3036. ))
  3037. {
  3038. pParams->lResult = PHONEERR_OPERATIONFAILED;
  3039. return;
  3040. }
  3041. if (!IsNTServer())
  3042. {
  3043. pParams->lResult = LINEERR_OPERATIONFAILED;
  3044. return;
  3045. }
  3046. bIsSharingEnabled = IsSharingEnabled();
  3047. if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_LOCKMMCWRITE)
  3048. {
  3049. EnterCriticalSection (&gMgmtCritSec);
  3050. if (gbLockMMCWrite)
  3051. {
  3052. pParams->lResult = TAPIERR_MMCWRITELOCKED;
  3053. }
  3054. else
  3055. {
  3056. gbLockMMCWrite = TRUE;
  3057. }
  3058. LeaveCriticalSection (&gMgmtCritSec);
  3059. if (pParams->lResult)
  3060. {
  3061. return;
  3062. }
  3063. else if (WaitForExclusiveClientAccess (ptClient))
  3064. {
  3065. SET_FLAG (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
  3066. UNLOCKTCLIENT (ptClient);
  3067. }
  3068. }
  3069. if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_UNLOCKMMCWRITE &&
  3070. WaitForExclusiveClientAccess (ptClient))
  3071. {
  3072. BOOL bToUnlock;
  3073. bToUnlock =
  3074. IS_FLAG_SET (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
  3075. RESET_FLAG (ptClient->dwFlags, PTCLIENT_FLAG_LOCKEDMMCWRITE);
  3076. UNLOCKTCLIENT (ptClient);
  3077. if (bToUnlock)
  3078. {
  3079. EnterCriticalSection (&gMgmtCritSec);
  3080. gbLockMMCWrite = FALSE;
  3081. LeaveCriticalSection (&gMgmtCritSec);
  3082. }
  3083. }
  3084. if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_SETACCOUNT)
  3085. {
  3086. HANDLE hToken;
  3087. LPWSTR pUserName, pDomainName, pPassword;
  3088. pUserName = (LPWSTR)
  3089. (((LPBYTE) pServerConfig) + pServerConfig->dwUserNameOffset);
  3090. pDomainName = (LPWSTR)
  3091. (((LPBYTE) pServerConfig) + pServerConfig->dwDomainNameOffset);
  3092. pPassword = (LPWSTR)
  3093. (((LPBYTE) pServerConfig) + pServerConfig->dwPasswordOffset);
  3094. //
  3095. // Make sure the new name/domain/password are valid
  3096. //
  3097. if (!LogonUserW(
  3098. pUserName,
  3099. pDomainName,
  3100. pPassword,
  3101. LOGON32_LOGON_NETWORK,
  3102. LOGON32_PROVIDER_DEFAULT,
  3103. &hToken
  3104. ))
  3105. {
  3106. LOG((TL_ERROR,
  3107. "MSetServerConfig: LogonUser failed, err=%ld",
  3108. GetLastError()
  3109. ));
  3110. pParams->lResult = ERROR_LOGON_FAILURE;
  3111. return;
  3112. }
  3113. CloseHandle (hToken);
  3114. //
  3115. //
  3116. //
  3117. if ((lResult = WriteServiceConfig(
  3118. pDomainName,
  3119. pUserName,
  3120. pPassword,
  3121. (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER)
  3122. )))
  3123. {
  3124. LOG((TL_ERROR,
  3125. "MSetServerConfig: WriteServiceConfig failed, err=%ld",
  3126. lResult
  3127. ));
  3128. pParams->lResult = lResult;
  3129. return;
  3130. }
  3131. }
  3132. if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER &&
  3133. !bIsSharingEnabled)
  3134. {
  3135. if ((pParams->lResult = CreateTapiSCP (NULL, NULL)) != 0)
  3136. {
  3137. LOG((TL_ERROR,
  3138. "MSetServerConfig: CreateTapiSCP failed, err=%ld",
  3139. pParams->lResult
  3140. ));
  3141. return;
  3142. }
  3143. }
  3144. else if (!(pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_ENABLESERVER) &&
  3145. bIsSharingEnabled)
  3146. {
  3147. if ((pParams->lResult = RemoveTapiSCP ()) != 0)
  3148. {
  3149. LOG((TL_ERROR,
  3150. "MSetServerConfig: RemoveTapiSCP failed, err=%ld",
  3151. pParams->lResult
  3152. ));
  3153. return;
  3154. }
  3155. else
  3156. {
  3157. // This is not a Telephony server anymore, so reset the flag
  3158. TapiGlobals.dwFlags = TapiGlobals.dwFlags & ~TAPIGLOBALS_SERVER;
  3159. }
  3160. }
  3161. if ((lResult = WriteRegistryKeys(
  3162. NULL,
  3163. NULL,
  3164. (DWORD) ((pServerConfig->dwFlags &
  3165. TAPISERVERCONFIGFLAGS_ENABLESERVER) ? 0 : 1)
  3166. )))
  3167. {
  3168. LOG((TL_ERROR,
  3169. "MSetServerConfig: WriteRegistryKeys failed, err=%ld",
  3170. lResult
  3171. ));
  3172. pParams->lResult = LINEERR_OPERATIONFAILED;
  3173. return;
  3174. }
  3175. if (pServerConfig->dwFlags & TAPISERVERCONFIGFLAGS_SETTAPIADMINISTRATORS)
  3176. {
  3177. WCHAR *pAdmin, buf[16];
  3178. DWORD i;
  3179. //
  3180. // Reset the TapiAdministrators section
  3181. //
  3182. if (WritePrivateProfileSectionW(
  3183. gszTapiAdministrators,
  3184. L"\0",
  3185. gszFileName) == 0)
  3186. {
  3187. pParams->lResult = LINEERR_OPERATIONFAILED;
  3188. return;
  3189. }
  3190. pAdmin = (WCHAR *)
  3191. (((LPBYTE) pServerConfig) + pServerConfig->dwAdministratorsOffset);
  3192. //
  3193. // For each admin in the list write out a "Domain\User=1"
  3194. // value to the TapiAdministrators section
  3195. //
  3196. for (i = 0; *pAdmin != L'\0'; i++)
  3197. {
  3198. if (WritePrivateProfileStringW(
  3199. gszTapiAdministrators,
  3200. pAdmin,
  3201. L"1",
  3202. gszFileName
  3203. ) == 0)
  3204. {
  3205. pParams->lResult = LINEERR_OPERATIONFAILED;
  3206. return;
  3207. }
  3208. pAdmin += (wcslen (pAdmin) + 1);
  3209. }
  3210. }
  3211. }
  3212. typedef BOOL ( APIENTRY GETFILEVERSIONINFO(
  3213. LPWSTR lptstrFilename, // pointer to filename string
  3214. DWORD dwHandle, // ignored
  3215. DWORD dwLen, // size of buffer
  3216. LPVOID lpData // pointer to buffer to receive file-version info.
  3217. ));
  3218. typedef DWORD ( APIENTRY GETFILEVERSIONINFOSIZE(
  3219. LPWSTR lptstrFilename, // pointer to filename string
  3220. LPDWORD lpdwHandle // pointer to variable to receive zero
  3221. ));
  3222. typedef BOOL ( APIENTRY VERQUERYVALUE(
  3223. const LPVOID pBlock, // address of buffer for version resource
  3224. LPWSTR lpSubBlock, // address of value to retrieve
  3225. LPVOID *lplpBuffer, // address of buffer for version pointer
  3226. PUINT puLen // address of version-value length buffer
  3227. ));
  3228. static WCHAR gszVarFileInfo[] = L"\\VarFileInfo\\Translation";
  3229. static WCHAR gszStringFileInfo[] = L"\\StringFileInfo\\%04x%04x\\FileDescription";
  3230. //
  3231. // EmanP
  3232. // Given a multisz of file names,
  3233. // allocates a multisz of friendly names.
  3234. // Returns the number of bytes in the frienly name multisz
  3235. //
  3236. //
  3237. DWORD
  3238. GetProviderFriendlyName(
  3239. /*IN */ WCHAR *pFileNameBuf,
  3240. /*OUT*/ WCHAR **ppFriendlyNameBuf
  3241. )
  3242. {
  3243. DWORD dwBufTotalSize = 0,
  3244. dwBufUsedSize = 0,
  3245. dwVerSize = 0,
  3246. dwSize,
  3247. dwVerHandle;
  3248. UINT uItemSize;
  3249. HINSTANCE hVerDll;
  3250. GETFILEVERSIONINFO *pGetFileVersionInfo;
  3251. GETFILEVERSIONINFOSIZE *pGetFileVersionInfoSize;
  3252. VERQUERYVALUE *pVerQueryValue;
  3253. WCHAR *pFileName = pFileNameBuf,
  3254. *pszBuffer,
  3255. *pFriendlyNameBuf = NULL,
  3256. *p;
  3257. BYTE *pbVerData = NULL;
  3258. WCHAR szItem[1024];
  3259. WORD wLangID;
  3260. WORD wUserLangID;
  3261. WORD wCodePage;
  3262. DWORD dwIdx;
  3263. if (NULL == pFileName ||
  3264. NULL == ppFriendlyNameBuf)
  3265. {
  3266. return 0;
  3267. }
  3268. //
  3269. // First, load VERSION.DLL
  3270. //
  3271. hVerDll = LoadLibrary( TEXT("Version.dll") );
  3272. if ( NULL == hVerDll )
  3273. {
  3274. LOG((TL_ERROR,
  3275. "LoadLibrary('VERSION.DLL') failed! err=0x%08lx",
  3276. GetLastError()
  3277. ));
  3278. return 0;
  3279. }
  3280. //
  3281. // Now, get the needed entry points into VERSION.DLL.
  3282. // Use only UNICODE versions.
  3283. //
  3284. pGetFileVersionInfo = (GETFILEVERSIONINFO*) GetProcAddress(
  3285. hVerDll,
  3286. "GetFileVersionInfoW"
  3287. );
  3288. if ( NULL == pGetFileVersionInfo )
  3289. {
  3290. LOG((TL_ERROR,
  3291. "GetProcAddress('VERSION.DLL', 'GetFileVersionInfoW') " \
  3292. "failed! err=0x%08lx",
  3293. GetLastError()
  3294. ));
  3295. goto _Return;
  3296. }
  3297. pGetFileVersionInfoSize = (GETFILEVERSIONINFOSIZE *) GetProcAddress(
  3298. hVerDll,
  3299. "GetFileVersionInfoSizeW"
  3300. );
  3301. if ( NULL == pGetFileVersionInfoSize )
  3302. {
  3303. LOG((TL_ERROR,
  3304. "GetProcAddress('VERSION.DLL', 'GetFileVersionInfoSizeW') " \
  3305. "failed! err=0x%08lx",
  3306. GetLastError()
  3307. ));
  3308. goto _Return;
  3309. }
  3310. pVerQueryValue = (VERQUERYVALUE *) GetProcAddress(
  3311. hVerDll,
  3312. "VerQueryValueW"
  3313. );
  3314. if ( NULL == pVerQueryValue )
  3315. {
  3316. LOG((TL_ERROR,
  3317. "GetProcAddress('VERSION.DLL', 'VerQueryValueW') " \
  3318. "failed! err=0x%08lx",
  3319. GetLastError()
  3320. ));
  3321. goto _Return;
  3322. }
  3323. //
  3324. // Get the current UI language ( this is needed if MUI is enabled )
  3325. //
  3326. wUserLangID = GetUserDefaultUILanguage ();
  3327. //
  3328. // For each filename in the input multisz,
  3329. // try to get it's friendly name. If anything fails,
  3330. // make the friendly name the same as the file name.
  3331. //
  3332. for (; 0 != *pFileName; pFileName += lstrlenW(pFileName)+1)
  3333. {
  3334. pszBuffer = NULL;
  3335. //
  3336. // 1. Get the size needed for the verion resource
  3337. //
  3338. if ((dwSize = pGetFileVersionInfoSize( pFileName, &dwVerHandle )) == 0)
  3339. {
  3340. LOG((TL_ERROR, "GetFileVersionInfoSize failure for %S", pFileName ));
  3341. goto _UseFileName;
  3342. }
  3343. //
  3344. // 2. If our current buffer is smaller than needed, reallocate it.
  3345. //
  3346. if (dwSize > dwVerSize)
  3347. {
  3348. if (NULL != pbVerData)
  3349. {
  3350. ServerFree (pbVerData);
  3351. }
  3352. dwVerSize = dwSize + 16;
  3353. pbVerData = ServerAlloc( dwVerSize );
  3354. if ( pbVerData == NULL )
  3355. {
  3356. dwVerSize = 0;
  3357. goto _UseFileName;
  3358. }
  3359. }
  3360. //
  3361. // 3. Now, get the version information for the file.
  3362. //
  3363. if (pGetFileVersionInfo(
  3364. pFileName,
  3365. dwVerHandle,
  3366. dwVerSize,
  3367. pbVerData
  3368. ) == FALSE )
  3369. {
  3370. LOG((TL_ERROR, "GetFileVersionInfo failure for %S", pFileName ));
  3371. goto _UseFileName;
  3372. }
  3373. //
  3374. // 4. Get the Language/Code page translation
  3375. //
  3376. // NOTE: bug in VerQueryValue, can't handle static CS based str
  3377. //
  3378. lstrcpyW ( szItem, gszVarFileInfo );
  3379. if ((pVerQueryValue(
  3380. pbVerData,
  3381. szItem,
  3382. &pszBuffer,
  3383. (LPUINT) &uItemSize
  3384. ) == FALSE) ||
  3385. (uItemSize == 0))
  3386. {
  3387. LOG((TL_ERROR,
  3388. "ERROR: VerQueryValue failure for %S on file %S",
  3389. szItem,
  3390. pFileName
  3391. ));
  3392. pszBuffer = NULL;
  3393. goto _UseFileName;
  3394. }
  3395. wCodePage = 0;
  3396. wLangID = wUserLangID;
  3397. //
  3398. // lookup the current user UI language ID in the file version info
  3399. //
  3400. if (0 != wLangID)
  3401. {
  3402. for( dwIdx=0; dwIdx < uItemSize/sizeof(DWORD); dwIdx++ )
  3403. {
  3404. if ( *(WORD*)((DWORD*)pszBuffer + dwIdx) == wLangID )
  3405. {
  3406. wCodePage = *( (WORD*)((DWORD*)pszBuffer + dwIdx) + 1);
  3407. break;
  3408. }
  3409. }
  3410. if( dwIdx == uItemSize/sizeof(DWORD) )
  3411. {
  3412. wLangID = 0;
  3413. }
  3414. }
  3415. //
  3416. // if GetUserDefaultUILanguage() failed,
  3417. // or the current user UI language doesn't show up in the file version info
  3418. // just use the first language in the file version
  3419. //
  3420. if (0 == wLangID)
  3421. {
  3422. wLangID = *(LPWORD)pszBuffer;
  3423. wCodePage = *(((LPWORD)pszBuffer)+1);
  3424. }
  3425. //
  3426. // 5. Get the FileDescription in the language obtained above.
  3427. // (We use the FileDescription as friendly name).
  3428. //
  3429. wsprintfW(
  3430. szItem,
  3431. gszStringFileInfo,
  3432. wLangID,
  3433. wCodePage
  3434. );
  3435. if ((pVerQueryValue(
  3436. pbVerData,
  3437. szItem,
  3438. &pszBuffer,
  3439. (LPUINT) &uItemSize
  3440. ) == FALSE) ||
  3441. (uItemSize == 0))
  3442. {
  3443. LOG((TL_ERROR,
  3444. "ERROR: VerQueryValue failure for %S on file %S",
  3445. szItem,
  3446. pFileName
  3447. ));
  3448. pszBuffer = NULL;
  3449. goto _UseFileName;
  3450. }
  3451. _UseFileName:
  3452. if (NULL == pszBuffer)
  3453. {
  3454. //
  3455. // Something went wrong and we couldn't get
  3456. // the file description. Use the file name
  3457. // instead.
  3458. //
  3459. pszBuffer = pFileName;
  3460. }
  3461. //
  3462. // At this point, pszBuffer points to a (UNICODE) string
  3463. // containing what we deem to be the friendly name.
  3464. // Let's append it to the OUT multisz.
  3465. //
  3466. dwSize = (lstrlenW (pszBuffer) + 1) * sizeof (WCHAR);
  3467. if ((dwSize + dwBufUsedSize) > dwBufTotalSize)
  3468. {
  3469. if (!(p = ServerAlloc (dwBufTotalSize += 512)))
  3470. {
  3471. //
  3472. // We don't have enough memory.
  3473. // Release what we allocated until now, and return 0.
  3474. //
  3475. if (NULL != pFriendlyNameBuf)
  3476. {
  3477. ServerFree (pFriendlyNameBuf);
  3478. }
  3479. dwBufUsedSize = 0;
  3480. break;
  3481. }
  3482. if (dwBufUsedSize)
  3483. {
  3484. CopyMemory (p, pFriendlyNameBuf, dwBufUsedSize);
  3485. ServerFree (pFriendlyNameBuf);
  3486. }
  3487. pFriendlyNameBuf = p;
  3488. }
  3489. CopyMemory(
  3490. ((LPBYTE) pFriendlyNameBuf) + dwBufUsedSize,
  3491. pszBuffer,
  3492. dwSize
  3493. );
  3494. dwBufUsedSize += dwSize;
  3495. }
  3496. _Return:
  3497. //
  3498. // We don't need the library anymore.
  3499. // We don't need the version buffer either.
  3500. //
  3501. FreeLibrary (hVerDll);
  3502. if (NULL != pbVerData)
  3503. {
  3504. ServerFree (pbVerData);
  3505. }
  3506. if (0 != dwBufUsedSize)
  3507. {
  3508. *ppFriendlyNameBuf = pFriendlyNameBuf;
  3509. }
  3510. return dwBufUsedSize;
  3511. }
  3512. void WINAPI MGetDeviceFlags (
  3513. PTCLIENT ptClient,
  3514. PMMCGETDEVICEFLAGS_PARAMS pParams,
  3515. DWORD dwParamsBufferSize,
  3516. LPBYTE pDataBuf,
  3517. LPDWORD pdwNumBytesReturned
  3518. )
  3519. {
  3520. DWORD dwDeviceID;
  3521. TAPIPERMANENTID ID;
  3522. *pdwNumBytesReturned = sizeof (TAPI32_MSG);
  3523. // Support calls on line device only for now
  3524. if (!pParams->fLine)
  3525. {
  3526. pParams->lResult = LINEERR_OPERATIONUNAVAIL;
  3527. return;
  3528. }
  3529. ID.dwDeviceID = pParams->dwPermanentDeviceID;
  3530. ID.dwProviderID = pParams->dwProviderID;
  3531. EnterCriticalSection(&gMgmtCritSec);
  3532. if (gpLineDevFlags == NULL)
  3533. {
  3534. pParams->lResult = LINEERR_OPERATIONUNAVAIL;
  3535. goto ExitHere;
  3536. }
  3537. dwDeviceID = GetDeviceIDFromPermanentID (ID, pParams->fLine);
  3538. if (dwDeviceID == 0xffffffff || dwDeviceID >= gdwNumFlags)
  3539. {
  3540. pParams->lResult = LINEERR_OPERATIONUNAVAIL;
  3541. goto ExitHere;
  3542. }
  3543. pParams->dwDeviceID = dwDeviceID;
  3544. pParams->dwFlags = gpLineDevFlags[dwDeviceID];
  3545. ExitHere:
  3546. LeaveCriticalSection (&gMgmtCritSec);
  3547. return;
  3548. }