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.

2772 lines
60 KiB

  1. #include "winnt.hxx"
  2. #pragma hdrstop
  3. HRESULT
  4. ConvertSafeArrayToVariantArray(
  5. VARIANT varSafeArray,
  6. PVARIANT * ppVarArray,
  7. PDWORD pdwNumVariants
  8. );
  9. HRESULT
  10. ConvertByRefSafeArrayToVariantArray(
  11. VARIANT varSafeArray,
  12. PVARIANT * ppVarArray,
  13. PDWORD pdwNumVariants
  14. );
  15. HRESULT
  16. CreatePropEntry(
  17. LPWSTR szPropName,
  18. ADSTYPE dwADsType,
  19. VARIANT varData,
  20. REFIID riid,
  21. LPVOID * ppDispatch
  22. );
  23. FILTERS Filters[] = {
  24. {L"user", WINNT_USER_ID},
  25. {L"group", WINNT_GROUP_ID}, // for backward compatibility
  26. {L"localgroup", WINNT_LOCALGROUP_ID},
  27. {L"globalgroup", WINNT_GLOBALGROUP_ID},
  28. {L"printqueue", WINNT_PRINTER_ID},
  29. {L"domain", WINNT_DOMAIN_ID},
  30. {L"computer", WINNT_COMPUTER_ID},
  31. {L"service", WINNT_SERVICE_ID},
  32. {L"fileshare", WINNT_FILESHARE_ID},
  33. {L"schema", WINNT_SCHEMA_ID},
  34. {L"class", WINNT_CLASS_ID},
  35. {L"syntax", WINNT_SYNTAX_ID},
  36. {L"property", WINNT_PROPERTY_ID},
  37. {L"FPNWfileshare", WINNT_FPNW_FILESHARE_ID}
  38. };
  39. #define MAX_FILTERS (sizeof(Filters)/sizeof(FILTERS))
  40. PFILTERS gpFilters = Filters;
  41. DWORD gdwMaxFilters = MAX_FILTERS;
  42. extern WCHAR * szProviderName;
  43. //+------------------------------------------------------------------------
  44. //
  45. // Class: Common
  46. //
  47. // Purpose: Contains Winnt routines and properties that are common to
  48. // all Winnt objects. Winnt objects get the routines and
  49. // properties through C++ inheritance.
  50. //
  51. //-------------------------------------------------------------------------
  52. HRESULT
  53. BuildADsPath(
  54. LPWSTR Parent,
  55. LPWSTR Name,
  56. LPWSTR *pADsPath
  57. )
  58. {
  59. WCHAR ADsPath[MAX_PATH];
  60. WCHAR ProviderName[MAX_PATH];
  61. HRESULT hr = S_OK;
  62. LPWSTR pszDisplayName = NULL;
  63. //
  64. // We will assert if bad parameters are passed to us.
  65. // This is because this should never be the case. This
  66. // is an internal call
  67. //
  68. ADsAssert(Parent && Name);
  69. ADsAssert(pADsPath);
  70. hr = GetDisplayName(
  71. Name,
  72. &pszDisplayName
  73. );
  74. BAIL_ON_FAILURE(hr);
  75. if (!pszDisplayName || !*pszDisplayName) {
  76. //
  77. // The display name has to be valid.
  78. //
  79. BAIL_ON_FAILURE(hr = E_FAIL);
  80. }
  81. //
  82. // Special case the Namespace object; if
  83. // the parent is L"ADs:", then Name = ADsPath
  84. //
  85. if (!_wcsicmp(Parent, L"ADs:")) {
  86. *pADsPath = AllocADsStr(pszDisplayName);
  87. if (*pADsPath == NULL) {
  88. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  89. }
  90. else {
  91. hr = S_OK;
  92. goto cleanup;
  93. }
  94. }
  95. //
  96. // Make sure that the buffer will be large enough.
  97. // MAX_PATH - 3 is used because we use one character for the NULL terminator
  98. // and at the most, 2 slashes in the middle of the string
  99. //
  100. if ((wcslen(pszDisplayName) + wcslen(Parent)) > MAX_PATH - 3)
  101. {
  102. BAIL_ON_FAILURE(hr = E_FAIL);
  103. }
  104. //
  105. // The rest of the cases we expect valid data,
  106. // Path, Parent and Name are read-only, the end-user
  107. // cannot modify this data
  108. //
  109. //
  110. // For the first object, the domain object we do not add
  111. // the first backslash; so we examine that the parent is
  112. // L"WinNT:" and skip the slash otherwise we start with
  113. // the slash
  114. //
  115. wsprintf(ProviderName, L"%s:", szProviderName);
  116. wcscpy(ADsPath, Parent);
  117. if (_wcsicmp(ADsPath, ProviderName)) {
  118. wcscat(ADsPath, L"/");
  119. }else {
  120. wcscat(ADsPath, L"//");
  121. }
  122. wcscat(ADsPath, pszDisplayName);
  123. *pADsPath = AllocADsStr(ADsPath);
  124. if (*pADsPath == NULL)
  125. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  126. cleanup:
  127. error:
  128. if (pszDisplayName) {
  129. FreeADsMem(pszDisplayName);
  130. }
  131. RRETURN(hr);
  132. }
  133. HRESULT
  134. BuildSchemaPath(
  135. LPWSTR Parent,
  136. LPWSTR Name,
  137. LPWSTR Schema,
  138. LPWSTR *pSchemaPath
  139. )
  140. {
  141. WCHAR SchemaPath[MAX_PATH];
  142. WCHAR ProviderName[MAX_PATH];
  143. HRESULT hr = S_OK;
  144. OBJECTINFO ObjectInfo;
  145. POBJECTINFO pObjectInfo = &ObjectInfo;
  146. CLexer Lexer(Parent);
  147. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  148. //
  149. // We will assert if bad parameters are passed to us.
  150. // This is because this should never be the case. This
  151. // is an internal call
  152. //
  153. ADsAssert(Parent);
  154. ADsAssert(pSchemaPath);
  155. //
  156. // If no schema name is passed in, then there is no schema path
  157. //
  158. if ( Schema == NULL || *Schema == 0 ){
  159. *pSchemaPath = AllocADsStr(L"");
  160. RRETURN(*pSchemaPath ? S_OK: E_OUTOFMEMORY );
  161. }
  162. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  163. hr = Object(&Lexer, pObjectInfo);
  164. BAIL_ON_FAILURE(hr);
  165. wsprintf(SchemaPath, L"%s://", szProviderName);
  166. if (!pObjectInfo->NumComponents) {
  167. if( (wcslen(Name) + wcslen(szProviderName) + 4) > MAX_PATH ) {
  168. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  169. }
  170. wcscat(SchemaPath, Name);
  171. }else{
  172. if( (wcslen(pObjectInfo->DisplayComponentArray[0]) +
  173. wcslen(szProviderName) + 4) > MAX_PATH ) {
  174. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  175. }
  176. wcscat(SchemaPath, pObjectInfo->DisplayComponentArray[0]);
  177. }
  178. if( (wcslen(SchemaPath) + wcslen(SCHEMA_NAME) + wcslen(Schema) + 3) >
  179. MAX_PATH ) {
  180. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  181. }
  182. wcscat( SchemaPath, L"/");
  183. wcscat( SchemaPath, SCHEMA_NAME );
  184. wcscat( SchemaPath, L"/");
  185. wcscat( SchemaPath, Schema );
  186. *pSchemaPath = AllocADsStr(SchemaPath);
  187. hr = pSchemaPath ? S_OK: E_OUTOFMEMORY ;
  188. error:
  189. FreeObjectInfo( &ObjectInfo, TRUE );
  190. RRETURN(hr);
  191. }
  192. HRESULT
  193. BuildADsGuid(
  194. REFCLSID clsid,
  195. LPWSTR *pADsClass
  196. )
  197. {
  198. WCHAR ADsClass[MAX_PATH];
  199. if (!StringFromGUID2(clsid, ADsClass, MAX_PATH)) {
  200. //
  201. // MAX_PATH should be more than enough for the GUID.
  202. //
  203. ADsAssert(!"GUID too big !!!");
  204. RRETURN(E_FAIL);
  205. }
  206. *pADsClass = AllocADsStr(ADsClass);
  207. RRETURN (*pADsClass ? S_OK: E_OUTOFMEMORY);
  208. }
  209. HRESULT
  210. MakeUncName(
  211. LPWSTR szSrcBuffer,
  212. LPWSTR szTargBuffer
  213. )
  214. {
  215. //
  216. // The szTargBuffer MUST be at least MAX_PATH characters in length
  217. //
  218. ADsAssert(szSrcBuffer);
  219. ADsAssert(szTargBuffer);
  220. if (!szSrcBuffer || !szTargBuffer)
  221. {
  222. RRETURN(E_ADS_BAD_PARAMETER);
  223. }
  224. wcscpy(szTargBuffer, L"\\\\");
  225. //
  226. // Only concatenate up to the size of the (buffer - 3)
  227. // (for the 2 slashes plus the null terminator)
  228. //
  229. wcsncat(szTargBuffer, szSrcBuffer, MAX_PATH - 3);
  230. //
  231. // If the string was truncated, return it anyway, but indicate that
  232. // an error occurred.
  233. //
  234. if (wcslen(szSrcBuffer) > MAX_PATH - 3)
  235. {
  236. RRETURN(E_ADS_BAD_PARAMETER);
  237. }
  238. RRETURN(S_OK);
  239. }
  240. HRESULT
  241. ValidateOutParameter(
  242. BSTR * retval
  243. )
  244. {
  245. if (!retval) {
  246. RRETURN(E_ADS_BAD_PARAMETER);
  247. }
  248. RRETURN(S_OK);
  249. }
  250. HRESULT
  251. BuildObjectInfo(
  252. LPWSTR ADsParent,
  253. LPWSTR Name,
  254. POBJECTINFO * ppObjectInfo
  255. )
  256. {
  257. WCHAR szBuffer[MAX_PATH];
  258. HRESULT hr;
  259. POBJECTINFO pObjectInfo = NULL;
  260. //
  261. // Both should be set in this call, cannot have a NULL parent.
  262. //
  263. if (!ADsParent || !*ADsParent) {
  264. RRETURN(E_ADS_BAD_PARAMETER);
  265. }
  266. //
  267. // We need to make sure that the path is not greater
  268. // than MAX_PATH + 2 = 1 for / and another for \0
  269. //
  270. if ((wcslen(ADsParent) + wcslen(Name) + 2) > MAX_PATH) {
  271. RRETURN(E_ADS_BAD_PARAMETER);
  272. }
  273. wcscpy(szBuffer, ADsParent);
  274. wcscat(szBuffer, L"/");
  275. wcscat(szBuffer, Name);
  276. CLexer Lexer(szBuffer);
  277. pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
  278. if (!pObjectInfo) {
  279. hr = E_OUTOFMEMORY;
  280. BAIL_ON_FAILURE(hr);
  281. }
  282. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  283. hr = Object(&Lexer, pObjectInfo);
  284. BAIL_ON_FAILURE(hr);
  285. *ppObjectInfo = pObjectInfo;
  286. RRETURN(hr);
  287. error:
  288. if (pObjectInfo) {
  289. FreeObjectInfo(pObjectInfo);
  290. }
  291. *ppObjectInfo = NULL;
  292. RRETURN(hr);
  293. }
  294. HRESULT
  295. BuildObjectInfo(
  296. LPWSTR ADsPath,
  297. POBJECTINFO * ppObjectInfo
  298. )
  299. {
  300. HRESULT hr;
  301. POBJECTINFO pObjectInfo = NULL;
  302. CLexer Lexer(ADsPath);
  303. pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
  304. if (!pObjectInfo) {
  305. hr = E_OUTOFMEMORY;
  306. BAIL_ON_FAILURE(hr);
  307. }
  308. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  309. hr = Object(&Lexer, pObjectInfo);
  310. BAIL_ON_FAILURE(hr);
  311. *ppObjectInfo = pObjectInfo;
  312. RRETURN(hr);
  313. error:
  314. if (pObjectInfo) {
  315. FreeObjectInfo(pObjectInfo);
  316. }
  317. *ppObjectInfo = NULL;
  318. RRETURN(hr);
  319. }
  320. HRESULT
  321. MakeWinNTAccountName(
  322. POBJECTINFO pObjectInfo,
  323. LPWSTR szUserAccount,
  324. BOOL fConnectToReg
  325. )
  326. {
  327. HRESULT hr = S_OK;
  328. DWORD dwNumComp = 0;
  329. DWORD dwProductType = PRODTYPE_INVALID;
  330. WCHAR szDomain[MAX_PATH];
  331. WCHAR szSAMName[MAX_ADS_PATH];
  332. BOOL fReplacedWithDC = FALSE;
  333. // The credentials are needed to pass into WinNTGetCachedComputerName
  334. CWinNTCredentials nullCredentials;
  335. if (!pObjectInfo || !szUserAccount)
  336. {
  337. RRETURN(E_ADS_BAD_PARAMETER);
  338. }
  339. // Need szSAMName as dummy param
  340. szSAMName[0] = szUserAccount[0] = L'\0';
  341. dwNumComp = pObjectInfo->NumComponents;
  342. switch (dwNumComp) {
  343. case 2:
  344. case 3:
  345. //
  346. // Check if machine is a dc
  347. //
  348. //
  349. // Going to try getComputerName first as the NetWkstaGetInfo call
  350. // times out faster than the RegConnect call we use in
  351. // GetMachineProductType - AjayR 11-06-98.
  352. //
  353. if (fConnectToReg) {
  354. if (dwNumComp==2) {
  355. //
  356. // we don't have domain name in pObjectInfo, let's try
  357. // to get it from the dc name (comp[0])
  358. //
  359. hr = WinNTGetCachedComputerName(
  360. pObjectInfo->ComponentArray[0],
  361. szUserAccount,
  362. szSAMName,
  363. nullCredentials
  364. );
  365. if (SUCCEEDED(hr))
  366. {
  367. fReplacedWithDC = TRUE;
  368. }
  369. }
  370. else // dwNumComp==3
  371. {
  372. //
  373. // We have domain name (comp[0]) in our objectInfo, let's use
  374. // it. Can call ValidateComputerName here, but not needed
  375. // since error will be caught next.
  376. //
  377. wcscpy(szUserAccount, pObjectInfo->ComponentArray[0]);
  378. fReplacedWithDC = TRUE;
  379. }
  380. if (fReplacedWithDC) {
  381. //
  382. // Now try connecting to make sure it is a DC
  383. // otherwise we should not do this replacement
  384. //
  385. hr = GetMachineProductType(
  386. pObjectInfo->ComponentArray[dwNumComp-2],
  387. &dwProductType
  388. );
  389. BAIL_ON_FAILURE(hr);
  390. if (dwProductType != PRODTYPE_DC) {
  391. //
  392. // We cannot use szUserAccount as it has
  393. // bad info
  394. //
  395. fReplacedWithDC = FALSE;
  396. hr = E_FAIL;
  397. }
  398. }
  399. }// if fConnectToReg
  400. BAIL_ON_FAILURE(hr);
  401. //
  402. // Do not want to replace machine name with domain since not dc or
  403. // dc but can't replace - best efforts fail
  404. //
  405. if (fReplacedWithDC==FALSE)
  406. {
  407. wcscpy(szUserAccount, pObjectInfo->ComponentArray[dwNumComp-2]);
  408. }
  409. //
  410. // Add \UserName to account name
  411. //
  412. wcscat(szUserAccount, L"\\");
  413. wcscat(szUserAccount, pObjectInfo->ComponentArray[dwNumComp-1]);
  414. break;
  415. default:
  416. RRETURN(E_ADS_UNKNOWN_OBJECT);
  417. }
  418. error:
  419. RRETURN(hr);
  420. }
  421. HRESULT
  422. MakeWinNTDomainAndName(
  423. POBJECTINFO pObjectInfo,
  424. LPWSTR szDomName
  425. )
  426. {
  427. DWORD dwNumComp = pObjectInfo->NumComponents;
  428. switch (dwNumComp) {
  429. case 2:
  430. case 3:
  431. wcscpy(szDomName, pObjectInfo->ComponentArray[dwNumComp - 2]);
  432. wcscat(szDomName, L"\\");
  433. wcscat(szDomName, pObjectInfo->ComponentArray[dwNumComp - 1]);
  434. break;
  435. default:
  436. RRETURN(E_ADS_UNKNOWN_OBJECT);
  437. }
  438. RRETURN(S_OK);
  439. }
  440. HRESULT
  441. ValidateObject(
  442. DWORD dwObjectType,
  443. POBJECTINFO pObjectInfo,
  444. CWinNTCredentials& Credentials
  445. )
  446. {
  447. ULONG uGroupType;
  448. DWORD dwParentId;
  449. switch (dwObjectType) {
  450. case WINNT_USER_ID:
  451. RRETURN(ValidateUserObject(pObjectInfo, &dwParentId, Credentials));
  452. case WINNT_GROUP_ID:
  453. RRETURN(ValidateGroupObject(
  454. pObjectInfo,
  455. &uGroupType,
  456. &dwParentId,
  457. Credentials
  458. ));
  459. case WINNT_COMPUTER_ID:
  460. RRETURN(ValidateComputerObject(pObjectInfo, Credentials));
  461. case WINNT_PRINTER_ID:
  462. RRETURN(ValidatePrinterObject(pObjectInfo, Credentials));
  463. case WINNT_SERVICE_ID:
  464. RRETURN(ValidateServiceObject(pObjectInfo, Credentials));
  465. case WINNT_FILESHARE_ID:
  466. RRETURN(ValidateFileShareObject(pObjectInfo, Credentials));
  467. default:
  468. RRETURN(E_FAIL);
  469. }
  470. }
  471. VOID
  472. FreeObjectInfo(
  473. POBJECTINFO pObjectInfo,
  474. BOOL fStatic
  475. )
  476. {
  477. DWORD i = 0;
  478. if (!pObjectInfo) {
  479. return;
  480. }
  481. FreeADsStr( pObjectInfo->ProviderName );
  482. for (i = 0; i < pObjectInfo->NumComponents; i++ ) {
  483. FreeADsStr(pObjectInfo->ComponentArray[i]);
  484. FreeADsStr(pObjectInfo->DisplayComponentArray[i]);
  485. }
  486. if ( !fStatic )
  487. FreeADsMem(pObjectInfo);
  488. }
  489. HRESULT
  490. CopyObjectInfo(
  491. POBJECTINFO pSrcObjectInfo,
  492. POBJECTINFO *pTargObjectInfo
  493. )
  494. {
  495. POBJECTINFO pObjectInfo = NULL;
  496. HRESULT hr S_OK;
  497. DWORD i;
  498. if(!pSrcObjectInfo){
  499. RRETURN(S_OK);
  500. }
  501. pObjectInfo = (POBJECTINFO)AllocADsMem(sizeof(OBJECTINFO));
  502. if (!pObjectInfo) {
  503. hr = E_OUTOFMEMORY;
  504. BAIL_ON_FAILURE(hr);
  505. }
  506. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  507. pObjectInfo->ObjectType = pSrcObjectInfo->ObjectType;
  508. pObjectInfo->NumComponents = pSrcObjectInfo->NumComponents;
  509. pObjectInfo->ProviderName = AllocADsStr(pSrcObjectInfo->ProviderName);
  510. for(i=0; i<pSrcObjectInfo->NumComponents; i++){
  511. pObjectInfo->ComponentArray[i] =
  512. AllocADsStr(pSrcObjectInfo->ComponentArray[i]);
  513. pObjectInfo->DisplayComponentArray[i] =
  514. AllocADsStr(pSrcObjectInfo->DisplayComponentArray[i]);
  515. }
  516. *pTargObjectInfo = pObjectInfo;
  517. RRETURN(hr);
  518. error:
  519. RRETURN(hr);
  520. }
  521. HRESULT
  522. GetObjectType(
  523. PFILTERS pFilters,
  524. DWORD dwMaxFilters,
  525. LPWSTR ClassName,
  526. PDWORD pdwObjectType
  527. )
  528. {
  529. DWORD i = 0;
  530. ADsAssert(pdwObjectType);
  531. for (i = 0; i < dwMaxFilters; i++) {
  532. if (!_wcsicmp(ClassName, (pFilters + i)->szObjectName)) {
  533. *pdwObjectType = (pFilters + i)->dwFilterId;
  534. RRETURN(S_OK);
  535. }
  536. }
  537. *pdwObjectType = 0;
  538. RRETURN(E_INVALIDARG);
  539. }
  540. HRESULT
  541. ValidateProvider(
  542. POBJECTINFO pObjectInfo
  543. )
  544. {
  545. //
  546. // The provider name is case-sensitive. This is a restriction that OLE
  547. // has put on us.
  548. //
  549. if (!(wcscmp(pObjectInfo->ProviderName, szProviderName))) {
  550. RRETURN(S_OK);
  551. }
  552. RRETURN(E_FAIL);
  553. }
  554. HRESULT
  555. GetDomainFromPath(
  556. LPTSTR ADsPath,
  557. LPTSTR szDomainName
  558. )
  559. {
  560. OBJECTINFO ObjectInfo;
  561. POBJECTINFO pObjectInfo = &ObjectInfo;
  562. CLexer Lexer(ADsPath);
  563. HRESULT hr = S_OK;
  564. //assumption: Valid strings are passed to GetDomainFromPath
  565. ADsAssert(ADsPath);
  566. ADsAssert(szDomainName);
  567. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  568. hr = Object(&Lexer, pObjectInfo);
  569. BAIL_ON_FAILURE(hr);
  570. if (pObjectInfo->NumComponents) {
  571. wcscpy(szDomainName, pObjectInfo->ComponentArray[0]);
  572. }else {
  573. hr = E_FAIL;
  574. }
  575. error:
  576. FreeObjectInfo( &ObjectInfo, TRUE );
  577. RRETURN(hr);
  578. }
  579. HRESULT
  580. GetServerFromPath(
  581. LPTSTR ADsPath,
  582. LPTSTR szServerName
  583. )
  584. {
  585. OBJECTINFO ObjectInfo;
  586. POBJECTINFO pObjectInfo = &ObjectInfo;
  587. CLexer Lexer(ADsPath);
  588. HRESULT hr = S_OK;
  589. //assumption: Valid strings are passed to GetDomainFromPath
  590. ADsAssert(ADsPath);
  591. ADsAssert(szServerName);
  592. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  593. hr = Object(&Lexer, pObjectInfo);
  594. BAIL_ON_FAILURE(hr);
  595. if (pObjectInfo->NumComponents > 1) {
  596. wcscpy(szServerName, pObjectInfo->ComponentArray[1]);
  597. }else {
  598. hr = E_FAIL;
  599. }
  600. error:
  601. FreeObjectInfo( &ObjectInfo, TRUE );
  602. RRETURN(hr);
  603. }
  604. DWORD
  605. TickCountDiff(
  606. DWORD dwTime1,
  607. DWORD dwTime2
  608. )
  609. {
  610. //
  611. // does dwTime1 - dwTime2 and takes care of wraparound.
  612. // The first time must be later than the second
  613. // Restriction:: The two times must have been taken not more than
  614. // 49.7 days apart
  615. //
  616. DWORD dwRetval;
  617. if(dwTime1 >= dwTime2){
  618. dwRetval = dwTime1 - dwTime2;
  619. }
  620. else{
  621. dwRetval = dwTime2 - dwTime1;
  622. dwRetval = MAX_DWORD - dwRetval;
  623. }
  624. return dwRetval;
  625. }
  626. HRESULT
  627. DelimitedStringToVariant(
  628. LPTSTR pszString,
  629. VARIANT *pvar,
  630. TCHAR Delimiter
  631. )
  632. {
  633. SAFEARRAYBOUND sabound[1];
  634. DWORD dwElements;
  635. LPTSTR pszCurrPos = pszString;
  636. LPTSTR *rgszStrings = NULL;
  637. SAFEARRAY *psa = NULL;
  638. VARIANT v;
  639. HRESULT hr = S_OK;
  640. LONG i;
  641. //
  642. // This function converts a delimited string into a VARIANT of
  643. // safe arrays.
  644. //
  645. // Assumption: a valid string are passed to this function
  646. // note that the input string gets destroyed in the process
  647. //
  648. //
  649. // scan the delimited string once to find out the dimension
  650. //
  651. //
  652. // in order to filter for NULL input values do a sanity check for
  653. // length of input string.
  654. //
  655. if (!pszString){
  656. sabound[0].cElements = 0;
  657. sabound[0].lLbound = 0;
  658. psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
  659. if (psa == NULL){
  660. hr = E_OUTOFMEMORY;
  661. goto error;
  662. }
  663. VariantInit(pvar);
  664. V_VT(pvar) = VT_ARRAY|VT_VARIANT;
  665. V_ARRAY(pvar) = psa;
  666. goto error;
  667. }
  668. dwElements = (wcslen(pszString) == 0) ? 0: 1 ;
  669. while(!(*pszCurrPos == TEXT('\0'))){
  670. if(*pszCurrPos == Delimiter){
  671. dwElements++;
  672. *pszCurrPos = TEXT('\0');
  673. }
  674. pszCurrPos++;
  675. }
  676. rgszStrings = (LPTSTR *)AllocADsMem(sizeof(LPTSTR)*dwElements);
  677. if(!rgszStrings){
  678. hr = E_OUTOFMEMORY;
  679. goto error;
  680. }
  681. //
  682. // scan string again and put the appropriate pointers
  683. //
  684. pszCurrPos = pszString;
  685. if(rgszStrings != NULL){
  686. (*rgszStrings) = pszCurrPos;
  687. }
  688. i = 1;
  689. while(i < (LONG)dwElements){
  690. if(*pszCurrPos == TEXT('\0')){
  691. *(rgszStrings+i) = ++pszCurrPos;
  692. i++;
  693. }
  694. pszCurrPos++;
  695. }
  696. //
  697. // create the safearray
  698. //
  699. sabound[0].cElements = dwElements;
  700. sabound[0].lLbound = 0;
  701. psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
  702. if (psa == NULL){
  703. hr = E_OUTOFMEMORY;
  704. goto error;
  705. }
  706. for(i=0; i<(LONG)dwElements; i++){
  707. VariantInit(&v);
  708. V_VT(&v) = VT_BSTR;
  709. hr = ADsAllocString(*(rgszStrings+i), &(V_BSTR(&v)));
  710. BAIL_ON_FAILURE(hr);
  711. //
  712. // Stick the caller provided data into the end of the SafeArray
  713. //
  714. hr = SafeArrayPutElement(psa, &i, &v);
  715. VariantClear(&v);
  716. BAIL_ON_FAILURE(hr);
  717. }
  718. //
  719. // convert this safearray into a VARIANT
  720. //
  721. VariantInit(pvar);
  722. V_VT(pvar) = VT_ARRAY|VT_VARIANT;
  723. V_ARRAY(pvar) = psa;
  724. error:
  725. if(rgszStrings && dwElements != 0){
  726. FreeADsMem(rgszStrings);
  727. }
  728. RRETURN(hr);
  729. }
  730. HRESULT
  731. BuildComputerFromObjectInfo(
  732. POBJECTINFO pObjectInfo,
  733. LPTSTR pszADsPath
  734. )
  735. {
  736. if(!pObjectInfo){
  737. RRETURN(E_FAIL);
  738. }
  739. if(pObjectInfo->NumComponents == 3) {
  740. wsprintf(
  741. pszADsPath,
  742. L"%s://%s/%s",
  743. pObjectInfo->ProviderName,
  744. pObjectInfo->ComponentArray[0],
  745. pObjectInfo->ComponentArray[1]
  746. );
  747. } else if (pObjectInfo->NumComponents == 2){
  748. wsprintf(
  749. pszADsPath,
  750. L"%s://%s",
  751. pObjectInfo->ProviderName,
  752. pObjectInfo->ComponentArray[0]
  753. );
  754. } else {
  755. RRETURN(E_FAIL);
  756. }
  757. RRETURN(S_OK);
  758. }
  759. HRESULT
  760. FPNWSERVERADDRtoString(
  761. FPNWSERVERADDR WkstaAddress,
  762. LPWSTR * ppszString
  763. )
  764. {
  765. HRESULT hr = S_OK;
  766. TCHAR szNibble[2]; //one number and a null termination
  767. USHORT usNibble;
  768. int i;
  769. TCHAR szWkstaAddr[MAX_PATH];
  770. //
  771. // assumption: valid input values are passed to this function.
  772. //
  773. //
  774. // First 4 bytes is network address, then a dot and then bytes 5-10
  775. // are physical node address. Each byte consumes 2 chars space.
  776. // Then a byte for TEXT('\0')
  777. //
  778. _tcscpy(szWkstaAddr, TEXT(""));
  779. for( i=0; i < 4; i++){
  780. usNibble = WkstaAddress[i] & 0xF0;
  781. usNibble = usNibble >> 4;
  782. _itot(usNibble, szNibble, 16 );
  783. _tcscat(szWkstaAddr, szNibble);
  784. usNibble = WkstaAddress[i] & 0xF;
  785. _itot(usNibble, szNibble, 16 );
  786. _tcscat(szWkstaAddr, szNibble);
  787. }
  788. _tcscat(szWkstaAddr, TEXT("."));
  789. for(i=4; i<10 ; i++){
  790. usNibble = WkstaAddress[i] & 0xF0;
  791. usNibble = usNibble >> 4;
  792. _itot(usNibble, szNibble, 16 );
  793. _tcscat(szWkstaAddr, szNibble);
  794. usNibble = WkstaAddress[i] & 0xF;
  795. _itot(usNibble, szNibble, 16 );
  796. _tcscat(szWkstaAddr, szNibble);
  797. }
  798. *ppszString = AllocADsStr(szWkstaAddr);
  799. if(!*ppszString){
  800. hr = E_OUTOFMEMORY;
  801. }
  802. RRETURN(hr);
  803. }
  804. PKEYDATA
  805. CreateTokenList(
  806. LPWSTR pKeyData
  807. )
  808. {
  809. DWORD cTokens;
  810. DWORD cb;
  811. PKEYDATA pResult;
  812. LPWSTR pDest;
  813. LPWSTR psz = pKeyData;
  814. LPWSTR *ppToken;
  815. if (!psz || !*psz)
  816. return NULL;
  817. cTokens=1;
  818. // Scan through the string looking for commas,
  819. // ensuring that each is followed by a non-NULL character:
  820. while ((psz = wcschr(psz, L',')) && psz[1]) {
  821. cTokens++;
  822. psz++;
  823. }
  824. cb = sizeof(KEYDATA) + (cTokens-1) * sizeof(LPWSTR) +
  825. wcslen(pKeyData)*sizeof(WCHAR) + sizeof(WCHAR);
  826. if (!(pResult = (PKEYDATA)AllocADsMem(cb)))
  827. return NULL;
  828. // Initialise pDest to point beyond the token pointers:
  829. pDest = (LPWSTR)((LPBYTE)pResult + sizeof(KEYDATA) +
  830. (cTokens-1) * sizeof(LPWSTR));
  831. // Then copy the key data buffer there:
  832. wcscpy(pDest, pKeyData);
  833. ppToken = pResult->pTokens;
  834. // Remember, wcstok has the side effect of replacing the delimiter
  835. // by NULL, which is precisely what we want:
  836. psz = wcstok (pDest, L",");
  837. while (psz) {
  838. *ppToken++ = psz;
  839. psz = wcstok (NULL, L",");
  840. }
  841. pResult->cTokens = cTokens;
  842. return( pResult );
  843. }
  844. STDMETHODIMP
  845. GenericGetPropertyManager(
  846. CPropertyCache * pPropertyCache,
  847. THIS_ BSTR bstrName,
  848. VARIANT FAR* pvProp
  849. )
  850. {
  851. HRESULT hr = S_OK;
  852. DWORD dwSyntaxId;
  853. DWORD dwNumValues;
  854. DWORD dwInfoLevel;
  855. LPNTOBJECT pNtSrcObjects = NULL;
  856. //
  857. // For those who know no not what they do
  858. //
  859. if (!pvProp) {
  860. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  861. }
  862. //
  863. // retrieve data object from cache; if one exists
  864. hr = pPropertyCache->getproperty(
  865. bstrName,
  866. &dwSyntaxId,
  867. &dwNumValues,
  868. &pNtSrcObjects
  869. );
  870. BAIL_ON_FAILURE(hr);
  871. //
  872. // translate the Nt objects to variants
  873. //
  874. if (dwNumValues == 1) {
  875. hr = NtTypeToVarTypeCopy(
  876. pNtSrcObjects,
  877. pvProp
  878. );
  879. }else {
  880. hr = NtTypeToVarTypeCopyConstruct(
  881. pNtSrcObjects,
  882. dwNumValues,
  883. pvProp
  884. );
  885. }
  886. BAIL_ON_FAILURE(hr);
  887. error:
  888. if (pNtSrcObjects) {
  889. NTTypeFreeNTObjects(
  890. pNtSrcObjects,
  891. dwNumValues
  892. );
  893. }
  894. RRETURN(hr);
  895. }
  896. STDMETHODIMP
  897. GenericPutPropertyManager(
  898. CPropertyCache * pPropertyCache,
  899. PPROPERTYINFO pSchemaProps,
  900. DWORD dwSchemaPropSize,
  901. THIS_ BSTR bstrName,
  902. VARIANT vProp,
  903. BOOL fCheckSchemaWriteAccess
  904. )
  905. {
  906. HRESULT hr = S_OK;
  907. DWORD dwSyntaxId = 0;
  908. DWORD dwIndex = 0;
  909. LPNTOBJECT pNtDestObjects = NULL;
  910. VARIANT * pVarArray = NULL;
  911. VARIANT * pvProp = NULL;
  912. DWORD dwNumValues = 0;
  913. //
  914. // check if property in schema and get syntax of property
  915. //
  916. hr = ValidatePropertyinSchemaClass(
  917. pSchemaProps,
  918. dwSchemaPropSize,
  919. bstrName,
  920. &dwSyntaxId
  921. );
  922. if(TRUE == fCheckSchemaWriteAccess) {
  923. //
  924. // check if this is a writeable property in the schema
  925. //
  926. hr = ValidateIfWriteableProperty(
  927. pSchemaProps,
  928. dwSchemaPropSize,
  929. bstrName
  930. );
  931. BAIL_ON_FAILURE(hr);
  932. }
  933. //
  934. // Issue: How do we handle multi-valued support
  935. //
  936. //
  937. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  938. // We should dereference a VT_BYREF|VT_VARIANT once and see
  939. // what's inside.
  940. //
  941. pvProp = &vProp;
  942. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  943. pvProp = V_VARIANTREF(&vProp);
  944. }
  945. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
  946. (V_VT(&vProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
  947. hr = ConvertByRefSafeArrayToVariantArray(
  948. *pvProp,
  949. &pVarArray,
  950. &dwNumValues
  951. );
  952. BAIL_ON_FAILURE(hr);
  953. if( (0 == dwNumValues) && (NULL == pVarArray) ) {
  954. // return error if the safearray had no elements. Otherwise, the
  955. // NT object stored in the property cache is garbage.
  956. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  957. }
  958. pvProp = pVarArray;
  959. }else {
  960. dwNumValues = 1;
  961. }
  962. hr = VarTypeToNtTypeCopyConstruct(
  963. dwSyntaxId,
  964. pvProp,
  965. dwNumValues,
  966. &pNtDestObjects
  967. );
  968. BAIL_ON_FAILURE(hr);
  969. //
  970. // Find this property in the cache
  971. //
  972. hr = pPropertyCache->findproperty(
  973. bstrName,
  974. &dwIndex
  975. );
  976. //
  977. // If this property does not exist in the
  978. // cache, add this property into the cache.
  979. //
  980. if (FAILED(hr)) {
  981. hr = pPropertyCache->addproperty(
  982. bstrName,
  983. dwSyntaxId,
  984. dwNumValues,
  985. pNtDestObjects
  986. );
  987. //
  988. // If the operation fails for some reason
  989. // move on to the next property
  990. //
  991. BAIL_ON_FAILURE(hr);
  992. }
  993. //
  994. // Now update the property in the cache
  995. //
  996. hr = pPropertyCache->putproperty(
  997. bstrName,
  998. dwSyntaxId,
  999. dwNumValues,
  1000. pNtDestObjects
  1001. );
  1002. BAIL_ON_FAILURE(hr);
  1003. error:
  1004. if (pNtDestObjects) {
  1005. NTTypeFreeNTObjects(
  1006. pNtDestObjects,
  1007. dwNumValues
  1008. );
  1009. }
  1010. if (pVarArray) {
  1011. DWORD i = 0;
  1012. for (i = 0; i < dwNumValues; i++) {
  1013. VariantClear(pVarArray + i);
  1014. }
  1015. FreeADsMem(pVarArray);
  1016. }
  1017. RRETURN(hr);
  1018. }
  1019. STDMETHODIMP
  1020. GenericGetExPropertyManager(
  1021. DWORD dwObjectState,
  1022. CPropertyCache * pPropertyCache,
  1023. THIS_ BSTR bstrName,
  1024. VARIANT FAR* pvProp
  1025. )
  1026. {
  1027. HRESULT hr = S_OK;
  1028. DWORD dwSyntaxId;
  1029. DWORD dwNumValues;
  1030. LPNTOBJECT pNtSrcObjects = NULL;
  1031. if (!pvProp)
  1032. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1033. //
  1034. // retrieve data object from cache; if one exis
  1035. //
  1036. if (dwObjectState == ADS_OBJECT_UNBOUND) {
  1037. hr = pPropertyCache->unboundgetproperty(
  1038. bstrName,
  1039. &dwSyntaxId,
  1040. &dwNumValues,
  1041. &pNtSrcObjects
  1042. );
  1043. BAIL_ON_FAILURE(hr);
  1044. }else {
  1045. hr = pPropertyCache->getproperty(
  1046. bstrName,
  1047. &dwSyntaxId,
  1048. &dwNumValues,
  1049. &pNtSrcObjects
  1050. );
  1051. BAIL_ON_FAILURE(hr);
  1052. }
  1053. //
  1054. // translate the Nds objects to variants
  1055. //
  1056. hr = NtTypeToVarTypeCopyConstruct(
  1057. pNtSrcObjects,
  1058. dwNumValues,
  1059. pvProp
  1060. );
  1061. BAIL_ON_FAILURE(hr);
  1062. error:
  1063. if (pNtSrcObjects) {
  1064. NTTypeFreeNTObjects(
  1065. pNtSrcObjects,
  1066. dwNumValues
  1067. );
  1068. }
  1069. RRETURN(hr);
  1070. }
  1071. STDMETHODIMP
  1072. GenericPutExPropertyManager(
  1073. CPropertyCache * pPropertyCache,
  1074. PPROPERTYINFO pSchemaProps,
  1075. DWORD dwSchemaPropSize,
  1076. THIS_ BSTR bstrName,
  1077. VARIANT vProp
  1078. )
  1079. {
  1080. HRESULT hr = S_OK;
  1081. DWORD dwSyntaxId = 0;
  1082. DWORD dwIndex = 0;
  1083. LPNTOBJECT pNtDestObjects = NULL;
  1084. VARIANT * pVarArray = NULL;
  1085. VARIANT * pvProp = NULL;
  1086. DWORD dwNumValues = 0;
  1087. //
  1088. // check if property in schema and get syntax of property
  1089. //
  1090. hr = ValidatePropertyinSchemaClass(
  1091. pSchemaProps,
  1092. dwSchemaPropSize,
  1093. bstrName,
  1094. &dwSyntaxId
  1095. );
  1096. //
  1097. // check if this is a writeable property in the schema
  1098. //
  1099. hr = ValidateIfWriteableProperty(
  1100. pSchemaProps,
  1101. dwSchemaPropSize,
  1102. bstrName
  1103. );
  1104. BAIL_ON_FAILURE(hr);
  1105. //
  1106. // Issue: How do we handle multi-valued support
  1107. //
  1108. //
  1109. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1110. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1111. // what's inside.
  1112. //
  1113. pvProp = &vProp;
  1114. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1115. pvProp = V_VARIANTREF(&vProp);
  1116. }
  1117. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
  1118. (V_VT(&vProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
  1119. hr = ConvertByRefSafeArrayToVariantArray(
  1120. *pvProp,
  1121. &pVarArray,
  1122. &dwNumValues
  1123. );
  1124. BAIL_ON_FAILURE(hr);
  1125. if( (0 == dwNumValues) && (NULL == pVarArray) ) {
  1126. // return error if the safearray had no elements. Otherwise, the
  1127. // NT object stored in the property cache is garbage.
  1128. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1129. }
  1130. pvProp = pVarArray;
  1131. }else {
  1132. hr = E_FAIL;
  1133. BAIL_ON_FAILURE(hr);
  1134. }
  1135. //
  1136. // check if the variant maps to the syntax of this property
  1137. //
  1138. hr = VarTypeToNtTypeCopyConstruct(
  1139. dwSyntaxId,
  1140. pvProp,
  1141. dwNumValues,
  1142. &pNtDestObjects
  1143. );
  1144. BAIL_ON_FAILURE(hr);
  1145. //
  1146. // Find this property in the cache
  1147. //
  1148. hr = pPropertyCache->findproperty(
  1149. bstrName,
  1150. &dwIndex
  1151. );
  1152. //
  1153. // If this property does not exist in the
  1154. // cache, add this property into the cache.
  1155. //
  1156. if (FAILED(hr)) {
  1157. hr = pPropertyCache->addproperty(
  1158. bstrName,
  1159. dwSyntaxId,
  1160. dwNumValues,
  1161. pNtDestObjects
  1162. );
  1163. //
  1164. // If the operation fails for some reason
  1165. // move on to the next property
  1166. //
  1167. BAIL_ON_FAILURE(hr);
  1168. }
  1169. //
  1170. // Now update the property in the cache
  1171. //
  1172. hr = pPropertyCache->putproperty(
  1173. bstrName,
  1174. dwSyntaxId,
  1175. dwNumValues,
  1176. pNtDestObjects
  1177. );
  1178. BAIL_ON_FAILURE(hr);
  1179. error:
  1180. if (pNtDestObjects) {
  1181. NTTypeFreeNTObjects(
  1182. pNtDestObjects,
  1183. dwNumValues
  1184. );
  1185. }
  1186. if (pVarArray) {
  1187. DWORD i = 0;
  1188. for (i = 0; i < dwNumValues; i++) {
  1189. VariantClear(pVarArray + i);
  1190. }
  1191. FreeADsMem(pVarArray);
  1192. }
  1193. RRETURN(hr);
  1194. }
  1195. DWORD
  1196. DelimitedStrSize(
  1197. LPWSTR pszString,
  1198. WCHAR Delimiter
  1199. )
  1200. {
  1201. DWORD dwElements = (wcslen(pszString) == 0) ? 0: 1 ;
  1202. LPTSTR pszCurrPos = pszString;
  1203. if (!pszString || !*pszString) {
  1204. return dwElements;
  1205. }
  1206. while(!(*pszCurrPos == TEXT('\0'))){
  1207. if(*pszCurrPos == Delimiter){
  1208. dwElements++;
  1209. *pszCurrPos = TEXT('\0');
  1210. }
  1211. pszCurrPos++;
  1212. }
  1213. return dwElements;
  1214. }
  1215. DWORD
  1216. NulledStrSize(
  1217. LPWSTR pszString
  1218. )
  1219. {
  1220. DWORD dwElements = 0;
  1221. LPTSTR pszCurrPos = pszString;
  1222. BOOL foundNULL = FALSE;
  1223. if (!pszString || !*pszString) {
  1224. return dwElements;
  1225. }
  1226. while(!(*pszCurrPos == TEXT('\0') && foundNULL== TRUE)){
  1227. if(*pszCurrPos == TEXT('\0')){
  1228. dwElements++;
  1229. foundNULL = TRUE;
  1230. } else {
  1231. foundNULL = FALSE;
  1232. }
  1233. pszCurrPos++;
  1234. }
  1235. return dwElements;
  1236. }
  1237. HRESULT
  1238. GenericPropCountPropertyManager(
  1239. CPropertyCache * pPropertyCache,
  1240. PLONG plCount
  1241. )
  1242. {
  1243. HRESULT hr = E_FAIL;
  1244. if (!plCount)
  1245. hr = E_ADS_BAD_PARAMETER;
  1246. else if (pPropertyCache) {
  1247. hr = pPropertyCache->get_PropertyCount((PDWORD)plCount);
  1248. }
  1249. RRETURN(hr);
  1250. }
  1251. HRESULT
  1252. GenericNextPropertyManager(
  1253. CPropertyCache * pPropertyCache,
  1254. VARIANT FAR *pVariant
  1255. )
  1256. {
  1257. HRESULT hr = E_FAIL;
  1258. DWORD dwSyntaxId = 0;
  1259. DWORD dwNumValues = 0;
  1260. LPNTOBJECT pNtSrcObjects = NULL;
  1261. VARIANT varData;
  1262. IDispatch * pDispatch = NULL;
  1263. VariantInit(&varData);
  1264. if (!pVariant)
  1265. BAIL_ON_FAILURE(E_ADS_BAD_PARAMETER);
  1266. hr = pPropertyCache->unboundgetproperty(
  1267. pPropertyCache->get_CurrentIndex(),
  1268. &dwSyntaxId,
  1269. &dwNumValues,
  1270. &pNtSrcObjects
  1271. );
  1272. BAIL_ON_FAILURE(hr);
  1273. //
  1274. // translate the Nt objects to variants
  1275. //
  1276. hr = ConvertNtValuesToVariant(
  1277. pPropertyCache->get_CurrentPropName(),
  1278. pNtSrcObjects,
  1279. dwNumValues,
  1280. pVariant
  1281. );
  1282. BAIL_ON_FAILURE(hr);
  1283. error:
  1284. //
  1285. // - goto next one even if error to avoid infinite looping at a property
  1286. // which we cannot convert (e.g. schemaless server property.)
  1287. // - do not return the result of Skip() as current operation does not
  1288. // depend on the sucess of Skip().
  1289. //
  1290. pPropertyCache->skip_propindex(
  1291. 1
  1292. );
  1293. if (pNtSrcObjects) {
  1294. NTTypeFreeNTObjects(
  1295. pNtSrcObjects,
  1296. dwNumValues
  1297. );
  1298. }
  1299. RRETURN(hr);
  1300. }
  1301. HRESULT
  1302. GenericSkipPropertyManager(
  1303. CPropertyCache * pPropertyCache,
  1304. ULONG cElements
  1305. )
  1306. {
  1307. HRESULT hr = E_FAIL;
  1308. hr = pPropertyCache->skip_propindex(
  1309. cElements
  1310. );
  1311. RRETURN(hr);
  1312. }
  1313. HRESULT
  1314. GenericResetPropertyManager(
  1315. CPropertyCache * pPropertyCache
  1316. )
  1317. {
  1318. pPropertyCache->reset_propindex();
  1319. RRETURN(S_OK);
  1320. }
  1321. HRESULT
  1322. GenericDeletePropertyManager(
  1323. CPropertyCache * pPropertyCache,
  1324. VARIANT varEntry
  1325. )
  1326. {
  1327. HRESULT hr = S_OK;
  1328. DWORD dwIndex = 0;
  1329. switch (V_VT(&varEntry)) {
  1330. case VT_BSTR:
  1331. hr = pPropertyCache->findproperty(
  1332. V_BSTR(&varEntry),
  1333. &dwIndex
  1334. );
  1335. BAIL_ON_FAILURE(hr);
  1336. break;
  1337. case VT_I4:
  1338. dwIndex = V_I4(&varEntry);
  1339. break;
  1340. case VT_I2:
  1341. dwIndex = V_I2(&varEntry);
  1342. break;
  1343. default:
  1344. hr = E_FAIL;
  1345. BAIL_ON_FAILURE(hr);
  1346. }
  1347. hr = pPropertyCache->deleteproperty(
  1348. dwIndex
  1349. );
  1350. error:
  1351. RRETURN(hr);
  1352. }
  1353. HRESULT
  1354. GenericPutPropItemPropertyManager(
  1355. CPropertyCache * pPropertyCache,
  1356. PPROPERTYINFO pSchemaProps,
  1357. DWORD dwSchemaPropSize,
  1358. VARIANT varData
  1359. )
  1360. {
  1361. HRESULT hr = S_OK;
  1362. DWORD dwSyntaxId = 0;
  1363. DWORD dwIndex = 0;
  1364. WCHAR szPropertyName[MAX_PATH] = L"";
  1365. LPNTOBJECT pNtDestObjects = NULL;
  1366. DWORD dwNumValues = 0;
  1367. DWORD dwControlCode = 0;
  1368. hr = ConvertVariantToNtValues(
  1369. varData,
  1370. pSchemaProps,
  1371. dwSchemaPropSize,
  1372. szPropertyName,
  1373. &pNtDestObjects,
  1374. &dwNumValues,
  1375. &dwSyntaxId,
  1376. &dwControlCode
  1377. );
  1378. BAIL_ON_FAILURE(hr);
  1379. if (dwControlCode != ADS_PROPERTY_UPDATE) {
  1380. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1381. }
  1382. //
  1383. // check if this is a writeable property in the schema
  1384. //
  1385. hr = ValidateIfWriteableProperty(
  1386. pSchemaProps,
  1387. dwSchemaPropSize,
  1388. szPropertyName
  1389. );
  1390. BAIL_ON_FAILURE(hr);
  1391. //
  1392. // Find this property in the cache
  1393. //
  1394. hr = pPropertyCache->findproperty(
  1395. szPropertyName,
  1396. &dwIndex
  1397. );
  1398. //
  1399. // If this property does not exist in the
  1400. // cache, add this property into the cache.
  1401. //
  1402. if (FAILED(hr)) {
  1403. hr = pPropertyCache->addproperty(
  1404. szPropertyName,
  1405. dwSyntaxId,
  1406. dwNumValues,
  1407. pNtDestObjects
  1408. );
  1409. //
  1410. // If the operation fails for some reason
  1411. // move on to the next property
  1412. //
  1413. BAIL_ON_FAILURE(hr);
  1414. }
  1415. //
  1416. // Now update the property in the cache
  1417. //
  1418. hr = pPropertyCache->putproperty(
  1419. szPropertyName,
  1420. dwSyntaxId,
  1421. dwNumValues,
  1422. pNtDestObjects
  1423. );
  1424. BAIL_ON_FAILURE(hr);
  1425. error:
  1426. if (pNtDestObjects) {
  1427. NTTypeFreeNTObjects(
  1428. pNtDestObjects,
  1429. dwNumValues
  1430. );
  1431. }
  1432. RRETURN(hr);
  1433. }
  1434. HRESULT
  1435. GenericGetPropItemPropertyManager(
  1436. CPropertyCache * pPropertyCache,
  1437. DWORD dwObjectState,
  1438. BSTR bstrName,
  1439. LONG lnADsType,
  1440. VARIANT * pVariant
  1441. )
  1442. {
  1443. HRESULT hr = S_OK;
  1444. DWORD dwSyntaxId;
  1445. DWORD dwNumValues;
  1446. LPNTOBJECT pNtSrcObjects = NULL;
  1447. if (!pVariant)
  1448. BAIL_ON_FAILURE(E_ADS_BAD_PARAMETER);
  1449. //
  1450. // retrieve data object from cache; if one exis
  1451. //
  1452. if (dwObjectState == ADS_OBJECT_UNBOUND) {
  1453. hr = pPropertyCache->unboundgetproperty(
  1454. bstrName,
  1455. &dwSyntaxId,
  1456. &dwNumValues,
  1457. &pNtSrcObjects
  1458. );
  1459. BAIL_ON_FAILURE(hr);
  1460. }else {
  1461. hr = pPropertyCache->getproperty(
  1462. bstrName,
  1463. &dwSyntaxId,
  1464. &dwNumValues,
  1465. &pNtSrcObjects
  1466. );
  1467. BAIL_ON_FAILURE(hr);
  1468. }
  1469. //
  1470. // translate the Nds objects to variants
  1471. //
  1472. hr = ConvertNtValuesToVariant(
  1473. bstrName,
  1474. pNtSrcObjects,
  1475. dwNumValues,
  1476. pVariant
  1477. );
  1478. BAIL_ON_FAILURE(hr);
  1479. error:
  1480. if (pNtSrcObjects) {
  1481. NTTypeFreeNTObjects(
  1482. pNtSrcObjects,
  1483. dwNumValues
  1484. );
  1485. }
  1486. RRETURN(hr);
  1487. }
  1488. HRESULT
  1489. GenericItemPropertyManager(
  1490. CPropertyCache * pPropertyCache,
  1491. DWORD dwObjectState,
  1492. VARIANT varIndex,
  1493. VARIANT *pVariant
  1494. )
  1495. {
  1496. HRESULT hr = S_OK;
  1497. DWORD dwSyntaxId;
  1498. DWORD dwNumValues;
  1499. LPNTOBJECT pNtSrcObjects = NULL;
  1500. LPWSTR szPropName = NULL;
  1501. VARIANT *pvVar = &varIndex;
  1502. if (!pVariant)
  1503. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1504. //
  1505. // retrieve data object from cache; if one exis
  1506. //
  1507. if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
  1508. //
  1509. // The value is being passed in byref so we need to
  1510. // deref it for vbs stuff to work
  1511. //
  1512. pvVar = V_VARIANTREF(&varIndex);
  1513. }
  1514. switch (V_VT(pvVar)) {
  1515. case VT_BSTR:
  1516. if (dwObjectState == ADS_OBJECT_UNBOUND) {
  1517. hr = pPropertyCache->unboundgetproperty(
  1518. V_BSTR(pvVar),
  1519. &dwSyntaxId,
  1520. &dwNumValues,
  1521. &pNtSrcObjects
  1522. );
  1523. BAIL_ON_FAILURE(hr);
  1524. }else {
  1525. hr = pPropertyCache->getproperty(
  1526. V_BSTR(pvVar),
  1527. &dwSyntaxId,
  1528. &dwNumValues,
  1529. &pNtSrcObjects
  1530. );
  1531. BAIL_ON_FAILURE(hr);
  1532. }
  1533. hr = ConvertNtValuesToVariant(
  1534. V_BSTR(pvVar),
  1535. pNtSrcObjects,
  1536. dwNumValues,
  1537. pVariant
  1538. );
  1539. BAIL_ON_FAILURE(hr);
  1540. break;
  1541. case VT_I4:
  1542. hr = pPropertyCache->unboundgetproperty(
  1543. V_I4(pvVar),
  1544. &dwSyntaxId,
  1545. &dwNumValues,
  1546. &pNtSrcObjects
  1547. );
  1548. BAIL_ON_FAILURE(hr);
  1549. szPropName = pPropertyCache->get_PropName(V_I4(pvVar));
  1550. hr = ConvertNtValuesToVariant(
  1551. szPropName,
  1552. pNtSrcObjects,
  1553. dwNumValues,
  1554. pVariant
  1555. );
  1556. BAIL_ON_FAILURE(hr);
  1557. break;
  1558. case VT_I2:
  1559. hr = pPropertyCache->unboundgetproperty(
  1560. (DWORD)V_I2(pvVar),
  1561. &dwSyntaxId,
  1562. &dwNumValues,
  1563. &pNtSrcObjects
  1564. );
  1565. BAIL_ON_FAILURE(hr);
  1566. szPropName = pPropertyCache->get_PropName(V_I2(pvVar));
  1567. hr = ConvertNtValuesToVariant(
  1568. szPropName,
  1569. pNtSrcObjects,
  1570. dwNumValues,
  1571. pVariant
  1572. );
  1573. BAIL_ON_FAILURE(hr);
  1574. break;
  1575. default:
  1576. hr = E_FAIL;
  1577. BAIL_ON_FAILURE(hr);
  1578. }
  1579. error:
  1580. if (pNtSrcObjects) {
  1581. NTTypeFreeNTObjects(
  1582. pNtSrcObjects,
  1583. dwNumValues
  1584. );
  1585. }
  1586. RRETURN(hr);
  1587. }
  1588. HRESULT
  1589. GenericPurgePropertyManager(
  1590. CPropertyCache * pPropertyCache
  1591. )
  1592. {
  1593. pPropertyCache->flushpropcache();
  1594. RRETURN(S_OK);
  1595. }
  1596. HRESULT
  1597. CreatePropEntry(
  1598. LPWSTR szPropName,
  1599. ADSTYPE dwADsType,
  1600. VARIANT varData,
  1601. REFIID riid,
  1602. LPVOID * ppDispatch
  1603. )
  1604. {
  1605. HRESULT hr = S_OK;
  1606. IADsPropertyEntry * pPropEntry = NULL;
  1607. hr = CoCreateInstance(
  1608. CLSID_PropertyEntry,
  1609. NULL,
  1610. CLSCTX_INPROC_SERVER,
  1611. IID_IADsPropertyEntry,
  1612. (void **)&pPropEntry
  1613. );
  1614. BAIL_ON_FAILURE(hr);
  1615. hr = pPropEntry->put_Name(szPropName);
  1616. BAIL_ON_FAILURE(hr);
  1617. hr = pPropEntry->put_Values(varData);
  1618. BAIL_ON_FAILURE(hr);
  1619. hr = pPropEntry->put_ADsType(dwADsType);
  1620. BAIL_ON_FAILURE(hr);
  1621. // no control code
  1622. hr = pPropEntry->QueryInterface(
  1623. riid,
  1624. ppDispatch
  1625. );
  1626. BAIL_ON_FAILURE(hr);
  1627. error:
  1628. if (pPropEntry) {
  1629. pPropEntry->Release();
  1630. }
  1631. RRETURN(hr);
  1632. }
  1633. HRESULT
  1634. ConvertNtValuesToVariant(
  1635. LPWSTR szPropertyName,
  1636. PNTOBJECT pNtSrcObject,
  1637. DWORD dwNumValues,
  1638. PVARIANT pVariant
  1639. )
  1640. {
  1641. HRESULT hr = S_OK;
  1642. VARIANT varData;
  1643. IDispatch * pDispatch = NULL;
  1644. PADSVALUE pAdsValues = NULL;
  1645. ADSTYPE dwADsType = ADSTYPE_INVALID;
  1646. VariantInit(&varData);
  1647. VariantInit(pVariant);
  1648. if (dwNumValues>0) {
  1649. hr = NTTypeToAdsTypeCopyConstruct(
  1650. pNtSrcObject,
  1651. dwNumValues,
  1652. &pAdsValues
  1653. );
  1654. if (SUCCEEDED(hr)) {
  1655. hr = AdsTypeToPropVariant(
  1656. pAdsValues,
  1657. dwNumValues,
  1658. &varData
  1659. );
  1660. BAIL_ON_FAILURE(hr);
  1661. dwADsType = pAdsValues->dwType;
  1662. }
  1663. else if (hr==E_OUTOFMEMORY) {
  1664. BAIL_ON_FAILURE(hr);
  1665. }
  1666. //
  1667. // failed because of NTType is not supported yet (e.g DelimitedString)
  1668. // in NTTypeToAdsTypeCopyConstruct() conversion
  1669. // -> use empty variant now.
  1670. //
  1671. else {
  1672. VariantInit(&varData);
  1673. }
  1674. }
  1675. hr = CreatePropEntry(
  1676. szPropertyName,
  1677. dwADsType,
  1678. varData,
  1679. IID_IDispatch,
  1680. (void **)&pDispatch
  1681. );
  1682. BAIL_ON_FAILURE(hr);
  1683. V_DISPATCH(pVariant) = pDispatch;
  1684. V_VT(pVariant) = VT_DISPATCH;
  1685. error:
  1686. VariantClear(&varData);
  1687. if (pAdsValues) {
  1688. AdsFreeAdsValues(
  1689. pAdsValues,
  1690. dwNumValues
  1691. );
  1692. FreeADsMem( pAdsValues );
  1693. }
  1694. RRETURN(hr);
  1695. }
  1696. HRESULT
  1697. ConvertVariantToVariantArray(
  1698. VARIANT varData,
  1699. VARIANT ** ppVarArray,
  1700. DWORD * pdwNumValues
  1701. )
  1702. {
  1703. DWORD dwNumValues = 0;
  1704. VARIANT * pVarArray = NULL;
  1705. HRESULT hr = S_OK;
  1706. VARIANT * pVarData = NULL;
  1707. *ppVarArray = NULL;
  1708. *pdwNumValues = 0;
  1709. //
  1710. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1711. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1712. // what's inside.
  1713. //
  1714. pVarData = &varData;
  1715. if (V_VT(pVarData) == (VT_BYREF|VT_VARIANT)) {
  1716. pVarData = V_VARIANTREF(&varData);
  1717. }
  1718. if ((V_VT(pVarData) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  1719. (V_VT(&varData) == (VT_VARIANT|VT_ARRAY))) {
  1720. hr = ConvertSafeArrayToVariantArray(
  1721. *pVarData,
  1722. &pVarArray,
  1723. &dwNumValues
  1724. );
  1725. BAIL_ON_FAILURE(hr);
  1726. } else {
  1727. hr = E_FAIL;
  1728. BAIL_ON_FAILURE(hr);
  1729. }
  1730. *ppVarArray = pVarArray;
  1731. *pdwNumValues = dwNumValues;
  1732. error:
  1733. RRETURN(hr);
  1734. }
  1735. void
  1736. FreeVariantArray(
  1737. VARIANT * pVarArray,
  1738. DWORD dwNumValues
  1739. )
  1740. {
  1741. if (pVarArray) {
  1742. DWORD i = 0;
  1743. for (i = 0; i < dwNumValues; i++) {
  1744. VariantClear(pVarArray + i);
  1745. }
  1746. FreeADsMem(pVarArray);
  1747. }
  1748. }
  1749. HRESULT
  1750. ConvertVariantToNtValues(
  1751. VARIANT varData,
  1752. PPROPERTYINFO pSchemaProps,
  1753. DWORD dwSchemaPropSize,
  1754. LPWSTR szPropertyName,
  1755. PNTOBJECT *ppNtDestObjects,
  1756. PDWORD pdwNumValues,
  1757. PDWORD pdwSyntaxId,
  1758. PDWORD pdwControlCode
  1759. )
  1760. {
  1761. HRESULT hr = S_OK;
  1762. IADsPropertyEntry * pPropEntry = NULL;
  1763. IDispatch * pDispatch = NULL;
  1764. BSTR bstrPropName = NULL;
  1765. DWORD dwControlCode = 0;
  1766. DWORD dwAdsType = 0;
  1767. VARIANT varValues;
  1768. VARIANT * pVarArray = NULL;
  1769. DWORD dwNumValues = 0;
  1770. PADSVALUE pAdsValues = NULL;
  1771. DWORD dwAdsValues = 0;
  1772. PNTOBJECT pNtDestObjects = 0;
  1773. DWORD dwNumNtObjects = 0;
  1774. DWORD dwNtSyntaxId = 0;
  1775. if (V_VT(&varData) != VT_DISPATCH) {
  1776. RRETURN (hr = DISP_E_TYPEMISMATCH);
  1777. }
  1778. pDispatch = V_DISPATCH(&varData);
  1779. hr = pDispatch->QueryInterface(
  1780. IID_IADsPropertyEntry,
  1781. (void **)&pPropEntry
  1782. );
  1783. BAIL_ON_FAILURE(hr);
  1784. VariantInit(&varValues);
  1785. VariantClear(&varValues);
  1786. hr = pPropEntry->get_Name(&bstrPropName);
  1787. BAIL_ON_FAILURE(hr);
  1788. if(wcslen(bstrPropName) < MAX_PATH)
  1789. wcscpy(szPropertyName, bstrPropName);
  1790. else {
  1791. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  1792. }
  1793. hr = pPropEntry->get_ControlCode((long *)&dwControlCode);
  1794. BAIL_ON_FAILURE(hr);
  1795. *pdwControlCode = dwControlCode;
  1796. hr = pPropEntry->get_ADsType((long *)&dwAdsType);
  1797. BAIL_ON_FAILURE(hr);
  1798. hr = pPropEntry->get_Values(&varValues);
  1799. BAIL_ON_FAILURE(hr);
  1800. hr = ConvertVariantToVariantArray(
  1801. varValues,
  1802. &pVarArray,
  1803. &dwNumValues
  1804. );
  1805. BAIL_ON_FAILURE(hr);
  1806. if (dwNumValues) {
  1807. hr = PropVariantToAdsType(
  1808. pVarArray,
  1809. dwNumValues,
  1810. &pAdsValues,
  1811. &dwAdsValues
  1812. );
  1813. BAIL_ON_FAILURE(hr);
  1814. hr = AdsTypeToNTTypeCopyConstruct(
  1815. pAdsValues,
  1816. dwAdsValues,
  1817. &pNtDestObjects,
  1818. &dwNumNtObjects,
  1819. &dwNtSyntaxId
  1820. );
  1821. BAIL_ON_FAILURE(hr);
  1822. }
  1823. *pdwNumValues = dwNumValues;
  1824. *ppNtDestObjects = pNtDestObjects;
  1825. *pdwSyntaxId = dwNtSyntaxId;
  1826. error:
  1827. if (pVarArray) {
  1828. FreeVariantArray(
  1829. pVarArray,
  1830. dwNumValues
  1831. );
  1832. }
  1833. if (pPropEntry) {
  1834. pPropEntry->Release();
  1835. }
  1836. VariantClear(&varValues);
  1837. if (pAdsValues) {
  1838. AdsFreeAdsValues(
  1839. pAdsValues,
  1840. dwAdsValues
  1841. );
  1842. FreeADsMem( pAdsValues );
  1843. }
  1844. RRETURN(hr);
  1845. }
  1846. HRESULT
  1847. GetMachineProductType(
  1848. IN LPTSTR pszServer,
  1849. OUT PRODUCTTYPE *pdwProductType
  1850. )
  1851. {
  1852. HRESULT hr = S_OK;
  1853. LONG dwStatus;
  1854. HKEY hkLocalMachine = NULL;
  1855. HKEY hkProductOptions = NULL;
  1856. DWORD dwValueType;
  1857. WCHAR szData[20];
  1858. DWORD dwDataSize = sizeof(szData);
  1859. //
  1860. // pszServer can be NULL for local server
  1861. //
  1862. if (!pdwProductType)
  1863. RRETURN(E_ADS_BAD_PARAMETER);
  1864. *pdwProductType = PRODTYPE_INVALID;
  1865. //
  1866. // Connect to remote's machine registry
  1867. //
  1868. dwStatus = RegConnectRegistry(
  1869. pszServer,
  1870. HKEY_LOCAL_MACHINE,
  1871. &hkLocalMachine
  1872. );
  1873. if (dwStatus != ERROR_SUCCESS)
  1874. {
  1875. hr = HRESULT_FROM_WIN32(dwStatus);
  1876. BAIL_ON_FAILURE(hr);
  1877. }
  1878. //
  1879. // Open key ProductOptions
  1880. //
  1881. dwStatus = RegOpenKeyEx(
  1882. hkLocalMachine,
  1883. L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
  1884. 0,
  1885. KEY_QUERY_VALUE,
  1886. &hkProductOptions
  1887. );
  1888. if (dwStatus != ERROR_SUCCESS)
  1889. {
  1890. hr = HRESULT_FROM_WIN32(dwStatus);
  1891. BAIL_ON_FAILURE(hr);
  1892. }
  1893. //
  1894. // Get Value of Product Type
  1895. //
  1896. dwStatus = RegQueryValueEx(
  1897. hkProductOptions,
  1898. L"ProductType",
  1899. NULL,
  1900. &dwValueType,
  1901. (LPBYTE) szData,
  1902. &dwDataSize
  1903. );
  1904. //
  1905. // check server type
  1906. //
  1907. if (_wcsicmp(szData, WINNT_A_LANMANNT_W)==0)
  1908. {
  1909. *pdwProductType = PRODTYPE_DC;
  1910. }
  1911. else if (_wcsicmp(szData, WINNT_A_SERVERNT_W)==0)
  1912. {
  1913. *pdwProductType = PRODTYPE_STDALONESVR;
  1914. }
  1915. else if (_wcsicmp(szData, WINNT_A_WINNT_W)==0)
  1916. {
  1917. *pdwProductType = PRODTYPE_WKSTA;
  1918. }
  1919. else
  1920. {
  1921. hr = E_FAIL;
  1922. BAIL_ON_FAILURE(hr);
  1923. }
  1924. error:
  1925. if ( hkLocalMachine )
  1926. RegCloseKey(hkLocalMachine);
  1927. if ( hkProductOptions )
  1928. RegCloseKey(hkProductOptions);
  1929. RRETURN(hr);
  1930. }
  1931. //
  1932. // Get Sid of account name [lpszAccountName] from server [lpszServerName].
  1933. // Unmarshall the Sid into cache [pPropertyCache] if [fExplict] is TRUE.
  1934. // Use local machine if [lpszServerName] == NULL.
  1935. //
  1936. HRESULT
  1937. GetSidIntoCache(
  1938. IN LPTSTR lpszServerName,
  1939. IN LPTSTR lpszAccountName,
  1940. IN CPropertyCache * pPropertyCache,
  1941. IN BOOL fExplicit
  1942. )
  1943. {
  1944. HRESULT hr = S_OK;
  1945. BOOL fGotSid = FALSE;
  1946. DWORD dwErr = 0;
  1947. PSID pSid = NULL;
  1948. DWORD dwSidLength = 0;
  1949. WCHAR szNewAccountName[MAX_PATH+UNLEN+2];
  1950. LPTSTR lpSrvName;
  1951. //
  1952. // default cbSid size :
  1953. // - 1 (revision), 1 (authid), max sub(auth)
  1954. // - * 8 (rev, authid, subid all < 8), but use 8 in case of
  1955. // structure aligment because of compiler/machine (we want
  1956. // LookUpAccountName() to succeed at first attempt as much
  1957. // as possible to min this wired call)
  1958. //
  1959. const DWORD maxSid = (1+1+SID_MAX_SUB_AUTHORITIES) * 8;
  1960. DWORD cbSid = maxSid;
  1961. //
  1962. // dummies
  1963. //
  1964. TCHAR szRefDomainName[MAX_PATH];
  1965. DWORD cbRefDomainName = MAX_PATH;
  1966. SID_NAME_USE eNameUse;
  1967. if (!lpszAccountName)
  1968. RRETURN(E_ADS_INVALID_USER_OBJECT);
  1969. if (!pPropertyCache)
  1970. RRETURN(E_ADS_BAD_PARAMETER);
  1971. //
  1972. // allocate sid and RefDomainName buffer
  1973. //
  1974. pSid = (PSID) AllocADsMem(
  1975. cbSid
  1976. );
  1977. if (!pSid) {
  1978. hr = E_OUTOFMEMORY;
  1979. BAIL_ON_FAILURE(hr);
  1980. }
  1981. //
  1982. // get sid and other unused info from server
  1983. //
  1984. fGotSid = LookupAccountName(
  1985. lpszServerName,
  1986. lpszAccountName,
  1987. pSid,
  1988. &cbSid,
  1989. szRefDomainName,
  1990. &cbRefDomainName,
  1991. &eNameUse
  1992. );
  1993. if (!fGotSid) {
  1994. if (cbSid>maxSid) {
  1995. //
  1996. // Fail becuase buffer size required > what we have allocated
  1997. // for some reasons, retry with correct buffer size
  1998. //
  1999. FreeADsMem(pSid);
  2000. pSid = (PSID) AllocADsMem(
  2001. cbSid
  2002. );
  2003. if (!pSid) {
  2004. hr = E_OUTOFMEMORY;
  2005. BAIL_ON_FAILURE(hr);
  2006. }
  2007. fGotSid = LookupAccountName(
  2008. lpszServerName,
  2009. lpszAccountName,
  2010. pSid,
  2011. &cbSid,
  2012. szRefDomainName,
  2013. &cbRefDomainName,
  2014. &eNameUse
  2015. );
  2016. if (!fGotSid) {
  2017. //
  2018. // Fail on retry with proper buffer size, can do no more
  2019. //
  2020. dwErr = GetLastError();
  2021. hr = HRESULT_FROM_WIN32(dwErr);
  2022. }
  2023. } else {
  2024. //
  2025. // Fail becuase of reasons other then buffer size, not need to
  2026. // retry.
  2027. //
  2028. dwErr = GetLastError();
  2029. hr = HRESULT_FROM_WIN32(dwErr);
  2030. }
  2031. }
  2032. if( fGotSid && (eNameUse == SidTypeDomain) ) {
  2033. lpSrvName = lpszServerName;
  2034. if (lpszServerName && (lpszServerName[0] == L'\\') && (lpszServerName[1] == L'\\')) {
  2035. lpSrvName += 2;
  2036. }
  2037. #ifdef WIN95
  2038. if (!_wcsicmp(lpszAccountName, lpSrvName)) {
  2039. #else
  2040. if (CompareStringW(
  2041. LOCALE_SYSTEM_DEFAULT,
  2042. NORM_IGNORECASE,
  2043. lpszAccountName,
  2044. -1,
  2045. lpSrvName,
  2046. -1
  2047. ) == CSTR_EQUAL ) {
  2048. #endif
  2049. wcscpy(szNewAccountName, lpSrvName);
  2050. wcscat(szNewAccountName, L"\\");
  2051. wcscat(szNewAccountName, lpszAccountName);
  2052. cbSid = maxSid;
  2053. cbRefDomainName = MAX_PATH;
  2054. fGotSid = LookupAccountName(
  2055. lpszServerName,
  2056. szNewAccountName,
  2057. pSid,
  2058. &cbSid,
  2059. szRefDomainName,
  2060. &cbRefDomainName,
  2061. &eNameUse
  2062. );
  2063. if (!fGotSid) {
  2064. if (cbSid>maxSid) {
  2065. //
  2066. // Fail becuase buffer size required > what we have allocated
  2067. // for some reasons, retry with correct buffer size
  2068. //
  2069. FreeADsMem(pSid);
  2070. pSid = (PSID) AllocADsMem(
  2071. cbSid
  2072. );
  2073. if (!pSid) {
  2074. hr = E_OUTOFMEMORY;
  2075. BAIL_ON_FAILURE(hr);
  2076. }
  2077. fGotSid = LookupAccountName(
  2078. lpszServerName,
  2079. szNewAccountName,
  2080. pSid,
  2081. &cbSid,
  2082. szRefDomainName,
  2083. &cbRefDomainName,
  2084. &eNameUse
  2085. );
  2086. if (!fGotSid) {
  2087. //
  2088. // Fail on retry with proper buffer size, can do no more
  2089. //
  2090. dwErr = GetLastError();
  2091. hr = HRESULT_FROM_WIN32(dwErr);
  2092. }
  2093. } else {
  2094. //
  2095. // Fail becuase of reasons other then buffer size, not need to
  2096. // retry.
  2097. //
  2098. dwErr = GetLastError();
  2099. hr = HRESULT_FROM_WIN32(dwErr);
  2100. }
  2101. }
  2102. }
  2103. }
  2104. BAIL_ON_FAILURE(hr);
  2105. //
  2106. // On NT4 for some reason GetLengthSID does not set lasterror to 0
  2107. //
  2108. SetLastError(NO_ERROR);
  2109. dwSidLength = GetLengthSid((PSID) pSid);
  2110. dwErr = GetLastError();
  2111. //
  2112. // This is an extra check to make sure that we have the
  2113. // correct length.
  2114. //
  2115. if (dwErr != NO_ERROR) {
  2116. hr = HRESULT_FROM_WIN32(dwErr);
  2117. }
  2118. BAIL_ON_FAILURE(hr);
  2119. //
  2120. // store Sid in property cache
  2121. //
  2122. hr = SetOctetPropertyInCache(
  2123. pPropertyCache,
  2124. TEXT("objectSid"),
  2125. (PBYTE) pSid,
  2126. dwSidLength,
  2127. fExplicit
  2128. );
  2129. BAIL_ON_FAILURE(hr);
  2130. error:
  2131. if (pSid) {
  2132. FreeADsMem(pSid);
  2133. }
  2134. RRETURN(hr);
  2135. }