Leaked source code of windows server 2003
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.

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