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

698 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. rnduser.cpp
  5. Abstract:
  6. This module contains implementation of CUser object.
  7. Author:
  8. Rajeevb,
  9. Modification history:
  10. Mu Han (muhan) 12-5-1997
  11. --*/
  12. #include "stdafx.h"
  13. #include "rnduser.h"
  14. const WCHAR * const UserAttributeNames[] =
  15. {
  16. L"SamAccountName", // ZoltanS: was "cn" -- we need SamAccountName for ntds.
  17. L"telephoneNumber",
  18. L"IPPhone"
  19. };
  20. #define INC_ACCESS_ACL_SIZE(_SIZE_, _SID_) \
  21. _SIZE_ += (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(_SID_));
  22. #define BAIL_ON_BOOLFAIL(_FN_) \
  23. if ( !_FN_ ) \
  24. { \
  25. hr = HRESULT_FROM_WIN32(GetLastError()); \
  26. goto failed; \
  27. }
  28. #define ACCESS_READ 0x10
  29. #define ACCESS_WRITE 0x20
  30. #define ACCESS_MODIFY (ACCESS_WRITE | WRITE_DAC)
  31. #define ACCESS_DELETE DELETE
  32. #define ACCESS_ALL (ACCESS_READ | ACCESS_MODIFY | ACCESS_DELETE)
  33. HRESULT
  34. ConvertStringToSid(
  35. IN PWSTR string,
  36. OUT PSID *sid,
  37. OUT PDWORD pdwSidSize,
  38. OUT PWSTR *end
  39. );
  40. HRESULT
  41. ConvertACLToVariant(
  42. PACL pACL,
  43. LPVARIANT pvarACL
  44. );
  45. /////////////////////////////////////////////////////////////////////////////
  46. // non-interface class methods
  47. /////////////////////////////////////////////////////////////////////////////
  48. HRESULT CUser::Init(BSTR bName)
  49. {
  50. HRESULT hr;
  51. hr = SetSingleValue(UA_USERNAME, bName);
  52. BAIL_IF_FAIL(hr, "can't set user name");
  53. hr = SetDefaultSD();
  54. BAIL_IF_FAIL(hr, "Init the security descriptor");
  55. return hr;
  56. }
  57. HRESULT
  58. CUser::GetSingleValueBstr(
  59. IN OBJECT_ATTRIBUTE Attribute,
  60. OUT BSTR * AttributeValue
  61. )
  62. {
  63. LOG((MSP_INFO, "CUser::GetSingleValueBstr - entered"));
  64. BAIL_IF_BAD_WRITE_PTR(AttributeValue, E_POINTER);
  65. if (!ValidUserAttribute(Attribute))
  66. {
  67. LOG((MSP_ERROR, "Invalid Attribute, %d", Attribute));
  68. return E_FAIL;
  69. }
  70. CLock Lock(m_lock);
  71. if(!m_Attributes[UserAttrIndex(Attribute)])
  72. {
  73. LOG((MSP_ERROR, "Attribute %S is not found",
  74. UserAttributeName(Attribute)));
  75. return E_FAIL;
  76. }
  77. *AttributeValue = SysAllocString(m_Attributes[UserAttrIndex(Attribute)]);
  78. if (*AttributeValue == NULL)
  79. {
  80. return E_OUTOFMEMORY;
  81. }
  82. LOG((MSP_INFO, "CUser::get %S: %S",
  83. UserAttributeName(Attribute), *AttributeValue));
  84. return S_OK;
  85. }
  86. HRESULT
  87. CUser::SetSingleValue(
  88. IN OBJECT_ATTRIBUTE Attribute,
  89. IN WCHAR * AttributeValue
  90. )
  91. {
  92. LOG((MSP_INFO, "CUser::SetSingleValue - entered"));
  93. if (!ValidUserAttribute(Attribute))
  94. {
  95. LOG((MSP_ERROR, "Invalid Attribute, %d", Attribute));
  96. return E_FAIL;
  97. }
  98. if (AttributeValue != NULL)
  99. {
  100. BAIL_IF_BAD_READ_PTR(AttributeValue, E_POINTER);
  101. }
  102. CLock Lock(m_lock);
  103. if (!m_Attributes[UserAttrIndex(Attribute)].set(AttributeValue))
  104. {
  105. LOG((MSP_ERROR, "Can not add attribute %S",
  106. UserAttributeName(Attribute)));
  107. return E_OUTOFMEMORY;
  108. }
  109. LOG((MSP_INFO, "CUser::set %S to %S",
  110. UserAttributeName(Attribute), AttributeValue));
  111. return S_OK;
  112. }
  113. /*++
  114. Routine Description:
  115. Set the right security descriptor for the conference.
  116. Arguments:
  117. Return Value:
  118. HRESULT.
  119. --*/
  120. HRESULT
  121. CUser::SetDefaultSD()
  122. {
  123. LOG((MSP_INFO, "CConference::SetDefaultSD - entered"));
  124. //
  125. // The security descriptor
  126. //
  127. IADsSecurityDescriptor* pSecDesc = NULL;
  128. HRESULT hr = S_OK;
  129. bool bOwner = false, bWorld = false;
  130. PACL pACL = NULL;
  131. PSID pSidWorld = NULL;
  132. DWORD dwAclSize = sizeof(ACL), dwTemp;
  133. BSTR bstrTemp = NULL;
  134. LPWSTR pszTemp = NULL;
  135. HANDLE hToken;
  136. UCHAR *pInfoBuffer = NULL;
  137. DWORD cbInfoBuffer = 512;
  138. //
  139. // Try to get the thread or process token
  140. //
  141. if( !OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken) )
  142. {
  143. //
  144. // If there was a sever error we exit
  145. //
  146. if( GetLastError() != ERROR_NO_TOKEN )
  147. {
  148. LOG((MSP_ERROR, "CConference::SetDefaultSD - exit E_FAIL "
  149. "OpenThreadToken failed!"));
  150. return E_FAIL;
  151. }
  152. //
  153. // Attempt to open the process token, since no thread token exists
  154. //
  155. if( !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) )
  156. {
  157. LOG((MSP_ERROR, "CConference::SetDefaultSD - exit E_FAIL "
  158. "OpenProcessToken failed"));
  159. return E_FAIL;
  160. }
  161. }
  162. //
  163. // Loop until we have a large enough structure
  164. //
  165. while ( (pInfoBuffer = new UCHAR[cbInfoBuffer]) != NULL )
  166. {
  167. if ( !GetTokenInformation(hToken, TokenUser, pInfoBuffer, cbInfoBuffer, &cbInfoBuffer) )
  168. {
  169. delete pInfoBuffer;
  170. pInfoBuffer = NULL;
  171. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  172. return E_FAIL;
  173. }
  174. else
  175. {
  176. break;
  177. }
  178. }
  179. CloseHandle(hToken);
  180. //
  181. // Did we get the owner ACL?
  182. //
  183. if ( pInfoBuffer )
  184. {
  185. INC_ACCESS_ACL_SIZE( dwAclSize, ((PTOKEN_USER) pInfoBuffer)->User.Sid );
  186. bOwner = true;
  187. }
  188. //
  189. // Make SID for "Everyone"
  190. //
  191. SysReAllocString( &bstrTemp, L"S-1-1-0" );
  192. hr = ConvertStringToSid( bstrTemp, &pSidWorld, &dwTemp, &pszTemp );
  193. if ( SUCCEEDED(hr) )
  194. {
  195. INC_ACCESS_ACL_SIZE( dwAclSize, pSidWorld );
  196. bWorld = true;
  197. }
  198. //
  199. // Create a security descriptor
  200. //
  201. hr = CoCreateInstance(
  202. CLSID_SecurityDescriptor,
  203. NULL,
  204. CLSCTX_INPROC_SERVER,
  205. IID_IADsSecurityDescriptor,
  206. (void **)&pSecDesc
  207. );
  208. if( FAILED(hr) )
  209. {
  210. LOG((MSP_ERROR, "CConference::SetDefaultSD - exit 0x%08x "
  211. "Create security descriptor failed!", hr));
  212. goto failed;
  213. }
  214. //
  215. // Create the ACL containing the Owner and World ACEs
  216. //
  217. pACL = (PACL) new BYTE[dwAclSize];
  218. if ( pACL )
  219. {
  220. BAIL_ON_BOOLFAIL( InitializeAcl(pACL, dwAclSize, ACL_REVISION) );
  221. // Add World Rights
  222. if ( bWorld )
  223. {
  224. if ( bOwner )
  225. {
  226. BAIL_ON_BOOLFAIL( AddAccessAllowedAce(pACL, ACL_REVISION, ACCESS_READ, pSidWorld) );
  227. }
  228. else
  229. {
  230. BAIL_ON_BOOLFAIL( AddAccessAllowedAce(pACL, ACL_REVISION, ACCESS_ALL , pSidWorld) );
  231. }
  232. }
  233. // Add Creator rights
  234. if ( bOwner )
  235. BAIL_ON_BOOLFAIL( AddAccessAllowedAce(pACL, ACL_REVISION, ACCESS_ALL, ((PTOKEN_USER) pInfoBuffer)->User.Sid) );
  236. // Set the DACL onto our security descriptor
  237. VARIANT varDACL;
  238. VariantInit( &varDACL );
  239. if ( SUCCEEDED(hr = ConvertACLToVariant((PACL) pACL, &varDACL)) )
  240. {
  241. if ( SUCCEEDED(hr = pSecDesc->put_DaclDefaulted(FALSE)) )
  242. {
  243. hr = pSecDesc->put_DiscretionaryAcl( V_DISPATCH(&varDACL) );
  244. if( SUCCEEDED(hr) )
  245. {
  246. hr = put_SecurityDescriptor((IDispatch*)pSecDesc);
  247. if( SUCCEEDED(hr) )
  248. {
  249. hr = this->put_SecurityDescriptorIsModified(TRUE);
  250. }
  251. }
  252. }
  253. }
  254. VariantClear( &varDACL );
  255. }
  256. else
  257. {
  258. hr = E_OUTOFMEMORY;
  259. }
  260. // Clean up
  261. failed:
  262. SysFreeString( bstrTemp );
  263. if ( pACL ) delete pACL;
  264. if ( pSidWorld ) delete pSidWorld;
  265. if ( pInfoBuffer ) delete pInfoBuffer;
  266. if( pSecDesc ) pSecDesc->Release();
  267. LOG((MSP_INFO, "CConference::SetDefaultSD - exit 0x%08x", hr));
  268. return hr;
  269. }
  270. /////////////////////////////////////////////////////////////////////////////
  271. // ITDirectoryObject
  272. /////////////////////////////////////////////////////////////////////////////
  273. STDMETHODIMP CUser::get_Name(BSTR * ppVal)
  274. {
  275. return GetSingleValueBstr(UA_USERNAME, ppVal);
  276. }
  277. STDMETHODIMP CUser::put_Name(BSTR pVal)
  278. {
  279. return SetSingleValue(UA_USERNAME, pVal);
  280. }
  281. STDMETHODIMP CUser::get_DialableAddrs(
  282. IN long dwAddressTypes, //defined in tapi.h
  283. OUT VARIANT * pVariant
  284. )
  285. {
  286. BAIL_IF_BAD_WRITE_PTR(pVariant, E_POINTER);
  287. HRESULT hr;
  288. BSTR *Addresses = new BSTR[1]; // only one for now.
  289. BAIL_IF_NULL(Addresses, E_OUTOFMEMORY);
  290. switch (dwAddressTypes)
  291. {
  292. case LINEADDRESSTYPE_DOMAINNAME:
  293. hr = GetSingleValueBstr(UA_IPPHONE_PRIMARY, &Addresses[0]);
  294. break;
  295. case LINEADDRESSTYPE_IPADDRESS:
  296. {
  297. BSTR pDomainName;
  298. DWORD dwIP;
  299. hr = GetSingleValueBstr(UA_IPPHONE_PRIMARY, &pDomainName);
  300. if ( SUCCEEDED(hr) )
  301. {
  302. hr = ResolveHostName(0, pDomainName, NULL, &dwIP);
  303. SysFreeString(pDomainName);
  304. if ( SUCCEEDED(hr) )
  305. {
  306. WCHAR wszIP[20];
  307. ipAddressToStringW(wszIP, dwIP);
  308. Addresses[0] = SysAllocString(wszIP);
  309. if ( Addresses[0] == NULL )
  310. {
  311. hr = E_OUTOFMEMORY;
  312. }
  313. }
  314. }
  315. }
  316. break;
  317. case LINEADDRESSTYPE_PHONENUMBER:
  318. hr = GetSingleValueBstr(UA_TELEPHONE_NUMBER, &Addresses[0]);
  319. break;
  320. default:
  321. hr = E_FAIL;
  322. break;
  323. }
  324. DWORD dwCount = (FAILED(hr)) ? 0 : 1;
  325. hr = ::CreateBstrCollection(dwCount, // count
  326. &Addresses[0], // begin pointer
  327. &Addresses[dwCount], // end pointer
  328. pVariant, // return value
  329. AtlFlagTakeOwnership); // flags
  330. // the collection will destroy the Addresses array eventually.
  331. // no need to free anything here. Even if we tell it to hand
  332. // out zero objects, it will delete the array on construction.
  333. // (ZoltanS verified.)
  334. return hr;
  335. }
  336. STDMETHODIMP CUser::EnumerateDialableAddrs(
  337. IN DWORD dwAddressTypes, //defined in tapi.h
  338. OUT IEnumDialableAddrs ** ppEnumDialableAddrs
  339. )
  340. {
  341. BAIL_IF_BAD_WRITE_PTR(ppEnumDialableAddrs, E_POINTER);
  342. HRESULT hr;
  343. BSTR *Addresses = new BSTR[1]; // only one for now.
  344. BAIL_IF_NULL(Addresses, E_OUTOFMEMORY);
  345. switch (dwAddressTypes)
  346. {
  347. case LINEADDRESSTYPE_IPADDRESS:
  348. {
  349. BSTR pDomainName;
  350. DWORD dwIP;
  351. hr = GetSingleValueBstr(UA_IPPHONE_PRIMARY, &pDomainName);
  352. if ( SUCCEEDED(hr) )
  353. {
  354. hr = ResolveHostName(0, pDomainName, NULL, &dwIP);
  355. SysFreeString(pDomainName);
  356. if ( SUCCEEDED(hr) )
  357. {
  358. WCHAR wszIP[20];
  359. ipAddressToStringW(wszIP, dwIP);
  360. Addresses[0] = SysAllocString(wszIP);
  361. if ( Addresses[0] == NULL )
  362. {
  363. hr = E_OUTOFMEMORY;
  364. }
  365. }
  366. }
  367. }
  368. break;
  369. case LINEADDRESSTYPE_DOMAINNAME:
  370. hr = GetSingleValueBstr(UA_IPPHONE_PRIMARY, &Addresses[0]);
  371. break;
  372. case LINEADDRESSTYPE_PHONENUMBER:
  373. hr = GetSingleValueBstr(UA_TELEPHONE_NUMBER, &Addresses[0]);
  374. break;
  375. default:
  376. hr = E_FAIL;
  377. break;
  378. }
  379. DWORD dwCount = (FAILED(hr)) ? 0 : 1;
  380. hr = ::CreateDialableAddressEnumerator(
  381. &Addresses[0],
  382. &Addresses[dwCount],
  383. ppEnumDialableAddrs
  384. );
  385. // the enumerator will destroy the Addresses array eventually,
  386. // so no need to free anything here. Even if we tell it to hand
  387. // out zero objects, it will delete the array on destruction.
  388. // (ZoltanS verified.)
  389. return hr;
  390. }
  391. STDMETHODIMP CUser::GetAttribute(
  392. IN OBJECT_ATTRIBUTE Attribute,
  393. OUT BSTR * ppAttributeValue
  394. )
  395. {
  396. return GetSingleValueBstr(Attribute, ppAttributeValue);
  397. }
  398. STDMETHODIMP CUser::SetAttribute(
  399. IN OBJECT_ATTRIBUTE Attribute,
  400. IN BSTR pAttributeValue
  401. )
  402. {
  403. return SetSingleValue(Attribute, pAttributeValue);
  404. }
  405. STDMETHODIMP CUser::GetTTL(
  406. OUT DWORD * pdwTTL
  407. )
  408. {
  409. BAIL_IF_BAD_WRITE_PTR(pdwTTL, E_POINTER);
  410. *pdwTTL = 0;
  411. return S_OK;
  412. }
  413. /////////////////////////////////////////////////////////////////////////////
  414. // ITDirectoryObjectUser
  415. /////////////////////////////////////////////////////////////////////////////
  416. STDMETHODIMP CUser::get_IPPhonePrimary(
  417. OUT BSTR *pVal
  418. )
  419. {
  420. return GetSingleValueBstr(UA_IPPHONE_PRIMARY, pVal);
  421. }
  422. STDMETHODIMP CUser::put_IPPhonePrimary(
  423. IN BSTR newVal
  424. )
  425. {
  426. // ZoltanS: we now need to check the BSTR, as the ResolveHostName
  427. // call below doesn't check it before using it.
  428. // Second argument is the maximum length of string to check -- we want
  429. // to check the whole thing, so we say (UINT) -1, which is about 2^32.
  430. if ( IsBadStringPtr(newVal, (UINT) -1) )
  431. {
  432. LOG((MSP_ERROR, "CUser::put_IPPhonePrimary: bad BSTR"));
  433. return E_POINTER;
  434. }
  435. // ZoltanS: We shouldn't let the user set an IPPhonePrimary value that
  436. // doesn't resolve to a known host / IP. Check here.
  437. char * pchFullDNSName = NULL; // we don't really care what we get
  438. DWORD dwIp = 0; // we don't really care what we get
  439. // This is our utility function from rndutil.cpp.
  440. HRESULT hr = ResolveHostName(0, newVal, &pchFullDNSName, &dwIp);
  441. if (FAILED(hr))
  442. {
  443. LOG((MSP_ERROR, "CUser::put_IPPhonePrimary: unresolvable name"));
  444. return hr;
  445. }
  446. // Now actually set it.
  447. return SetSingleValue(UA_IPPHONE_PRIMARY, newVal);
  448. }
  449. typedef IDispatchImpl<ITDirectoryObjectUserVtbl<CUser>, &IID_ITDirectoryObjectUser, &LIBID_RENDLib> CTDirObjUser;
  450. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  451. //
  452. // CUser::GetIDsOfNames
  453. //
  454. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  455. STDMETHODIMP CUser::GetIDsOfNames(REFIID riid,
  456. LPOLESTR* rgszNames,
  457. UINT cNames,
  458. LCID lcid,
  459. DISPID* rgdispid
  460. )
  461. {
  462. LOG((MSP_TRACE, "CUser::GetIDsOfNames[%p] - enter. Name [%S]",this, *rgszNames));
  463. HRESULT hr = DISP_E_UNKNOWNNAME;
  464. //
  465. // See if the requsted method belongs to the default interface
  466. //
  467. hr = CTDirObjUser::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  468. if (SUCCEEDED(hr))
  469. {
  470. LOG((MSP_TRACE, "CUser::GetIDsOfNames - found %S on CTDirObjUser", *rgszNames));
  471. rgdispid[0] |= IDISPDIROBJUSER;
  472. return hr;
  473. }
  474. //
  475. // If not, then try the CDirectoryObject base class
  476. //
  477. hr = CDirectoryObject::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  478. if (SUCCEEDED(hr))
  479. {
  480. LOG((MSP_TRACE, "CUser::GetIDsOfNames - found %S on CDirectoryObject", *rgszNames));
  481. rgdispid[0] |= IDISPDIROBJECT;
  482. return hr;
  483. }
  484. LOG((MSP_ERROR, "CUser::GetIDsOfNames[%p] - finish. didn't find %S on our iterfaces",*rgszNames));
  485. return hr;
  486. }
  487. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  488. //
  489. // CUser::Invoke
  490. //
  491. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  492. STDMETHODIMP CUser::Invoke(DISPID dispidMember,
  493. REFIID riid,
  494. LCID lcid,
  495. WORD wFlags,
  496. DISPPARAMS* pdispparams,
  497. VARIANT* pvarResult,
  498. EXCEPINFO* pexcepinfo,
  499. UINT* puArgErr
  500. )
  501. {
  502. LOG((MSP_TRACE, "CUser::Invoke[%p] - enter. dispidMember %lx",this, dispidMember));
  503. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  504. DWORD dwInterface = (dispidMember & INTERFACEMASK);
  505. //
  506. // Call invoke for the required interface
  507. //
  508. switch (dwInterface)
  509. {
  510. case IDISPDIROBJUSER:
  511. {
  512. hr = CTDirObjUser::Invoke(dispidMember,
  513. riid,
  514. lcid,
  515. wFlags,
  516. pdispparams,
  517. pvarResult,
  518. pexcepinfo,
  519. puArgErr
  520. );
  521. LOG((MSP_TRACE, "CUser::Invoke - ITDirectoryObjectUser"));
  522. break;
  523. }
  524. case IDISPDIROBJECT:
  525. {
  526. hr = CDirectoryObject::Invoke(dispidMember,
  527. riid,
  528. lcid,
  529. wFlags,
  530. pdispparams,
  531. pvarResult,
  532. pexcepinfo,
  533. puArgErr
  534. );
  535. LOG((MSP_TRACE, "CUser::Invoke - ITDirectoryObject"));
  536. break;
  537. }
  538. } // end switch (dwInterface)
  539. LOG((MSP_TRACE, "CUser::Invoke[%p] - finish. hr = %lx", hr));
  540. return hr;
  541. }