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.

980 lines
24 KiB

  1. // Util.cpp : Implementation of ds routines and classes
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. // Copyright (C) Microsoft Corporation, 1992 - 1999
  6. //
  7. // File: Util.cpp
  8. //
  9. // Contents: Utility functions
  10. //
  11. // History: 02-Oct-96 WayneSc Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "stdafx.h"
  16. #include "util.h"
  17. #include "sddl.h" // ConvertStringSecurityDescriptorToSecurityDescriptor
  18. #include "sddlp.h" // ConvertStringSDToSDDomain
  19. #include "ntsecapi.h" // LSA APIs
  20. #ifdef _DEBUG
  21. #define new DEBUG_NEW
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25. #define MAX_STRING 1024
  26. //+----------------------------------------------------------------------------
  27. //
  28. // Function: LoadStringToTchar
  29. //
  30. // Sysnopsis: Loads the given string into an allocated buffer that must be
  31. // caller freed using delete.
  32. //
  33. //-----------------------------------------------------------------------------
  34. BOOL LoadStringToTchar(int ids, PTSTR * pptstr)
  35. {
  36. TCHAR szBuf[MAX_STRING];
  37. if (!LoadString(_Module.GetModuleInstance(), ids, szBuf, MAX_STRING - 1))
  38. {
  39. return FALSE;
  40. }
  41. *pptstr = new TCHAR[_tcslen(szBuf) + 1];
  42. if (*pptstr == NULL)
  43. {
  44. return FALSE;
  45. };
  46. _tcscpy(*pptstr, szBuf);
  47. return TRUE;
  48. }
  49. //
  50. // These routines courtesy of Felix Wong -- JonN 2/24/98
  51. //
  52. // just guessing at what Felix meant by these -- JonN 2/24/98
  53. #define RRETURN(hr) { ASSERT( SUCCEEDED(hr) ); return hr; }
  54. #define BAIL_ON_FAILURE if ( FAILED(hr) ) { ASSERT(FALSE); goto error; }
  55. //////////////////////////////////////////////////////////////////////////
  56. // Variant Utilitites
  57. //
  58. HRESULT BinaryToVariant(DWORD Length,
  59. BYTE* pByte,
  60. VARIANT* lpVarDestObject)
  61. {
  62. HRESULT hr = S_OK;
  63. SAFEARRAY *aList = NULL;
  64. SAFEARRAYBOUND aBound;
  65. CHAR HUGEP *pArray = NULL;
  66. aBound.lLbound = 0;
  67. aBound.cElements = Length;
  68. aList = SafeArrayCreate( VT_UI1, 1, &aBound );
  69. if ( aList == NULL )
  70. {
  71. hr = E_OUTOFMEMORY;
  72. BAIL_ON_FAILURE(hr);
  73. }
  74. hr = SafeArrayAccessData( aList, (void HUGEP * FAR *) &pArray );
  75. BAIL_ON_FAILURE(hr);
  76. memcpy( pArray, pByte, aBound.cElements );
  77. SafeArrayUnaccessData( aList );
  78. V_VT(lpVarDestObject) = VT_ARRAY | VT_UI1;
  79. V_ARRAY(lpVarDestObject) = aList;
  80. RRETURN(hr);
  81. error:
  82. if ( aList )
  83. {
  84. SafeArrayDestroy( aList );
  85. }
  86. RRETURN(hr);
  87. }
  88. HRESULT HrVariantToStringList(const CComVariant& refvar,
  89. CStringList& refstringlist)
  90. {
  91. HRESULT hr = S_OK;
  92. long start, end, current;
  93. if (V_VT(&refvar) == VT_BSTR)
  94. {
  95. refstringlist.AddHead( V_BSTR(&refvar) );
  96. return S_OK;
  97. }
  98. //
  99. // Check the VARIANT to make sure we have
  100. // an array of variants.
  101. //
  102. if ( V_VT(&refvar) != ( VT_ARRAY | VT_VARIANT ) )
  103. {
  104. ASSERT(FALSE);
  105. return E_UNEXPECTED;
  106. }
  107. SAFEARRAY *saAttributes = V_ARRAY( &refvar );
  108. //
  109. // Figure out the dimensions of the array.
  110. //
  111. hr = SafeArrayGetLBound( saAttributes, 1, &start );
  112. if( FAILED(hr) )
  113. return hr;
  114. hr = SafeArrayGetUBound( saAttributes, 1, &end );
  115. if( FAILED(hr) )
  116. return hr;
  117. CComVariant SingleResult;
  118. //
  119. // Process the array elements.
  120. //
  121. for ( current = start; current <= end; current++)
  122. {
  123. hr = SafeArrayGetElement( saAttributes, &current, &SingleResult );
  124. if( FAILED(hr) )
  125. return hr;
  126. if ( V_VT(&SingleResult) != VT_BSTR )
  127. return E_UNEXPECTED;
  128. refstringlist.AddHead( V_BSTR(&SingleResult) );
  129. }
  130. return S_OK;
  131. } // VariantToStringList()
  132. HRESULT HrStringListToVariant(CComVariant& refvar,
  133. const CStringList& refstringlist)
  134. {
  135. HRESULT hr = S_OK;
  136. int cCount = (int)refstringlist.GetCount();
  137. SAFEARRAYBOUND rgsabound[1];
  138. rgsabound[0].lLbound = 0;
  139. rgsabound[0].cElements = cCount;
  140. SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
  141. if (NULL == psa)
  142. return E_OUTOFMEMORY;
  143. V_VT(&refvar) = VT_VARIANT|VT_ARRAY;
  144. V_ARRAY(&refvar) = psa;
  145. POSITION pos = refstringlist.GetHeadPosition();
  146. long i;
  147. for (i = 0; i < cCount, pos != NULL; i++)
  148. {
  149. CComVariant SingleResult; // declare inside loop. Otherwise, throws
  150. // exception in destructor if nothing added.
  151. V_VT(&SingleResult) = VT_BSTR;
  152. V_BSTR(&SingleResult) = T2BSTR((LPCTSTR)refstringlist.GetNext(pos));
  153. hr = SafeArrayPutElement(psa, &i, &SingleResult);
  154. if( FAILED(hr) )
  155. return hr;
  156. }
  157. if (i != cCount || pos != NULL)
  158. return E_UNEXPECTED;
  159. return hr;
  160. } // StringListToVariant()
  161. //////////////////////////////////////////////////////////
  162. // streaming helper functions
  163. HRESULT SaveStringHelper(LPCWSTR pwsz, IStream* pStm)
  164. {
  165. ASSERT(pStm);
  166. ULONG nBytesWritten;
  167. HRESULT hr;
  168. //
  169. // wcslen returns a size_t and to make that consoles work the same
  170. // on any platform we always convert to a DWORD
  171. //
  172. DWORD nLen = static_cast<DWORD>(wcslen(pwsz)+1); // WCHAR including NULL
  173. hr = pStm->Write((void*)&nLen, sizeof(DWORD),&nBytesWritten);
  174. ASSERT(nBytesWritten == sizeof(DWORD));
  175. if (FAILED(hr))
  176. return hr;
  177. hr = pStm->Write((void*)pwsz, sizeof(WCHAR)*nLen,&nBytesWritten);
  178. ASSERT(nBytesWritten == sizeof(WCHAR)*nLen);
  179. TRACE(_T("SaveStringHelper(<%s> nLen = %d\n"),pwsz,nLen);
  180. return hr;
  181. }
  182. HRESULT LoadStringHelper(CString& sz, IStream* pStm)
  183. {
  184. ASSERT(pStm);
  185. HRESULT hr;
  186. ULONG nBytesRead;
  187. DWORD nLen = 0;
  188. hr = pStm->Read((void*)&nLen,sizeof(DWORD), &nBytesRead);
  189. ASSERT(nBytesRead == sizeof(DWORD));
  190. if (FAILED(hr) || (nBytesRead != sizeof(DWORD)))
  191. return hr;
  192. // bound the read so that a malicious console file cannot consume all
  193. // the system memory (amount is arbitrary but should be large enough
  194. // for the stuff we are storing in the console file)
  195. nLen = min(nLen, MAX_PATH*2);
  196. hr = pStm->Read((void*)sz.GetBuffer(nLen),sizeof(WCHAR)*nLen, &nBytesRead);
  197. ASSERT(nBytesRead == sizeof(WCHAR)*nLen);
  198. sz.ReleaseBuffer();
  199. TRACE(_T("LoadStringHelper(<%s> nLen = %d\n"),(LPCTSTR)sz,nLen);
  200. return hr;
  201. }
  202. HRESULT SaveDWordHelper(IStream* pStm, DWORD dw)
  203. {
  204. ULONG nBytesWritten;
  205. HRESULT hr = pStm->Write((void*)&dw, sizeof(DWORD),&nBytesWritten);
  206. if (nBytesWritten < sizeof(DWORD))
  207. hr = STG_E_CANTSAVE;
  208. return hr;
  209. }
  210. HRESULT LoadDWordHelper(IStream* pStm, DWORD* pdw)
  211. {
  212. ULONG nBytesRead;
  213. HRESULT hr = pStm->Read((void*)pdw,sizeof(DWORD), &nBytesRead);
  214. ASSERT(nBytesRead == sizeof(DWORD));
  215. return hr;
  216. }
  217. void GetCurrentTimeStampMinusInterval(DWORD dwDays,
  218. LARGE_INTEGER* pLI)
  219. {
  220. ASSERT(pLI);
  221. FILETIME ftCurrent;
  222. GetSystemTimeAsFileTime(&ftCurrent);
  223. pLI->LowPart = ftCurrent.dwLowDateTime;
  224. pLI->HighPart = ftCurrent.dwHighDateTime;
  225. pLI->QuadPart -= ((((ULONGLONG)dwDays * 24) * 60) * 60) * 10000000;
  226. }
  227. /////////////////////////////////////////////////////////////////////
  228. // CCommandLineOptions
  229. //
  230. // helper function to parse a single command and match it with a given switch
  231. //
  232. BOOL _LoadCommandLineValue(IN LPCWSTR lpszSwitch,
  233. IN LPCWSTR lpszArg,
  234. OUT CString* pszValue)
  235. {
  236. ASSERT(lpszSwitch != NULL);
  237. ASSERT(lpszArg != NULL);
  238. int nSwitchLen = lstrlen(lpszSwitch); // not counting NULL
  239. // check if the arg is the one we look for
  240. if (_wcsnicmp(lpszSwitch, lpszArg, nSwitchLen) == 0)
  241. {
  242. // got it, copy the value
  243. if (pszValue != NULL)
  244. (*pszValue) = lpszArg+nSwitchLen;
  245. return TRUE;
  246. }
  247. // not found, empty string
  248. if (pszValue != NULL)
  249. pszValue->Empty();
  250. return FALSE;
  251. }
  252. void CCommandLineOptions::Initialize()
  253. {
  254. // command line overrides the snapin understands,
  255. // not subject to localization
  256. static LPCWSTR lpszOverrideDomainCommandLine = L"/Domain=";
  257. static LPCWSTR lpszOverrideServerCommandLine = L"/Server=";
  258. static LPCWSTR lpszOverrideRDNCommandLine = L"/RDN=";
  259. static LPCWSTR lpszOverrideSavedQueriesCommandLine = L"/Queries=";
  260. #ifdef DBG
  261. static LPCWSTR lpszOverrideNoNameCommandLine = L"/NoName";
  262. #endif
  263. // do it only once
  264. if (m_bInit)
  265. {
  266. return;
  267. }
  268. m_bInit = TRUE;
  269. //
  270. // see if we have command line arguments
  271. //
  272. LPCWSTR * lpServiceArgVectors; // Array of pointers to string
  273. int cArgs = 0; // Count of arguments
  274. lpServiceArgVectors = (LPCWSTR *)CommandLineToArgvW(GetCommandLineW(), OUT &cArgs);
  275. if (lpServiceArgVectors == NULL)
  276. {
  277. // none, just return
  278. return;
  279. }
  280. // loop and search for pertinent strings
  281. for (int i = 1; i < cArgs; i++)
  282. {
  283. ASSERT(lpServiceArgVectors[i] != NULL);
  284. TRACE (_T("command line arg: %s\n"), lpServiceArgVectors[i]);
  285. if (_LoadCommandLineValue(lpszOverrideDomainCommandLine,
  286. lpServiceArgVectors[i], &m_szOverrideDomainName))
  287. {
  288. continue;
  289. }
  290. if (_LoadCommandLineValue(lpszOverrideServerCommandLine,
  291. lpServiceArgVectors[i], &m_szOverrideServerName))
  292. {
  293. continue;
  294. }
  295. if (_LoadCommandLineValue(lpszOverrideRDNCommandLine,
  296. lpServiceArgVectors[i], &m_szOverrideRDN))
  297. {
  298. continue;
  299. }
  300. if (_LoadCommandLineValue(lpszOverrideSavedQueriesCommandLine,
  301. lpServiceArgVectors[i], &m_szSavedQueriesXMLFile))
  302. {
  303. continue;
  304. }
  305. #ifdef DBG
  306. if (_LoadCommandLineValue(lpszOverrideNoNameCommandLine,
  307. lpServiceArgVectors[i], NULL))
  308. {
  309. continue;
  310. }
  311. #endif
  312. }
  313. LocalFree(lpServiceArgVectors);
  314. }
  315. ////////////////////////////////////////////////////////////////
  316. // Type conversions for LARGE_INTEGERs
  317. void wtoli(LPCWSTR p, LARGE_INTEGER& liOut)
  318. {
  319. liOut.QuadPart = 0;
  320. BOOL bNeg = FALSE;
  321. if (*p == L'-')
  322. {
  323. bNeg = TRUE;
  324. p++;
  325. }
  326. while (*p != L'\0')
  327. {
  328. liOut.QuadPart = 10 * liOut.QuadPart + (*p-L'0');
  329. p++;
  330. }
  331. if (bNeg)
  332. {
  333. liOut.QuadPart *= -1;
  334. }
  335. }
  336. void litow(LARGE_INTEGER& li, CString& sResult)
  337. {
  338. LARGE_INTEGER n;
  339. n.QuadPart = li.QuadPart;
  340. if (n.QuadPart == 0)
  341. {
  342. sResult = L"0";
  343. }
  344. else
  345. {
  346. CString sNeg;
  347. sResult = L"";
  348. if (n.QuadPart < 0)
  349. {
  350. sNeg = CString(L'-');
  351. n.QuadPart *= -1;
  352. }
  353. while (n.QuadPart > 0)
  354. {
  355. sResult += CString(L'0' + static_cast<WCHAR>(n.QuadPart % 10));
  356. n.QuadPart = n.QuadPart / 10;
  357. }
  358. sResult = sResult + sNeg;
  359. }
  360. sResult.MakeReverse();
  361. }
  362. // This wrapper function required to make prefast shut up when we are
  363. // initializing a critical section in a constructor.
  364. void
  365. ExceptionPropagatingInitializeCriticalSection(LPCRITICAL_SECTION critsec)
  366. {
  367. __try
  368. {
  369. ::InitializeCriticalSection(critsec);
  370. }
  371. //
  372. // propagate the exception to our caller.
  373. //
  374. __except (EXCEPTION_CONTINUE_SEARCH)
  375. {
  376. }
  377. }
  378. /*******************************************************************
  379. NAME: GetLSAConnection
  380. SYNOPSIS: Wrapper for LsaOpenPolicy
  381. ENTRY: pszServer - the server on which to make the connection
  382. EXIT:
  383. RETURNS: LSA_HANDLE if successful, NULL otherwise
  384. NOTES:
  385. HISTORY:
  386. JeffreyS 08-Oct-1996 Created
  387. ********************************************************************/
  388. LSA_HANDLE
  389. GetLSAConnection(LPCTSTR pszServer, DWORD dwAccessDesired)
  390. {
  391. LSA_HANDLE hPolicy = NULL;
  392. LSA_UNICODE_STRING uszServer = {0};
  393. LSA_UNICODE_STRING *puszServer = NULL;
  394. LSA_OBJECT_ATTRIBUTES oa;
  395. SECURITY_QUALITY_OF_SERVICE sqos;
  396. sqos.Length = sizeof(sqos);
  397. sqos.ImpersonationLevel = SecurityImpersonation;
  398. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  399. sqos.EffectiveOnly = FALSE;
  400. InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);
  401. oa.SecurityQualityOfService = &sqos;
  402. if (pszServer &&
  403. *pszServer &&
  404. RtlCreateUnicodeString(&uszServer, pszServer))
  405. {
  406. puszServer = &uszServer;
  407. }
  408. LsaOpenPolicy(puszServer, &oa, dwAccessDesired, &hPolicy);
  409. if (puszServer)
  410. RtlFreeUnicodeString(puszServer);
  411. return hPolicy;
  412. }
  413. HRESULT
  414. GetDomainSid(LPCWSTR pszServer, PSID *ppSid)
  415. {
  416. HRESULT hr = S_OK;
  417. NTSTATUS nts = STATUS_SUCCESS;
  418. PPOLICY_ACCOUNT_DOMAIN_INFO pDomainInfo = NULL;
  419. if(!pszServer || !ppSid)
  420. return E_INVALIDARG;
  421. *ppSid = NULL;
  422. LSA_HANDLE hLSA = GetLSAConnection(pszServer, POLICY_VIEW_LOCAL_INFORMATION);
  423. if (!hLSA)
  424. {
  425. hr = E_FAIL;
  426. goto exit_gracefully;
  427. }
  428. nts = LsaQueryInformationPolicy(hLSA,
  429. PolicyAccountDomainInformation,
  430. (PVOID*)&pDomainInfo);
  431. if(nts != STATUS_SUCCESS)
  432. {
  433. hr = E_FAIL;
  434. goto exit_gracefully;
  435. }
  436. if (pDomainInfo && pDomainInfo->DomainSid)
  437. {
  438. ULONG cbSid = GetLengthSid(pDomainInfo->DomainSid);
  439. *ppSid = (PSID) LocalAlloc(LPTR, cbSid);
  440. if (!*ppSid)
  441. {
  442. hr = E_OUTOFMEMORY;
  443. goto exit_gracefully;
  444. }
  445. CopyMemory(*ppSid, pDomainInfo->DomainSid, cbSid);
  446. }
  447. exit_gracefully:
  448. if(pDomainInfo)
  449. LsaFreeMemory(pDomainInfo);
  450. if(hLSA)
  451. LsaClose(hLSA);
  452. return hr;
  453. }
  454. //
  455. // include and defines for ldap calls
  456. //
  457. #include <winldap.h>
  458. #include <ntldap.h>
  459. typedef LDAP * (LDAPAPI *PFN_LDAP_OPEN)( PWCHAR, ULONG );
  460. typedef ULONG (LDAPAPI *PFN_LDAP_UNBIND)( LDAP * );
  461. typedef ULONG (LDAPAPI *PFN_LDAP_SEARCH)(LDAP *, PWCHAR, ULONG, PWCHAR, PWCHAR *, ULONG,PLDAPControlA *, PLDAPControlA *, struct l_timeval *, ULONG, LDAPMessage **);
  462. typedef LDAPMessage * (LDAPAPI *PFN_LDAP_FIRST_ENTRY)( LDAP *, LDAPMessage * );
  463. typedef PWCHAR * (LDAPAPI *PFN_LDAP_GET_VALUE)(LDAP *, LDAPMessage *, PWCHAR );
  464. typedef ULONG (LDAPAPI *PFN_LDAP_MSGFREE)( LDAPMessage * );
  465. typedef ULONG (LDAPAPI *PFN_LDAP_VALUE_FREE)( PWCHAR * );
  466. typedef ULONG (LDAPAPI *PFN_LDAP_MAP_ERROR)( ULONG );
  467. HRESULT
  468. GetRootDomainSid(LPCWSTR pszServer, PSID *ppSid)
  469. {
  470. //
  471. // get root domain sid, save it in RootDomSidBuf (global)
  472. // this function is called within the critical section
  473. //
  474. // 1) ldap_open to the DC of interest.
  475. // 2) you do not need to ldap_connect - the following step works anonymously
  476. // 3) read the operational attribute rootDomainNamingContext and provide the
  477. // operational control LDAP_SERVER_EXTENDED_DN_OID as defined in sdk\inc\ntldap.h.
  478. DWORD Win32rc=NO_ERROR;
  479. HINSTANCE hLdapDll=NULL;
  480. PFN_LDAP_OPEN pfnLdapOpen=NULL;
  481. PFN_LDAP_UNBIND pfnLdapUnbind=NULL;
  482. PFN_LDAP_SEARCH pfnLdapSearch=NULL;
  483. PFN_LDAP_FIRST_ENTRY pfnLdapFirstEntry=NULL;
  484. PFN_LDAP_GET_VALUE pfnLdapGetValue=NULL;
  485. PFN_LDAP_MSGFREE pfnLdapMsgFree=NULL;
  486. PFN_LDAP_VALUE_FREE pfnLdapValueFree=NULL;
  487. PFN_LDAP_MAP_ERROR pfnLdapMapError=NULL;
  488. PLDAP phLdap=NULL;
  489. LDAPControlW serverControls =
  490. { LDAP_SERVER_EXTENDED_DN_OID_W,
  491. { 0, NULL },
  492. TRUE
  493. };
  494. LPWSTR Attribs[] = { LDAP_OPATT_ROOT_DOMAIN_NAMING_CONTEXT_W, NULL };
  495. PLDAPControlW rServerControls[] = { &serverControls, NULL };
  496. PLDAPMessage pMessage = NULL;
  497. LDAPMessage *pEntry = NULL;
  498. PWCHAR *ppszValues=NULL;
  499. LPWSTR pSidStart, pSidEnd, pParse;
  500. BYTE *pDest = NULL;
  501. BYTE OneByte;
  502. DWORD RootDomSidBuf[sizeof(SID)/sizeof(DWORD)+5];
  503. hLdapDll = LoadLibraryA("wldap32.dll");
  504. if ( hLdapDll)
  505. {
  506. pfnLdapOpen = (PFN_LDAP_OPEN)GetProcAddress(hLdapDll,
  507. "ldap_openW");
  508. pfnLdapUnbind = (PFN_LDAP_UNBIND)GetProcAddress(hLdapDll,
  509. "ldap_unbind");
  510. pfnLdapSearch = (PFN_LDAP_SEARCH)GetProcAddress(hLdapDll,
  511. "ldap_search_ext_sW");
  512. pfnLdapFirstEntry = (PFN_LDAP_FIRST_ENTRY)GetProcAddress(hLdapDll,
  513. "ldap_first_entry");
  514. pfnLdapGetValue = (PFN_LDAP_GET_VALUE)GetProcAddress(hLdapDll,
  515. "ldap_get_valuesW");
  516. pfnLdapMsgFree = (PFN_LDAP_MSGFREE)GetProcAddress(hLdapDll,
  517. "ldap_msgfree");
  518. pfnLdapValueFree = (PFN_LDAP_VALUE_FREE)GetProcAddress(hLdapDll,
  519. "ldap_value_freeW");
  520. pfnLdapMapError = (PFN_LDAP_MAP_ERROR)GetProcAddress(hLdapDll,
  521. "LdapMapErrorToWin32");
  522. }
  523. if ( pfnLdapOpen == NULL ||
  524. pfnLdapUnbind == NULL ||
  525. pfnLdapSearch == NULL ||
  526. pfnLdapFirstEntry == NULL ||
  527. pfnLdapGetValue == NULL ||
  528. pfnLdapMsgFree == NULL ||
  529. pfnLdapValueFree == NULL ||
  530. pfnLdapMapError == NULL )
  531. {
  532. Win32rc = ERROR_PROC_NOT_FOUND;
  533. }
  534. else
  535. {
  536. //
  537. // bind to ldap
  538. //
  539. phLdap = (*pfnLdapOpen)((PWCHAR)pszServer, LDAP_PORT);
  540. if ( phLdap == NULL )
  541. Win32rc = ERROR_FILE_NOT_FOUND;
  542. }
  543. if ( NO_ERROR == Win32rc )
  544. {
  545. //
  546. // now get the ldap handle,
  547. //
  548. Win32rc = (*pfnLdapSearch)(
  549. phLdap,
  550. L"",
  551. LDAP_SCOPE_BASE,
  552. L"(objectClass=*)",
  553. Attribs,
  554. 0,
  555. (PLDAPControlA *)&rServerControls,
  556. NULL,
  557. NULL,
  558. 10000,
  559. &pMessage);
  560. if( Win32rc == NO_ERROR && pMessage )
  561. {
  562. Win32rc = ERROR_SUCCESS;
  563. pEntry = (*pfnLdapFirstEntry)(phLdap, pMessage);
  564. if(pEntry == NULL)
  565. {
  566. Win32rc = (*pfnLdapMapError)( phLdap->ld_errno );
  567. }
  568. else
  569. {
  570. //
  571. // Now, we'll have to get the values
  572. //
  573. ppszValues = (*pfnLdapGetValue)(phLdap,
  574. pEntry,
  575. Attribs[0]);
  576. if( ppszValues == NULL)
  577. {
  578. Win32rc = (*pfnLdapMapError)( phLdap->ld_errno );
  579. }
  580. else if ( ppszValues[0] && ppszValues[0][0] != '\0' )
  581. {
  582. //
  583. // ppszValues[0] is the value to parse.
  584. // The data will be returned as something like:
  585. // <GUID=278676f8d753d211a61ad7e2dfa25f11>;<SID=010400000000000515000000828ba6289b0bc11e67c2ef7f>;DC=colinbrdom1,DC=nttest,DC=microsoft,DC=com
  586. // Parse through this to find the <SID=xxxxxx> part. Note that it may be missing, but the GUID= and trailer should not be.
  587. // The xxxxx represents the hex nibbles of the SID. Translate to the binary form and case to a SID.
  588. pSidStart = wcsstr(ppszValues[0], L"<SID=");
  589. if ( pSidStart )
  590. {
  591. //
  592. // find the end of this SID
  593. //
  594. pSidEnd = wcsstr(pSidStart, L">");
  595. if ( pSidEnd )
  596. {
  597. pParse = pSidStart + 5;
  598. pDest = (BYTE *)RootDomSidBuf;
  599. while ( pParse < pSidEnd-1 )
  600. {
  601. if ( *pParse >= '0' && *pParse <= '9' )
  602. {
  603. OneByte = (BYTE) ((*pParse - '0') * 16);
  604. }
  605. else
  606. {
  607. OneByte = (BYTE) ( (tolower(*pParse) - 'a' + 10) * 16 );
  608. }
  609. if ( *(pParse+1) >= '0' && *(pParse+1) <= '9' )
  610. {
  611. OneByte = OneByte + (BYTE) ( (*(pParse+1)) - '0' ) ;
  612. }
  613. else
  614. {
  615. OneByte = OneByte + (BYTE) ( tolower(*(pParse+1)) - 'a' + 10 ) ;
  616. }
  617. *pDest = OneByte;
  618. pDest++;
  619. pParse += 2;
  620. }
  621. ULONG cbSid = GetLengthSid((PSID)RootDomSidBuf);
  622. *ppSid = (PSID) LocalAlloc(LPTR, cbSid);
  623. if (!*ppSid)
  624. {
  625. Win32rc = ERROR_NOT_ENOUGH_MEMORY;
  626. }
  627. CopyMemory(*ppSid, (PSID)RootDomSidBuf, cbSid);
  628. ASSERT(IsValidSid(*ppSid));
  629. }
  630. else
  631. {
  632. Win32rc = ERROR_OBJECT_NOT_FOUND;
  633. }
  634. }
  635. else
  636. {
  637. Win32rc = ERROR_OBJECT_NOT_FOUND;
  638. }
  639. (*pfnLdapValueFree)(ppszValues);
  640. }
  641. else
  642. {
  643. Win32rc = ERROR_OBJECT_NOT_FOUND;
  644. }
  645. }
  646. (*pfnLdapMsgFree)(pMessage);
  647. }
  648. }
  649. //
  650. // even though it's not binded, use unbind to close
  651. //
  652. if ( phLdap != NULL && pfnLdapUnbind )
  653. (*pfnLdapUnbind)(phLdap);
  654. if ( hLdapDll )
  655. {
  656. FreeLibrary(hLdapDll);
  657. }
  658. return HRESULT_FROM_WIN32(Win32rc);
  659. }
  660. // If the server is non-NULL then this function will get the domain SID and the root
  661. // domain SID and call ConvertStringSDToSDDomain. If server is NULl then we will just
  662. // use ConvertStringSecurityDescriptorToSecurityDescriptor
  663. HRESULT CSimpleSecurityDescriptorHolder::InitializeFromSDDL(PCWSTR server, PWSTR pszSDDL)
  664. {
  665. if (!pszSDDL)
  666. {
  667. ASSERT(pszSDDL);
  668. return E_INVALIDARG;
  669. }
  670. HRESULT hr = S_OK;
  671. bool fallbackToStdConvert = true;
  672. PSID pDomainSID = 0;
  673. PSID pRootDomainSID = 0;
  674. do
  675. {
  676. if (!server)
  677. {
  678. break;
  679. }
  680. hr = GetDomainSid(server, &pDomainSID);
  681. if (FAILED(hr))
  682. {
  683. break;
  684. }
  685. hr = GetRootDomainSid(server, &pRootDomainSID);
  686. if (FAILED(hr))
  687. {
  688. break;
  689. }
  690. BOOL result =
  691. ConvertStringSDToSDDomain(
  692. pDomainSID,
  693. pRootDomainSID,
  694. pszSDDL,
  695. SDDL_REVISION_1,
  696. &m_pSD,
  697. 0);
  698. if (!result)
  699. {
  700. DWORD error = GetLastError();
  701. hr = HRESULT_FROM_WIN32(error);
  702. break;
  703. }
  704. fallbackToStdConvert = false;
  705. } while (false);
  706. if (fallbackToStdConvert)
  707. {
  708. BOOL result =
  709. ConvertStringSecurityDescriptorToSecurityDescriptor(
  710. pszSDDL,
  711. SDDL_REVISION_1,
  712. &m_pSD,
  713. 0);
  714. if (!result)
  715. {
  716. DWORD err = GetLastError();
  717. hr = HRESULT_FROM_WIN32(err);
  718. }
  719. }
  720. if (pDomainSID)
  721. {
  722. LocalFree(pDomainSID);
  723. }
  724. if (pRootDomainSID)
  725. {
  726. LocalFree(pRootDomainSID);
  727. }
  728. return hr;
  729. }
  730. HRESULT
  731. MyGetModuleFileName(
  732. HINSTANCE hInstance,
  733. CString& moduleName)
  734. {
  735. HRESULT hr = S_OK;
  736. WCHAR* szModule = 0;
  737. DWORD bufferSizeInCharacters = MAX_PATH;
  738. do
  739. {
  740. if (szModule)
  741. {
  742. delete[] szModule;
  743. szModule = 0;
  744. }
  745. szModule = new WCHAR[bufferSizeInCharacters + 1];
  746. if (!szModule)
  747. {
  748. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  749. break;
  750. }
  751. ZeroMemory(szModule, sizeof(WCHAR) * (bufferSizeInCharacters + 1));
  752. DWORD result =
  753. ::GetModuleFileName(
  754. hInstance,
  755. szModule,
  756. bufferSizeInCharacters);
  757. if (!result)
  758. {
  759. DWORD err = ::GetLastError();
  760. hr = HRESULT_FROM_WIN32(err);
  761. break;
  762. }
  763. if (result < bufferSizeInCharacters)
  764. {
  765. break;
  766. }
  767. // truncation occurred, grow the buffer and try again
  768. bufferSizeInCharacters *= 2;
  769. } while (bufferSizeInCharacters < USHRT_MAX);
  770. if (SUCCEEDED(hr))
  771. {
  772. moduleName = szModule;
  773. }
  774. if (szModule)
  775. {
  776. delete[] szModule;
  777. }
  778. return hr;
  779. }