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

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