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.

871 lines
20 KiB

  1. // Copyright (C) 1999 Microsoft Corporation
  2. //
  3. // Implementation of ICloneSecurityPrincipal
  4. //
  5. // sburns 5-10-99
  6. #include "headers.hxx"
  7. #include "resource.h"
  8. #include "implmain.hpp"
  9. #include "common.hpp"
  10. const size_t NUMBER_OF_AUTOMATION_INTERFACES = 3;
  11. CloneSecurityPrincipal::CloneSecurityPrincipal()
  12. :
  13. connection(0),
  14. refcount(1), // implicit AddRef
  15. m_pSID(NULL)
  16. {
  17. LOG_CTOR(CloneSecurityPrincipal);
  18. m_ppTypeInfo = new ITypeInfo*[NUMBER_OF_AUTOMATION_INTERFACES];
  19. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  20. {
  21. m_ppTypeInfo[i] = NULL;
  22. }
  23. ITypeLib *ptl = 0;
  24. HRESULT hr = LoadRegTypeLib(LIBID_CloneSecurityPrincipalLib, 1, 0, 0, &ptl);
  25. if (SUCCEEDED(hr))
  26. {
  27. ptl->GetTypeInfoOfGuid(IID_ICloneSecurityPrincipal, &(m_ppTypeInfo[0]));
  28. ptl->GetTypeInfoOfGuid(IID_IADsSID, &(m_ppTypeInfo[1]));
  29. ptl->GetTypeInfoOfGuid(IID_IADsError, &(m_ppTypeInfo[2]));
  30. ptl->Release();
  31. }
  32. }
  33. CloneSecurityPrincipal::~CloneSecurityPrincipal()
  34. {
  35. LOG_DTOR(CloneSecurityPrincipal);
  36. ASSERT(refcount == 0);
  37. delete connection;
  38. if ( m_pSID )
  39. FreeADsMem( m_pSID );
  40. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  41. {
  42. m_ppTypeInfo[i]->Release();
  43. }
  44. delete[] m_ppTypeInfo;
  45. }
  46. HRESULT __stdcall
  47. CloneSecurityPrincipal::QueryInterface(REFIID riid, void **ppv)
  48. {
  49. LOG_FUNCTION(CloneSecurityPrincipal::QueryInterface);
  50. if (riid == IID_IUnknown)
  51. {
  52. LOG(L"IUnknown");
  53. *ppv = (IUnknown*)(ICloneSecurityPrincipal*)(this);
  54. }
  55. else if (riid == IID_ICloneSecurityPrincipal)
  56. {
  57. LOG(L"ICloneSecurityPrincipal");
  58. *ppv = static_cast<ICloneSecurityPrincipal*>(this);
  59. }
  60. else if (riid == IID_IADsSID)
  61. {
  62. LOG(L"IADsSID");
  63. *ppv = static_cast<IADsSID*>(this);
  64. }
  65. else if (riid == IID_IADsError)
  66. {
  67. LOG(L"IADsError");
  68. *ppv = static_cast<IADsError*>(this);
  69. }
  70. else if (riid == IID_IDispatch && m_ppTypeInfo[0])
  71. {
  72. LOG(L"IDispatch");
  73. *ppv = (IDispatch*)(ICloneSecurityPrincipal*)(this);
  74. }
  75. else if (riid == IID_ISupportErrorInfo)
  76. {
  77. LOG(L"ISupportErrorInfo");
  78. *ppv = (ISupportErrorInfo*)(this);
  79. }
  80. else
  81. {
  82. LOG(L"unknown");
  83. return (*ppv = 0), E_NOINTERFACE;
  84. }
  85. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  86. return S_OK;
  87. }
  88. ULONG __stdcall
  89. CloneSecurityPrincipal::AddRef(void)
  90. {
  91. LOG_ADDREF(CloneSecurityPrincipal);
  92. return Win::InterlockedIncrement(refcount);
  93. }
  94. ULONG __stdcall
  95. CloneSecurityPrincipal::Release(void)
  96. {
  97. LOG_RELEASE(CloneSecurityPrincipal);
  98. // need to copy the result of the decrement, because if we delete this,
  99. // refcount will no longer be valid memory, and that might hose
  100. // multithreaded callers. NTRAID#NTBUG9-566901-2002/03/06-sburns
  101. long newref = Win::InterlockedDecrement(refcount);
  102. if (newref == 0)
  103. {
  104. delete this;
  105. return 0;
  106. }
  107. // we should not have decremented into negative values.
  108. ASSERT(newref > 0);
  109. return newref;
  110. }
  111. HRESULT __stdcall
  112. CloneSecurityPrincipal::GetTypeInfoCount(UINT *pcti)
  113. {
  114. LOG_FUNCTION(CloneSecurityPrincipal::GetTypeInfoCount);
  115. if (pcti == 0)
  116. {
  117. return E_POINTER;
  118. }
  119. *pcti = 1;
  120. return S_OK;
  121. }
  122. HRESULT __stdcall
  123. CloneSecurityPrincipal::GetTypeInfo(UINT cti, LCID, ITypeInfo **ppti)
  124. {
  125. LOG_FUNCTION(CloneSecurityPrincipal::GetTypeInfo);
  126. if (ppti == 0)
  127. {
  128. return E_POINTER;
  129. }
  130. if (cti != 0)
  131. {
  132. *ppti = 0;
  133. return DISP_E_BADINDEX;
  134. }
  135. (*ppti = m_ppTypeInfo[0])->AddRef();
  136. return S_OK;
  137. }
  138. HRESULT __stdcall
  139. CloneSecurityPrincipal::GetIDsOfNames(
  140. REFIID riid,
  141. OLECHAR **prgpsz,
  142. UINT cNames,
  143. LCID lcid,
  144. DISPID *prgids)
  145. {
  146. LOG_FUNCTION(CloneSecurityPrincipal::GetIDsOfNames);
  147. HRESULT hr = S_OK;
  148. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  149. {
  150. hr = (m_ppTypeInfo[i])->GetIDsOfNames(prgpsz, cNames, prgids);
  151. if (SUCCEEDED(hr) || DISP_E_UNKNOWNNAME != hr)
  152. break;
  153. }
  154. return hr;
  155. }
  156. HRESULT __stdcall
  157. CloneSecurityPrincipal::Invoke(
  158. DISPID id,
  159. REFIID riid,
  160. LCID lcid,
  161. WORD wFlags,
  162. DISPPARAMS *params,
  163. VARIANT *pVarResult,
  164. EXCEPINFO *pei,
  165. UINT *puArgErr)
  166. {
  167. LOG_FUNCTION(CloneSecurityPrincipal::Invoke);
  168. HRESULT hr = S_OK;
  169. IDispatch *pDispatch[NUMBER_OF_AUTOMATION_INTERFACES] =
  170. {
  171. (IDispatch*)(ICloneSecurityPrincipal *)(this),
  172. (IDispatch*)(IADsSID *)(this),
  173. (IDispatch*)(IADsError *)(this)
  174. };
  175. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  176. {
  177. hr = (m_ppTypeInfo[i])->Invoke(
  178. pDispatch[i],
  179. id,
  180. wFlags,
  181. params,
  182. pVarResult,
  183. pei,
  184. puArgErr);
  185. if (DISP_E_MEMBERNOTFOUND != hr)
  186. break;
  187. }
  188. return hr;
  189. }
  190. HRESULT __stdcall
  191. CloneSecurityPrincipal::InterfaceSupportsErrorInfo(const IID& iid)
  192. {
  193. LOG_FUNCTION(CloneSecurityPrincipal::InterfaceSupportsErrorInfo);
  194. if (iid == IID_ICloneSecurityPrincipal ||
  195. iid == IID_IADsSID ||
  196. iid == IID_IADsError)
  197. {
  198. return S_OK;
  199. }
  200. return S_FALSE;
  201. }
  202. HRESULT __stdcall
  203. CloneSecurityPrincipal::Connect(
  204. BSTR srcDC,
  205. BSTR srcDomain,
  206. BSTR dstDC,
  207. BSTR dstDomain)
  208. {
  209. LOG_FUNCTION(CloneSecurityPrincipal::Connect);
  210. delete connection;
  211. connection = new Connection();
  212. // Even though a null parameter is technically illegal (the types are
  213. // BSTR), we thoughtfully accomodate the inattentive C++ user which may
  214. // prefer to pass null pointers instead of empty BSTRs
  215. return connection->Connect(
  216. srcDC ? srcDC : L"",
  217. srcDomain ? srcDomain : L"",
  218. dstDC ? dstDC : L"",
  219. dstDomain ? dstDomain : L"");
  220. }
  221. HRESULT __stdcall
  222. CloneSecurityPrincipal::AddSidHistory(
  223. BSTR srcPrincipalSamName,
  224. BSTR dstPrincipalSamName,
  225. long flags)
  226. {
  227. LOG_FUNCTION(CloneSecurityPrincipal::AddSidHistory);
  228. // Even though a null parameter is technically illegal (the types are
  229. // BSTR), we thoughtfully accomodate the inattentive C++ user which may
  230. // prefer to pass null pointers instead of empty BSTRs
  231. return
  232. DoAddSidHistory(
  233. srcPrincipalSamName ? srcPrincipalSamName : L"",
  234. dstPrincipalSamName ? dstPrincipalSamName : L"",
  235. flags);
  236. }
  237. HRESULT __stdcall
  238. CloneSecurityPrincipal::CopyDownlevelUserProperties(
  239. BSTR srcSamName,
  240. BSTR dstSamName,
  241. long flags)
  242. {
  243. LOG_FUNCTION(CloneSecurityPrincipal::CopyDownlevelUserProperties);
  244. // Even though a null parameter is technically illegal (the types are
  245. // BSTR), we thoughtfully accomodate the inattentive C++ user which may
  246. // prefer to pass null pointers instead of empty BSTRs
  247. return
  248. DoCopyDownlevelUserProperties(
  249. srcSamName ? srcSamName : L"",
  250. dstSamName ? dstSamName : L"",
  251. flags);
  252. }
  253. //+-----------------------------------------------------------------------
  254. //
  255. // Function: CloneSecurityPrincipal::GetMembersSIDs
  256. //
  257. // Synopsis: retrieve the <sid=XXXX> of all members of dstGroupDN.
  258. //
  259. //------------------------------------------------------------------------
  260. #define ATTRIBUTE_MEMBER L"member"
  261. HRESULT __stdcall
  262. CloneSecurityPrincipal::GetMembersSIDs(
  263. BSTR dstGroupDN,
  264. VARIANT* pVal)
  265. {
  266. // init the OUT parameter to hold an array of variants
  267. VariantInit(pVal);
  268. pVal->vt = VT_ARRAY | VT_VARIANT ;
  269. HRESULT hr = S_OK;
  270. std::vector<BSTR> values;
  271. PLDAPMessage pMsg = 0;
  272. LPTSTR lpszAttrs[] = {ATTRIBUTE_MEMBER, 0};
  273. LDAPControl serverControls = {LDAP_SERVER_EXTENDED_DN_OID_W, {0, (PCHAR)NULL}, TRUE};
  274. PLDAPControl aServerControls[] = {&serverControls, NULL};
  275. PLDAP pldap = connection->m_pldap;
  276. do
  277. {
  278. // the ldap connection to dstDC should have already been established
  279. if (!pldap)
  280. {
  281. hr = E_UNEXPECTED;
  282. LOG(L"pldap is null!");
  283. SetComError(IDS_OBJECT_STATE_BAD);
  284. break;
  285. }
  286. hr =
  287. Win32ToHresult(
  288. ldap_search_ext_s(
  289. pldap,
  290. dstGroupDN,
  291. LDAP_SCOPE_BASE, // scope
  292. _T("(objectClass=group)"), // filter
  293. lpszAttrs, // attrs[]
  294. 0, // atrssonly
  295. (PLDAPControl*) aServerControls, // ServerControls
  296. NULL, // ClientControls
  297. 0, // no time limit
  298. 0, // no SizeLimit
  299. &pMsg));
  300. BREAK_ON_FAILED_HRESULT(hr);
  301. BSTR bstr = NULL;
  302. PTSTR pStart = NULL;
  303. PTSTR pEnd = NULL;
  304. PTSTR* ppValues = ldap_get_values(pldap, pMsg, ATTRIBUTE_MEMBER);
  305. if (!ppValues)
  306. {
  307. break;
  308. }
  309. PTSTR *p = ppValues;
  310. while(*p)
  311. {
  312. // *p is a string in the following format:
  313. // "<GUID=42e87199a88c854998dad04be4b8d29f>;<SID=0105000000
  314. // 00000515000000a23ca6557d03c651772c315d00040000>;CN=S-1-
  315. // 5-21-1436957858-1371931517-1563503735-1024,CN=Foreign
  316. // SecurityPrincipals,DC=linan,DC=nttest,DC=microsoft,DC=com"
  317. if ( (pStart = _tcsstr(*p, _T("<SID="))) &&
  318. (pEnd = _tcschr(pStart, _T('>'))) )
  319. {
  320. // retrieve <sid=XXXXX>, and add it to the vector
  321. if ( !(bstr = SysAllocStringLen(pStart, static_cast<UINT>(pEnd - pStart + 1))) )
  322. {
  323. hr = E_OUTOFMEMORY;
  324. SetComError(IDS_OUT_OF_MEMORY);
  325. break;
  326. }
  327. values.push_back(bstr);
  328. }
  329. p++;
  330. }
  331. ldap_value_free(ppValues);
  332. // SysAllocString may have failed and terminated the preceeding loop
  333. BREAK_ON_FAILED_HRESULT(hr);
  334. // populate the OUT parameter: the array of variants
  335. if (values.size() > 0)
  336. {
  337. SAFEARRAYBOUND bounds = {values.size(), 0};
  338. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, &bounds);
  339. VARIANT* varArray;
  340. SafeArrayAccessData(psa, (void**)&varArray);
  341. int i = 0;
  342. for (
  343. std::vector<BSTR>::iterator it = values.begin();
  344. it != values.end();
  345. ++it, ++i)
  346. {
  347. VariantInit(&(varArray[i]));
  348. varArray[i].vt = VT_BSTR;
  349. varArray[i].bstrVal = *it;
  350. }
  351. SafeArrayUnaccessData(psa);
  352. pVal->parray = psa;
  353. }
  354. }
  355. while (0);
  356. if (pMsg)
  357. {
  358. ldap_msgfree(pMsg);
  359. }
  360. if (FAILED(hr))
  361. {
  362. for (
  363. std::vector<BSTR>::iterator it = values.begin();
  364. it != values.end();
  365. ++it)
  366. {
  367. // REVIEWED-2002/03/25-sburns hiding BSTRs in an STL container
  368. // confuses prefast: *it really does refer to a BSTR -- see the
  369. // push_back call that populates the container.
  370. SysFreeString(*it);
  371. }
  372. }
  373. return hr;
  374. }
  375. /////////////////////////////////////////////////////////////////////////////
  376. // IADsSID methods
  377. HRESULT VariantToSID(VARIANT *pVar , PSID *ppSID );
  378. HRESULT ByteToHexString(LPBYTE pByte, DWORD dwLength, LPTSTR *ppRet);
  379. // only support ADS_SID_ACTIVE_DIRECTORY_PATH and ADS_SID_WINNT_PATH and ADS_SID_SDDL
  380. STDMETHODIMP CloneSecurityPrincipal::SetAs(long lFormat, VARIANT var)
  381. {
  382. LOG_FUNCTION(CloneSecurityPrincipal::SetAs);
  383. PSID pNew = NULL ;
  384. HRESULT hr = S_OK;
  385. //
  386. // performing the necessary indirection if the source is VT_BYREF
  387. //
  388. VARIANT varData;
  389. VariantInit(&varData);
  390. hr = VariantCopyInd(&varData, (LPVARIANT)&var);
  391. if (FAILED(hr))
  392. return hr;
  393. switch( lFormat )
  394. {
  395. case ADS_SID_ACTIVE_DIRECTORY_PATH:
  396. {
  397. if ( V_VT(&varData) != VT_BSTR )
  398. return E_INVALIDARG;
  399. IDirectoryObject *pDir;
  400. hr = ADsGetObject( V_BSTR(&varData), IID_IDirectoryObject, (void**) &pDir );
  401. if ( FAILED(hr) )
  402. return hr;
  403. ADS_ATTR_INFO *pAttrInfo=NULL;
  404. DWORD dwReturn;
  405. LPWSTR pAttrNames[]={L"objectSID" };
  406. DWORD dwNumAttr=sizeof(pAttrNames)/sizeof(LPWSTR);
  407. hr = pDir->GetObjectAttributes( pAttrNames,
  408. dwNumAttr,
  409. &pAttrInfo,
  410. &dwReturn );
  411. if ( SUCCEEDED(hr) )
  412. {
  413. pNew = (PSID) AllocADsMem( pAttrInfo->pADsValues->OctetString.dwLength );
  414. if (!pNew)
  415. hr = E_OUTOFMEMORY;
  416. else
  417. // REVIEWED-2002/03/06-sburns correct byte count passed.
  418. CopyMemory( pNew, pAttrInfo->pADsValues->OctetString.lpValue,
  419. pAttrInfo->pADsValues->OctetString.dwLength );
  420. FreeADsMem( pAttrInfo );
  421. }
  422. pDir->Release();
  423. }
  424. break;
  425. case ADS_SID_WINNT_PATH:
  426. {
  427. if ( V_VT(&varData) != VT_BSTR )
  428. return E_INVALIDARG;
  429. IADs *pADs;
  430. hr = ADsGetObject( V_BSTR(&varData), IID_IADs, (void**) &pADs );
  431. if ( FAILED(hr) )
  432. return hr;
  433. VARIANT var1;
  434. VariantInit(&var1);
  435. hr = pADs->Get(AutoBstr(L"objectSID"), &var1 );
  436. if ( SUCCEEDED(hr) )
  437. hr = VariantToSID( &var1, &pNew );
  438. pADs->Release();
  439. }
  440. break;
  441. case ADS_SID_SDDL:
  442. {
  443. if ( V_VT(&varData) != VT_BSTR )
  444. return E_INVALIDARG;
  445. LPCTSTR pszSID = V_BSTR(&varData);
  446. PSID pSID = NULL;
  447. if ( !ConvertStringSidToSid( pszSID, &pSID ) )
  448. {
  449. hr = HRESULT_FROM_WIN32(GetLastError());
  450. } else
  451. {
  452. DWORD dwLength = GetLengthSid(pSID);
  453. pNew = (PSID)AllocADsMem(dwLength);
  454. if (!pNew)
  455. hr = E_OUTOFMEMORY;
  456. else
  457. // REVIEWED-2002/03/06-sburns correct byte count passed.
  458. CopyMemory(pNew, pSID, dwLength);
  459. LocalFree(pSID);
  460. }
  461. }
  462. break;
  463. case ADS_SID_RAW:
  464. {
  465. // raw, meaning a variant (VT_ARRAY | VT_U1) containing the sid in the
  466. // same format as returned by the ObjectSid property.
  467. LOG(L"ADS_SID_RAW");
  468. if (V_VT(&varData) != (VT_ARRAY| VT_UI1))
  469. {
  470. return E_INVALIDARG;
  471. }
  472. hr = VariantToSID(&varData, &pNew);
  473. LOG_HRESULT(hr);
  474. break;
  475. }
  476. default:
  477. return E_INVALIDARG; // unrecognized flag.
  478. }
  479. if ( FAILED(hr) )
  480. return hr;
  481. if ( !pNew )
  482. return E_FAIL;
  483. if (!IsValidSid( pNew ) )
  484. {
  485. FreeADsMem( pNew );
  486. return E_FAIL;
  487. }
  488. if ( m_pSID )
  489. FreeADsMem( m_pSID );
  490. m_pSID = pNew;
  491. return hr;
  492. }
  493. // only support ADS_SID_SDDL and ADS_SID_HEXSTRING
  494. STDMETHODIMP CloneSecurityPrincipal::GetAs(long lFormat, VARIANT *pVar)
  495. {
  496. if ( !m_pSID )
  497. return E_INVALIDARG;
  498. HRESULT hr = S_OK;
  499. VariantClear(pVar);
  500. switch( lFormat )
  501. {
  502. case ADS_SID_HEXSTRING:
  503. {
  504. LPTSTR pStr;
  505. hr = ByteToHexString( (LPBYTE) m_pSID, GetLengthSid( m_pSID), &pStr );
  506. if ( SUCCEEDED(hr) )
  507. {
  508. V_VT( pVar ) = VT_BSTR;
  509. V_BSTR( pVar ) = SysAllocString(pStr);
  510. FreeADsMem( pStr );
  511. }
  512. }
  513. break;
  514. case ADS_SID_SDDL:
  515. {
  516. LPTSTR pszSID;
  517. if ( ConvertSidToStringSid( m_pSID, &pszSID ))
  518. {
  519. V_VT( pVar ) = VT_BSTR;
  520. V_BSTR( pVar ) = SysAllocString(pszSID);
  521. LocalFree( pszSID );
  522. } else
  523. hr = HRESULT_FROM_WIN32(GetLastError());
  524. }
  525. break;
  526. default:
  527. hr = E_INVALIDARG; // unrecognized flag.
  528. }
  529. return hr;
  530. }
  531. HRESULT VariantToSID(VARIANT *pVar , PSID *ppSID )
  532. {
  533. HRESULT hr = S_OK;
  534. SAFEARRAY *aList = NULL;
  535. CHAR HUGEP *pArray = NULL;
  536. DWORD dwLower, dwUpper, dwLength;
  537. hr = SafeArrayGetLBound(V_ARRAY(pVar),
  538. 1,
  539. (long FAR *) &dwLower );
  540. hr = SafeArrayGetUBound(V_ARRAY(pVar),
  541. 1,
  542. (long FAR *) &dwUpper );
  543. dwLength = dwUpper - dwLower;
  544. *ppSID = (PSID) AllocADsMem( dwLength + 1);
  545. aList = V_ARRAY( pVar );
  546. if ( aList == NULL )
  547. return E_UNEXPECTED;
  548. hr = SafeArrayAccessData( aList, (void HUGEP * FAR *) &pArray );
  549. if ( !SUCCEEDED(hr) )
  550. return hr;
  551. // REVIEWED-2002/03/06-sburns correct byte count passed
  552. CopyMemory( *ppSID, pArray, dwLength );
  553. SafeArrayUnaccessData( aList );
  554. if (!IsValidSid(*ppSID) )
  555. return E_FAIL;
  556. return hr;
  557. }
  558. HRESULT ByteToHexString( LPBYTE pByte, DWORD dwLength, LPTSTR *ppRet )
  559. {
  560. LPTSTR pDest=NULL;
  561. LPTSTR pHead=NULL;
  562. pDest = pHead = (LPTSTR) AllocADsMem( ((dwLength+1)*2) * sizeof(TCHAR));
  563. if( pHead == NULL )
  564. return E_OUTOFMEMORY;
  565. //////////////////////////////////
  566. // Convert into the Hex String
  567. //////////////////////////////////
  568. for (DWORD idx=0; idx < dwLength; idx++, pDest+=2, pByte++ )
  569. {
  570. // REVIEWED-2002/03/06-sburns should consider strsafe function, but
  571. // pDest is correct length and null terminated.
  572. wsprintf(pDest, _T("%02X"), *pByte );
  573. }
  574. *ppRet = pHead;
  575. return S_OK;
  576. }
  577. /////////////////////////////////////////////////////////////////////////////
  578. // IADsError methods
  579. HRESULT
  580. GetMessageHelper(
  581. OUT BSTR *pbstr,
  582. IN HRESULT hrErr,
  583. IN DWORD dwFlags,
  584. IN HINSTANCE hMsgDll = NULL
  585. );
  586. #define FACILITY_ADSI 0x00005000
  587. String
  588. GetErrorMessageADSIExtended(HRESULT hr)
  589. {
  590. LOG_FUNCTION2(GetErrorMessageADSIExtended, String::format("%1!08X!", hr));
  591. if (!FAILED(hr))
  592. {
  593. // no messages for success!
  594. return String();
  595. }
  596. String errmsg = GetErrorMessage(hr);
  597. if ((hr & FACILITY_ADSI) || //adsi
  598. HRESULT_FACILITY(hr) == FACILITY_WIN32 ) // and win32
  599. {
  600. WCHAR szBuffer[MAX_PATH];
  601. WCHAR szName[MAX_PATH];
  602. DWORD dwError;
  603. HRESULT hrEx = ADsGetLastError( &dwError, szBuffer, (sizeof(szBuffer)/sizeof(WCHAR))-1,
  604. szName, (sizeof(szName)/sizeof(WCHAR))-1 );
  605. if ( SUCCEEDED(hrEx) && dwError != ERROR_INVALID_DATA && wcslen(szBuffer))
  606. {
  607. String errmsgextended;
  608. errmsgextended = String::format(IDS_ADSI_EXTENDED_ERROR, errmsg.c_str(), szName, szBuffer);
  609. return errmsgextended;
  610. }
  611. }
  612. return errmsg;
  613. }
  614. HRESULT __stdcall
  615. CloneSecurityPrincipal::GetErrorMsg(
  616. long hrErr,
  617. BSTR* pbstrMsg)
  618. {
  619. String s = GetErrorMessageADSIExtended(hrErr);
  620. *pbstrMsg = SysAllocString(const_cast<String::value_type*>(s.c_str()));
  621. if (!*pbstrMsg)
  622. return E_OUTOFMEMORY;
  623. return S_OK;
  624. }
  625. //
  626. // S_OK: found and returned in pbstr
  627. // S_FALSE: message not found
  628. // hr: some error happened
  629. //
  630. HRESULT
  631. GetMessageHelper(
  632. OUT BSTR *pbstr,
  633. IN HRESULT hrErr,
  634. IN DWORD dwFlags,
  635. IN HINSTANCE hMsgDll
  636. )
  637. {
  638. *pbstr = NULL;
  639. LPTSTR lpBuffer = NULL;
  640. DWORD dwRet =
  641. FormatMessage(
  642. FORMAT_MESSAGE_ALLOCATE_BUFFER | dwFlags,
  643. (LPCVOID) hMsgDll,
  644. hrErr,
  645. 0,
  646. (LPTSTR) &lpBuffer,
  647. 0,
  648. NULL);
  649. if ( !dwRet )
  650. {
  651. DWORD dwErr = GetLastError();
  652. if (ERROR_MR_MID_NOT_FOUND == dwErr)
  653. return S_FALSE;
  654. else
  655. return HRESULT_FROM_WIN32(dwErr);
  656. }
  657. *pbstr = SysAllocString(lpBuffer);
  658. LocalFree(lpBuffer);
  659. if (!*pbstr)
  660. return E_OUTOFMEMORY;
  661. return S_OK;
  662. }