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.

2577 lines
63 KiB

  1. /*++ BUILD Version: 0000 // Increment this if a change has global effects
  2. Copyright (c) 2000 - 2002 Microsoft Corporation
  3. Module Name:
  4. dspub.cpp
  5. Abstract:
  6. Src module for tapi server DS publishing
  7. Author:
  8. Xiaohai Zhang (xzhang) 10-March-2000
  9. Revision History:
  10. --*/
  11. #include "windows.h"
  12. #include "objbase.h"
  13. #include "winbase.h"
  14. #include "sddl.h"
  15. #include "iads.h"
  16. #include "activeds.h"
  17. #include "tapi.h"
  18. #include "tspi.h"
  19. #include "utils.h"
  20. #include "client.h"
  21. #include "server.h"
  22. #include "private.h"
  23. #include "tchar.h"
  24. #define SECURITY_WIN32
  25. #include "sspi.h"
  26. #include "secext.h"
  27. #include "psapi.h"
  28. extern "C" {
  29. extern const TCHAR gszRegKeyTelephony[];
  30. extern DWORD gdwTapiSCPTTL;
  31. extern const TCHAR gszRegTapisrvSCPGuid[];
  32. }
  33. const TCHAR gszTapisrvBindingInfo[] = TEXT("E{\\pipe\\tapsrv}P{ncacn_np}C{%s}A{%s}S{%s}TTL{%s}");
  34. const TCHAR gszVenderMS[] = TEXT("Microsoft");
  35. const TCHAR gszMSGuid[] = TEXT("937924B8-AA44-11d2-81F1-00C04FB9624E");
  36. const WCHAR gwszTapisrvRDN[] = L"CN=Telephony Service";
  37. const TCHAR gszTapisrvProdName[] = TEXT("Telephony Service");
  38. // gszTapisrvGuid needs to be consistant with remotesp\dslookup.cpp
  39. const TCHAR gszTapisrvGuid[] = TEXT("B1A37774-E3F7-488E-ADBFD4DB8A4AB2E5");
  40. const TCHAR gwszProxyRDN[] = L"cn=TAPI Proxy Server";
  41. const TCHAR gszProxyProdName[] = TEXT("TAPI Proxy Server");
  42. const TCHAR gszProxyGuid[] = TEXT("A2657445-3E27-400B-851A-456C41666E37");
  43. const TCHAR gszRegProxySCPGuid[] = TEXT("PROXYSCPGUID");
  44. typedef struct _PROXY_SCP_ENTRY {
  45. // A valid CLSID requires 38 chars
  46. TCHAR szClsid[40];
  47. // A binding GUID is of format
  48. // LDAP://<GUID={B1A37774-E3F7-488E-ADBFD4DB8A4AB2E5}>
  49. // required size is 38+14=52 chars
  50. TCHAR szObjGuid[56];
  51. // Ref count for this entry
  52. DWORD dwRefCount;
  53. } PROXY_SCP_ENTRY, *PPROXY_SCP_ENTRY;
  54. typedef struct _PROXY_SCPS {
  55. DWORD dwTotalEntries;
  56. DWORD dwUsedEntries;
  57. PROXY_SCP_ENTRY * aEntries;
  58. } PROXY_SCPS, *PPROXY_SCPS;
  59. PROXY_SCPS gProxyScps;
  60. #define MAX_SD 2048
  61. //
  62. // GetTokenUser
  63. //
  64. // Based on hAccessToken, call GetTokenInformation
  65. // to retrieve TokenUser info
  66. //
  67. HRESULT
  68. GetTokenUser (HANDLE hAccessToken, PTOKEN_USER * ppUser)
  69. {
  70. HRESULT hr = S_OK;
  71. DWORD dwInfoSize = 0;
  72. PTOKEN_USER ptuUser = NULL;
  73. DWORD ntsResult;
  74. if (!GetTokenInformation(
  75. hAccessToken,
  76. TokenUser,
  77. NULL,
  78. 0,
  79. &dwInfoSize
  80. ))
  81. {
  82. ntsResult = GetLastError();
  83. if (ntsResult != ERROR_INSUFFICIENT_BUFFER)
  84. {
  85. hr = HRESULT_FROM_WIN32 (ntsResult);
  86. goto ExitHere;
  87. }
  88. }
  89. ptuUser = (PTOKEN_USER) ServerAlloc (dwInfoSize);
  90. if (ptuUser == NULL)
  91. {
  92. hr = LINEERR_NOMEM;
  93. goto ExitHere;
  94. }
  95. if (!GetTokenInformation(
  96. hAccessToken,
  97. TokenUser,
  98. ptuUser,
  99. dwInfoSize,
  100. &dwInfoSize
  101. ))
  102. {
  103. ServerFree (ptuUser);
  104. hr = HRESULT_FROM_WIN32 (GetLastError());
  105. goto ExitHere;
  106. }
  107. *ppUser = ptuUser;
  108. ExitHere:
  109. return hr;
  110. }
  111. //
  112. // IsLocalSystem
  113. //
  114. // This function makes the determination if the given process token
  115. // is running as LocalSystem or LocalService or NetworkService
  116. // Returns S_OK if it is, S_FALSE if it is not LocalSystem.
  117. //
  118. HRESULT
  119. IsLocalSystem(HANDLE hAccessToken)
  120. {
  121. HRESULT hr = S_OK;
  122. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  123. PSID pLocalSid = NULL;
  124. PSID pLocalServiceSid = NULL;
  125. PSID pNetworkServiceSid = NULL;
  126. PTOKEN_USER ptuUser = NULL;
  127. hr = GetTokenUser (hAccessToken, &ptuUser);
  128. if (FAILED(hr))
  129. {
  130. goto ExitHere;
  131. }
  132. if (!AllocateAndInitializeSid (
  133. &NtAuthority,
  134. 1,
  135. SECURITY_LOCAL_SYSTEM_RID,
  136. 0, 0, 0, 0, 0, 0, 0,
  137. &pLocalSid) ||
  138. !AllocateAndInitializeSid (
  139. &NtAuthority,
  140. 1,
  141. SECURITY_LOCAL_SERVICE_RID,
  142. 0, 0, 0, 0, 0, 0, 0,
  143. &pLocalServiceSid) ||
  144. !AllocateAndInitializeSid (
  145. &NtAuthority,
  146. 1,
  147. SECURITY_NETWORK_SERVICE_RID,
  148. 0, 0, 0, 0, 0, 0, 0,
  149. &pNetworkServiceSid)
  150. )
  151. {
  152. hr = HRESULT_FROM_WIN32(GetLastError());
  153. goto ExitHere;
  154. }
  155. if (!EqualSid(pLocalSid, ptuUser->User.Sid) &&
  156. !EqualSid(pLocalServiceSid, ptuUser->User.Sid) &&
  157. !EqualSid(pNetworkServiceSid, ptuUser->User.Sid))
  158. {
  159. hr = S_FALSE;
  160. }
  161. ExitHere:
  162. if (NULL != ptuUser)
  163. {
  164. ServerFree (ptuUser);
  165. }
  166. if (NULL != pLocalSid)
  167. {
  168. FreeSid(pLocalSid);
  169. }
  170. if (NULL != pLocalServiceSid)
  171. {
  172. FreeSid (pLocalServiceSid);
  173. }
  174. if (NULL != pNetworkServiceSid)
  175. {
  176. FreeSid (pNetworkServiceSid);
  177. }
  178. return hr;
  179. }
  180. //
  181. // IsCurrentLocalSystem
  182. //
  183. // IsCurrentLocalSystem checks to see if current thread/process
  184. // runs in LocalSystem account
  185. //
  186. HRESULT
  187. IsCurrentLocalSystem ()
  188. {
  189. HRESULT hr = S_OK;
  190. HANDLE hToken = NULL;
  191. if (!OpenThreadToken(
  192. GetCurrentThread(),
  193. TOKEN_QUERY,
  194. FALSE,
  195. &hToken))
  196. {
  197. if(!OpenProcessToken(
  198. GetCurrentProcess(),
  199. TOKEN_QUERY,
  200. &hToken
  201. ))
  202. {
  203. hr = HRESULT_FROM_WIN32(GetLastError());
  204. goto ExitHere;
  205. }
  206. }
  207. hr = IsLocalSystem (hToken);
  208. CloseHandle (hToken);
  209. ExitHere:
  210. return hr;
  211. }
  212. HRESULT
  213. SetPrivilege(
  214. HANDLE hToken, // token handle
  215. LPCTSTR Privilege, // Privilege to enable/disable
  216. BOOL bEnablePrivilege // to enable or disable privilege
  217. )
  218. {
  219. HRESULT hr = S_OK;
  220. TOKEN_PRIVILEGES tp;
  221. LUID luid;
  222. TOKEN_PRIVILEGES tpPrevious;
  223. DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
  224. DWORD dwErr;
  225. if(!LookupPrivilegeValue( NULL, Privilege, &luid ))
  226. {
  227. hr = HRESULT_FROM_WIN32 (GetLastError ());
  228. goto ExitHere;
  229. }
  230. //
  231. // first pass. get current privilege setting
  232. //
  233. tp.PrivilegeCount = 1;
  234. tp.Privileges[0].Luid = luid;
  235. tp.Privileges[0].Attributes = 0;
  236. AdjustTokenPrivileges(
  237. hToken,
  238. FALSE,
  239. &tp,
  240. sizeof(TOKEN_PRIVILEGES),
  241. &tpPrevious,
  242. &cbPrevious
  243. );
  244. dwErr = GetLastError ();
  245. if (dwErr != ERROR_SUCCESS)
  246. {
  247. hr = HRESULT_FROM_WIN32 (dwErr);
  248. goto ExitHere;
  249. }
  250. //
  251. // second pass. set privilege based on previous setting
  252. //
  253. tpPrevious.PrivilegeCount = 1;
  254. tpPrevious.Privileges[0].Luid = luid;
  255. if(bEnablePrivilege)
  256. {
  257. tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  258. }
  259. else
  260. {
  261. tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
  262. tpPrevious.Privileges[0].Attributes);
  263. }
  264. AdjustTokenPrivileges(
  265. hToken,
  266. FALSE,
  267. &tpPrevious,
  268. cbPrevious,
  269. NULL,
  270. NULL
  271. );
  272. dwErr = GetLastError ();
  273. if (dwErr != ERROR_SUCCESS)
  274. {
  275. hr = HRESULT_FROM_WIN32 (dwErr);
  276. goto ExitHere;
  277. }
  278. ExitHere:
  279. return hr;
  280. }
  281. HRESULT
  282. SetCurrentPrivilege (
  283. LPCTSTR Privilege, // Privilege to enable/disable
  284. BOOL bEnablePrivilege // to enable or disable privilege
  285. )
  286. {
  287. HRESULT hr = S_OK;
  288. HANDLE hToken = NULL;
  289. if (!OpenThreadToken(
  290. GetCurrentThread(),
  291. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  292. FALSE,
  293. &hToken))
  294. {
  295. if(!OpenProcessToken(
  296. GetCurrentProcess(),
  297. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  298. &hToken
  299. ))
  300. {
  301. hr = HRESULT_FROM_WIN32(GetLastError());
  302. goto ExitHere;
  303. }
  304. }
  305. hr = SetPrivilege(hToken, Privilege, bEnablePrivilege);
  306. ExitHere:
  307. if (hToken)
  308. {
  309. CloseHandle(hToken);
  310. }
  311. return hr;
  312. }
  313. //
  314. // SetSidOnAcl
  315. //
  316. BOOL
  317. SetSidOnAcl(
  318. PSID pSid,
  319. PACL pAclSource,
  320. PACL *pAclDestination,
  321. DWORD AccessMask,
  322. BYTE AceFlags,
  323. BOOL bAddSid
  324. )
  325. {
  326. HRESULT hr = S_OK;
  327. ACL_SIZE_INFORMATION AclInfo;
  328. DWORD dwNewAclSize, dwErr;
  329. LPVOID pAce;
  330. DWORD AceCounter;
  331. //
  332. // If we were given a NULL Acl, just provide a NULL Acl
  333. //
  334. *pAclDestination = NULL;
  335. if(pAclSource == NULL || !IsValidSid(pSid))
  336. {
  337. hr = E_INVALIDARG;
  338. goto ExitHere;
  339. }
  340. if(!GetAclInformation(
  341. pAclSource,
  342. &AclInfo,
  343. sizeof(ACL_SIZE_INFORMATION),
  344. AclSizeInformation
  345. ))
  346. {
  347. hr = HRESULT_FROM_WIN32 (GetLastError ());
  348. goto ExitHere;
  349. }
  350. //
  351. // compute size for new Acl, based on addition or subtraction of Ace
  352. //
  353. if(bAddSid)
  354. {
  355. dwNewAclSize=AclInfo.AclBytesInUse +
  356. sizeof(ACCESS_ALLOWED_ACE) +
  357. GetLengthSid(pSid) -
  358. sizeof(DWORD) ;
  359. }
  360. else
  361. {
  362. dwNewAclSize=AclInfo.AclBytesInUse -
  363. sizeof(ACCESS_ALLOWED_ACE) -
  364. GetLengthSid(pSid) +
  365. sizeof(DWORD) ;
  366. }
  367. *pAclDestination = (PACL)ServerAlloc(dwNewAclSize);
  368. if(*pAclDestination == NULL) {
  369. hr = LINEERR_NOMEM;
  370. goto ExitHere;
  371. }
  372. //
  373. // initialize new Acl
  374. //
  375. if(!InitializeAcl(
  376. *pAclDestination,
  377. dwNewAclSize,
  378. ACL_REVISION
  379. ))
  380. {
  381. hr = HRESULT_FROM_WIN32 (GetLastError ());
  382. goto ExitHere;
  383. }
  384. //
  385. // if appropriate, add ace representing pSid
  386. //
  387. if(bAddSid)
  388. {
  389. PACCESS_ALLOWED_ACE pNewAce;
  390. if(!AddAccessAllowedAce(
  391. *pAclDestination,
  392. ACL_REVISION,
  393. AccessMask,
  394. pSid
  395. ))
  396. {
  397. hr = HRESULT_FROM_WIN32 (GetLastError ());
  398. goto ExitHere;
  399. }
  400. //
  401. // get pointer to ace we just added, so we can change the AceFlags
  402. //
  403. if(!GetAce(
  404. *pAclDestination,
  405. 0, // this is the first ace in the Acl
  406. (void**) &pNewAce
  407. ))
  408. {
  409. hr = HRESULT_FROM_WIN32 (GetLastError ());
  410. goto ExitHere;
  411. }
  412. pNewAce->Header.AceFlags = AceFlags;
  413. }
  414. //
  415. // copy existing aces to new Acl
  416. //
  417. for(AceCounter = 0 ; AceCounter < AclInfo.AceCount ; AceCounter++) {
  418. //
  419. // fetch existing ace
  420. //
  421. if(!GetAce(pAclSource, AceCounter, &pAce))
  422. {
  423. hr = HRESULT_FROM_WIN32 (GetLastError ());
  424. goto ExitHere;
  425. }
  426. //
  427. // check to see if we are removing the Ace
  428. //
  429. if(!bAddSid) {
  430. //
  431. // we only care about ACCESS_ALLOWED aces
  432. //
  433. if((((PACE_HEADER)pAce)->AceType) == ACCESS_ALLOWED_ACE_TYPE)
  434. {
  435. PSID pTempSid=(PSID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
  436. //
  437. // if the Sid matches, skip adding this Sid
  438. //
  439. if(EqualSid(pSid, pTempSid))
  440. {
  441. continue;
  442. }
  443. }
  444. }
  445. //
  446. // append ace to Acl
  447. //
  448. if(!AddAce(
  449. *pAclDestination,
  450. ACL_REVISION,
  451. MAXDWORD, // maintain Ace order
  452. pAce,
  453. ((PACE_HEADER)pAce)->AceSize
  454. ))
  455. {
  456. hr = HRESULT_FROM_WIN32 (GetLastError ());
  457. goto ExitHere;
  458. }
  459. }
  460. ExitHere:
  461. //
  462. // free memory if an error occurred
  463. //
  464. if(hr) {
  465. if(*pAclDestination != NULL)
  466. {
  467. ServerFree(*pAclDestination);
  468. }
  469. }
  470. return hr;
  471. }
  472. //
  473. // AddSIDToKernelObject()
  474. //
  475. // This function takes a given SID and dwAccess and adds it to a given token.
  476. //
  477. // ** Be sure to restore old kernel object
  478. // ** using call to GetKernelObjectSecurity()
  479. //
  480. HRESULT
  481. AddSIDToKernelObjectDacl(
  482. PSID pSid,
  483. DWORD dwAccess,
  484. HANDLE OriginalToken,
  485. PSECURITY_DESCRIPTOR* ppSDOld)
  486. {
  487. HRESULT hr = S_OK;
  488. PSECURITY_DESCRIPTOR pSD = NULL;
  489. SECURITY_DESCRIPTOR sdNew;
  490. DWORD cbByte = MAX_SD, cbNeeded = 0, dwErr = 0;
  491. PACL pOldDacl = NULL, pNewDacl = NULL;
  492. BOOL fDaclPresent, fDaclDefaulted, fRet = FALSE;
  493. pSD = (PSECURITY_DESCRIPTOR) ServerAlloc(cbByte);
  494. if (NULL == pSD)
  495. {
  496. hr = LINEERR_NOMEM;
  497. goto ExitHere;
  498. }
  499. if (!InitializeSecurityDescriptor(
  500. &sdNew,
  501. SECURITY_DESCRIPTOR_REVISION
  502. ))
  503. {
  504. hr = HRESULT_FROM_WIN32 (GetLastError());
  505. goto ExitHere;
  506. }
  507. if (!GetKernelObjectSecurity(
  508. OriginalToken,
  509. DACL_SECURITY_INFORMATION,
  510. pSD,
  511. cbByte,
  512. &cbNeeded
  513. ))
  514. {
  515. dwErr = GetLastError();
  516. if (cbNeeded > MAX_SD && dwErr == ERROR_MORE_DATA)
  517. {
  518. ServerFree(pSD);
  519. pSD = (PSECURITY_DESCRIPTOR) ServerAlloc(cbNeeded);
  520. if (NULL == pSD)
  521. {
  522. hr = LINEERR_NOMEM;
  523. goto ExitHere;
  524. }
  525. if (!GetKernelObjectSecurity(
  526. OriginalToken,
  527. DACL_SECURITY_INFORMATION,
  528. pSD,
  529. cbNeeded,
  530. &cbNeeded
  531. ))
  532. {
  533. hr = HRESULT_FROM_WIN32 (GetLastError());
  534. goto ExitHere;
  535. }
  536. dwErr = 0;
  537. }
  538. if (dwErr != 0)
  539. {
  540. hr = HRESULT_FROM_WIN32 (dwErr);
  541. goto ExitHere;
  542. }
  543. }
  544. if (!GetSecurityDescriptorDacl(
  545. pSD,
  546. &fDaclPresent,
  547. &pOldDacl,
  548. &fDaclDefaulted
  549. ))
  550. {
  551. hr = HRESULT_FROM_WIN32 (GetLastError());
  552. goto ExitHere;
  553. }
  554. hr = SetSidOnAcl(
  555. pSid,
  556. pOldDacl,
  557. &pNewDacl,
  558. dwAccess,
  559. 0,
  560. TRUE
  561. );
  562. if (hr)
  563. {
  564. goto ExitHere;
  565. }
  566. if (!SetSecurityDescriptorDacl(
  567. &sdNew,
  568. TRUE,
  569. pNewDacl,
  570. FALSE
  571. ))
  572. {
  573. hr = HRESULT_FROM_WIN32 (GetLastError());
  574. goto ExitHere;
  575. }
  576. if (!SetKernelObjectSecurity(
  577. OriginalToken,
  578. DACL_SECURITY_INFORMATION,
  579. &sdNew
  580. ))
  581. {
  582. hr = HRESULT_FROM_WIN32 (GetLastError());
  583. goto ExitHere;
  584. }
  585. *ppSDOld = pSD;
  586. ExitHere:
  587. if (NULL != pNewDacl)
  588. {
  589. ServerFree(pNewDacl);
  590. }
  591. if (hr)
  592. {
  593. if (NULL != pSD)
  594. {
  595. ServerFree(pSD);
  596. *ppSDOld = NULL;
  597. }
  598. }
  599. return hr;
  600. }
  601. //
  602. // SetTokenDefaultDacl
  603. //
  604. // This function makes pSidUser and LocalSystem account
  605. // have full access in the default DACL of the access token
  606. // this is necessary for CreateThread to succeed without
  607. // an assert in checked build
  608. //
  609. HRESULT
  610. SetTokenDefaultDacl(HANDLE hAccessToken, PSID pSidUser)
  611. {
  612. HRESULT hr = S_OK;
  613. SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY;
  614. PSID pLocalSid = NULL;
  615. TOKEN_DEFAULT_DACL defDACL = {0};
  616. DWORD cbDACL;
  617. if (!AllocateAndInitializeSid(
  618. &IDAuthorityNT,
  619. 1,
  620. SECURITY_LOCAL_SYSTEM_RID,
  621. 0,0,0,0,0,0,0,
  622. &pLocalSid
  623. ))
  624. {
  625. hr = HRESULT_FROM_WIN32(GetLastError());
  626. goto ExitHere;
  627. }
  628. cbDACL = sizeof(ACL) +
  629. sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid (pLocalSid) +
  630. sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid (pSidUser);
  631. defDACL.DefaultDacl = (PACL) ServerAlloc (cbDACL);
  632. if (defDACL.DefaultDacl == NULL)
  633. {
  634. hr = LINEERR_NOMEM;
  635. goto ExitHere;
  636. }
  637. if (!InitializeAcl (
  638. defDACL.DefaultDacl,
  639. cbDACL,
  640. ACL_REVISION
  641. ))
  642. {
  643. hr = HRESULT_FROM_WIN32(GetLastError());
  644. goto ExitHere;
  645. }
  646. if (!AddAccessAllowedAce (
  647. defDACL.DefaultDacl,
  648. ACL_REVISION,
  649. GENERIC_ALL,
  650. pLocalSid
  651. ) ||
  652. !AddAccessAllowedAce (
  653. defDACL.DefaultDacl,
  654. ACL_REVISION,
  655. GENERIC_ALL,
  656. pSidUser
  657. ))
  658. {
  659. hr = HRESULT_FROM_WIN32(GetLastError());
  660. goto ExitHere;
  661. }
  662. if (!SetTokenInformation (
  663. hAccessToken,
  664. TokenDefaultDacl,
  665. &defDACL,
  666. sizeof(TOKEN_DEFAULT_DACL)
  667. ))
  668. {
  669. hr = HRESULT_FROM_WIN32(GetLastError());
  670. goto ExitHere;
  671. }
  672. ExitHere:
  673. if (NULL != pLocalSid)
  674. {
  675. FreeSid(pLocalSid);
  676. }
  677. if (defDACL.DefaultDacl != NULL)
  678. {
  679. ServerFree (defDACL.DefaultDacl);
  680. }
  681. return hr;
  682. }
  683. //
  684. // GetLocalSystemToken
  685. //
  686. // This function grabs a process token from a LocalSystem process and uses it
  687. // to impersonate when ncessary
  688. //
  689. HRESULT
  690. GetLocalSystemToken(HANDLE* phRet)
  691. {
  692. HRESULT hr = S_OK;
  693. DWORD rgDefPIDs[128];
  694. DWORD * rgPIDs = rgDefPIDs;
  695. DWORD cbPIDs = sizeof(rgDefPIDs), cbNeeded;
  696. DWORD i;
  697. HANDLE hProcess = NULL;
  698. HANDLE hPToken = NULL, hPDupToken = NULL, hPTokenNew = NULL;
  699. HANDLE hToken;
  700. PTOKEN_USER ptuUser = NULL;
  701. BOOL fSet = FALSE;
  702. PSECURITY_DESCRIPTOR pSD = NULL;
  703. //
  704. // Set up necessary privilege for follow-on security operation
  705. //
  706. if(hr = SetCurrentPrivilege(SE_DEBUG_NAME, TRUE))
  707. {
  708. goto ExitHere;
  709. }
  710. if(hr = SetCurrentPrivilege(SE_TAKE_OWNERSHIP_NAME, TRUE))
  711. {
  712. goto ExitHere;
  713. }
  714. //
  715. // Get the current thread/process token user info
  716. //
  717. if (!OpenThreadToken(
  718. GetCurrentThread(),
  719. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  720. FALSE,
  721. &hToken))
  722. {
  723. if(!OpenProcessToken(
  724. GetCurrentProcess(),
  725. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  726. &hToken
  727. ))
  728. {
  729. hr = HRESULT_FROM_WIN32(GetLastError());
  730. goto ExitHere;
  731. }
  732. }
  733. hr = GetTokenUser (hToken, &ptuUser);
  734. CloseHandle (hToken);
  735. if (hr)
  736. {
  737. goto ExitHere;
  738. }
  739. //
  740. // Get the list of process IDs in the system
  741. //
  742. while (1)
  743. {
  744. if (!EnumProcesses (
  745. rgPIDs,
  746. cbPIDs,
  747. &cbNeeded
  748. ))
  749. {
  750. hr = HRESULT_FROM_WIN32(GetLastError());
  751. goto ExitHere;
  752. }
  753. // Break out if we have large enough buf
  754. if (cbNeeded < cbPIDs)
  755. {
  756. break;
  757. }
  758. // Otherwise, alloc larger buffer
  759. if (rgPIDs != rgDefPIDs)
  760. {
  761. ServerFree (rgPIDs);
  762. }
  763. cbPIDs += 256;
  764. rgPIDs = (DWORD *)ServerAlloc (cbPIDs);
  765. if (rgPIDs == NULL)
  766. {
  767. hr = LINEERR_NOMEM;
  768. goto ExitHere;
  769. }
  770. }
  771. //
  772. // Walk processes until we find one that's running as
  773. // local system
  774. //
  775. for (i = 1; i < (cbNeeded / sizeof(DWORD)); i++)
  776. {
  777. hProcess = OpenProcess(
  778. PROCESS_ALL_ACCESS,
  779. FALSE,
  780. rgPIDs[i]
  781. );
  782. if (NULL == hProcess)
  783. {
  784. hr = HRESULT_FROM_WIN32(GetLastError());
  785. goto ExitHere;
  786. }
  787. if (!OpenProcessToken(
  788. hProcess,
  789. READ_CONTROL | WRITE_DAC,
  790. &hPToken
  791. ))
  792. {
  793. hr = HRESULT_FROM_WIN32(GetLastError());
  794. goto ExitHere;
  795. }
  796. //
  797. // We have got the process token, but in general
  798. // we do not have TOKEN_DUPLICATE access. So we
  799. // go ahead and whack the DACL of the object to
  800. // grant us the access right.
  801. // IMPORTANT: need to restore the original SD
  802. //
  803. if (hr = AddSIDToKernelObjectDacl(
  804. ptuUser->User.Sid,
  805. TOKEN_DUPLICATE,
  806. hPToken,
  807. &pSD
  808. ))
  809. {
  810. goto ExitHere;
  811. }
  812. fSet = TRUE;
  813. if (!OpenProcessToken(
  814. hProcess,
  815. TOKEN_DUPLICATE,
  816. &hPTokenNew
  817. ))
  818. {
  819. hr = HRESULT_FROM_WIN32(GetLastError());
  820. goto ExitHere;
  821. }
  822. //
  823. // Duplicate the token
  824. //
  825. if (!DuplicateTokenEx(
  826. hPTokenNew,
  827. TOKEN_ALL_ACCESS,
  828. NULL,
  829. SecurityImpersonation,
  830. TokenPrimary,
  831. &hPDupToken
  832. ))
  833. {
  834. hr = HRESULT_FROM_WIN32(GetLastError());
  835. goto ExitHere;
  836. }
  837. if (IsLocalSystem (hPDupToken) == S_OK &&
  838. SetTokenDefaultDacl (
  839. hPDupToken,
  840. ptuUser->User.Sid) == S_OK)
  841. {
  842. break;
  843. }
  844. //
  845. // Loop cleanup
  846. //
  847. if (!SetKernelObjectSecurity(
  848. hPToken,
  849. DACL_SECURITY_INFORMATION,
  850. pSD
  851. ))
  852. {
  853. hr = HRESULT_FROM_WIN32(GetLastError());
  854. goto ExitHere;
  855. }
  856. fSet = FALSE;
  857. if (hPDupToken)
  858. {
  859. CloseHandle (hPDupToken);
  860. hPDupToken = NULL;
  861. }
  862. if (hPTokenNew)
  863. {
  864. CloseHandle (hPTokenNew);
  865. hPTokenNew = NULL;
  866. }
  867. if (pSD != NULL)
  868. {
  869. ServerFree (pSD);
  870. pSD = NULL;
  871. }
  872. if (hPToken)
  873. {
  874. CloseHandle (hPToken);
  875. hPToken = NULL;
  876. }
  877. if (hProcess)
  878. {
  879. CloseHandle (hProcess);
  880. hProcess = NULL;
  881. }
  882. }
  883. if (i >= cbNeeded / sizeof(DWORD))
  884. {
  885. hr = S_FALSE;
  886. }
  887. ExitHere:
  888. if (fSet)
  889. {
  890. if (!SetKernelObjectSecurity(
  891. hPToken,
  892. DACL_SECURITY_INFORMATION,
  893. pSD
  894. ))
  895. {
  896. hr = HRESULT_FROM_WIN32(GetLastError());
  897. }
  898. }
  899. if (hPTokenNew)
  900. {
  901. CloseHandle (hPTokenNew);
  902. }
  903. if (hPToken)
  904. {
  905. CloseHandle (hPToken);
  906. }
  907. if (pSD != NULL)
  908. {
  909. ServerFree (pSD);
  910. }
  911. if (hProcess)
  912. {
  913. CloseHandle (hProcess);
  914. }
  915. if (rgPIDs != rgDefPIDs)
  916. {
  917. ServerFree (rgPIDs);
  918. }
  919. if (ptuUser)
  920. {
  921. ServerFree (ptuUser);
  922. }
  923. if (hr)
  924. {
  925. *phRet = NULL;
  926. if (hPDupToken)
  927. {
  928. CloseHandle (hPDupToken);
  929. }
  930. }
  931. else
  932. {
  933. *phRet = hPDupToken;
  934. }
  935. return hr;
  936. }
  937. //
  938. // ImpersonateLocalSystem
  939. //
  940. HRESULT ImpersonateLocalSystem ()
  941. {
  942. HRESULT hr = S_OK;
  943. HANDLE hTokenLocalSys;
  944. hr = GetLocalSystemToken (&hTokenLocalSys);
  945. if (FAILED (hr))
  946. {
  947. goto ExitHere;
  948. }
  949. if (!ImpersonateLoggedOnUser(
  950. hTokenLocalSys
  951. ))
  952. {
  953. hr = HRESULT_FROM_WIN32 (GetLastError ());
  954. goto ExitHere;
  955. }
  956. ExitHere:
  957. if (hTokenLocalSys)
  958. {
  959. CloseHandle (hTokenLocalSys);
  960. }
  961. return hr;
  962. }
  963. //
  964. // RevertLocalSystemImp
  965. //
  966. // Revert the LocalSystem account impersonation
  967. //
  968. HRESULT RevertLocalSystemImp ()
  969. {
  970. HRESULT hr;
  971. if (!RevertToSelf())
  972. {
  973. hr = HRESULT_FROM_WIN32 (GetLastError ());
  974. }
  975. else
  976. {
  977. hr = S_OK;
  978. }
  979. return hr;
  980. }
  981. //
  982. // AllowAccessToScpProperties
  983. //
  984. // The ACEs grant read/write access to the computer account
  985. // under which the TAPI service instance will be running
  986. //
  987. HRESULT AllowAccessToScpProperties(
  988. IADs *pSCPObject // IADs pointer to the SCP object.
  989. )
  990. {
  991. HRESULT hr = S_OK;
  992. VARIANT varSD;
  993. LPOLESTR szAttribute = L"nTSecurityDescriptor";
  994. DWORD dwLen;
  995. IADsSecurityDescriptor *pSD = NULL;
  996. IADsAccessControlList *pACL = NULL;
  997. IDispatch *pDisp = NULL;
  998. IADsAccessControlEntry *pACE1 = NULL;
  999. IADsAccessControlEntry *pACE2 = NULL;
  1000. IDispatch *pDispACE = NULL;
  1001. long lFlags = 0L;
  1002. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  1003. PSID pSid = NULL;
  1004. LPOLESTR szTrustee = NULL;
  1005. SID_IDENTIFIER_AUTHORITY siaAll = SECURITY_WORLD_SID_AUTHORITY;
  1006. PSID pSidAll = NULL;
  1007. LPOLESTR szTrusteeAll = NULL;
  1008. //
  1009. // Give tapi server service logon account full control
  1010. //
  1011. if(!AllocateAndInitializeSid(
  1012. &sia,
  1013. 1,
  1014. SECURITY_SERVICE_RID,
  1015. 0, 0, 0, 0, 0, 0, 0,
  1016. &pSid
  1017. ) ||
  1018. !ConvertSidToStringSidW (pSid, &szTrustee))
  1019. {
  1020. hr = HRESULT_FROM_NT(GetLastError());
  1021. goto ExitHere;
  1022. }
  1023. //
  1024. // Give everyone read access
  1025. //
  1026. if(!AllocateAndInitializeSid(
  1027. &siaAll,
  1028. 1,
  1029. SECURITY_WORLD_RID,
  1030. 0, 0, 0, 0, 0, 0, 0,
  1031. &pSidAll
  1032. ) ||
  1033. !ConvertSidToStringSidW (pSidAll, &szTrusteeAll))
  1034. {
  1035. hr = HRESULT_FROM_NT(GetLastError());
  1036. goto ExitHere;
  1037. }
  1038. //
  1039. // Now get the nTSecurityDescriptor
  1040. //
  1041. VariantClear(&varSD);
  1042. hr = pSCPObject->Get(szAttribute, &varSD);
  1043. if (FAILED(hr) || (varSD.vt!=VT_DISPATCH)) {
  1044. LOG((TL_ERROR, "Get nTSecurityDescriptor failed: 0x%x\n", hr));
  1045. goto ExitHere;
  1046. }
  1047. //
  1048. // Use the V_DISPATCH macro to get the IDispatch pointer from VARIANT
  1049. // structure and QueryInterface for an IADsSecurityDescriptor pointer.
  1050. //
  1051. hr = V_DISPATCH( &varSD )->QueryInterface(
  1052. IID_IADsSecurityDescriptor,
  1053. (void**)&pSD
  1054. );
  1055. if (FAILED(hr)) {
  1056. LOG((TL_ERROR, "Couldn't get IADsSecurityDescriptor: 0x%x\n", hr));
  1057. goto ExitHere;
  1058. }
  1059. // Get an IADsAccessControlList pointer to the security descriptor's DACL.
  1060. hr = pSD->get_DiscretionaryAcl(&pDisp);
  1061. if (SUCCEEDED(hr))
  1062. hr = pDisp->QueryInterface(IID_IADsAccessControlList,(void**)&pACL);
  1063. if (FAILED(hr)) {
  1064. LOG((TL_ERROR, "Couldn't get DACL: 0x%x\n", hr));
  1065. goto ExitHere;
  1066. }
  1067. // Create the COM object for the first ACE.
  1068. hr = CoCreateInstance(
  1069. CLSID_AccessControlEntry,
  1070. NULL,
  1071. CLSCTX_INPROC_SERVER,
  1072. IID_IADsAccessControlEntry,
  1073. (void **)&pACE1
  1074. );
  1075. // Create the COM object for the second ACE.
  1076. if (SUCCEEDED(hr))
  1077. {
  1078. hr = CoCreateInstance(
  1079. CLSID_AccessControlEntry,
  1080. NULL,
  1081. CLSCTX_INPROC_SERVER,
  1082. IID_IADsAccessControlEntry,
  1083. (void **)&pACE2
  1084. );
  1085. }
  1086. if (FAILED(hr)) {
  1087. LOG((TL_ERROR, "Couldn't create ACEs: 0x%x\n", hr));
  1088. goto ExitHere;
  1089. }
  1090. //
  1091. // Set the properties of the two ACEs.
  1092. //
  1093. // Set the trustee
  1094. hr = pACE1->put_Trustee( szTrustee );
  1095. hr = pACE2->put_Trustee( szTrusteeAll );
  1096. //
  1097. // Set the access rights
  1098. //
  1099. // Full access for service logon account
  1100. hr = pACE1->put_AccessMask(
  1101. ADS_RIGHT_DELETE | ADS_RIGHT_READ_CONTROL |
  1102. ADS_RIGHT_WRITE_DAC | ADS_RIGHT_WRITE_OWNER |
  1103. ADS_RIGHT_SYNCHRONIZE | ADS_RIGHT_ACCESS_SYSTEM_SECURITY |
  1104. ADS_RIGHT_GENERIC_READ | ADS_RIGHT_GENERIC_WRITE |
  1105. ADS_RIGHT_GENERIC_EXECUTE | ADS_RIGHT_GENERIC_ALL |
  1106. ADS_RIGHT_DS_CREATE_CHILD | ADS_RIGHT_DS_DELETE_CHILD |
  1107. ADS_RIGHT_ACTRL_DS_LIST | ADS_RIGHT_DS_SELF |
  1108. ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_DS_WRITE_PROP |
  1109. ADS_RIGHT_DS_DELETE_TREE | ADS_RIGHT_DS_LIST_OBJECT |
  1110. ADS_RIGHT_DS_CONTROL_ACCESS
  1111. );
  1112. // Read access for everyone
  1113. hr = pACE2->put_AccessMask(
  1114. ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_READ_CONTROL |
  1115. ADS_RIGHT_GENERIC_READ | ADS_RIGHT_ACTRL_DS_LIST |
  1116. ADS_RIGHT_DS_LIST_OBJECT
  1117. );
  1118. // Set the ACE type.
  1119. hr = pACE1->put_AceType( ADS_ACETYPE_ACCESS_ALLOWED_OBJECT );
  1120. hr = pACE2->put_AceType( ADS_ACETYPE_ACCESS_ALLOWED_OBJECT );
  1121. // Set AceFlags to zero because ACE is not inheritable.
  1122. hr = pACE1->put_AceFlags( 0 );
  1123. hr = pACE2->put_AceFlags( 0 );
  1124. // Set Flags to indicate an ACE that protects a specified object.
  1125. hr = pACE1->put_Flags( 0 );
  1126. hr = pACE2->put_Flags( 0 );
  1127. // Set ObjectType to the schemaIDGUID of the attribute.
  1128. hr = pACE1->put_ObjectType( NULL );
  1129. hr = pACE2->put_ObjectType( NULL );
  1130. // Add the ACEs to the DACL. Need an IDispatch pointer for each ACE
  1131. // to pass to the AddAce method.
  1132. hr = pACE1->QueryInterface(IID_IDispatch,(void**)&pDispACE);
  1133. if (SUCCEEDED(hr))
  1134. {
  1135. hr = pACL->AddAce(pDispACE);
  1136. }
  1137. if (FAILED(hr)) {
  1138. LOG((TL_ERROR, "Couldn't add first ACE: 0x%x\n", hr));
  1139. goto ExitHere;
  1140. }
  1141. else
  1142. {
  1143. if (pDispACE)
  1144. pDispACE->Release();
  1145. pDispACE = NULL;
  1146. }
  1147. // Do it again for the second ACE.
  1148. hr = pACE2->QueryInterface(IID_IDispatch, (void**)&pDispACE);
  1149. if (SUCCEEDED(hr))
  1150. {
  1151. hr = pACL->AddAce(pDispACE);
  1152. }
  1153. if (FAILED(hr)) {
  1154. LOG((TL_ERROR, "Couldn't add second ACE: 0x%x\n", hr));
  1155. goto ExitHere;
  1156. }
  1157. // Write the modified DACL back to the security descriptor.
  1158. hr = pSD->put_DiscretionaryAcl(pDisp);
  1159. if (SUCCEEDED(hr))
  1160. {
  1161. // Write the ntSecurityDescriptor property to the property cache.
  1162. hr = pSCPObject->Put(szAttribute, varSD);
  1163. if (SUCCEEDED(hr))
  1164. {
  1165. // SetInfo updates the SCP object in the directory.
  1166. hr = pSCPObject->SetInfo();
  1167. }
  1168. }
  1169. ExitHere:
  1170. if (pDispACE)
  1171. pDispACE->Release();
  1172. if (pACE1)
  1173. pACE1->Release();
  1174. if (pACE2)
  1175. pACE2->Release();
  1176. if (pACL)
  1177. pACL->Release();
  1178. if (pDisp)
  1179. pDisp->Release();
  1180. if (pSD)
  1181. pSD->Release();
  1182. if (szTrustee)
  1183. LocalFree (szTrustee);
  1184. if (pSid)
  1185. FreeSid (pSid);
  1186. if (szTrusteeAll)
  1187. LocalFree (szTrusteeAll);
  1188. if (pSidAll)
  1189. FreeSid (pSidAll);
  1190. VariantClear(&varSD);
  1191. return hr;
  1192. }
  1193. /**********************************************************
  1194. * SCP Creation
  1195. *********************************************************/
  1196. //
  1197. // CreateSCP
  1198. //
  1199. // Creates a server Service Connection Point object
  1200. // under the local host computer object
  1201. //
  1202. // Parameters:
  1203. // wszRDN - RDN
  1204. // szProductName - A member of "keywords" property
  1205. // szProductGuid - A member of "keywords" property
  1206. // szExtraKey - An extra member of "keywords" property
  1207. // szBindingInfo - value of property "serviceBindingInformation"
  1208. // szObjGuidVlueName
  1209. // - The value name to store the SCP object GUID
  1210. // under HKLM\Software\Microsoft\Windows\
  1211. // CurrentVersion\Telephony\
  1212. // if this value is NULL, we don't cache it in registry
  1213. // ppBindByGuidStr - For returning the SCP object GUID in the
  1214. // format of LPTSTR, if this is NULL, the GUID is
  1215. // not returned
  1216. //
  1217. HRESULT CreateSCP (
  1218. LPWSTR wszRDN,
  1219. LPTSTR szProductName,
  1220. LPTSTR szProductGuid,
  1221. LPTSTR szExtraKey,
  1222. LPTSTR szBindingInfo,
  1223. LPTSTR szObjGuidValueName,
  1224. LPTSTR * ppBindByGuidStr
  1225. )
  1226. {
  1227. DWORD dwStat, dwAttr, dwLen;
  1228. HRESULT hr = S_OK;
  1229. IDispatch *pDisp = NULL; // returned dispinterface of new object
  1230. IDirectoryObject *pComp = NULL; // Computer object; parent of SCP
  1231. IADs *pIADsSCP = NULL; // IADs interface on new object
  1232. BOOL bCoInited = FALSE;
  1233. BOOL bRevert = FALSE;
  1234. //
  1235. // Values for SCPs keywords attribute. Tapisrv product GUID is defined
  1236. // in server.h, vendor GUID is from MSDN
  1237. //
  1238. DWORD dwNumKeywords = 4;
  1239. TCHAR *KwVal[5]={
  1240. (LPTSTR) gszMSGuid, // Vendor GUID
  1241. (LPTSTR) szProductGuid, // Product GUID
  1242. (LPTSTR) gszVenderMS, // Vendor Name
  1243. (LPTSTR) szProductName, // Product Name
  1244. NULL
  1245. };
  1246. if (szExtraKey != NULL && szExtraKey[0] != 0)
  1247. {
  1248. KwVal[4] = szExtraKey;
  1249. ++dwNumKeywords;
  1250. }
  1251. TCHAR szServer[MAX_PATH];
  1252. TCHAR szBinding[128];
  1253. TCHAR szDn[MAX_PATH];
  1254. TCHAR szAdsPath[MAX_PATH];
  1255. HKEY hReg = NULL;
  1256. DWORD dwDisp;
  1257. ADSVALUE cn,objclass,keywords[4],binding,
  1258. classname,dnsname,nametype;
  1259. //
  1260. // SCP attributes to set during creation of SCP.
  1261. //
  1262. ADS_ATTR_INFO ScpAttribs[] = {
  1263. {TEXT("cn"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &cn, 1},
  1264. {TEXT("objectClass"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING,
  1265. &objclass, 1},
  1266. {TEXT("keywords"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING,
  1267. keywords, dwNumKeywords},
  1268. {TEXT("serviceDNSName"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING,
  1269. &dnsname, 1},
  1270. {TEXT("serviceDNSNameType"), ADS_ATTR_UPDATE,ADSTYPE_CASE_IGNORE_STRING,
  1271. &nametype, 1},
  1272. {TEXT("serviceClassName"), ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING,
  1273. &classname, 1},
  1274. {TEXT("serviceBindingInformation"), ADS_ATTR_UPDATE,
  1275. ADSTYPE_CASE_IGNORE_STRING,
  1276. &binding, 1},
  1277. };
  1278. // A binding GUID is of format
  1279. // LDAP:<GUID=B1A37774-E3F7-488E-ADBFD4DB8A4AB2E5>
  1280. BSTR bstrGuid = NULL;
  1281. TCHAR szBindByGuidStr[64];
  1282. //
  1283. // Do CoInitializeEx
  1284. //
  1285. hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
  1286. if (FAILED (hr))
  1287. {
  1288. goto ExitHere;
  1289. }
  1290. bCoInited = TRUE;
  1291. //
  1292. // Do all the operation in LocalSystem account
  1293. //
  1294. if (IsCurrentLocalSystem () != S_OK)
  1295. {
  1296. hr = ImpersonateLocalSystem ();
  1297. if (hr)
  1298. {
  1299. goto ExitHere;
  1300. }
  1301. bRevert = TRUE;
  1302. }
  1303. //
  1304. // Get the DNS name of the local computer
  1305. //
  1306. dwLen = sizeof(szServer);
  1307. if (!GetComputerNameEx(
  1308. ComputerNameDnsFullyQualified,
  1309. szServer,
  1310. &dwLen
  1311. ))
  1312. {
  1313. hr = HRESULT_FROM_NT(GetLastError());
  1314. LOG((TL_ERROR, "GetComputerNameEx: %s\n", szServer));
  1315. goto ExitHere;
  1316. }
  1317. //
  1318. // Fill in the attribute values to be stored in the SCP.
  1319. //
  1320. cn.dwType = ADSTYPE_CASE_IGNORE_STRING;
  1321. cn.CaseIgnoreString = wszRDN + 3; // 3 is the size of "CN="
  1322. objclass.dwType = ADSTYPE_CASE_IGNORE_STRING;
  1323. objclass.CaseIgnoreString = TEXT("serviceConnectionPoint");
  1324. keywords[0].dwType = ADSTYPE_CASE_IGNORE_STRING;
  1325. keywords[1].dwType = ADSTYPE_CASE_IGNORE_STRING;
  1326. keywords[2].dwType = ADSTYPE_CASE_IGNORE_STRING;
  1327. keywords[3].dwType = ADSTYPE_CASE_IGNORE_STRING;
  1328. keywords[4].dwType = ADSTYPE_CASE_IGNORE_STRING;
  1329. keywords[0].CaseIgnoreString=KwVal[0];
  1330. keywords[1].CaseIgnoreString=KwVal[1];
  1331. keywords[2].CaseIgnoreString=KwVal[2];
  1332. keywords[3].CaseIgnoreString=KwVal[3];
  1333. keywords[4].CaseIgnoreString=KwVal[4];
  1334. dnsname.dwType = ADSTYPE_CASE_IGNORE_STRING;
  1335. dnsname.CaseIgnoreString = szServer;
  1336. nametype.dwType = ADSTYPE_CASE_IGNORE_STRING;
  1337. nametype.CaseIgnoreString = TEXT("A");
  1338. classname.dwType = ADSTYPE_CASE_IGNORE_STRING;
  1339. classname.CaseIgnoreString = szProductName;
  1340. binding.dwType = ADSTYPE_CASE_IGNORE_STRING;
  1341. binding.CaseIgnoreString = szBindingInfo;
  1342. //
  1343. // Get the distinguished name of the computer object for the local computer
  1344. //
  1345. dwLen = sizeof(szDn);
  1346. if (!GetComputerObjectName(NameFullyQualifiedDN, szDn, &dwLen))
  1347. {
  1348. hr = HRESULT_FROM_NT(GetLastError());
  1349. LOG((TL_ERROR, "GetComputerObjectName: %s\n", szDn));
  1350. goto ExitHere;
  1351. }
  1352. //
  1353. // Compose the ADSpath and bind to the computer object for the local computer
  1354. //
  1355. _tcscpy(szAdsPath,TEXT("LDAP://"));
  1356. _tcscat(szAdsPath,szDn);
  1357. hr = ADsGetObject(szAdsPath, IID_IDirectoryObject, (void **)&pComp);
  1358. if (FAILED(hr)) {
  1359. LOG((TL_ERROR, "Failed to bind Computer Object.",hr));
  1360. goto ExitHere;
  1361. }
  1362. //*******************************************************************
  1363. // Publish the SCP as a child of the computer object
  1364. //*******************************************************************
  1365. // Figure out attribute count.
  1366. dwAttr = sizeof(ScpAttribs)/sizeof(ADS_ATTR_INFO);
  1367. // Do the Deed!
  1368. hr = pComp->CreateDSObject(
  1369. wszRDN,
  1370. ScpAttribs,
  1371. dwAttr,
  1372. &pDisp
  1373. );
  1374. if (FAILED(hr)) {
  1375. LOG((TL_ERROR, "Failed to create SCP: 0x%x\n", hr));
  1376. if (HRESULT_CODE(hr) == ERROR_OBJECT_ALREADY_EXISTS)
  1377. {
  1378. hr = HRESULT_FROM_NT (TAPIERR_SCP_ALREADY_EXISTS);
  1379. }
  1380. goto ExitHere;
  1381. }
  1382. // Query for an IADs pointer on the SCP object.
  1383. hr = pDisp->QueryInterface(IID_IADs,(void **)&pIADsSCP);
  1384. if (FAILED(hr)) {
  1385. LOG((TL_ERROR, "Failed to QI for IADs: 0x%x\n",hr));
  1386. goto ExitHere;
  1387. }
  1388. // Set ACEs on SCP so service can modify it.
  1389. hr = AllowAccessToScpProperties(
  1390. pIADsSCP // IADs pointer to the SCP object.
  1391. );
  1392. if (FAILED(hr)) {
  1393. LOG((TL_ERROR, "Failed to set ACEs on SCP DACL: 0x%x\n", hr));
  1394. goto ExitHere;
  1395. }
  1396. // Retrieve the SCP's objectGUID in format suitable for binding.
  1397. hr = pIADsSCP->get_GUID(&bstrGuid);
  1398. if (FAILED(hr)) {
  1399. LOG((TL_ERROR, "Failed to get GUID: 0x%x\n", hr));
  1400. goto ExitHere;
  1401. }
  1402. // Build a string for binding to the object by GUID
  1403. _tcscpy(szBindByGuidStr, TEXT("LDAP://<GUID="));
  1404. _tcscat(szBindByGuidStr, bstrGuid);
  1405. _tcscat(szBindByGuidStr, TEXT(">"));
  1406. LOG((TL_INFO, "GUID binding string: %s\n", szBindByGuidStr));
  1407. // Set the returning BindByGuidStr if any
  1408. if (ppBindByGuidStr)
  1409. {
  1410. *ppBindByGuidStr = (LPTSTR) ServerAlloc (
  1411. (_tcslen (szBindByGuidStr) + 1) * sizeof(TCHAR)
  1412. );
  1413. if (*ppBindByGuidStr == NULL)
  1414. {
  1415. hr = LINEERR_NOMEM;
  1416. goto ExitHere;
  1417. }
  1418. _tcscpy (*ppBindByGuidStr, szBindByGuidStr);
  1419. }
  1420. // Create a registry key under
  1421. // HKEY_LOCAL_MACHINE\SOFTWARE\Vendor\Product.
  1422. if (szObjGuidValueName)
  1423. {
  1424. dwStat = RegCreateKeyEx(
  1425. HKEY_LOCAL_MACHINE,
  1426. gszRegKeyTelephony,
  1427. 0,
  1428. NULL,
  1429. REG_OPTION_NON_VOLATILE,
  1430. KEY_SET_VALUE,
  1431. NULL,
  1432. &hReg,
  1433. &dwDisp);
  1434. if (dwStat != NO_ERROR) {
  1435. hr = HRESULT_FROM_NT(GetLastError());
  1436. LOG((TL_ERROR, "RegCreateKeyEx failed: 0x%x\n", hr));
  1437. return hr;
  1438. }
  1439. // Cache the GUID binding string under the registry key.
  1440. dwStat = RegSetValueEx(
  1441. hReg,
  1442. szObjGuidValueName,
  1443. 0,
  1444. REG_SZ,
  1445. (const BYTE *)szBindByGuidStr,
  1446. sizeof(TCHAR)*(_tcslen(szBindByGuidStr))
  1447. );
  1448. if (dwStat != NO_ERROR) {
  1449. hr = HRESULT_FROM_NT(GetLastError());
  1450. LOG((TL_ERROR, "RegSetValueEx failed: 0x%x\n", hr));
  1451. // goto ExitHere;
  1452. }
  1453. }
  1454. ExitHere:
  1455. if (pDisp)
  1456. {
  1457. pDisp->Release();
  1458. }
  1459. if (pIADsSCP)
  1460. {
  1461. pIADsSCP->Release();
  1462. }
  1463. if (hReg)
  1464. {
  1465. RegCloseKey(hReg);
  1466. }
  1467. if (bstrGuid)
  1468. {
  1469. SysFreeString (bstrGuid);
  1470. }
  1471. if (pComp)
  1472. {
  1473. if (FAILED(hr))
  1474. {
  1475. pComp->DeleteDSObject (wszRDN);
  1476. }
  1477. pComp->Release();
  1478. }
  1479. if (bRevert)
  1480. {
  1481. RevertLocalSystemImp ();
  1482. }
  1483. if (bCoInited)
  1484. {
  1485. CoUninitialize ();
  1486. }
  1487. return hr;
  1488. }
  1489. //
  1490. // CreateTapiSCP
  1491. //
  1492. // Creates the TAPI server Service Connection Point object
  1493. // under the local host computer object
  1494. //
  1495. // Parameters:
  1496. // pGuidAssoc - GUID of the line/user association objecct GUID
  1497. // currently NULL
  1498. // pGuidCluster - The cluster object GUID this server belonging to
  1499. //
  1500. HRESULT CreateTapiSCP (
  1501. GUID * pGuidAssoc,
  1502. GUID * pGuidCluster
  1503. )
  1504. {
  1505. DWORD dwStat, dwAttr, dwLen;
  1506. HRESULT hr = S_OK;
  1507. TCHAR szGUIDCluster[40];
  1508. TCHAR szGUIDAssoc[40];
  1509. TCHAR szBinding[128];
  1510. // Construct the binding information
  1511. if (pGuidCluster != NULL)
  1512. {
  1513. StringFromGUID2 (
  1514. *pGuidCluster,
  1515. szGUIDCluster,
  1516. sizeof(szGUIDCluster) / sizeof(TCHAR)
  1517. );
  1518. }
  1519. else
  1520. {
  1521. szGUIDCluster[0] = 0;
  1522. }
  1523. if (pGuidAssoc != NULL)
  1524. {
  1525. StringFromGUID2 (
  1526. *pGuidAssoc,
  1527. szGUIDAssoc,
  1528. sizeof(szGUIDAssoc) / sizeof(TCHAR)
  1529. );
  1530. }
  1531. else
  1532. {
  1533. szGUIDAssoc[0] = 0;
  1534. }
  1535. wsprintf(
  1536. szBinding,
  1537. gszTapisrvBindingInfo,
  1538. szGUIDCluster,
  1539. szGUIDAssoc,
  1540. TEXT("Inactive"),
  1541. TEXT("")
  1542. );
  1543. hr = CreateSCP (
  1544. (LPWSTR) gwszTapisrvRDN,
  1545. (LPTSTR) gszTapisrvProdName,
  1546. (LPTSTR) gszTapisrvGuid,
  1547. (pGuidCluster == NULL) ? NULL : ((LPTSTR)szGUIDCluster),
  1548. (LPTSTR) szBinding,
  1549. (LPTSTR) gszRegTapisrvSCPGuid,
  1550. NULL
  1551. );
  1552. return hr;
  1553. }
  1554. //
  1555. // CreateProxySCP
  1556. //
  1557. // Creates the TAPI proxy server Service Connection Point object
  1558. // under the local host computer object
  1559. //
  1560. // Parameters:
  1561. // szClsid - class ID of the proxy server object for DCOM invokation
  1562. // ppBindByGuidStr
  1563. // - where to return the BindByGuid string pointer
  1564. //
  1565. HRESULT CreateProxySCP (
  1566. LPTSTR szClsid,
  1567. LPTSTR * ppBindByGuidStr
  1568. )
  1569. {
  1570. HRESULT hr = S_OK;
  1571. // RDN size include "cn=TAPI Proxy Server" + szClsid(38ch)
  1572. WCHAR wszRDN[128];
  1573. WCHAR *psz;
  1574. wcscpy (wszRDN, gwszProxyRDN);
  1575. wcscat (wszRDN, L"{");
  1576. psz = wszRDN + wcslen(wszRDN);
  1577. #ifndef UNICODE
  1578. if (MultiByteToWideChar (
  1579. CP_ACP,
  1580. MB_PRECOMPOSED,
  1581. szClsid,
  1582. -1,
  1583. psz,
  1584. (sizeof(wszRDN) - sizeof(gwszProxyRDN)) / sizeof(WCHAR) - 3
  1585. // 3 is to compensate for the two brace
  1586. ) == 0)
  1587. {
  1588. hr = HRESULT_FROM_NT(GetLastError());
  1589. goto ExitHere;
  1590. }
  1591. #else
  1592. wcscat (wszRDN, szClsid);
  1593. #endif
  1594. wcscat (wszRDN, L"}");
  1595. hr = CreateSCP (
  1596. (LPWSTR) wszRDN,
  1597. (LPTSTR) gszProxyProdName,
  1598. (LPTSTR) gszProxyGuid,
  1599. NULL,
  1600. (LPTSTR) szClsid,
  1601. NULL,
  1602. ppBindByGuidStr
  1603. );
  1604. return hr;
  1605. }
  1606. /**********************************************************
  1607. * SCP Update
  1608. *********************************************************/
  1609. //
  1610. // UpdateSCP
  1611. //
  1612. // Update a general SCP properties when necessary to keep every
  1613. // piece ofthe information up to date. The following will be checked:
  1614. // 1. Check the serviceDNSName property against current computer
  1615. // DNS name to ensure consistancy
  1616. // 2. Check the binding information with the information given
  1617. //
  1618. // Parameters:
  1619. // szAdsPath - The ADs path of the SCP object
  1620. // szBinding - The binding information to compare with
  1621. //
  1622. HRESULT UpdateSCP (
  1623. LPTSTR szAdsPath,
  1624. LPTSTR szBinding
  1625. )
  1626. {
  1627. HRESULT hr = S_OK;
  1628. DWORD dwAttrs;
  1629. int i;
  1630. ADSVALUE dnsname,binding;
  1631. DWORD dwLen;
  1632. BOOL bUpdate=FALSE;
  1633. BOOL bCoInited = FALSE;
  1634. BOOL bRevert = FALSE;
  1635. IDirectoryObject *pObj = NULL;
  1636. PADS_ATTR_INFO pAttribs = NULL;
  1637. TCHAR szServer[MAX_PATH];
  1638. TCHAR *pszAttrs[]={
  1639. TEXT("serviceDNSName"),
  1640. TEXT("serviceBindingInformation")
  1641. };
  1642. ADS_ATTR_INFO Attribs[]={
  1643. {TEXT("serviceDNSName"),ADS_ATTR_UPDATE,ADSTYPE_CASE_IGNORE_STRING,&
  1644. dnsname,1},
  1645. {TEXT("serviceBindingInformation"),ADS_ATTR_UPDATE,
  1646. ADSTYPE_CASE_IGNORE_STRING,&binding,1},
  1647. };
  1648. //
  1649. // Do CoInitializeEx
  1650. //
  1651. hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
  1652. if (FAILED (hr))
  1653. {
  1654. goto ExitHere;
  1655. }
  1656. bCoInited = TRUE;
  1657. //
  1658. // Do all the operation in LocalSystem account
  1659. //
  1660. if (IsCurrentLocalSystem() != S_OK)
  1661. {
  1662. hr = ImpersonateLocalSystem ();
  1663. if (hr)
  1664. {
  1665. goto ExitHere;
  1666. }
  1667. bRevert = TRUE;
  1668. }
  1669. // Get the DNS name of the host server.
  1670. dwLen = sizeof(szServer)/sizeof(TCHAR);
  1671. if (!GetComputerNameEx(ComputerNameDnsFullyQualified, szServer, &dwLen))
  1672. {
  1673. hr = HRESULT_FROM_NT(GetLastError());
  1674. goto ExitHere;
  1675. }
  1676. // Bind to the SCP.
  1677. hr = ADsGetObject(szAdsPath, IID_IDirectoryObject, (void **)&pObj);
  1678. if (FAILED(hr))
  1679. {
  1680. LOG((TL_ERROR,
  1681. "ADsGetObject failed to bind to GUID (bind string: %S): ",
  1682. szAdsPath
  1683. ));
  1684. goto ExitHere;
  1685. }
  1686. // Retrieve attributes from the SCP.
  1687. hr = pObj->GetObjectAttributes(pszAttrs, 2, &pAttribs, &dwAttrs);
  1688. if (FAILED(hr)) {
  1689. LOG((TL_ERROR, "GetObjectAttributes failed"));
  1690. goto ExitHere;
  1691. }
  1692. // Check if we got the correct attribute type
  1693. if (pAttribs->dwADsType != ADSTYPE_CASE_IGNORE_STRING ||
  1694. (pAttribs+1)->dwADsType != ADSTYPE_CASE_IGNORE_STRING)
  1695. {
  1696. LOG((TL_ERROR,
  1697. "GetObjectAttributes returned dwADsType (%d,%d) instead of CASE_IGNORE_STRING",
  1698. pAttribs->dwADsType,
  1699. (pAttribs+1)->dwADsType
  1700. ));
  1701. goto ExitHere;
  1702. }
  1703. // Compare the current DNS name and port to the values retrieved from
  1704. // the SCP. Update the SCP only if something has changed.
  1705. for (i=0; i<(LONG)dwAttrs; i++)
  1706. {
  1707. if (_tcsicmp(TEXT("serviceDNSName"), pAttribs[i].pszAttrName)==0)
  1708. {
  1709. if (_tcsicmp(szServer, pAttribs[i].pADsValues->CaseIgnoreString) != 0)
  1710. {
  1711. LOG((TL_ERROR, "serviceDNSName being updated", 0));
  1712. bUpdate = TRUE;
  1713. }
  1714. else
  1715. {
  1716. LOG((TL_ERROR, "serviceDNSName okay", 0));
  1717. }
  1718. }
  1719. else if (_tcsicmp(
  1720. TEXT("serviceBindingInformation"),
  1721. pAttribs[i].pszAttrName
  1722. )==0)
  1723. {
  1724. if (_tcsicmp(szBinding, pAttribs[i].pADsValues->CaseIgnoreString) != 0)
  1725. {
  1726. LOG((TL_ERROR, "serviceBindingInformation being updated", 0));
  1727. bUpdate = TRUE;
  1728. }
  1729. else
  1730. {
  1731. LOG((TL_ERROR, "serviceBindingInformation okay"));
  1732. }
  1733. }
  1734. }
  1735. // The binding information or server name have changed,
  1736. // so update the SCP values.
  1737. if (bUpdate)
  1738. {
  1739. dnsname.dwType = ADSTYPE_CASE_IGNORE_STRING;
  1740. dnsname.CaseIgnoreString = szServer;
  1741. binding.dwType = ADSTYPE_CASE_IGNORE_STRING;
  1742. binding.CaseIgnoreString = szBinding;
  1743. hr = pObj->SetObjectAttributes(Attribs, 2, &dwAttrs);
  1744. if (FAILED(hr))
  1745. {
  1746. LOG((TL_ERROR, "ScpUpdate: Failed to set SCP values.", hr));
  1747. goto ExitHere;
  1748. }
  1749. }
  1750. ExitHere:
  1751. if (pAttribs)
  1752. {
  1753. FreeADsMem(pAttribs);
  1754. }
  1755. if (pObj)
  1756. {
  1757. pObj->Release();
  1758. }
  1759. if (bRevert)
  1760. {
  1761. RevertLocalSystemImp ();
  1762. }
  1763. if (bCoInited)
  1764. {
  1765. CoUninitialize ();
  1766. }
  1767. return hr;
  1768. }
  1769. //
  1770. // UpdateTapiSCP
  1771. //
  1772. // Update TAPI server SCP properties when necessary to keep every
  1773. // piece ofthe information up to date. The following will be checked:
  1774. //
  1775. // Parameters:
  1776. // pGuidAssoc - The line/user association guid
  1777. // pGuidCluster - The cluster GUID
  1778. //
  1779. HRESULT UpdateTapiSCP (
  1780. BOOL bActive,
  1781. GUID * pGuidAssoc,
  1782. GUID * pGuidCluster
  1783. )
  1784. {
  1785. HRESULT hr = S_OK;
  1786. TCHAR szGUIDCluster[40];
  1787. TCHAR szGUIDAssoc[40];
  1788. TCHAR szBinding[128];
  1789. DWORD dwStat, dwType, dwLen;
  1790. HKEY hReg = NULL;
  1791. TCHAR szAdsPath[MAX_PATH];
  1792. // Open the service's registry key.
  1793. dwStat = RegOpenKeyEx(
  1794. HKEY_LOCAL_MACHINE,
  1795. gszRegKeyTelephony,
  1796. 0,
  1797. KEY_QUERY_VALUE,
  1798. &hReg
  1799. );
  1800. if (dwStat != NO_ERROR)
  1801. {
  1802. // Probably because the SCP never published, CreateTapiSCP
  1803. LOG((TL_ERROR, "RegOpenKeyEx failed", dwStat));
  1804. hr = HRESULT_FROM_NT(dwStat);
  1805. goto ExitHere;
  1806. }
  1807. // Get the GUID binding string used to bind to the service's SCP.
  1808. dwLen = sizeof(szAdsPath);
  1809. dwStat = RegQueryValueEx(
  1810. hReg,
  1811. gszRegTapisrvSCPGuid,
  1812. 0,
  1813. &dwType,
  1814. (LPBYTE)szAdsPath,
  1815. &dwLen
  1816. );
  1817. if (dwStat != NO_ERROR)
  1818. {
  1819. LOG((TL_ERROR, "RegQueryValueEx failed", dwStat));
  1820. if (TapiGlobals.dwFlags & TAPIGLOBALS_SERVER)
  1821. {
  1822. if (FAILED(hr = CreateTapiSCP (pGuidAssoc, pGuidCluster)))
  1823. {
  1824. LOG((TL_ERROR, "UpdateTapiSCP: CreateTapiSCP failed"));
  1825. goto ExitHere;
  1826. }
  1827. // CreateTapiSCP succeeded, need to read the guid
  1828. dwLen = sizeof(szAdsPath);
  1829. dwStat = RegQueryValueEx(
  1830. hReg,
  1831. gszRegTapisrvSCPGuid,
  1832. 0,
  1833. &dwType,
  1834. (LPBYTE)szAdsPath,
  1835. &dwLen
  1836. );
  1837. if (dwStat != NO_ERROR)
  1838. {
  1839. LOG((TL_ERROR, "UpdateTapiSCP: CreateTapiSCP succeeded but cannot read the guid"));
  1840. hr = HRESULT_FROM_NT(dwStat);
  1841. goto ExitHere;
  1842. }
  1843. }
  1844. else
  1845. {
  1846. hr = HRESULT_FROM_NT(dwStat);
  1847. goto ExitHere;
  1848. }
  1849. }
  1850. // Format to generate desired binding information
  1851. if (pGuidCluster != NULL)
  1852. {
  1853. StringFromGUID2 (
  1854. *pGuidCluster,
  1855. szGUIDCluster,
  1856. sizeof(szGUIDCluster) / sizeof(TCHAR)
  1857. );
  1858. }
  1859. else
  1860. {
  1861. szGUIDCluster[0] = 0;
  1862. }
  1863. if (pGuidAssoc != NULL)
  1864. {
  1865. StringFromGUID2 (
  1866. *pGuidAssoc,
  1867. szGUIDAssoc,
  1868. sizeof(szGUIDAssoc) / sizeof(TCHAR)
  1869. );
  1870. }
  1871. else
  1872. {
  1873. szGUIDAssoc[0] = 0;
  1874. }
  1875. //
  1876. // Now construct the serviceBindingInformation based on the
  1877. // service status
  1878. //
  1879. if (bActive)
  1880. {
  1881. TCHAR szTTL[64];
  1882. FILETIME ftCur;
  1883. ULONGLONG ullInc, ullTime;
  1884. SYSTEMTIME stExp;
  1885. // Get current time
  1886. GetSystemTimeAsFileTime (&ftCur);
  1887. CopyMemory (&ullTime, &ftCur, sizeof(ULONGLONG));
  1888. // Get the time increment for gdwTapiSCPTTL minutes
  1889. // FILETIME is in the unit of 100 nanoseconds
  1890. ullInc = ((ULONGLONG)gdwTapiSCPTTL) * 60 * 10000000;
  1891. // Get the record expiration time
  1892. ullTime += ullInc;
  1893. CopyMemory (&ftCur, &ullTime, sizeof(FILETIME));
  1894. //
  1895. // Convert the expiration time to system time and
  1896. // format the string
  1897. //
  1898. // The current TTL string is the concatenation of
  1899. // Year, Month, Date, Hour, Minute, Second, Milliseconds
  1900. // There are 5 digits allocated for year, 3 digits for
  1901. // milliseconds, and 2 digits fro the remaining fields
  1902. // all the numbers are zero padded to fill the extra space
  1903. //
  1904. // Format here needs to be consistant with \
  1905. // sp\remotesp\dslookup.cpp
  1906. //
  1907. FileTimeToSystemTime (&ftCur, &stExp);
  1908. wsprintf (
  1909. szTTL,
  1910. TEXT("%05d%02d%02d%02d%02d%02d%03d"),
  1911. stExp.wYear,
  1912. stExp.wMonth,
  1913. stExp.wDay,
  1914. stExp.wHour,
  1915. stExp.wMinute,
  1916. stExp.wSecond,
  1917. stExp.wMilliseconds
  1918. );
  1919. wsprintf(
  1920. szBinding,
  1921. gszTapisrvBindingInfo,
  1922. szGUIDCluster,
  1923. szGUIDAssoc,
  1924. TEXT("Active"),
  1925. szTTL
  1926. );
  1927. }
  1928. else
  1929. {
  1930. wsprintf(
  1931. szBinding,
  1932. gszTapisrvBindingInfo,
  1933. szGUIDCluster,
  1934. szGUIDAssoc,
  1935. TEXT("Inactive"),
  1936. TEXT("")
  1937. );
  1938. }
  1939. hr = UpdateSCP (
  1940. szAdsPath,
  1941. szBinding
  1942. );
  1943. ExitHere:
  1944. if (hReg)
  1945. {
  1946. RegCloseKey (hReg);
  1947. }
  1948. return hr;
  1949. }
  1950. //
  1951. // Proxy server exists only if TAPI server are alive
  1952. // the DS information not likely to change when TAPI server is
  1953. // alive, so no SCP updating routine for Proxy server
  1954. //
  1955. /**********************************************************
  1956. * SCP Removal
  1957. *********************************************************/
  1958. //
  1959. // RemoveSCP
  1960. //
  1961. // Removes a Service Connection Point object from the
  1962. // local host computer object.
  1963. //
  1964. // Parameters:
  1965. // wszRDN - the RDN of the SCP to delete
  1966. // szRegNameToDel
  1967. // - The registery value name to be deleted
  1968. // If this value is NULL, no registry del
  1969. //
  1970. HRESULT RemoveSCP (
  1971. LPWSTR wszRDN,
  1972. LPTSTR szRegNameToDel
  1973. )
  1974. {
  1975. HRESULT hr = S_OK;
  1976. TCHAR szServer[MAX_PATH];
  1977. TCHAR szAdsPath[MAX_PATH];
  1978. DWORD dwLen, dwStat;
  1979. HKEY hReg;
  1980. IDirectoryObject * pComp = NULL;
  1981. BOOL bCoInited = FALSE;
  1982. BOOL bRevert = FALSE;
  1983. //
  1984. // Do CoInitializeEx
  1985. //
  1986. hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
  1987. if (FAILED (hr))
  1988. {
  1989. goto ExitHere;
  1990. }
  1991. bCoInited = TRUE;
  1992. //
  1993. // Do all the operation in LocalSystem account
  1994. //
  1995. if (IsCurrentLocalSystem() != S_OK)
  1996. {
  1997. hr = ImpersonateLocalSystem ();
  1998. if (hr)
  1999. {
  2000. goto ExitHere;
  2001. }
  2002. bRevert = TRUE;
  2003. }
  2004. // Get the DNS name of the host server.
  2005. dwLen = sizeof(szServer);
  2006. if (!GetComputerObjectName(NameFullyQualifiedDN, szServer, &dwLen))
  2007. {
  2008. hr = HRESULT_FROM_NT(GetLastError());
  2009. goto ExitHere;
  2010. }
  2011. //
  2012. // Compose the ADSpath and bind to the computer object for the local computer
  2013. //
  2014. _tcscpy(szAdsPath,TEXT("LDAP://"));
  2015. _tcscat(szAdsPath,szServer);
  2016. hr = ADsGetObject(szAdsPath, IID_IDirectoryObject, (void **)&pComp);
  2017. if (FAILED(hr)) {
  2018. LOG((TL_ERROR, "Failed (%x) to bind Computer Object.",hr));
  2019. goto ExitHere;
  2020. }
  2021. hr = pComp->DeleteDSObject (wszRDN);
  2022. if (FAILED (hr))
  2023. {
  2024. LOG((TL_ERROR, "Failed (%x) to Delete Tapisrv Object.",hr));
  2025. if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
  2026. {
  2027. hr = HRESULT_FROM_NT (TAPIERR_SCP_DOES_NOT_EXIST);
  2028. }
  2029. goto ExitHere;
  2030. }
  2031. // Open the service's registry key.
  2032. if (szRegNameToDel)
  2033. {
  2034. dwStat = RegOpenKeyEx(
  2035. HKEY_LOCAL_MACHINE,
  2036. gszRegKeyTelephony,
  2037. 0,
  2038. KEY_QUERY_VALUE | KEY_WRITE,
  2039. &hReg);
  2040. if (dwStat == NO_ERROR)
  2041. {
  2042. RegDeleteValue (
  2043. hReg,
  2044. szRegNameToDel
  2045. );
  2046. RegCloseKey (hReg);
  2047. }
  2048. else
  2049. {
  2050. LOG((TL_ERROR, "RegOpenKeyEx failed", dwStat));
  2051. hr = HRESULT_FROM_NT(GetLastError());
  2052. // goto ExitHere;
  2053. }
  2054. }
  2055. ExitHere:
  2056. if (pComp)
  2057. pComp->Release();
  2058. if (bRevert)
  2059. {
  2060. RevertLocalSystemImp ();
  2061. }
  2062. if (bCoInited)
  2063. {
  2064. CoUninitialize ();
  2065. }
  2066. return hr;
  2067. }
  2068. //
  2069. // RemoveTapiSCP
  2070. //
  2071. // Removes the TAPI server Service Connection Point object from the
  2072. // local host computer object. This happens if a TAPI server machine
  2073. // retires from service.
  2074. //
  2075. HRESULT RemoveTapiSCP (
  2076. )
  2077. {
  2078. return RemoveSCP (
  2079. (LPWSTR) gwszTapisrvRDN,
  2080. (LPTSTR) gszRegTapisrvSCPGuid
  2081. );
  2082. }
  2083. //
  2084. // RemoveProxySCP
  2085. //
  2086. // Removes the proxy server Service Connection Point object from the
  2087. // local host computer object. This happens if the last line is closed
  2088. // from a certain proxy server (CLSID)
  2089. //
  2090. HRESULT RemoveProxySCP (
  2091. LPTSTR szClsid
  2092. )
  2093. {
  2094. HRESULT hr = S_OK;
  2095. // Construct the RDN
  2096. // RDN size include "cn=TAPI Proxy Server" + szClsid(38ch)
  2097. WCHAR wszRDN[128];
  2098. WCHAR *psz;
  2099. wcscpy (wszRDN, gwszProxyRDN);
  2100. wcscat (wszRDN, L"{");
  2101. psz = wszRDN + wcslen(wszRDN);
  2102. #ifndef UNICODE
  2103. if (MultiByteToWideChar (
  2104. CP_ACP,
  2105. MB_PRECOMPOSED,
  2106. szClsid,
  2107. -1,
  2108. psz,
  2109. (sizeof(wszRDN) - sizeof(gwszProxyRDN)) / sizeof(WCHAR) - 3
  2110. // 3 is to compensate for the two brace
  2111. ) == 0)
  2112. {
  2113. hr = HRESULT_FROM_NT(GetLastError());
  2114. goto ExitHere;
  2115. }
  2116. #else
  2117. wcscat (wszRDN, szClsid);
  2118. #endif
  2119. wcscat (wszRDN, L"}");
  2120. // Call RemoveSCP
  2121. hr = RemoveSCP (
  2122. wszRDN,
  2123. NULL
  2124. );
  2125. //ExitHere:
  2126. return hr;
  2127. }
  2128. /**********************************************************
  2129. * Proxy Server SCP management
  2130. *********************************************************/
  2131. //
  2132. // The Rules:
  2133. // 1. An array of created SCP objects and their corresponding CLSID
  2134. // is maintained in a global data structure PROXY_SCPS
  2135. // 2. ServerInit calls OnProxySCPInit & ServerShutdown calls
  2136. // OnProxySCPShutdown
  2137. // 3. Every LOpen with proxy privilege will call OnProxyLineOpen with
  2138. // the proxy server CLSID as the input parameter.
  2139. // An SCP object will be created for a new CLSID, subsequent LOpen
  2140. // with the same CLSID will only increment the ref count
  2141. // 4. Every LClose with on a line (opened with proxy privilege) will call
  2142. // OnProxyLineClose with the proxy server CLSID as the input parameter
  2143. // The ref count is decemented every time for the SCP with the CLSID,
  2144. // if the ref count goes to zero, the SCP object will be deleted.
  2145. //
  2146. HRESULT OnProxySCPInit (
  2147. )
  2148. {
  2149. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  2150. ZeroMemory (&gProxyScps, sizeof(gProxyScps));
  2151. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  2152. return S_OK;
  2153. }
  2154. HRESULT OnProxySCPShutdown (
  2155. )
  2156. {
  2157. DWORD i;
  2158. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  2159. for (i = 0; i < gProxyScps.dwUsedEntries; ++i)
  2160. {
  2161. RemoveProxySCP (gProxyScps.aEntries[i].szClsid);
  2162. }
  2163. if (gProxyScps.aEntries != NULL)
  2164. {
  2165. ServerFree (gProxyScps.aEntries);
  2166. }
  2167. ZeroMemory (&gProxyScps, sizeof(gProxyScps));
  2168. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  2169. return S_OK;
  2170. }
  2171. HRESULT OnProxyLineOpen (
  2172. LPTSTR szClsid
  2173. )
  2174. {
  2175. HRESULT hr = S_OK;
  2176. BOOL fExists = FALSE;
  2177. DWORD i;
  2178. // Skip beginning/trailing white space
  2179. while (*szClsid == TEXT(' ') || *szClsid == TEXT('\t'))
  2180. ++ szClsid;
  2181. // A valid CLSID string should only contain 38 chars
  2182. if (_tcslen (szClsid) > 40)
  2183. {
  2184. hr = E_INVALIDARG;
  2185. goto ExitHere;
  2186. }
  2187. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  2188. // Is SCP for this szClsid already created (in array)?
  2189. for (i = 0; i < gProxyScps.dwUsedEntries; ++i)
  2190. {
  2191. if (_tcsicmp (
  2192. gProxyScps.aEntries[i].szClsid,
  2193. szClsid
  2194. ) == 0)
  2195. {
  2196. fExists = TRUE;
  2197. break;
  2198. }
  2199. }
  2200. // If already exists, inc the ref count
  2201. if (fExists)
  2202. {
  2203. gProxyScps.aEntries[i].dwRefCount++;
  2204. }
  2205. // If not exists, create the new SCP and cache it
  2206. else
  2207. {
  2208. LPTSTR pBindByGuidStr;
  2209. hr = CreateProxySCP (szClsid, &pBindByGuidStr);
  2210. if (FAILED (hr))
  2211. {
  2212. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  2213. goto ExitHere;
  2214. }
  2215. if (gProxyScps.dwUsedEntries >= gProxyScps.dwTotalEntries)
  2216. {
  2217. // Increase the size
  2218. PROXY_SCP_ENTRY * pNew;
  2219. pNew = (PPROXY_SCP_ENTRY) ServerAlloc (
  2220. sizeof(PROXY_SCP_ENTRY) * (gProxyScps.dwTotalEntries + 16)
  2221. );
  2222. if (pNew == NULL)
  2223. {
  2224. hr = LINEERR_NOMEM;
  2225. ServerFree (pBindByGuidStr);
  2226. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  2227. goto ExitHere;
  2228. }
  2229. CopyMemory (
  2230. pNew,
  2231. gProxyScps.aEntries,
  2232. sizeof(PROXY_SCP_ENTRY) * gProxyScps.dwTotalEntries
  2233. );
  2234. ServerFree (gProxyScps.aEntries);
  2235. gProxyScps.aEntries = pNew;
  2236. gProxyScps.dwTotalEntries += 16;
  2237. }
  2238. i = gProxyScps.dwUsedEntries++;
  2239. _tcscpy (gProxyScps.aEntries[i].szClsid, szClsid);
  2240. _tcscpy (gProxyScps.aEntries[i].szObjGuid, pBindByGuidStr);
  2241. gProxyScps.aEntries[i].dwRefCount = 1;
  2242. ServerFree (pBindByGuidStr);
  2243. }
  2244. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  2245. ExitHere:
  2246. return hr;
  2247. }
  2248. HRESULT OnProxyLineClose (
  2249. LPTSTR szClsid
  2250. )
  2251. {
  2252. HRESULT hr = S_OK;
  2253. BOOL fExists = FALSE;
  2254. DWORD i;
  2255. // Skip beginning/trailing white space
  2256. while (*szClsid == TEXT(' ') || *szClsid == TEXT('\t'))
  2257. ++ szClsid;
  2258. // A valid CLSID string should only contain 38 chars
  2259. if (_tcslen (szClsid) > 40)
  2260. {
  2261. hr = E_INVALIDARG;
  2262. goto ExitHere;
  2263. }
  2264. TapiEnterCriticalSection (&TapiGlobals.CritSec);
  2265. // Is SCP for this szClsid already created (in array)?
  2266. for (i = 0; i < gProxyScps.dwUsedEntries; ++i)
  2267. {
  2268. if (_tcsicmp (
  2269. gProxyScps.aEntries[i].szClsid,
  2270. szClsid
  2271. ) == 0)
  2272. {
  2273. fExists = TRUE;
  2274. break;
  2275. }
  2276. }
  2277. if (fExists)
  2278. {
  2279. --gProxyScps.aEntries[i].dwRefCount;
  2280. // If ref count goes to zero, remove the SCP
  2281. if (gProxyScps.aEntries[i].dwRefCount == 0)
  2282. {
  2283. hr = RemoveProxySCP (gProxyScps.aEntries[i].szClsid);
  2284. if (i < gProxyScps.dwUsedEntries - 1)
  2285. {
  2286. MoveMemory (
  2287. gProxyScps.aEntries + i,
  2288. gProxyScps.aEntries + i + 1,
  2289. sizeof(PROXY_SCP_ENTRY) * (gProxyScps.dwUsedEntries - 1 - i)
  2290. );
  2291. }
  2292. --gProxyScps.dwUsedEntries;
  2293. }
  2294. }
  2295. TapiLeaveCriticalSection (&TapiGlobals.CritSec);
  2296. ExitHere:
  2297. return hr;
  2298. }