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.

3069 lines
81 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. rndils.cpp
  5. Abstract:
  6. This module contains implementation of CILSDirectory.
  7. --*/
  8. #include "stdafx.h"
  9. #include <limits.h>
  10. #include "rndcommc.h"
  11. #include "rndils.h"
  12. #include "rndldap.h"
  13. #include "rndcnf.h"
  14. #include "rndcoll.h"
  15. //
  16. // These are the names of the attributes we have to work with
  17. // in the ILS schema.
  18. //
  19. const WCHAR * const CILSDirectory::s_RTConferenceAttributes[] =
  20. {
  21. L"advertisingScope",
  22. L"conferenceBlob",
  23. L"generalDescription",
  24. L"isEncrypted",
  25. L"uid",
  26. L"originator",
  27. L"protocolId",
  28. L"startTime",
  29. L"stopTime",
  30. L"subType",
  31. L"URL"
  32. };
  33. //
  34. // The following are the attributes we make use of natively for
  35. // ILS user objects. (perhaps not all though?)
  36. //
  37. const WCHAR * const CILSDirectory::s_RTPersonAttributes[] =
  38. {
  39. L"cn",
  40. L"telephoneNumber",
  41. L"ipAddress"
  42. };
  43. // The following definitions are for NetMeeting compatibility only.
  44. const WCHAR * const g_NMAttributeNames[] =
  45. {
  46. L"applicationID",
  47. L"mimetype",
  48. L"GUID",
  49. L"protocolID",
  50. L"ProtocolMimeType",
  51. L"port",
  52. L"ILSA39321630",
  53. L"ILSA26214430",
  54. L"ILSA32964638",
  55. L"ILSA32833566"
  56. };
  57. const DWORD NUM_NM_ATTRIBUTES =
  58. (sizeof g_NMAttributeNames)/(sizeof (WCHAR *));
  59. const WCHAR * const g_NMAttributeValues[] =
  60. {
  61. L"ms-netmeeting", NULL,
  62. L"text/iuls", NULL,
  63. L"008aff194794cf118796444553540000", NULL,
  64. L"H323", NULL,
  65. L"text/h323", NULL,
  66. L"1720", NULL,
  67. L"4", NULL,
  68. L"0", NULL,
  69. L"1", NULL,
  70. L"1", NULL
  71. };
  72. const WCHAR * const g_NMRTPersonAttributeNames[] =
  73. {
  74. // ZoltanS: moved this out so we can make it look nicer: L"givenName",
  75. L"surname", // vocabulary word: this means "last name"
  76. L"location",
  77. L"sflags",
  78. L"c",
  79. L"comment",
  80. L"ssecurity",
  81. L"smodop",
  82. L"mimetype",
  83. L"GUID",
  84. L"ProtocolMimeType",
  85. L"port",
  86. L"ILSA39321630",
  87. L"ILSA26214430",
  88. L"ILSA32964638",
  89. L"ILSA32833566"
  90. };
  91. const DWORD NUM_NM_RTPERSON_ATTRIBUTES =
  92. (sizeof g_NMRTPersonAttributeNames)/(sizeof (WCHAR *));
  93. const WCHAR * const g_NMRTPersonAttributeValues[] =
  94. {
  95. // ZoltanS: we used to have this here: L"N/A", NULL,
  96. L" ", NULL, // ZoltanS was N/A. Need the space to avoid having nothing set.
  97. L"N/A", NULL,
  98. L"1", NULL,
  99. L"US", NULL,
  100. L"Generated by TAPI3", NULL,
  101. L"1508109", NULL,
  102. L"0", NULL,
  103. L"text/iuls", NULL,
  104. L"008aff194794cf118796444553540000", NULL,
  105. L"H323", NULL,
  106. L"1720", NULL,
  107. L"4", NULL,
  108. L"0", NULL,
  109. L"1", NULL,
  110. L"1", NULL
  111. };
  112. /////////////////////////////////////////////////////////////////////////////
  113. /////////////////////////////////////////////////////////////////////////////
  114. HRESULT CILSDirectory::FinalConstruct(void)
  115. {
  116. LOG((MSP_TRACE, "CILSDirectory::FinalConstruct - enter"));
  117. HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
  118. & m_pFTM );
  119. if ( FAILED(hr) )
  120. {
  121. LOG((MSP_INFO, "CILSDirectory::FinalConstruct - "
  122. "create FTM returned 0x%08x; exit", hr));
  123. return hr;
  124. }
  125. LOG((MSP_TRACE, "CILSDirectory::FinalConstruct - exit S_OK"));
  126. return S_OK;
  127. }
  128. /////////////////////////////////////////////////////////////////////////////
  129. // ldap helper functions
  130. /////////////////////////////////////////////////////////////////////////////
  131. HRESULT ValidateILSServer(IN LDAP *hLdap, IN TCHAR * org)
  132. /*++
  133. Routine Description:
  134. send a search to check if the RTConference schema is supported
  135. Arguments:
  136. hLdap - The handle to the ldap connection.
  137. org - The default naming context.
  138. Return Value:
  139. HRESULT.
  140. --*/
  141. {
  142. const WCHAR CN_WSTR[] = L"cn";
  143. const WCHAR CN_RTCONF_WSTR[] = L"cn=RTConference";
  144. const WCHAR SCHEMA[] = L",ou=admin,cn=schema";
  145. LOG((MSP_INFO, "::ValidateILSServer - entering"));
  146. // send a search (one level, base dn = "o=ORG,ou=admin,cn=schema",
  147. // filter = "cn=RTConference") ask for the cn attribute without the value
  148. PTCHAR Attributes[] = {(WCHAR *)CN_WSTR, NULL};
  149. // determine the organization - use the org portion of the directory path
  150. // string and the pre-cooked "ou=admin,cn=schema" string
  151. TCHAR *SchemaDn = new TCHAR[lstrlen(org) + lstrlen(SCHEMA) + 1];
  152. BAIL_IF_NULL(SchemaDn, E_OUTOFMEMORY);
  153. lstrcpy(SchemaDn, org);
  154. lstrcat(SchemaDn, SCHEMA);
  155. // print the base dn
  156. LDAPMessage *SearchResult;
  157. ULONG res = DoLdapSearch(
  158. hLdap, // ldap handle
  159. SchemaDn, // schema dn
  160. LDAP_SCOPE_ONELEVEL, // one level search
  161. (WCHAR *)CN_RTCONF_WSTR, // common name is RTConference
  162. Attributes, // array of attribute names
  163. TRUE, // don't return the attribute values
  164. &SearchResult // search results
  165. );
  166. // free the schema dn string
  167. delete SchemaDn;
  168. // check result of the search operation
  169. BAIL_IF_LDAP_FAIL(res, "search for RTConference schema");
  170. CLdapMsgPtr MessageHolder(SearchResult);
  171. // check the number of entries returned to determine if OK
  172. HRESULT hr = (0==ldap_count_entries(hLdap, SearchResult)) ? E_FAIL : S_OK;
  173. LOG((MSP_INFO, "::ValidateILSServer - exiting %x", hr));
  174. return hr;
  175. }
  176. /////////////////////////////////////////////////////////////////////////////
  177. // private functions
  178. /////////////////////////////////////////////////////////////////////////////
  179. HRESULT CILSDirectory::Init(
  180. IN const TCHAR * const strServerName,
  181. IN const WORD wPort
  182. )
  183. /*++
  184. Routine Description:
  185. Connect to the ILS server on a given port.
  186. Arguments:
  187. strServerName - The ILS server name.
  188. wPort - The port number.
  189. Return Value:
  190. HRESULT.
  191. --*/
  192. {
  193. if (strServerName != NULL)
  194. {
  195. int cbServerName = lstrlen(strServerName);
  196. // Make sure the adding operation don't go over the limits
  197. if( (cbServerName+1) <= cbServerName )
  198. {
  199. return E_INVALIDARG;
  200. }
  201. m_pServerName = new TCHAR [cbServerName + 1];
  202. if (m_pServerName == NULL)
  203. {
  204. return E_OUTOFMEMORY;
  205. }
  206. // Strange +1, lstrcpyn copies also the NULL terminator
  207. lstrcpyn(m_pServerName, strServerName, cbServerName+1);
  208. _ASSERTE( lstrlen(m_pServerName) == cbServerName );
  209. }
  210. m_wPort = wPort;
  211. return S_OK;
  212. }
  213. HRESULT
  214. CILSDirectory::TryServer(
  215. IN WORD Port
  216. )
  217. /*++
  218. Routine Description:
  219. Try to connect to the ILS server one the given port.
  220. Arguments:
  221. wPort - The port number.
  222. Return Value:
  223. HRESULT.
  224. --*/
  225. {
  226. LOG((MSP_INFO, "trying %S at port %d", m_pServerName, Port));
  227. // associate the ldap handle with the handle holder. in case of an error
  228. // and subsequent return (without being reset), the ldap handle is closed
  229. CLdapPtr hLdap = ldap_init(m_pServerName, Port);
  230. BAIL_IF_NULL((LDAP*)hLdap, HRESULT_FROM_WIN32(ERROR_BAD_NETPATH));
  231. LDAP_TIMEVAL Timeout;
  232. Timeout.tv_sec = REND_LDAP_TIMELIMIT;
  233. Timeout.tv_usec = 0;
  234. DWORD res = ldap_connect((LDAP*)hLdap, &Timeout);
  235. BAIL_IF_LDAP_FAIL(res, "connect to the server.");
  236. DWORD LdapVersion = 3;
  237. res = ldap_set_option((LDAP*)hLdap, LDAP_OPT_VERSION, &LdapVersion);
  238. BAIL_IF_LDAP_FAIL(res, "set ldap version to 3");
  239. res = ldap_set_option((LDAP*)hLdap, LDAP_OPT_TIMELIMIT, &Timeout);
  240. BAIL_IF_LDAP_FAIL(res, "set ldap timelimit");
  241. ULONG ldapOptionOn = PtrToUlong(LDAP_OPT_ON);
  242. res = ldap_set_option((LDAP*)hLdap, LDAP_OPT_AREC_EXCLUSIVE, &ldapOptionOn);
  243. BAIL_IF_LDAP_FAIL(res, "set ldap arec exclusive");
  244. if (m_IsSsl)
  245. {
  246. res = ldap_set_option(hLdap, LDAP_OPT_SSL, LDAP_OPT_ON);
  247. BAIL_IF_LDAP_FAIL(res, "set ssl option");
  248. }
  249. // if no directory path is specified, query the server
  250. // to determine the correct path
  251. CTstr namingContext;
  252. BAIL_IF_FAIL(
  253. ::GetNamingContext(hLdap, &namingContext),
  254. "read naming context"
  255. );
  256. // ZoltanS: this copies the namingContext string.
  257. BAIL_IF_FAIL(
  258. ValidateILSServer(hLdap, namingContext),
  259. "ValidateILSServer"
  260. );
  261. m_pContainer =
  262. new TCHAR[lstrlen(namingContext) + lstrlen(DYNAMIC_CONTAINER) + 1];
  263. BAIL_IF_NULL(m_pContainer, E_OUTOFMEMORY);
  264. m_pNMContainer =
  265. new TCHAR[lstrlen(namingContext) + lstrlen(NETMEETING_CONTAINER) + 1];
  266. BAIL_IF_NULL(m_pNMContainer, E_OUTOFMEMORY);
  267. m_ldap = hLdap;
  268. lstrcpy(m_pContainer, DYNAMIC_CONTAINER);
  269. lstrcat(m_pContainer, namingContext);
  270. lstrcpy(m_pNMContainer, NETMEETING_CONTAINER);
  271. lstrcat(m_pNMContainer, namingContext);
  272. // reset the holders so that they don't release anyting.
  273. hLdap = NULL;
  274. // ZoltanS fix: We were leaking this string. It is copied
  275. // everywhere above, so we should NOT reset the holder here!
  276. // --> namingContext = NULL;
  277. LOG((MSP_INFO, "CILSDirectory::TryServer - exiting OK"));
  278. return S_OK;
  279. }
  280. HRESULT CILSDirectory::MakeConferenceDN(
  281. IN TCHAR * pName,
  282. OUT TCHAR ** ppDN
  283. )
  284. /*++
  285. Routine Description:
  286. Construct the DN for a conference based on the name of the conference.
  287. Arguments:
  288. pName - The name of the conference.
  289. ppDN - The DN of the conference returned.
  290. Return Value:
  291. HRESULT.
  292. --*/
  293. {
  294. DWORD dwLen =
  295. lstrlen(m_pContainer) + lstrlen(ILS_CONF_DN_FORMAT)
  296. + lstrlen(pName) + 1;
  297. *ppDN = new TCHAR [dwLen];
  298. BAIL_IF_NULL(*ppDN, E_OUTOFMEMORY);
  299. wsprintf(*ppDN, ILS_CONF_DN_FORMAT, pName, m_pContainer);
  300. return S_OK;
  301. }
  302. HRESULT CILSDirectory::MakeUserCN(
  303. IN TCHAR * pName,
  304. IN TCHAR * pAddress,
  305. OUT TCHAR ** ppCN,
  306. OUT DWORD * pdwIP
  307. )
  308. /*++
  309. Routine Description:
  310. Construct a User's CN based on username and machine name. The machine
  311. name is resolved first the get the fully qualified DNS name. The CN is
  312. in the following format: email\DNSname.
  313. Arguments:
  314. pName - The name of the user.
  315. pAddress - The machine name.
  316. ppCN - The CN returned.
  317. pdwIP - The resolved IP address of the machine. Used later
  318. for Netmeeting. If this is NULL, then we don't care
  319. about the IP.
  320. Return Value:
  321. HRESULT.
  322. --*/
  323. {
  324. char *pchFullDNSName;
  325. if ( pdwIP == NULL )
  326. {
  327. BAIL_IF_FAIL(ResolveHostName(0, pAddress, &pchFullDNSName, NULL),
  328. "can't resolve host name");
  329. }
  330. else
  331. {
  332. // we care about the IP, so we must be publishing a user object
  333. // as opposed to refreshing or deleting. Make sure we use the
  334. // same IP as the interface that's used to reach the ILS server.
  335. BAIL_IF_FAIL(ResolveHostName(m_dwInterfaceAddress, pAddress, &pchFullDNSName, pdwIP),
  336. "can't resolve host name (matching interface address)");
  337. }
  338. DWORD dwLen = lstrlen(DYNAMIC_USER_CN_FORMAT)
  339. + lstrlen(pName) + lstrlenA(pchFullDNSName);
  340. *ppCN = new TCHAR [dwLen + 1];
  341. BAIL_IF_NULL(*ppCN, E_OUTOFMEMORY);
  342. wsprintf(*ppCN, DYNAMIC_USER_CN_FORMAT, pName, pchFullDNSName);
  343. return S_OK;
  344. }
  345. HRESULT CILSDirectory::MakeUserDN(
  346. IN TCHAR * pCN,
  347. OUT TCHAR ** ppDNRTPerson,
  348. OUT TCHAR ** ppDNNMPerson
  349. )
  350. /*++
  351. Routine Description:
  352. Construct the DNs for a user used in the Dynamic container and
  353. the Netmeeting's container.
  354. Arguments:
  355. pCN - the CN of a user.
  356. ppDNRTPerson - The DN of the user in the dynamic container.
  357. ppDNNMPerson - The DN of the user in NetMeeting's container.
  358. Return Value:
  359. HRESULT.
  360. --*/
  361. {
  362. // construct the DN for RTPerson.
  363. DWORD dwLen = lstrlen(m_pContainer)
  364. + lstrlen(DYNAMIC_USER_DN_FORMAT) + lstrlen(pCN);
  365. *ppDNRTPerson = new TCHAR [dwLen + 1];
  366. BAIL_IF_NULL(*ppDNRTPerson, E_OUTOFMEMORY);
  367. wsprintf(*ppDNRTPerson, DYNAMIC_USER_DN_FORMAT, pCN, m_pContainer);
  368. // construct the DN for NetMeeting's RTApplicationUser.
  369. dwLen = lstrlen(m_pNMContainer)
  370. + lstrlen(DYNAMIC_USER_DN_FORMAT) + lstrlen(pCN);
  371. *ppDNNMPerson = new TCHAR [dwLen + 1];
  372. if (*ppDNNMPerson == NULL)
  373. {
  374. delete *ppDNRTPerson;
  375. *ppDNRTPerson = NULL;
  376. return E_OUTOFMEMORY;
  377. }
  378. wsprintf(*ppDNNMPerson, DYNAMIC_USER_DN_FORMAT, pCN, m_pNMContainer);
  379. return S_OK;
  380. }
  381. HRESULT CILSDirectory::AddConferenceComplete(BOOL fModify,
  382. LDAP * ldap,
  383. TCHAR ** ppDN,
  384. LDAPMod ** mods,
  385. DWORD TTL1,
  386. DWORD TTL2)
  387. {
  388. if (fModify)
  389. {
  390. // Call the modify function to modify the object.
  391. BAIL_IF_LDAP_FAIL(DoLdapModify(FALSE, ldap, *ppDN, mods),
  392. "modify conference");
  393. }
  394. else
  395. {
  396. // Call the add function to create the object.
  397. BAIL_IF_LDAP_FAIL(DoLdapAdd(ldap, *ppDN, mods), "add conference");
  398. // next set the TTL value for this object
  399. BAIL_IF_FAIL(::SetTTL(ldap, *ppDN, (TTL1 == 0) ? TTL2 : TTL1),
  400. "Set ttl for conference");
  401. }
  402. return S_OK;
  403. }
  404. HRESULT CILSDirectory::AddConference(
  405. IN ITDirectoryObject *pDirectoryObject,
  406. IN BOOL fModify
  407. )
  408. /*++
  409. Routine Description:
  410. Add a new conference to the ILS server.
  411. Arguments:
  412. pDirectoryObject - a pointer to the conference.
  413. fModify - true if called by MofifyDirectoryObject
  414. false if called by AddDirectoryObject
  415. Return Values:
  416. Value Where defined What it means
  417. ----- ------------- -------------
  418. HRESULT from ATL QueryInterface
  419. HRESULT from pDirectoryObject->get_Name
  420. HRESULT from MakeConferenceDN
  421. HRESULT from pObjectPrivate->GetAttribute(MA_PROTOCOL)
  422. HRESULT from pObjectPrivate->GetAttribute(MA_CONFERENCE_BLOB)
  423. HRESULT from GetSecurityDescriptor
  424. HRESULT from
  425. --*/
  426. {
  427. // first query the private interface for attributes.
  428. CComPtr <ITDirectoryObjectPrivate> pObjectPrivate;
  429. BAIL_IF_FAIL(
  430. pDirectoryObject->QueryInterface(
  431. IID_ITDirectoryObjectPrivate,
  432. (void **)&pObjectPrivate
  433. ),
  434. "can't get the private directory object interface");
  435. // Get the name of the conference.
  436. CBstr bName;
  437. BAIL_IF_FAIL(pDirectoryObject->get_Name(&bName),
  438. "get conference name");
  439. // Construct the DN of the object.
  440. CTstr pDN;
  441. BAIL_IF_FAIL(
  442. MakeConferenceDN(bName, &pDN), "construct DN for conference"
  443. );
  444. // Get the protocol and the blob.
  445. CBstr bProtocol, bBlob;
  446. BAIL_IF_FAIL(pObjectPrivate->GetAttribute(MA_PROTOCOL, &bProtocol),
  447. "get conference protocol");
  448. BAIL_IF_FAIL(pObjectPrivate->GetAttribute(MA_CONFERENCE_BLOB, &bBlob),
  449. "get conference Blob");
  450. // Get the Security Descriptor. The pointer pSD is just a copy of a pointer
  451. // in the Conference object; the conference object retains ownership of the
  452. // data and we must be careful not to delete or modify this data.
  453. char * pSD;
  454. DWORD dwSDSize;
  455. BAIL_IF_FAIL(pObjectPrivate->GetConvertedSecurityDescriptor(&pSD, &dwSDSize),
  456. "get conference security descriptor");
  457. // Get the TTL setting.
  458. DWORD dwTTL;
  459. BAIL_IF_FAIL(pObjectPrivate->GetTTL(&dwTTL), "get conference TTL");
  460. // 4 attributes needs to be published.
  461. static const DWORD DWATTRIBUTES = 4;
  462. // Fist fill the modify structures required by LDAP.
  463. LDAPMod mod[DWATTRIBUTES];
  464. LDAPMod* mods[DWATTRIBUTES + 1];
  465. DWORD dwCount = 0;
  466. // The objectclass attribute.
  467. TCHAR * objectClass[] =
  468. {(WCHAR *)ILS_RTCONFERENCE, (WCHAR *)DYNAMICOBJECT, NULL};
  469. if (!fModify)
  470. {
  471. mod[dwCount].mod_values = objectClass;
  472. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  473. mod[dwCount].mod_type = (WCHAR *)OBJECTCLASS;
  474. dwCount ++;
  475. }
  476. // The protocol attribute.
  477. TCHAR * protocol[] = {(WCHAR *)bProtocol, NULL};
  478. mod[dwCount].mod_values = protocol;
  479. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  480. mod[dwCount].mod_type = (WCHAR *)RTConferenceAttributeName(MA_PROTOCOL);
  481. dwCount ++;
  482. // The blob attribute.
  483. TCHAR * blob[] = {(WCHAR *)bBlob, NULL};
  484. mod[dwCount].mod_values = blob;
  485. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  486. mod[dwCount].mod_type =
  487. (WCHAR *)RTConferenceAttributeName(MA_CONFERENCE_BLOB);
  488. dwCount ++;
  489. // ZoltanS fix: these locals should not be within the "if" below... if
  490. // they are, they might be deallocated before the function returns.
  491. // This has been broken for a long, long time (unrelated to IsModified
  492. // stuff below).
  493. berval BerVal;
  494. berval *sd[] = {&BerVal, NULL};
  495. HRESULT hr;
  496. //
  497. // If there is a security descriptor on the local object, perhaps send it
  498. // to the server.
  499. //
  500. if ( (char*)pSD != NULL )
  501. {
  502. BOOL fSendIt = FALSE;
  503. if ( ! fModify )
  504. {
  505. //
  506. // We are trying to add the conference, so we definitely need
  507. // to send the security descriptor. Note that we even want
  508. // to send it if it hasn't changed, as we may be sending it to
  509. // some new server other than where we got it (if this conference
  510. // object was retrieved from a server in the first place).
  511. //
  512. fSendIt = TRUE;
  513. }
  514. else
  515. {
  516. //
  517. // We are trying to modify the conference, so we send the
  518. // security descriptor if it has changed.
  519. //
  520. VARIANT_BOOL fChanged;
  521. hr = pObjectPrivate->get_SecurityDescriptorIsModified( &fChanged );
  522. if ( SUCCEEDED( hr ) && ( fChanged == VARIANT_TRUE ) )
  523. {
  524. fSendIt = TRUE;
  525. }
  526. }
  527. if ( fSendIt )
  528. {
  529. //
  530. // We've decided to send the ACL. Fail before adding / modifying
  531. // the conference if the ACL is unsafe (would prevent us from
  532. // later deleting or modifying our own conference).
  533. //
  534. hr = TestAclSafety(pSD, dwSDSize);
  535. if ( FAILED(hr) )
  536. {
  537. LOG((MSP_ERROR, "CILSDirectory::AddConference - "
  538. "ACL appears unsafe -- exit 0x%08x", hr));
  539. return hr;
  540. }
  541. //
  542. // We know we want to send the ACL and we can safely send the ACL.
  543. // Fill in the mods to send it.
  544. //
  545. BerVal.bv_len = dwSDSize;
  546. BerVal.bv_val = (char*)pSD;
  547. mod[dwCount].mod_bvalues = sd;
  548. mod[dwCount].mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  549. mod[dwCount].mod_type = (WCHAR *)NT_SECURITY_DESCRIPTOR;
  550. dwCount ++;
  551. }
  552. }
  553. //
  554. // All done with the mods. Package them up and write to the server.
  555. //
  556. DWORD i;
  557. for (i = 0; i < dwCount; i ++)
  558. {
  559. mods[i] = &mod[i];
  560. }
  561. mods[i] = NULL;
  562. LOG((MSP_INFO, "%S %S", fModify ? _T("modifying") : _T("adding"), pDN));
  563. hr = AddConferenceComplete(fModify, m_ldap, &pDN, mods, dwTTL, m_TTL);
  564. if ( SUCCEEDED(hr) )
  565. {
  566. pObjectPrivate->put_SecurityDescriptorIsModified( VARIANT_FALSE );
  567. }
  568. return hr;
  569. }
  570. //////////////////////////////////////////////////////////////////////////////
  571. //
  572. // This method tests if the given ACL (security descriptor) is "safe".
  573. // "Safe" is defined as allowing the creator to modify and delete the
  574. // object; modification is tested via the TTL field.
  575. //
  576. // This test is needed to prevent leaving "ghost" objects on the server
  577. // when modifying the TTL of a newly-created conference fails because of
  578. // insfufficient access rights. This will happen if a user messes up
  579. // ACL creation or if the server does not understand the domain trustees
  580. // in the ACL (e.g., server machine is not in a domain).
  581. //
  582. // The test is performed by creating a "dummy" test object with a random
  583. // name in the container normally used for conferences. The object will
  584. // not show up in a normal conference or user enumeration because it does
  585. // not have the required attributes.
  586. //
  587. //
  588. HRESULT CILSDirectory::TestAclSafety(
  589. IN char * pSD,
  590. IN DWORD dwSDSize
  591. )
  592. {
  593. LOG((MSP_TRACE, "CILSDirectory::TestACLSafety - enter"));
  594. //
  595. // First fill in the modify structures required by LDAP.
  596. // We use only the object class and the security descriptor.
  597. // Therefore this will not show up as a valid conference
  598. // during an enumeration.
  599. //
  600. static const DWORD DWATTRIBUTES = 2;
  601. LDAPMod mod[DWATTRIBUTES];
  602. LDAPMod* mods[DWATTRIBUTES + 1];
  603. DWORD dwCount = 0;
  604. TCHAR * objectClass[] =
  605. {(WCHAR *)ILS_RTCONFERENCE, (WCHAR *)DYNAMICOBJECT, NULL};
  606. mod[dwCount].mod_values = objectClass;
  607. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  608. mod[dwCount].mod_type = (WCHAR *)OBJECTCLASS;
  609. dwCount ++;
  610. berval BerVal;
  611. berval *sd[] = {&BerVal, NULL};
  612. BerVal.bv_len = dwSDSize;
  613. BerVal.bv_val = (char*)pSD;
  614. mod[dwCount].mod_bvalues = sd;
  615. mod[dwCount].mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  616. mod[dwCount].mod_type = (WCHAR *)NT_SECURITY_DESCRIPTOR;
  617. dwCount ++;
  618. DWORD i;
  619. for (i = 0; i < dwCount; i ++)
  620. {
  621. mods[i] = &mod[i];
  622. }
  623. mods[i] = NULL;
  624. //
  625. // Try to add an object in the dynamic container with the above mods.
  626. // Use a name composed of a random number printed to a string. If the
  627. // names happen to conflict with another such dummy conference, then
  628. // try again in a loop.
  629. //
  630. // Randomization is apparently per-DLL -- Sdpblb.dll does srand() but
  631. // it doesn't seem to affect rand() calls within rend.dll. We therefore do
  632. // srand( time( NULL ) ) on DLL_PROCESS_ATTACH.
  633. //
  634. HRESULT hr;
  635. int iRandomNumber;
  636. TCHAR ptszRandomNumber[30];
  637. TCHAR * pDN = NULL;
  638. do
  639. {
  640. if ( pDN != NULL )
  641. {
  642. delete pDN;
  643. }
  644. iRandomNumber = rand();
  645. wsprintf(ptszRandomNumber, _T("%d"), iRandomNumber);
  646. hr = CILSDirectory::MakeConferenceDN(ptszRandomNumber, &pDN);
  647. if ( FAILED(hr) )
  648. {
  649. LOG((MSP_ERROR, "CILSDirectory::TestACLSafety - "
  650. "test DN construction failed - exit 0x%08x", hr));
  651. return hr;
  652. }
  653. LOG((MSP_TRACE, "CILSDirectory::TestACLSafety - "
  654. "trying to create test object DN %S", pDN));
  655. hr = GetLdapHResultIfFailed( DoLdapAdd(m_ldap, pDN, mods) );
  656. }
  657. while ( hr == GetLdapHResultIfFailed( LDAP_ALREADY_EXISTS ) );
  658. if ( FAILED(hr) )
  659. {
  660. LOG((MSP_ERROR, "CILSDirectory::TestACLSafety - "
  661. "test addition failed and not duplicate - exit 0x%08x", hr));
  662. delete pDN;
  663. return hr;
  664. }
  665. //
  666. // Now that we have the test object, try modifying it.
  667. //
  668. LOG((MSP_TRACE, "CILSDirectory::TestACLSafety - "
  669. "trying to modify test object..."));
  670. HRESULT hrModify = ::SetTTL( m_ldap, pDN, MINIMUM_TTL );
  671. //
  672. // Now delete it. We do this even if we already know that the ACL is bad
  673. // because the modify failed; we want to get rid of the object if
  674. // possible.
  675. //
  676. LOG((MSP_TRACE, "CILSDirectory::TestACLSafety - "
  677. "trying to delete test object..."));
  678. hr = GetLdapHResultIfFailed( DoLdapDelete(m_ldap, pDN) );
  679. delete pDN;
  680. //
  681. // Now determine the verdict and return.
  682. //
  683. if ( FAILED(hr) )
  684. {
  685. LOG((MSP_ERROR, "CILSDirectory::TestACLSafety - "
  686. "test deletion (+ modification?) failed - ACL unsafe - "
  687. "exit 0x%08x", hr));
  688. return hr;
  689. }
  690. if ( FAILED( hrModify ) )
  691. {
  692. LOG((MSP_ERROR, "CILSDirectory::TestACLSafety - "
  693. "test deletion ok; test modification failed - ACL unsafe - "
  694. "exit 0x%08x", hrModify));
  695. return hrModify;
  696. }
  697. LOG((MSP_TRACE, "CILSDirectory::TestACLSafety - exit S_OK"));
  698. return S_OK;
  699. }
  700. HRESULT CILSDirectory::PublishRTPerson(
  701. IN TCHAR * pCN,
  702. IN TCHAR * pDN,
  703. IN TCHAR * pIPAddress,
  704. IN DWORD dwTTL,
  705. IN BOOL fModify,
  706. IN char * pSD,
  707. IN DWORD dwSDSize
  708. )
  709. /*++
  710. Routine Description:
  711. Create a RTPerson object in the dynamic container.
  712. Arguments:
  713. pCN - The cn of the user.
  714. pDN - The dn of the user.
  715. pIPAddress - The ip address of the machine.
  716. dwTTL - The ttl of this object.
  717. fModify - modify or add.
  718. Return Value:
  719. HRESULT.
  720. --*/
  721. {
  722. // UPDATE THIS whenever you add an explicitly set attribute below
  723. // (ie, not one of those with default values in the array associated
  724. // with NUM_NM_RTPERSON_ATTRIBUTES).
  725. static const DWORD DWCOREATTRIBUTES = 5;
  726. // Fist create the object.
  727. LDAPMod mod[NUM_NM_RTPERSON_ATTRIBUTES + DWCOREATTRIBUTES];
  728. DWORD dwCount = 0;
  729. //
  730. // We are not allowed to modify the object class. Therefore we only mention
  731. // this if we are adding the object to the server, not modifying it.
  732. //
  733. // Fix: this is allocated on the stack, so we must do it here; if we stick
  734. // it inside the if below, it gets deallocated immediately.
  735. TCHAR * objectClass[] = {(WCHAR *)ILS_RTPERSON, (WCHAR *)DYNAMICOBJECT, NULL};
  736. if ( ! fModify )
  737. {
  738. // Object class.
  739. // only need this attribute if not modifying.
  740. mod[dwCount].mod_values = objectClass;
  741. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  742. mod[dwCount].mod_type = (WCHAR *)OBJECTCLASS;
  743. dwCount ++;
  744. }
  745. // IP address.
  746. TCHAR * IPPhone[] = {(WCHAR *)pIPAddress, NULL};
  747. mod[dwCount].mod_values = IPPhone;
  748. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  749. mod[dwCount].mod_type = (WCHAR *)ILS_IPADDRESS;
  750. dwCount ++;
  751. //
  752. // Make pUserName the user portion of the CN (user]machine).
  753. //
  754. CTstr pUserName = new TCHAR[ lstrlen(pCN) + 1 ];
  755. if ( pUserName == NULL )
  756. {
  757. return E_OUTOFMEMORY;
  758. }
  759. lstrcpy( pUserName, pCN );
  760. WCHAR * pCloseBracket = wcschr( pUserName, CLOSE_BRACKET_CHARACTER );
  761. if ( pCloseBracket == NULL )
  762. {
  763. // this is not the format generated by us -- very strange indeed!
  764. return E_UNEXPECTED;
  765. }
  766. *pCloseBracket = NULL_CHARACTER;
  767. //
  768. // We now have pUserName containing just the user name.
  769. // No need to delete it explicitly, as it is contained in a smart pointer.
  770. //
  771. // email: the user name
  772. TCHAR * Email[] = { (WCHAR *) ( (TCHAR *) pUserName ), NULL };
  773. mod[dwCount].mod_values = Email;
  774. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  775. mod[dwCount].mod_type = (WCHAR *)EMAIL;
  776. dwCount ++;
  777. // given name: the same as email (surname is just a space)
  778. mod[dwCount].mod_values = Email;
  779. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  780. mod[dwCount].mod_type = (WCHAR *)GIVEN_NAME;
  781. dwCount ++;
  782. DWORD i;
  783. for (i = 0; i < NUM_NM_RTPERSON_ATTRIBUTES; i ++)
  784. {
  785. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  786. mod[dwCount].mod_type = (WCHAR *)g_NMRTPersonAttributeNames[i];
  787. mod[dwCount].mod_values = (WCHAR **)&g_NMRTPersonAttributeValues[i * 2];
  788. dwCount ++;
  789. }
  790. // these locals should not be within the "if" below... if
  791. // they are, they might be deallocated before the function returns.
  792. berval BerVal;
  793. berval *sd[] = {&BerVal, NULL};
  794. // The security descriptor attribute.
  795. if ((char*)pSD != NULL)
  796. {
  797. BerVal.bv_len = dwSDSize;
  798. BerVal.bv_val = (char*)pSD;
  799. mod[dwCount].mod_bvalues = sd;
  800. mod[dwCount].mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  801. mod[dwCount].mod_type = (WCHAR *)NT_SECURITY_DESCRIPTOR;
  802. dwCount ++;
  803. }
  804. LDAPMod* mods[NUM_NM_RTPERSON_ATTRIBUTES + DWCOREATTRIBUTES + 1];
  805. for (i = 0; i < dwCount; i ++)
  806. {
  807. mods[i] = &mod[i];
  808. }
  809. mods[i] = NULL;
  810. if (fModify)
  811. {
  812. LOG((MSP_INFO, "modifying %S", pDN));
  813. // Call the modify function to modify the object.
  814. BAIL_IF_LDAP_FAIL(DoLdapModify(FALSE, m_ldap, pDN, mods), "modify RTPerson");
  815. }
  816. else
  817. {
  818. LOG((MSP_INFO, "adding %S", pDN));
  819. // Call the add function to create the object.
  820. BAIL_IF_LDAP_FAIL(DoLdapAdd(m_ldap, pDN, mods), "add RTPerson");
  821. // next set the TTL value for this object
  822. BAIL_IF_FAIL(::SetTTL(m_ldap, pDN, (dwTTL == 0) ? m_TTL : dwTTL),
  823. "Set ttl for RTPerson");
  824. }
  825. return S_OK;
  826. }
  827. HRESULT CILSDirectory::PublishNMPerson(
  828. IN TCHAR * pCN,
  829. IN TCHAR * pDN,
  830. IN TCHAR * pDNRTPerson,
  831. IN DWORD dwTTL,
  832. IN BOOL fModify,
  833. IN char * pSD,
  834. IN DWORD dwSDSize
  835. )
  836. /*++
  837. Routine Description:
  838. Create a applicationUser object in the netmeeting's container.
  839. Arguments:
  840. pCN - The cn of the user.
  841. pDN - The dn of the applicationUser object.
  842. pDNRTPerson - The dn of the RTPerson object in the dynamic container.
  843. dwTTL - The ttl of this object.
  844. fModify - modify or add.
  845. Return Value:
  846. HRESULT.
  847. --*/
  848. {
  849. // UPDATE THIS whenever you add an explicitly set attribute below
  850. // (ie, not one of those with default values in the array associated
  851. // with NUM_NM_ATTRIBUTES).
  852. static const DWORD DWCOREATTRIBUTES = 3;
  853. // Fist create the object.
  854. LDAPMod mod[NUM_NM_ATTRIBUTES + DWCOREATTRIBUTES]; // The modify sturctures used by LDAP
  855. DWORD dwCount = 0;
  856. //
  857. // We are not allowed to modify the object class. Therefore we only mention
  858. // this if we are adding the object to the server, not modifying it.
  859. //
  860. // Fix: this is allocated on the stack, so we must do it here; if we stick
  861. // it inside the if below, it gets deallocated immediately.
  862. TCHAR * objectClass[] =
  863. {(WCHAR *)RTAPPLICATIONUSER, (WCHAR *)DYNAMICOBJECT, NULL};
  864. if ( ! fModify )
  865. {
  866. // Object class.
  867. mod[dwCount].mod_values = objectClass;
  868. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  869. mod[dwCount].mod_type = (WCHAR *)OBJECTCLASS;
  870. dwCount ++;
  871. }
  872. // IP address.
  873. TCHAR * rtPerson[] = {(WCHAR *)pDNRTPerson, NULL};
  874. mod[dwCount].mod_values = rtPerson;
  875. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  876. mod[dwCount].mod_type = (WCHAR *)USEROBJECT;
  877. dwCount ++;
  878. for (DWORD i = 0; i < NUM_NM_ATTRIBUTES; i ++)
  879. {
  880. mod[dwCount].mod_op = LDAP_MOD_REPLACE;
  881. mod[dwCount].mod_type = (WCHAR *)g_NMAttributeNames[i];
  882. mod[dwCount].mod_values = (WCHAR **)&g_NMAttributeValues[i * 2];
  883. dwCount ++;
  884. }
  885. // these locals should not be within the "if" below... if
  886. // they are, they might be deallocated before the function returns.
  887. berval BerVal;
  888. berval *sd[] = {&BerVal, NULL};
  889. // The security descriptor attribute.
  890. if ((char*)pSD != NULL)
  891. {
  892. BerVal.bv_len = dwSDSize;
  893. BerVal.bv_val = (char*)pSD;
  894. mod[dwCount].mod_bvalues = sd;
  895. mod[dwCount].mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  896. mod[dwCount].mod_type = (WCHAR *)NT_SECURITY_DESCRIPTOR;
  897. dwCount ++;
  898. }
  899. LDAPMod* mods[NUM_NM_ATTRIBUTES + DWCOREATTRIBUTES + 1];
  900. for (i = 0; i < dwCount; i ++)
  901. {
  902. mods[i] = &mod[i];
  903. }
  904. mods[i] = NULL;
  905. if (fModify)
  906. {
  907. LOG((MSP_INFO, "modifying %S", pDN));
  908. // Call the modify function to modify the object.
  909. BAIL_IF_LDAP_FAIL(DoLdapModify(FALSE, m_ldap, pDN, mods), "modify NMPerson");
  910. }
  911. else
  912. {
  913. LOG((MSP_INFO, "adding %S", pDN));
  914. // Call the add function to create the object.
  915. BAIL_IF_LDAP_FAIL(DoLdapAdd(m_ldap, pDN, mods), "add NMPerson");
  916. // next set the TTL value for this object
  917. BAIL_IF_FAIL(::SetTTL(m_ldap, pDN, (dwTTL == 0) ? m_TTL : dwTTL),
  918. "Set ttl for NMPerson");
  919. }
  920. return S_OK;
  921. }
  922. HRESULT CILSDirectory::AddObjectToRefresh(
  923. IN WCHAR *pDN,
  924. IN long TTL
  925. )
  926. {
  927. //
  928. // Add a refresh table entry to the refresh table. The refresh table's add
  929. // method does an element-by-element copy of the entry that it is given.
  930. // This just copies the string pointer, so we need to allocate and copy
  931. // the string here.
  932. //
  933. RefreshTableEntry entry;
  934. entry.dwTTL = TTL;
  935. entry.pDN = new WCHAR[ wcslen(pDN) + 1 ];
  936. if ( entry.pDN == NULL )
  937. {
  938. LOG((MSP_ERROR, "Cannot allocate string for adding to refresh table"));
  939. return E_OUTOFMEMORY;
  940. }
  941. wcscpy( entry.pDN, pDN );
  942. //
  943. // Now add it to the refresh table.
  944. //
  945. BOOL fSuccess = m_RefreshTable.add(entry);
  946. if ( ! fSuccess )
  947. {
  948. LOG((MSP_ERROR, "Cannot add object to the refresh table"));
  949. return E_OUTOFMEMORY;
  950. }
  951. return S_OK;
  952. }
  953. HRESULT CILSDirectory::RemoveObjectToRefresh(
  954. IN WCHAR *pDN
  955. )
  956. {
  957. //
  958. // For each item in our refresh table
  959. //
  960. for ( DWORD i = 0; i < m_RefreshTable.size(); i++ )
  961. {
  962. //
  963. // If the desired DN matches the one in this item
  964. // then remove it and return success
  965. //
  966. if ( ! _wcsicmp( m_RefreshTable[i].pDN, pDN ) )
  967. {
  968. //
  969. // We new'ed the string when we added the entry.
  970. //
  971. delete m_RefreshTable[i].pDN;
  972. m_RefreshTable.removeAt(i);
  973. return S_OK;
  974. }
  975. }
  976. //
  977. // If we get here then there was no matching item
  978. //
  979. LOG((MSP_ERROR, "Cannot remove object from the refresh table"));
  980. return E_FAIL;
  981. }
  982. HRESULT CILSDirectory::AddUser(
  983. IN ITDirectoryObject *pDirectoryObject,
  984. IN BOOL fModify
  985. )
  986. /*++
  987. Routine Description:
  988. Publish a new user object.
  989. Arguments:
  990. pDirectoryObject - The object to be published.
  991. Return Value:
  992. HRESULT.
  993. --*/
  994. {
  995. // First find the interface for attributes.
  996. CComPtr <ITDirectoryObjectPrivate> pObjectPrivate;
  997. BAIL_IF_FAIL(
  998. pDirectoryObject->QueryInterface(
  999. IID_ITDirectoryObjectPrivate,
  1000. (void **)&pObjectPrivate
  1001. ),
  1002. "can't get the private directory object interface");
  1003. // Get the user name.
  1004. CBstr bName;
  1005. BAIL_IF_FAIL(pDirectoryObject->get_Name(&bName),
  1006. "get user name");
  1007. // Get the user's machine name.
  1008. CBstr bIPPhone;
  1009. BAIL_IF_FAIL(pObjectPrivate->GetAttribute(UA_IPPHONE_PRIMARY, &bIPPhone),
  1010. "get IPPhone");
  1011. // Resolve the machine name and construct the CN for the user.
  1012. CTstr pCN;
  1013. DWORD dwIP;
  1014. BAIL_IF_FAIL(
  1015. MakeUserCN(bName, bIPPhone, &pCN, &dwIP),
  1016. "construct CN for user"
  1017. );
  1018. // Construct the DNs for the RTPerson object and applicationuser object.
  1019. CTstr pDNRTPerson, pDNNMPerson;
  1020. BAIL_IF_FAIL(
  1021. MakeUserDN(pCN, &pDNRTPerson, &pDNNMPerson),
  1022. "construct DN for user"
  1023. );
  1024. // convert the IP address to a string.
  1025. // This convertion is because of NetMeeting.
  1026. TCHAR IPAddress[80];
  1027. wsprintf(IPAddress, _T("%u"), dwIP);
  1028. DWORD dwTTL;
  1029. BAIL_IF_FAIL(pObjectPrivate->GetTTL(&dwTTL), "get User TTL");
  1030. // Get the Security Descriptor. The pointer pSD is just a copy of a pointer
  1031. // in the Conference object; the conference object retains ownership of the
  1032. // data and we must be careful not to delete or modify this data.
  1033. char * pSD;
  1034. DWORD dwSDSize;
  1035. BAIL_IF_FAIL(pObjectPrivate->GetConvertedSecurityDescriptor(&pSD, &dwSDSize),
  1036. "get user object security descriptor");
  1037. VARIANT_BOOL fChanged;
  1038. if ( SUCCEEDED( pObjectPrivate->
  1039. get_SecurityDescriptorIsModified( &fChanged ) ) )
  1040. {
  1041. if ( fChanged == VARIANT_FALSE )
  1042. {
  1043. pSD = NULL; // do NOT delete the string (see above)
  1044. dwSDSize = 0;
  1045. }
  1046. }
  1047. // Create a rtApplicationUser under netmeeting's container. If we are adding
  1048. // and this returns already exists, then bailing is fine.
  1049. BAIL_IF_FAIL(PublishNMPerson(pCN, pDNNMPerson, pDNRTPerson, dwTTL, fModify, pSD, dwSDSize),
  1050. "Can't publish a NMPerson");
  1051. // Create the RTPerson in the dynamic container. According to Sun Shaw,
  1052. // this succeeds even if the object already exists, due to NetMeeting's
  1053. // requirements. (Yet another case of ILS being designed around NM.)
  1054. // We don't depend on the existence of that bug, however.
  1055. HRESULT hr = PublishRTPerson(pCN, pDNRTPerson, IPAddress, dwTTL, fModify, pSD, dwSDSize);
  1056. if (FAILED(hr))
  1057. {
  1058. LOG((MSP_ERROR, "Can't publish a RTPerson, hr:%x", hr));
  1059. if (!fModify)
  1060. {
  1061. // Call the delete function to delete the NMPerson object.
  1062. // This is needed to avoid leaving a phantom NMPerson when
  1063. // the NMPerson creation succeeds but we fail.
  1064. DoLdapDelete(m_ldap, pDNNMPerson);
  1065. }
  1066. return hr;
  1067. }
  1068. if (m_fAutoRefresh)
  1069. {
  1070. AddObjectToRefresh(pDNRTPerson, m_TTL);
  1071. AddObjectToRefresh(pDNNMPerson, m_TTL);
  1072. }
  1073. return S_OK;
  1074. }
  1075. HRESULT CILSDirectory::DeleteConference(
  1076. IN ITDirectoryObject *pDirectoryObject
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. Delete a conference from the ILS server.
  1081. Arguments:
  1082. pDirectoryObject - The object to be deleted.
  1083. Return Value:
  1084. HRESULT.
  1085. --*/
  1086. {
  1087. // Get the name.
  1088. CBstr bName;
  1089. BAIL_IF_FAIL(pDirectoryObject->get_Name(&bName),
  1090. "get conference name");
  1091. // construct the DN
  1092. CTstr pDN;
  1093. BAIL_IF_FAIL(
  1094. MakeConferenceDN(bName, &pDN), "construct DN for conference"
  1095. );
  1096. LOG((MSP_INFO, "deleting %S", pDN));
  1097. // Call the add function to create the object.
  1098. BAIL_IF_LDAP_FAIL(DoLdapDelete(m_ldap, pDN), "delete conference");
  1099. return S_OK;
  1100. }
  1101. HRESULT CILSDirectory::DeleteUser(
  1102. IN ITDirectoryObject *pDirectoryObject
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. Delete a user from the ILS server.
  1107. Arguments:
  1108. pDirectoryObject - The object to be deleted.
  1109. Return Value:
  1110. HRESULT.
  1111. --*/
  1112. {
  1113. // First find the interface for attributes.
  1114. CComPtr <ITDirectoryObjectPrivate> pObjectPrivate;
  1115. BAIL_IF_FAIL(
  1116. pDirectoryObject->QueryInterface(
  1117. IID_ITDirectoryObjectPrivate,
  1118. (void **)&pObjectPrivate
  1119. ),
  1120. "can't get the private directory object interface");
  1121. // Get the user name.
  1122. CBstr bName;
  1123. BAIL_IF_FAIL(pDirectoryObject->get_Name(&bName),
  1124. "get user name");
  1125. // Get the user's machine name.
  1126. CBstr bIPPhone;
  1127. BAIL_IF_FAIL(pObjectPrivate->GetAttribute(UA_IPPHONE_PRIMARY, &bIPPhone),
  1128. "get IPPhone");
  1129. // Resolve the machine name and construct the CN for the user.
  1130. CTstr pCN;
  1131. BAIL_IF_FAIL(
  1132. MakeUserCN(bName, bIPPhone, &pCN, NULL),
  1133. "construct CN for user"
  1134. );
  1135. // Construct the DNs for the RTPerson object and applicationuser object.
  1136. CTstr pDNRTPerson, pDNNMPerson;
  1137. BAIL_IF_FAIL(
  1138. MakeUserDN(pCN, &pDNRTPerson, &pDNNMPerson),
  1139. "construct DN for user"
  1140. );
  1141. //
  1142. // Now delete the TWO objects from the server.
  1143. //
  1144. HRESULT hrFinal = S_OK;
  1145. HRESULT hr;
  1146. ULONG ulResult;
  1147. // Call the delete function to delete the RTPerson object, but keep
  1148. // going if it fails, noting the error code.
  1149. LOG((MSP_INFO, "deleting %S", pDNRTPerson));
  1150. ulResult = DoLdapDelete(m_ldap, pDNRTPerson);
  1151. hr = LogAndGetLdapHResult(ulResult, _T("delete RTPerson"));
  1152. if (FAILED(hr)) { hrFinal = hr; }
  1153. // Call the delete function to delete the applicationuser object, but
  1154. // keep going if it fails, noting the error code.
  1155. LOG((MSP_INFO, "deleting %S", pDNNMPerson));
  1156. ulResult = DoLdapDelete(m_ldap, pDNNMPerson);
  1157. hr = LogAndGetLdapHResult(ulResult, _T("delete NMPerson"));
  1158. if (FAILED(hr)) { hrFinal = hr; }
  1159. // ZoltanS: we now always remove the refresh objects, even if removal failed.
  1160. if (m_fAutoRefresh)
  1161. {
  1162. RemoveObjectToRefresh(pDNRTPerson);
  1163. RemoveObjectToRefresh(pDNNMPerson);
  1164. }
  1165. return hrFinal;
  1166. }
  1167. HRESULT CILSDirectory::RefreshUser(
  1168. IN ITDirectoryObject *pDirectoryObject
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. Refresh a user's TTL on the ILS server.
  1173. Arguments:
  1174. pDirectoryObject - The object to be refreshed.
  1175. Return Value:
  1176. HRESULT.
  1177. --*/
  1178. {
  1179. // First find the interface for attributes.
  1180. CComPtr <ITDirectoryObjectPrivate> pObjectPrivate;
  1181. BAIL_IF_FAIL(
  1182. pDirectoryObject->QueryInterface(
  1183. IID_ITDirectoryObjectPrivate,
  1184. (void **)&pObjectPrivate
  1185. ),
  1186. "can't get the private directory object interface");
  1187. // Get the user name.
  1188. CBstr bName;
  1189. BAIL_IF_FAIL(pDirectoryObject->get_Name(&bName),
  1190. "get user name");
  1191. // Get the user's machine name.
  1192. CBstr bIPPhone;
  1193. BAIL_IF_FAIL(pObjectPrivate->GetAttribute(UA_IPPHONE_PRIMARY, &bIPPhone),
  1194. "get IPPhone");
  1195. // Resolve the machine name and construct the CN for the user.
  1196. CTstr pCN;
  1197. BAIL_IF_FAIL(
  1198. MakeUserCN(bName, bIPPhone, &pCN, NULL),
  1199. "construct CN for user"
  1200. );
  1201. // Construct the DNs for the RTPerson object and applicationuser object.
  1202. CTstr pDNRTPerson, pDNNMPerson;
  1203. BAIL_IF_FAIL(
  1204. MakeUserDN(pCN, &pDNRTPerson, &pDNNMPerson),
  1205. "construct DN for user"
  1206. );
  1207. // ZoltanS: this is fine; if one of them doesn't exist, then we're in trouble,
  1208. // so return the error.
  1209. // set ttl for the RTPerson object.
  1210. BAIL_IF_LDAP_FAIL(SetTTL(m_ldap, pDNRTPerson, m_TTL), "set ttl for RTPerson");
  1211. // set ttl for the NMPerson object.
  1212. BAIL_IF_LDAP_FAIL(SetTTL(m_ldap, pDNNMPerson, m_TTL), "set ttl for NMPerson");
  1213. //
  1214. // ZoltanS: If the app has enabled auto-refresh but does not add or modify its
  1215. // user object, but rather, just refreshes it (because the object is still around
  1216. // from a previous instance of the app, and "add" would fail), we still need to
  1217. // autorefresh it, as that's what the app wants.
  1218. //
  1219. if (m_fAutoRefresh)
  1220. {
  1221. AddObjectToRefresh(pDNRTPerson, m_TTL);
  1222. AddObjectToRefresh(pDNNMPerson, m_TTL);
  1223. }
  1224. return S_OK;
  1225. }
  1226. HRESULT CILSDirectory::CreateConference(
  1227. IN LDAPMessage * pEntry,
  1228. OUT ITDirectoryObject ** ppObject
  1229. )
  1230. /*++
  1231. Routine Description:
  1232. Create a conference object from the result of the LDAP search.
  1233. Arguments:
  1234. pEntry - The search result.
  1235. ppObject - The object to be created.
  1236. Return Value:
  1237. HRESULT.
  1238. --*/
  1239. {
  1240. CBstr bName, bProtocol, bBlob;
  1241. // Get the name of the conference.
  1242. BAIL_IF_FAIL(
  1243. ::GetAttributeValue(
  1244. m_ldap,
  1245. pEntry,
  1246. RTConferenceAttributeName(MA_MEETINGNAME),
  1247. &bName
  1248. ),
  1249. "get the conference name"
  1250. );
  1251. // Get the protocol ID of the conference.
  1252. BAIL_IF_FAIL(
  1253. ::GetAttributeValue(
  1254. m_ldap,
  1255. pEntry,
  1256. RTConferenceAttributeName(MA_PROTOCOL),
  1257. &bProtocol
  1258. ),
  1259. "get the conference protocol"
  1260. );
  1261. // Get the conference blob of the conference.
  1262. BAIL_IF_FAIL(
  1263. ::GetAttributeValue(
  1264. m_ldap,
  1265. pEntry,
  1266. RTConferenceAttributeName(MA_CONFERENCE_BLOB),
  1267. &bBlob
  1268. ),
  1269. "get the conference blob"
  1270. );
  1271. char * pSD = NULL;
  1272. DWORD dwSDSize = 0;
  1273. ::GetAttributeValueBer(
  1274. m_ldap,
  1275. pEntry,
  1276. NT_SECURITY_DESCRIPTOR,
  1277. &pSD,
  1278. &dwSDSize
  1279. );
  1280. // Create an empty conference.
  1281. HRESULT hr = ::CreateConferenceWithBlob(bName,
  1282. bProtocol,
  1283. bBlob,
  1284. pSD,
  1285. dwSDSize,
  1286. ppObject);
  1287. if ( FAILED(hr) )
  1288. {
  1289. LOG((MSP_ERROR, "CILSDirectory::CreateConference - "
  1290. "CreateConferenceWithBlob failed 0x%08x", hr));
  1291. delete pSD;
  1292. return hr;
  1293. }
  1294. //
  1295. // If the above succeeded then the conference object has taken ownership
  1296. // of pSD.
  1297. //
  1298. return S_OK;
  1299. }
  1300. HRESULT CILSDirectory::CreateUser(
  1301. IN LDAPMessage * pEntry,
  1302. IN ITDirectoryObject ** ppObject
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. Create a user object from the result of the LDAP search.
  1307. Arguments:
  1308. pEntry - The search result.
  1309. ppObject - The object to be created.
  1310. Return Value:
  1311. HRESULT.
  1312. --*/
  1313. {
  1314. CBstr bName;
  1315. // Get the name of the user.
  1316. BAIL_IF_FAIL(
  1317. ::GetAttributeValue(
  1318. m_ldap,
  1319. pEntry,
  1320. RTPersonAttributeName(UA_USERNAME),
  1321. &bName
  1322. ),
  1323. "get the user name"
  1324. );
  1325. CBstr bAddress;
  1326. // Grab the machine name from the name of the object. This can fail if
  1327. // we didn't publish the object (ie, it's a NetMeeting object). Also,
  1328. // check if the hostname isn't resolvable. In that case we also have
  1329. // to fall back on the IP address in the ipAddress attribute.
  1330. HRESULT hr;
  1331. hr = ParseUserName(bName, &bAddress);
  1332. if ( SUCCEEDED(hr) )
  1333. {
  1334. // Make sure we can get an IP from this name, at least for the moment.
  1335. // If not, release the name and indicate failure so we do our backup
  1336. // plan.
  1337. hr = ResolveHostName(0, bAddress, NULL, NULL);
  1338. if ( FAILED(hr) )
  1339. {
  1340. SysFreeString(bAddress);
  1341. }
  1342. }
  1343. if ( FAILED(hr) )
  1344. {
  1345. // In order to compatible with NetMeeting, we have to use IP address field.
  1346. CBstr bUglyIP;
  1347. BAIL_IF_FAIL(
  1348. ::GetAttributeValue(
  1349. m_ldap,
  1350. pEntry,
  1351. RTPersonAttributeName(UA_IPPHONE_PRIMARY),
  1352. &bUglyIP
  1353. ),
  1354. "get the user's IP address"
  1355. );
  1356. // We have to use NM's ugly format for the IP address. The IP address
  1357. // we got from netmeeting is a decimal string whose value is the dword
  1358. // value of the IP address in network order.
  1359. BAIL_IF_FAIL(UglyIPtoIP(bUglyIP, &bAddress), "Convert IP address");
  1360. }
  1361. // Create an empty user object.
  1362. CComPtr<ITDirectoryObject> pObject;
  1363. BAIL_IF_FAIL(::CreateEmptyUser(bName, &pObject), "CreateEmptyUser");
  1364. CComPtr <ITDirectoryObjectPrivate> pObjectPrivate;
  1365. BAIL_IF_FAIL(
  1366. pObject->QueryInterface(
  1367. IID_ITDirectoryObjectPrivate,
  1368. (void **)&pObjectPrivate
  1369. ),
  1370. "can't get the private directory object interface");
  1371. // Set the user attributes.
  1372. BAIL_IF_FAIL(pObjectPrivate->SetAttribute(UA_IPPHONE_PRIMARY, bAddress),
  1373. "set ipAddress");
  1374. //
  1375. // Set the security descriptor on the object.
  1376. //
  1377. char * pSD = NULL;
  1378. DWORD dwSDSize = 0;
  1379. ::GetAttributeValueBer(
  1380. m_ldap,
  1381. pEntry,
  1382. NT_SECURITY_DESCRIPTOR,
  1383. &pSD,
  1384. &dwSDSize
  1385. );
  1386. if ( pSD != NULL )
  1387. {
  1388. //
  1389. // Set the security descriptor in its "converted" (server) form.
  1390. //
  1391. hr = pObjectPrivate->PutConvertedSecurityDescriptor(pSD,
  1392. dwSDSize);
  1393. if ( FAILED(hr) )
  1394. {
  1395. LOG((MSP_ERROR, "PutConvertedSecurityDescriptor failed: %x", hr));
  1396. return hr;
  1397. }
  1398. }
  1399. *ppObject = pObject;
  1400. (*ppObject)->AddRef();
  1401. return S_OK;
  1402. }
  1403. HRESULT CILSDirectory::SearchObjects(
  1404. IN DIRECTORY_OBJECT_TYPE DirectoryObjectType,
  1405. IN BSTR pName,
  1406. OUT ITDirectoryObject *** pppDirectoryObject,
  1407. OUT DWORD * pdwSize
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. Search the ILS server for given type of objects.
  1412. Arguments:
  1413. DirectoryObjectType - The type of the object.
  1414. pName - The name to search for.
  1415. pppDirectoryObject - The returned array of objects.
  1416. pdwSize - The size of the array.
  1417. Return Value:
  1418. HRESULT.
  1419. --*/
  1420. {
  1421. TCHAR *pRDN;
  1422. TCHAR *Attributes[NUM_MEETING_ATTRIBUTES + 1]; // This is big enough now.
  1423. // Fill the attributes want to be returned.
  1424. switch (DirectoryObjectType)
  1425. {
  1426. case OT_CONFERENCE:
  1427. pRDN = (WCHAR*)ILS_UIDEQUALS;
  1428. Attributes[0] = (WCHAR *)RTConferenceAttributeName(MA_MEETINGNAME);
  1429. Attributes[1] = (WCHAR *)RTConferenceAttributeName(MA_PROTOCOL);
  1430. Attributes[2] = (WCHAR *)RTConferenceAttributeName(MA_CONFERENCE_BLOB);
  1431. Attributes[3] = (WCHAR *)NT_SECURITY_DESCRIPTOR;
  1432. Attributes[4] = NULL;
  1433. break;
  1434. case OT_USER:
  1435. pRDN = (WCHAR*)CNEQUALS;
  1436. Attributes[0] = (WCHAR *)RTPersonAttributeName(UA_USERNAME);
  1437. Attributes[1] = (WCHAR *)RTPersonAttributeName(UA_IPPHONE_PRIMARY);
  1438. Attributes[2] = (WCHAR *)NT_SECURITY_DESCRIPTOR;
  1439. Attributes[3] = NULL;
  1440. break;
  1441. default:
  1442. return E_FAIL;
  1443. }
  1444. // Construct the filter of the search.
  1445. int cbRDN = lstrlen(pRDN);
  1446. int cbName = lstrlen(pName);
  1447. if( (( cbRDN + cbName + 2)<= cbRDN) ||
  1448. ((cbRDN + cbName + 2) <= cbName) )
  1449. {
  1450. return E_FAIL;
  1451. }
  1452. CTstr pFilter = new TCHAR [cbRDN + cbName + 2];
  1453. BAIL_IF_NULL((TCHAR*)pFilter, E_OUTOFMEMORY);
  1454. lstrcpyn(pFilter, pRDN, cbRDN+1);
  1455. _ASSERTE( lstrlen(pFilter) == cbRDN );
  1456. lstrcpyn(pFilter+cbRDN, pName, cbName+1);
  1457. _ASSERTE( lstrlen(pFilter) == cbRDN+cbName );
  1458. if (pName[lstrlen(pName) - 1] != _T('*'))
  1459. {
  1460. lstrcat(pFilter, _T("*"));
  1461. }
  1462. // Search them.
  1463. CLdapMsgPtr pLdapMsg; // auto release message.
  1464. ULONG res = DoLdapSearch(
  1465. m_ldap, // ldap handle
  1466. m_pContainer, // schema dn
  1467. LDAP_SCOPE_ONELEVEL, // one level search
  1468. pFilter, // cn=Name or uid=Name
  1469. Attributes, // array of attribute names
  1470. FALSE, // return the attribute values
  1471. &pLdapMsg // search results
  1472. );
  1473. BAIL_IF_LDAP_FAIL(res, "search for objects");
  1474. // count the returned entries.
  1475. DWORD dwEntries = ldap_count_entries(m_ldap, pLdapMsg);
  1476. ITDirectoryObject ** pObjects = new PDIRECTORYOBJECT [dwEntries];
  1477. BAIL_IF_NULL(pObjects, E_OUTOFMEMORY);
  1478. // Create objects.
  1479. DWORD dwCount = 0;
  1480. LDAPMessage *pEntry = ldap_first_entry(m_ldap, pLdapMsg);
  1481. while (pEntry != NULL)
  1482. {
  1483. HRESULT hr;
  1484. switch (DirectoryObjectType)
  1485. {
  1486. case OT_CONFERENCE:
  1487. hr = CreateConference(pEntry, &pObjects[dwCount]);
  1488. break;
  1489. case OT_USER:
  1490. hr = CreateUser(pEntry, &pObjects[dwCount]);
  1491. break;
  1492. }
  1493. if (SUCCEEDED(hr))
  1494. {
  1495. dwCount ++;
  1496. }
  1497. // Get next entry.
  1498. pEntry = ldap_next_entry(m_ldap, pEntry);
  1499. }
  1500. *pppDirectoryObject = pObjects;
  1501. *pdwSize = dwCount;
  1502. return S_OK;
  1503. }
  1504. /////////////////////////////////////////////////////////////////////////////
  1505. // ILS Directory implementation
  1506. /////////////////////////////////////////////////////////////////////////////
  1507. STDMETHODIMP CILSDirectory::get_DirectoryType (
  1508. OUT DIRECTORY_TYPE * pDirectoryType
  1509. )
  1510. // Get the type of the directory.
  1511. {
  1512. if ( IsBadWritePtr(pDirectoryType, sizeof(DIRECTORY_TYPE) ) )
  1513. {
  1514. LOG((MSP_ERROR, "Directory.GetType, invalid pointer"));
  1515. return E_POINTER;
  1516. }
  1517. CLock Lock(m_lock);
  1518. *pDirectoryType = m_Type;
  1519. return S_OK;
  1520. }
  1521. STDMETHODIMP CILSDirectory::get_DisplayName (
  1522. OUT BSTR *ppServerName
  1523. )
  1524. // Get the display name of the directory.
  1525. {
  1526. BAIL_IF_BAD_WRITE_PTR(ppServerName, E_POINTER);
  1527. CLock Lock(m_lock);
  1528. if (m_pServerName == NULL)
  1529. {
  1530. *ppServerName = SysAllocString(L"");
  1531. }
  1532. else
  1533. {
  1534. *ppServerName = SysAllocString(m_pServerName);
  1535. }
  1536. if (*ppServerName == NULL)
  1537. {
  1538. LOG((MSP_ERROR, "get_DisplayName: out of memory."));
  1539. return E_OUTOFMEMORY;
  1540. }
  1541. return S_OK;
  1542. }
  1543. STDMETHODIMP CILSDirectory::get_IsDynamic(
  1544. OUT VARIANT_BOOL *pfDynamic
  1545. )
  1546. // find out if the directory is a dynamic one, meaning the object will be
  1547. // deleted after TTL runs out.
  1548. {
  1549. if ( IsBadWritePtr( pfDynamic, sizeof(VARIANT_BOOL) ) )
  1550. {
  1551. LOG((MSP_ERROR, "Directory.get_IsDynamic, invalid pointer"));
  1552. return E_POINTER;
  1553. }
  1554. *pfDynamic = VARIANT_TRUE;
  1555. return S_OK;
  1556. }
  1557. STDMETHODIMP CILSDirectory::get_DefaultObjectTTL(
  1558. OUT long *pTTL // in seconds
  1559. )
  1560. // The default TTL for object created. It is used when the object doesn't set
  1561. // a TTL. Conference object always has a TTL based on the stoptime.
  1562. {
  1563. if ( IsBadWritePtr( pTTL, sizeof(long) ) )
  1564. {
  1565. LOG((MSP_ERROR, "Directory.get_default objec TTL, invalid pointer"));
  1566. return E_POINTER;
  1567. }
  1568. CLock Lock(m_lock);
  1569. *pTTL = m_TTL;
  1570. return S_OK;
  1571. }
  1572. STDMETHODIMP CILSDirectory::put_DefaultObjectTTL(
  1573. IN long TTL // in sechods
  1574. )
  1575. // Change the default TTL, must be bigger then five minutes.
  1576. {
  1577. CLock Lock(m_lock);
  1578. if (TTL < MINIMUM_TTL)
  1579. {
  1580. return E_INVALIDARG;
  1581. }
  1582. m_TTL = TTL;
  1583. return S_OK;
  1584. }
  1585. STDMETHODIMP CILSDirectory::EnableAutoRefresh(
  1586. IN VARIANT_BOOL fEnable
  1587. )
  1588. // Enable auto refresh. Add this directory to the work threads that
  1589. // will notify the directory to update its objects.
  1590. {
  1591. HRESULT hr;
  1592. // ZoltanS: either VARIANT_TRUE or TRUE will work
  1593. // in case the caller doesn't know better
  1594. if (fEnable)
  1595. {
  1596. // Add this directory to the notify list of the work thread.
  1597. if (FAILED(hr = g_RendThread.AddDirectory(this)))
  1598. {
  1599. LOG((MSP_ERROR,
  1600. "Can not add this directory to the thread, %x", hr));
  1601. return hr;
  1602. }
  1603. }
  1604. else
  1605. {
  1606. // Remove this directory from the notify list of the work thread.
  1607. if (FAILED(hr = g_RendThread.RemoveDirectory(this)))
  1608. {
  1609. LOG((MSP_ERROR,
  1610. "Can not remove this directory from the thread, %x", hr));
  1611. return hr;
  1612. }
  1613. }
  1614. // ZoltanS: either VARIANT_TRUE or TRUE will work
  1615. // in case the caller doesn't know better
  1616. m_lock.Lock();
  1617. m_fAutoRefresh = ( fEnable ? VARIANT_TRUE : VARIANT_FALSE );
  1618. m_lock.Unlock();
  1619. return S_OK;
  1620. }
  1621. STDMETHODIMP CILSDirectory::Connect(
  1622. IN VARIANT_BOOL fSecure
  1623. )
  1624. // Connect to the server, using secure port or normal port.
  1625. {
  1626. CLock Lock(m_lock);
  1627. if (m_ldap != NULL)
  1628. {
  1629. LOG((MSP_ERROR, "already connected."));
  1630. return RND_ALREADY_CONNECTED;
  1631. }
  1632. if (m_pServerName == NULL)
  1633. {
  1634. LOG((MSP_ERROR, "No server specified."));
  1635. return RND_NULL_SERVER_NAME;
  1636. }
  1637. // ZoltanS: either VARIANT_TRUE or TRUE will work
  1638. // in case the caller doesn't know better
  1639. if (fSecure)
  1640. {
  1641. // the port is flipped from regular port to ssl port.
  1642. m_wPort = GetOtherPort(m_wPort);
  1643. m_IsSsl = TRUE;
  1644. }
  1645. HRESULT hr = TryServer(m_wPort);
  1646. // We support legacy servers by also trying the normal LDAP port if
  1647. // the normal ILS port fails. If the user specified a special port,
  1648. // then we don't do anything behind their back!
  1649. if ( FAILED(hr) && (hr != E_OUTOFMEMORY) && (m_wPort == ILS_PORT))
  1650. {
  1651. m_wPort = LDAP_PORT;
  1652. hr = TryServer(m_wPort);
  1653. }
  1654. if ( SUCCEEDED(hr) )
  1655. {
  1656. // find out which interface we use to reach this server, to make sure
  1657. // we use that interface whenever we publish our own IP address
  1658. // If this fails we will not be able to publish anything, so fail!
  1659. hr = DiscoverInterface();
  1660. }
  1661. if( FAILED(hr))
  1662. {
  1663. if( m_ldap)
  1664. {
  1665. ldap_unbind(m_ldap);
  1666. m_ldap = NULL;
  1667. }
  1668. if( fSecure == VARIANT_TRUE )
  1669. {
  1670. hr = E_INVALIDARG;
  1671. }
  1672. }
  1673. return hr;
  1674. }
  1675. HRESULT CILSDirectory::DiscoverInterface(void)
  1676. {
  1677. LOG((MSP_INFO, "CILSDirectory::DiscoverInterface - enter"));
  1678. //
  1679. // Winsock must be initialized at this point.
  1680. //
  1681. //
  1682. // Get the IP address of the server we're using
  1683. //
  1684. DWORD dwIP; // The IP address of the destination ILS server
  1685. HRESULT hr = ResolveHostName(0, m_pServerName, NULL, &dwIP);
  1686. if ( FAILED(hr) )
  1687. {
  1688. LOG((MSP_ERROR, "CILSDirectory::DiscoverInterface - "
  1689. "can't resolve host name - "
  1690. "strange, because we could connect! - exit 0x%08x", hr));
  1691. return hr;
  1692. }
  1693. //
  1694. // allocate a "fake" control socket
  1695. //
  1696. SOCKET hSocket = WSASocket(AF_INET, // af
  1697. SOCK_DGRAM, // type
  1698. IPPROTO_IP, // protocol
  1699. NULL, // lpProtocolInfo
  1700. 0, // g
  1701. 0 // dwFlags
  1702. );
  1703. if ( hSocket == INVALID_SOCKET )
  1704. {
  1705. hr = HRESULT_FROM_ERROR_CODE(WSAGetLastError());
  1706. LOG((MSP_ERROR, "CILSDirectory::DiscoverInterface - "
  1707. "WSASocket gave an invalid socket - exit 0x%08x", hr));
  1708. return hr;
  1709. }
  1710. //
  1711. // Query for the interface address based on destination.
  1712. //
  1713. SOCKADDR_IN DestAddr;
  1714. DestAddr.sin_family = AF_INET;
  1715. DestAddr.sin_port = 0;
  1716. DestAddr.sin_addr.s_addr = dwIP;
  1717. SOCKADDR_IN LocAddr;
  1718. DWORD dwStatus;
  1719. DWORD dwLocAddrSize = sizeof(SOCKADDR_IN);
  1720. DWORD dwNumBytesReturned = 0;
  1721. dwStatus = WSAIoctl(
  1722. hSocket, // SOCKET s
  1723. SIO_ROUTING_INTERFACE_QUERY, // DWORD dwIoControlCode
  1724. &DestAddr, // LPVOID lpvInBuffer
  1725. sizeof(SOCKADDR_IN), // DWORD cbInBuffer
  1726. &LocAddr, // LPVOID lpvOUTBuffer
  1727. dwLocAddrSize, // DWORD cbOUTBuffer
  1728. &dwNumBytesReturned, // LPDWORD lpcbBytesReturned
  1729. NULL, // LPWSAOVERLAPPED lpOverlapped
  1730. NULL // LPWSAOVERLAPPED_COMPLETION_ROUTINE lpComplROUTINE
  1731. );
  1732. //
  1733. // Don't close the socket yet, because the closesocket() call will
  1734. // overwrite the WSAGetLastError value in the failure case!
  1735. //
  1736. // Check for error and then close the socket.
  1737. //
  1738. if ( dwStatus == SOCKET_ERROR )
  1739. {
  1740. hr = HRESULT_FROM_ERROR_CODE(WSAGetLastError());
  1741. LOG((MSP_ERROR, "CILSDirectory::DiscoverInterface - "
  1742. "WSAIoctl failed - exit 0x%08x", hr));
  1743. closesocket(hSocket);
  1744. return hr;
  1745. }
  1746. closesocket(hSocket);
  1747. //
  1748. // Success - save the returned address in our member variable.
  1749. // Stored in network byte order.
  1750. //
  1751. m_dwInterfaceAddress = LocAddr.sin_addr.s_addr;
  1752. LOG((MSP_INFO, "CILSDirectory::DiscoverInterface - exit S_OK"));
  1753. return S_OK;
  1754. }
  1755. //
  1756. // ITDirectory::Bind
  1757. //
  1758. // Bind to the server.
  1759. //
  1760. // Currently recognized flags:
  1761. //
  1762. // RENDBIND_AUTHENTICATE 0x00000001
  1763. // RENDBIND_DEFAULTDOMAINNAME 0x00000002
  1764. // RENDBIND_DEFAULTUSERNAME 0x00000004
  1765. // RENDBIND_DEFAULTPASSWORD 0x00000008
  1766. //
  1767. // "Meta-flags" for convenience:
  1768. // RENDBIND_DEFAULTCREDENTIALS 0x0000000e
  1769. //
  1770. //
  1771. // All of this together means that the following three
  1772. // forms are all equivalent:
  1773. //
  1774. // BSTR es = SysAllocString(L"");
  1775. // hr = pITDirectory->Bind(es, es, es, RENDBIND_AUTHENTICATE |
  1776. // RENDBIND_DEFAULTCREDENTIALS);
  1777. // SysFreeString(es);
  1778. //
  1779. //
  1780. // BSTR es = SysAllocString(L"");
  1781. // hr = pITDirectory->Bind(es, es, es, RENDBIND_AUTHENTICATE |
  1782. // RENDBIND_DEFAULTDOMAINNAME |
  1783. // RENDBIND_DEFAULTUSERNAME |
  1784. // RENDBIND_DEFAULTPASSWORD);
  1785. // SysFreeString(es);
  1786. //
  1787. //
  1788. // hr = pITDirectory->Bind(NULL, NULL, NULL, RENDBIND_AUTHENTICATE);
  1789. //
  1790. //
  1791. STDMETHODIMP CILSDirectory::Bind (
  1792. IN BSTR pDomainName,
  1793. IN BSTR pUserName,
  1794. IN BSTR pPassword,
  1795. IN long lFlags
  1796. )
  1797. {
  1798. LOG((MSP_TRACE, "CILSDirectory Bind - enter"));
  1799. //
  1800. // Determine if we should authenticate.
  1801. //
  1802. BOOL fAuthenticate = FALSE;
  1803. if ( lFlags & RENDBIND_AUTHENTICATE )
  1804. {
  1805. fAuthenticate = TRUE;
  1806. }
  1807. //
  1808. // For scripting compatibility, force string parameters to NULL based
  1809. // on flags.
  1810. //
  1811. if ( lFlags & RENDBIND_DEFAULTDOMAINNAME )
  1812. {
  1813. pDomainName = NULL;
  1814. }
  1815. if ( lFlags & RENDBIND_DEFAULTUSERNAME )
  1816. {
  1817. pUserName = NULL;
  1818. }
  1819. if ( lFlags & RENDBIND_DEFAULTPASSWORD )
  1820. {
  1821. pPassword = NULL;
  1822. }
  1823. LOG((MSP_INFO, "Bind parameters: domain: `%S' user: `%S' "
  1824. "authenticate: %S)",
  1825. (pDomainName) ? pDomainName : L"<null>",
  1826. (pUserName) ? pUserName : L"<null>",
  1827. (fAuthenticate) ? L"yes" : L"no"));
  1828. //
  1829. // All flags processed -- lock and proceed with bind if connected.
  1830. //
  1831. CLock Lock(m_lock);
  1832. if (m_ldap == NULL)
  1833. {
  1834. LOG((MSP_ERROR, "not connected."));
  1835. return RND_NOT_CONNECTED;
  1836. }
  1837. //
  1838. // ZoltanS: check the arguments. NULL has meaning in each case, so they are
  1839. // OK for now. In each case we want to check any length string, so we
  1840. // specify (UINT) -1 as the length.
  1841. //
  1842. if ( (pDomainName != NULL) && IsBadStringPtr(pDomainName, (UINT) -1 ) )
  1843. {
  1844. LOG((MSP_ERROR, "CNTDirectory::Bind: bad non-NULL pDomainName argument"));
  1845. return E_POINTER;
  1846. }
  1847. if ( (pUserName != NULL) && IsBadStringPtr(pUserName, (UINT) -1 ) )
  1848. {
  1849. LOG((MSP_ERROR, "CNTDirectory::Bind: bad non-NULL pUserName argument"));
  1850. return E_POINTER;
  1851. }
  1852. if ( (pPassword != NULL) && IsBadStringPtr(pPassword, (UINT) -1 ) )
  1853. {
  1854. LOG((MSP_ERROR, "CNTDirectory::Bind: bad non-NULL pPassword argument"));
  1855. return E_POINTER;
  1856. }
  1857. ULONG res;
  1858. if ( m_IsSsl || (!fAuthenticate) )
  1859. {
  1860. // if encrypted or no secure authentication is required,
  1861. // simple bind is sufficient
  1862. // ldap_simple_bind_s does not use sspi to get default credentials. We are
  1863. // just specifying what we will actually pass on the wire.
  1864. if (pPassword == NULL)
  1865. {
  1866. LOG((MSP_ERROR, "invalid Bind parameters: no password specified"));
  1867. return E_INVALIDARG;
  1868. }
  1869. WCHAR * wszFullName;
  1870. if ( (pDomainName == NULL) && (pUserName == NULL) )
  1871. {
  1872. // No domain / user doesn't make sense.
  1873. LOG((MSP_ERROR, "invalid Bind paramters: domain and user not specified"));
  1874. return E_INVALIDARG;
  1875. }
  1876. else if (pDomainName == NULL)
  1877. {
  1878. // username only is okay
  1879. wszFullName = pUserName;
  1880. }
  1881. else if (pUserName == NULL)
  1882. {
  1883. // It doesn't make sense to specify domain but not user...
  1884. LOG((MSP_ERROR, "invalid Bind paramters: domain specified but not user"));
  1885. return E_INVALIDARG;
  1886. }
  1887. else
  1888. {
  1889. // We need domain\user. Allocate a string and sprintf into it.
  1890. // The + 2 is for the "\" and for the null termination.
  1891. wszFullName = new WCHAR[wcslen(pDomainName) + wcslen(pUserName) + 2];
  1892. BAIL_IF_NULL(wszFullName, E_OUTOFMEMORY);
  1893. wsprintf(wszFullName, L"%s\\%s", pDomainName, pUserName);
  1894. }
  1895. //
  1896. // Do the simple bind.
  1897. //
  1898. res = ldap_simple_bind_s(m_ldap, wszFullName, pPassword);
  1899. //
  1900. // If we constructed the full name string, we now need to delete it.
  1901. //
  1902. if (wszFullName != pUserName)
  1903. {
  1904. delete wszFullName;
  1905. }
  1906. //
  1907. // Bail if the simple bind failed.
  1908. //
  1909. BAIL_IF_LDAP_FAIL(res, "ldap simple bind");
  1910. }
  1911. else // try an SSPI bind
  1912. {
  1913. // if the domain name, user name or the password is non-null
  1914. if ( pDomainName || pUserName || pPassword )
  1915. {
  1916. // fill the credential structure
  1917. SEC_WINNT_AUTH_IDENTITY AuthI;
  1918. AuthI.User = (PTCHAR)pUserName;
  1919. AuthI.UserLength = (pUserName == NULL)? 0: wcslen(pUserName);
  1920. AuthI.Domain = (PTCHAR)pDomainName;
  1921. AuthI.DomainLength = (pDomainName == NULL)? 0: wcslen(pDomainName);
  1922. AuthI.Password = (PTCHAR)pPassword;
  1923. AuthI.PasswordLength = (pPassword == NULL)? 0: wcslen(pPassword);
  1924. AuthI.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  1925. res = ldap_bind_s(m_ldap, NULL, (TCHAR*)(&AuthI), LDAP_AUTH_NTLM);
  1926. BAIL_IF_LDAP_FAIL(res, "bind with authtication");
  1927. }
  1928. else
  1929. {
  1930. // Otherwise we've come in with NULL, NULL, NULL -
  1931. // pass in NULL, NULL. The reason do this is that ldap bind code
  1932. // does not process NULL, NULL, NULL in the
  1933. // SEC_WINNT_AUTH_IDENTITY blob !!!
  1934. ULONG res = ldap_bind_s(m_ldap, NULL, NULL, LDAP_AUTH_NTLM);
  1935. BAIL_IF_LDAP_FAIL(res, "bind with NULL NULL NULL");
  1936. }
  1937. }
  1938. LOG((MSP_TRACE, "CILSDirectory::Bind - exiting OK"));
  1939. return S_OK;
  1940. }
  1941. //////////////////////////////////////////////////////////////////////
  1942. // ITDirectory::AddDirectoryObject
  1943. //
  1944. // Return values:
  1945. // Value Where defined What it means
  1946. // ----- ------------- -------------
  1947. // RND_NOT_CONNECTED .\rnderr.h ::Connect not yet called
  1948. // E_POINTER sdk\inc\winerror.h pDirectoryObject is a bad pointer
  1949. // other from AddConference
  1950. // other from AddUser
  1951. //
  1952. STDMETHODIMP CILSDirectory::AddDirectoryObject (
  1953. IN ITDirectoryObject *pDirectoryObject
  1954. )
  1955. // publish a new object to the server.
  1956. {
  1957. if ( IsBadReadPtr(pDirectoryObject, sizeof(ITDirectoryObject) ) )
  1958. {
  1959. LOG((MSP_ERROR, "CILSDirectory::AddDirectoryObject - "
  1960. "bad directory object pointer - returning E_POINTER"));
  1961. return E_POINTER;
  1962. }
  1963. CLock Lock(m_lock);
  1964. if (m_ldap == NULL)
  1965. {
  1966. LOG((MSP_ERROR, "CILSDirectory::AddDirectoryObject - not connected."));
  1967. return RND_NOT_CONNECTED;
  1968. }
  1969. HRESULT hr;
  1970. DIRECTORY_OBJECT_TYPE type;
  1971. hr = pDirectoryObject->get_ObjectType(&type);
  1972. if ( FAILED(hr) )
  1973. {
  1974. LOG((MSP_ERROR, "CILSDirectory::AddDirectoryObject - "
  1975. "can't get object type; returning 0x%08x", hr));
  1976. return hr;
  1977. }
  1978. switch (type)
  1979. {
  1980. case OT_CONFERENCE:
  1981. hr = AddConference(pDirectoryObject, FALSE);
  1982. break;
  1983. case OT_USER:
  1984. hr = AddUser(pDirectoryObject, FALSE);
  1985. break;
  1986. }
  1987. return hr;
  1988. }
  1989. STDMETHODIMP CILSDirectory::ModifyDirectoryObject (
  1990. IN ITDirectoryObject *pDirectoryObject
  1991. )
  1992. // modify an object on the server.
  1993. {
  1994. if ( IsBadReadPtr(pDirectoryObject, sizeof(ITDirectoryObject) ) )
  1995. {
  1996. LOG((MSP_ERROR, "CILSDirectory::ModifyDirectoryObject - "
  1997. "bad directory object pointer - returning E_POINTER"));
  1998. return E_POINTER;
  1999. }
  2000. CLock Lock(m_lock);
  2001. if (m_ldap == NULL)
  2002. {
  2003. LOG((MSP_ERROR, "CILSDirectory::ModifyDirectoryObject - not connected."));
  2004. return RND_NOT_CONNECTED;
  2005. }
  2006. HRESULT hr;
  2007. DIRECTORY_OBJECT_TYPE type;
  2008. hr = pDirectoryObject->get_ObjectType(&type);
  2009. if ( FAILED(hr) )
  2010. {
  2011. LOG((MSP_ERROR, "CILSDirectory::ModifyDirectoryObject - "
  2012. "can't get object type; returning 0x%08x", hr));
  2013. return hr;
  2014. }
  2015. switch (type)
  2016. {
  2017. case OT_CONFERENCE:
  2018. hr = AddConference(pDirectoryObject, TRUE);
  2019. break;
  2020. case OT_USER:
  2021. hr = AddUser(pDirectoryObject, TRUE);
  2022. break;
  2023. }
  2024. return hr;
  2025. }
  2026. STDMETHODIMP CILSDirectory::RefreshDirectoryObject (
  2027. IN ITDirectoryObject *pDirectoryObject
  2028. )
  2029. // Refresh the TTL for the object and add the object to the refresh list
  2030. // if the autorefresh is enabled.
  2031. {
  2032. if ( IsBadReadPtr(pDirectoryObject, sizeof(ITDirectoryObject) ) )
  2033. {
  2034. LOG((MSP_ERROR, "CILSDirectory::RefreshDirectoryObject - "
  2035. "bad directory object pointer - returning E_POINTER"));
  2036. return E_POINTER;
  2037. }
  2038. CLock Lock(m_lock);
  2039. if (m_ldap == NULL)
  2040. {
  2041. LOG((MSP_ERROR, "CILSDirectory::RefreshDirectoryObject - not connected."));
  2042. return RND_NOT_CONNECTED;
  2043. }
  2044. HRESULT hr;
  2045. DIRECTORY_OBJECT_TYPE type;
  2046. hr = pDirectoryObject->get_ObjectType(&type);
  2047. if ( FAILED(hr) )
  2048. {
  2049. LOG((MSP_ERROR, "CILSDirectory::RefreshDirectoryObject - "
  2050. "can't get object type; returning 0x%08x", hr));
  2051. return hr;
  2052. }
  2053. switch (type)
  2054. {
  2055. case OT_CONFERENCE:
  2056. return S_OK; // conferences do not need refresh.
  2057. case OT_USER:
  2058. hr = RefreshUser(pDirectoryObject);
  2059. break;
  2060. }
  2061. return hr;
  2062. }
  2063. STDMETHODIMP CILSDirectory::DeleteDirectoryObject (
  2064. IN ITDirectoryObject *pDirectoryObject
  2065. )
  2066. // delete an object on the server.
  2067. {
  2068. if ( IsBadReadPtr(pDirectoryObject, sizeof(ITDirectoryObject) ) )
  2069. {
  2070. LOG((MSP_ERROR, "CILSDirectory::DeleteDirectoryObject - "
  2071. "bad directory object pointer - returning E_POINTER"));
  2072. return E_POINTER;
  2073. }
  2074. CLock Lock(m_lock);
  2075. if (m_ldap == NULL)
  2076. {
  2077. LOG((MSP_ERROR, "CILSDirectory::DeleteDirectoryObject - not connected."));
  2078. return RND_NOT_CONNECTED;
  2079. }
  2080. HRESULT hr;
  2081. DIRECTORY_OBJECT_TYPE type;
  2082. hr = pDirectoryObject->get_ObjectType(&type);
  2083. if ( FAILED(hr) )
  2084. {
  2085. LOG((MSP_ERROR, "CILSDirectory::DeleteDirectoryObject - "
  2086. "can't get object type; returning 0x%08x", hr));
  2087. return hr;
  2088. }
  2089. switch (type)
  2090. {
  2091. case OT_CONFERENCE:
  2092. hr = DeleteConference(pDirectoryObject);
  2093. break;
  2094. case OT_USER:
  2095. hr = DeleteUser(pDirectoryObject);
  2096. break;
  2097. }
  2098. return hr;
  2099. }
  2100. STDMETHODIMP CILSDirectory::get_DirectoryObjects (
  2101. IN DIRECTORY_OBJECT_TYPE DirectoryObjectType,
  2102. IN BSTR pName,
  2103. OUT VARIANT * pVariant
  2104. )
  2105. // search for objects on the server.
  2106. {
  2107. BAIL_IF_BAD_READ_PTR(pName, E_POINTER);
  2108. BAIL_IF_BAD_WRITE_PTR(pVariant, E_POINTER);
  2109. CLock Lock(m_lock);
  2110. if (m_ldap == NULL)
  2111. {
  2112. LOG((MSP_ERROR, "not connected."));
  2113. return RND_NOT_CONNECTED;
  2114. }
  2115. HRESULT hr;
  2116. ITDirectoryObject **pObjects;
  2117. DWORD dwSize;
  2118. // search and create objects.
  2119. hr = SearchObjects(DirectoryObjectType, pName, &pObjects, &dwSize);
  2120. BAIL_IF_FAIL(hr, "Search for objects");
  2121. // create a collection object that contains the objects.
  2122. hr = CreateInterfaceCollection(dwSize, // count
  2123. &pObjects[0], // begin ptr
  2124. &pObjects[dwSize], // end ptr
  2125. pVariant); // return value
  2126. for (DWORD i = 0; i < dwSize; i ++)
  2127. {
  2128. pObjects[i]->Release();
  2129. }
  2130. delete pObjects;
  2131. BAIL_IF_FAIL(hr, "Create collection of directory objects");
  2132. return hr;
  2133. }
  2134. STDMETHODIMP CILSDirectory::EnumerateDirectoryObjects (
  2135. IN DIRECTORY_OBJECT_TYPE DirectoryObjectType,
  2136. IN BSTR pName,
  2137. OUT IEnumDirectoryObject ** ppEnumObject
  2138. )
  2139. // search for the objects on the server.
  2140. {
  2141. BAIL_IF_BAD_READ_PTR(pName, E_POINTER);
  2142. BAIL_IF_BAD_WRITE_PTR(ppEnumObject, E_POINTER);
  2143. CLock Lock(m_lock);
  2144. if (m_ldap == NULL)
  2145. {
  2146. LOG((MSP_ERROR, "not connected."));
  2147. return RND_NOT_CONNECTED;
  2148. }
  2149. HRESULT hr;
  2150. ITDirectoryObject **pObjects;
  2151. DWORD dwSize;
  2152. // search and create objects.
  2153. hr = SearchObjects(DirectoryObjectType, pName, &pObjects, &dwSize);
  2154. BAIL_IF_FAIL(hr, "Search for objects");
  2155. // create a enumerator object that contains the objects.
  2156. hr = ::CreateDirectoryObjectEnumerator(
  2157. &pObjects[0],
  2158. &pObjects[dwSize],
  2159. ppEnumObject
  2160. );
  2161. for (DWORD i = 0; i < dwSize; i ++)
  2162. {
  2163. pObjects[i]->Release();
  2164. }
  2165. delete pObjects;
  2166. BAIL_IF_FAIL(hr, "Create enumerator of directory objects");
  2167. return hr;
  2168. }
  2169. /////////////////////////////////////////////////////////////////////////////
  2170. // ILSConfig implementation
  2171. /////////////////////////////////////////////////////////////////////////////
  2172. STDMETHODIMP CILSDirectory::get_Port (
  2173. OUT long *pPort
  2174. )
  2175. // get the current port used in Ldap connection.
  2176. {
  2177. if ( IsBadWritePtr(pPort, sizeof(long) ) )
  2178. {
  2179. LOG((MSP_ERROR, "Directory.get_Port, invalid pointer"));
  2180. return E_POINTER;
  2181. }
  2182. CLock Lock(m_lock);
  2183. *pPort = (long)m_wPort;
  2184. return S_OK;
  2185. }
  2186. STDMETHODIMP CILSDirectory::put_Port (
  2187. IN long Port
  2188. )
  2189. // set the port the user wants to use.
  2190. {
  2191. CLock Lock(m_lock);
  2192. if (m_ldap != NULL)
  2193. {
  2194. LOG((MSP_ERROR, "already connected."));
  2195. return RND_ALREADY_CONNECTED;
  2196. }
  2197. if (Port <= USHRT_MAX)
  2198. {
  2199. m_wPort = (WORD)Port;
  2200. return S_OK;
  2201. }
  2202. return E_INVALIDARG;
  2203. }
  2204. /////////////////////////////////////////////////////////////////////////////
  2205. // ITDynamic interface
  2206. /////////////////////////////////////////////////////////////////////////////
  2207. STDMETHODIMP CILSDirectory::Update(DWORD dwSecondsPassed)
  2208. // Update the TTL for object created in this directory. The worker thread
  2209. // sends a tick every minute.
  2210. {
  2211. if ( ! m_lock.TryLock() )
  2212. {
  2213. return S_OK;
  2214. }
  2215. LOG((MSP_TRACE, "CILSDirectory::Update is called, delta: %d", dwSecondsPassed));
  2216. //
  2217. // Go through the table to see if anyone needs refresh.
  2218. //
  2219. for ( DWORD i = 0; i < m_RefreshTable.size(); i++ )
  2220. {
  2221. WCHAR * pDN = m_RefreshTable[i].pDN;
  2222. DWORD dwTTL = m_RefreshTable[i].dwTTL;
  2223. LOG((MSP_TRACE, "\tExamining user object: %S", pDN ));
  2224. LOG((MSP_TRACE, "\t\tTime remaining: %d", dwTTL ));
  2225. if ( dwTTL <= ( 2 * dwSecondsPassed ) )
  2226. {
  2227. //
  2228. // refresh it if the TTL is going to expire within the next
  2229. // two clicks
  2230. //
  2231. LOG((MSP_TRACE, "\t\t\tREFRESHING"));
  2232. if ( SUCCEEDED( SetTTL( m_ldap, pDN, m_TTL) ) )
  2233. {
  2234. m_RefreshTable[i].dwTTL = m_TTL;
  2235. }
  2236. else
  2237. {
  2238. LOG((MSP_WARN, "\t\t\t\tRefresh failed; will try again next time"));
  2239. }
  2240. }
  2241. else
  2242. {
  2243. //
  2244. // Not about to expire right now so just keep track of the time before
  2245. // it expires
  2246. //
  2247. LOG((MSP_TRACE, "\t\t\tdecrementing"));
  2248. m_RefreshTable[i].dwTTL -= dwSecondsPassed;
  2249. }
  2250. }
  2251. m_lock.Unlock();
  2252. LOG((MSP_TRACE, "CILSDirectory::Update exit S_OK"));
  2253. return S_OK;
  2254. }
  2255. typedef IDispatchImpl<ITDirectoryVtbl<CILSDirectory>, &IID_ITDirectory, &LIBID_RENDLib> CTDirectory;
  2256. typedef IDispatchImpl<ITILSConfigVtbl<CILSDirectory>, &IID_ITILSConfig, &LIBID_RENDLib> CTILSConfig;
  2257. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  2258. //
  2259. // CILSDirectory::GetIDsOfNames
  2260. //
  2261. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  2262. STDMETHODIMP CILSDirectory::GetIDsOfNames(REFIID riid,
  2263. LPOLESTR* rgszNames,
  2264. UINT cNames,
  2265. LCID lcid,
  2266. DISPID* rgdispid
  2267. )
  2268. {
  2269. LOG((MSP_TRACE, "CILSDirectory::GetIDsOfNames[%p] - enter. Name [%S]",this, *rgszNames));
  2270. HRESULT hr = DISP_E_UNKNOWNNAME;
  2271. //
  2272. // See if the requsted method belongs to the default interface
  2273. //
  2274. hr = CTDirectory::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  2275. if (SUCCEEDED(hr))
  2276. {
  2277. LOG((MSP_TRACE, "CILSDirectory::GetIDsOfNames - found %S on CTDirectory", *rgszNames));
  2278. rgdispid[0] |= IDISPDIRECTORY;
  2279. return hr;
  2280. }
  2281. //
  2282. // If not, then try the ITILSConfig base class
  2283. //
  2284. hr = CTILSConfig::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  2285. if (SUCCEEDED(hr))
  2286. {
  2287. LOG((MSP_TRACE, "CILSDirectory::GetIDsOfNames - found %S on CTILSConfig", *rgszNames));
  2288. rgdispid[0] |= IDISPILSCONFIG;
  2289. return hr;
  2290. }
  2291. LOG((MSP_ERROR, "CILSDirectory::GetIDsOfNames[%p] - finish. didn't find %S on our iterfaces",*rgszNames));
  2292. return hr;
  2293. }
  2294. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  2295. //
  2296. // CILSDirectory::Invoke
  2297. //
  2298. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  2299. STDMETHODIMP CILSDirectory::Invoke(DISPID dispidMember,
  2300. REFIID riid,
  2301. LCID lcid,
  2302. WORD wFlags,
  2303. DISPPARAMS* pdispparams,
  2304. VARIANT* pvarResult,
  2305. EXCEPINFO* pexcepinfo,
  2306. UINT* puArgErr
  2307. )
  2308. {
  2309. LOG((MSP_TRACE, "CILSDirectory::Invoke[%p] - enter. dispidMember %lx",this, dispidMember));
  2310. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  2311. DWORD dwInterface = (dispidMember & INTERFACEMASK);
  2312. //
  2313. // Call invoke for the required interface
  2314. //
  2315. switch (dwInterface)
  2316. {
  2317. case IDISPDIRECTORY:
  2318. {
  2319. hr = CTDirectory::Invoke(dispidMember,
  2320. riid,
  2321. lcid,
  2322. wFlags,
  2323. pdispparams,
  2324. pvarResult,
  2325. pexcepinfo,
  2326. puArgErr
  2327. );
  2328. LOG((MSP_TRACE, "CILSDirectory::Invoke - ITDirectory"));
  2329. break;
  2330. }
  2331. case IDISPILSCONFIG:
  2332. {
  2333. hr = CTILSConfig::Invoke(dispidMember,
  2334. riid,
  2335. lcid,
  2336. wFlags,
  2337. pdispparams,
  2338. pvarResult,
  2339. pexcepinfo,
  2340. puArgErr
  2341. );
  2342. LOG((MSP_TRACE, "CILSDirectory::Invoke - ITILSConfig"));
  2343. break;
  2344. }
  2345. } // end switch (dwInterface)
  2346. LOG((MSP_TRACE, "CILSDirectory::Invoke[%p] - finish. hr = %lx", hr));
  2347. return hr;
  2348. }