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.

2468 lines
70 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. regvalue.cpp
  5. Abstract:
  6. Routines to read/write/configure registry value settings
  7. The following modules have links to registry values
  8. scejet.c <SceJetAddSection>
  9. inftojet.c <SceConvertpInfKeyValue>
  10. pfget.c <ScepGetRegistryValues>
  11. config.c <ScepConfigureRegistryValues>
  12. analyze.c <ScepAnalyzeRegistryValues>
  13. Author:
  14. Jin Huang (jinhuang) 07-Jan-1998
  15. Revision History:
  16. --*/
  17. #include "headers.h"
  18. #include "serverp.h"
  19. #include "regvalue.h"
  20. #include "pfp.h"
  21. DWORD
  22. ScepUnescapeAndAddCRLF(
  23. IN PWSTR pszSource,
  24. IN OUT PWSTR pszDest
  25. );
  26. DWORD
  27. ScepEscapeAndRemoveCRLF(
  28. IN const PWSTR pszSource,
  29. IN const DWORD dwSourceSize,
  30. IN OUT PWSTR pszDest
  31. );
  32. SCESTATUS
  33. ScepSaveRegistryValueToBuffer(
  34. IN DWORD RegType,
  35. IN PWSTR Value,
  36. IN DWORD dwBytes,
  37. IN OUT PSCE_REGISTRY_VALUE_INFO pRegValues
  38. );
  39. SCESTATUS
  40. ScepEnumAllRegValues(
  41. IN OUT PDWORD pCount,
  42. IN OUT PSCE_REGISTRY_VALUE_INFO *paRegValues
  43. );
  44. DWORD
  45. ScepAnalyzeOneRegistryValueNoValidate(
  46. IN HKEY hKey,
  47. IN PWSTR ValueName,
  48. IN PSCESECTION hSection OPTIONAL,
  49. IN DWORD dwAnalFlag,
  50. IN OUT PSCE_REGISTRY_VALUE_INFO pOneRegValue
  51. );
  52. SCESTATUS
  53. ScepGetRegistryValues(
  54. IN PSCECONTEXT hProfile,
  55. IN SCETYPE ProfileType,
  56. OUT PSCE_REGISTRY_VALUE_INFO * ppRegValues,
  57. OUT LPDWORD pValueCount,
  58. OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
  59. )
  60. /*++
  61. Routine Description:
  62. This routine retrieves registry values to secure from the Jet database
  63. and stores in the output buffer ppRegValues
  64. Arguments:
  65. hProfile - The profile handle context
  66. ppRegValues - the output array of registry values.
  67. pValueCount - the buffer to hold number of elements in the array
  68. Errlog - A buffer to hold all error codes/text encountered when
  69. parsing the INF file. If Errlog is NULL, no further error
  70. information is returned except the return DWORD
  71. Return value:
  72. SCESTATUS - SCESTATUS_SUCCESS
  73. SCESTATUS_NOT_ENOUGH_RESOURCE
  74. SCESTATUS_INVALID_PARAMETER
  75. SCESTATUS_BAD_FORMAT
  76. SCESTATUS_INVALID_DATA
  77. --*/
  78. {
  79. if ( !hProfile || !ppRegValues || !pValueCount ) {
  80. return(SCESTATUS_INVALID_PARAMETER);
  81. }
  82. SCESTATUS rc;
  83. PSCESECTION hSection=NULL;
  84. LPTSTR KeyName=NULL;
  85. DWORD KeyLen;
  86. DWORD i,j;
  87. LPTSTR ValueStr=NULL;
  88. LPTSTR Value=NULL;
  89. DWORD ValueLen;
  90. LONG dType;
  91. DWORD Status;
  92. DWORD dCount;
  93. rc = ScepOpenSectionForName(
  94. hProfile,
  95. (ProfileType==SCE_ENGINE_GPO) ? SCE_ENGINE_SCP : ProfileType,
  96. szRegistryValues,
  97. &hSection
  98. );
  99. if ( SCESTATUS_SUCCESS != rc ) {
  100. ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
  101. Errlog, SCEERR_OPEN,
  102. szRegistryValues
  103. );
  104. return(rc);
  105. }
  106. //
  107. // get total number of values in this section
  108. //
  109. *ppRegValues = NULL;
  110. rc = SceJetGetLineCount(
  111. hSection,
  112. NULL,
  113. FALSE,
  114. pValueCount
  115. );
  116. if ( SCESTATUS_SUCCESS == rc && *pValueCount > 0 ) {
  117. //
  118. // allocate memory for all objects
  119. //
  120. *ppRegValues = (PSCE_REGISTRY_VALUE_INFO)ScepAlloc( LMEM_ZEROINIT,
  121. *pValueCount*sizeof(SCE_REGISTRY_VALUE_INFO) );
  122. if ( *ppRegValues ) {
  123. //
  124. // goto the first line of this section
  125. //
  126. rc = SceJetGetValue(
  127. hSection,
  128. SCEJET_PREFIX_MATCH,
  129. NULL,
  130. NULL,
  131. 0,
  132. &KeyLen,
  133. NULL,
  134. 0,
  135. &ValueLen
  136. );
  137. i=0;
  138. JET_COLUMNID ColGpoID = 0;
  139. JET_ERR JetErr;
  140. LONG GpoID=0;
  141. DWORD Actual;
  142. if ( ProfileType == SCE_ENGINE_GPO ) {
  143. JET_COLUMNDEF ColumnGpoIDDef;
  144. JetErr = JetGetTableColumnInfo(
  145. hSection->JetSessionID,
  146. hSection->JetTableID,
  147. "GpoID",
  148. (VOID *)&ColumnGpoIDDef,
  149. sizeof(JET_COLUMNDEF),
  150. JET_ColInfo
  151. );
  152. if ( JET_errSuccess == JetErr ) {
  153. ColGpoID = ColumnGpoIDDef.columnid;
  154. }
  155. }
  156. //
  157. // this count is for SCE_ENGINE_GPO type
  158. //
  159. dCount=0;
  160. while ( rc == SCESTATUS_SUCCESS ||
  161. rc == SCESTATUS_BUFFER_TOO_SMALL ) {
  162. //
  163. // Get string key and a int value.
  164. //
  165. if ( i >= *pValueCount ) {
  166. //
  167. // more lines than allocated
  168. //
  169. rc = SCESTATUS_INVALID_DATA;
  170. ScepBuildErrorLogInfo(ERROR_INVALID_DATA,
  171. Errlog,
  172. SCEERR_MORE_OBJECTS,
  173. *pValueCount
  174. );
  175. break;
  176. }
  177. GpoID = 1;
  178. if ( ProfileType == SCE_ENGINE_GPO ) {
  179. GpoID = 0;
  180. if ( ColGpoID > 0 ) {
  181. //
  182. // query if the setting comes from a GPO
  183. // get GPO ID field from the current line
  184. //
  185. JetErr = JetRetrieveColumn(
  186. hSection->JetSessionID,
  187. hSection->JetTableID,
  188. ColGpoID,
  189. (void *)&GpoID,
  190. 4,
  191. &Actual,
  192. 0,
  193. NULL
  194. );
  195. }
  196. }
  197. if ( GpoID <= 0 ) {
  198. //
  199. // read next line
  200. //
  201. rc = SceJetGetValue(
  202. hSection,
  203. SCEJET_NEXT_LINE,
  204. NULL,
  205. NULL,
  206. 0,
  207. &KeyLen,
  208. NULL,
  209. 0,
  210. &ValueLen
  211. );
  212. continue;
  213. }
  214. dCount++;
  215. //
  216. // allocate memory for the group name and value string
  217. //
  218. KeyName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, KeyLen+2);
  219. if ( KeyName ) {
  220. Value = (PWSTR)ScepAlloc(LMEM_ZEROINIT, ValueLen+2);
  221. if ( Value ) {
  222. rc = SceJetGetValue(
  223. hSection,
  224. SCEJET_CURRENT,
  225. NULL,
  226. KeyName,
  227. KeyLen,
  228. &KeyLen,
  229. Value,
  230. ValueLen,
  231. &ValueLen
  232. );
  233. if ( rc == SCESTATUS_SUCCESS ||
  234. rc == SCESTATUS_BUFFER_TOO_SMALL ) {
  235. rc = SCESTATUS_SUCCESS;
  236. if ( ValueLen > 0 )
  237. Value[ValueLen/2] = L'\0';
  238. KeyName[KeyLen/2] = L'\0';
  239. if ( ValueLen > 0 && Value[0] != L'\0' ) {
  240. //
  241. // the first ansi character is the value type,
  242. // second ansi character is the status (if in SAP)
  243. // should be terminated by L'\0'
  244. //
  245. //dType = _wtol(Value);
  246. dType = *((CHAR *)Value) - '0';
  247. if ( *((CHAR *)Value+1) >= '0' ) {
  248. Status = *((CHAR *)Value+1) - '0';
  249. } else {
  250. Status = 0;
  251. }
  252. // if ( *(Value+2) ) { // a char and a null delimiter
  253. if ( ValueLen > 4 ) { // a char and a null delimiter
  254. //
  255. // the second field and after is the registry value
  256. // convert the multi-sz delimeter to ,
  257. //
  258. if ( dType == REG_MULTI_SZ &&
  259. (0 == _wcsicmp( KeyName, szLegalNoticeTextKeyName) ) ) {
  260. //
  261. // check for commas and escape them with "," so the UI etc.
  262. // understands this, since, at this point for lines such as
  263. // k=7,a",",b,c
  264. // pValueStr will be a,\0b\0c\0\0 which we should make
  265. // a","\0b\0c\0\0
  266. //
  267. DWORD dwCommaCount = 0;
  268. DWORD i = 0;
  269. for ( i=2; i< ValueLen/2 ; i++) {
  270. if ( Value[i] == L',' )
  271. dwCommaCount++;
  272. }
  273. if ( dwCommaCount > 0 ) {
  274. //
  275. // in this case we have to escape commas
  276. //
  277. PWSTR pszValueEscaped;
  278. DWORD dwBytes = (ValueLen/2 + 1 + dwCommaCount*2) * sizeof(WCHAR);
  279. pszValueEscaped = (PWSTR)ScepAlloc(LMEM_ZEROINIT, dwBytes);
  280. if (pszValueEscaped) {
  281. memset(pszValueEscaped, '\0', dwBytes);
  282. ValueLen = 2 * ScepEscapeString(Value,
  283. ValueLen/2,
  284. L',',
  285. L'"',
  286. pszValueEscaped
  287. );
  288. ScepFree(Value);
  289. Value = pszValueEscaped;
  290. } else {
  291. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  292. }
  293. }
  294. }
  295. ScepConvertMultiSzToDelim(Value+2, ValueLen/2-2, L'\0', L',');
  296. ValueStr = (PWSTR)ScepAlloc(0, (ValueLen/2-1)*sizeof(WCHAR));
  297. if ( ValueStr ) {
  298. wcscpy(ValueStr, Value+2);
  299. ValueStr[ValueLen/2-2] = L'\0';
  300. } else {
  301. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  302. }
  303. } // else no value available
  304. //
  305. // assign name to the output buffer
  306. //
  307. (*ppRegValues)[i].FullValueName = KeyName;
  308. KeyName = NULL;
  309. (*ppRegValues)[i].ValueType = dType;
  310. (*ppRegValues)[i].Value = ValueStr;
  311. (*ppRegValues)[i].Status = Status;
  312. ValueStr = NULL;
  313. //
  314. // increment the count
  315. //
  316. i++;
  317. } else {
  318. // shouldn't be possible to get into this loop
  319. // if it does, ignore this one
  320. rc = SCESTATUS_INVALID_DATA;
  321. }
  322. } else if ( rc != SCESTATUS_RECORD_NOT_FOUND ){
  323. ScepBuildErrorLogInfo( ERROR_READ_FAULT,
  324. Errlog,
  325. SCEERR_QUERY_VALUE,
  326. szRegistryValues
  327. );
  328. }
  329. if ( Value ) {
  330. ScepFree(Value);
  331. Value = NULL;
  332. }
  333. if ( ValueStr ) {
  334. ScepFree(ValueStr);
  335. ValueStr = NULL;
  336. }
  337. } else {
  338. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  339. }
  340. //
  341. // remember to free the KeyName
  342. //
  343. if ( KeyName ) {
  344. ScepFree(KeyName);
  345. KeyName = NULL;
  346. }
  347. if ( rc != SCESTATUS_SUCCESS ) {
  348. break;
  349. }
  350. //
  351. // read next line
  352. //
  353. rc = SceJetGetValue(
  354. hSection,
  355. SCEJET_NEXT_LINE,
  356. NULL,
  357. NULL,
  358. 0,
  359. &KeyLen,
  360. NULL,
  361. 0,
  362. &ValueLen
  363. );
  364. } else {
  365. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  366. }
  367. }
  368. } else {
  369. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  370. }
  371. }
  372. if ( rc == SCESTATUS_RECORD_NOT_FOUND ||
  373. rc == SCESTATUS_BUFFER_TOO_SMALL ) {
  374. rc = SCESTATUS_SUCCESS;
  375. }
  376. if ( rc != SCESTATUS_SUCCESS ) {
  377. //
  378. // free memory
  379. //
  380. ScepFreeRegistryValues( ppRegValues, *pValueCount );
  381. *ppRegValues = NULL;
  382. } else if ( ProfileType == SCE_ENGINE_GPO &&
  383. *pValueCount > dCount ) {
  384. //
  385. // reallocate the output buffer
  386. //
  387. if ( dCount > 0 ) {
  388. PSCE_REGISTRY_VALUE_INFO pTempRegValues = *ppRegValues;
  389. //
  390. // allocate memory for all objects
  391. //
  392. *ppRegValues = (PSCE_REGISTRY_VALUE_INFO)ScepAlloc( LMEM_ZEROINIT,
  393. dCount*sizeof(SCE_REGISTRY_VALUE_INFO) );
  394. if ( *ppRegValues ) {
  395. for ( i=0,j=0; i<*pValueCount; i++ ) {
  396. if ( pTempRegValues[i].Value ) {
  397. (*ppRegValues)[j].FullValueName = pTempRegValues[i].FullValueName;
  398. (*ppRegValues)[j].Value = pTempRegValues[i].Value;
  399. (*ppRegValues)[j].ValueType = pTempRegValues[i].ValueType;
  400. (*ppRegValues)[j].Status = pTempRegValues[i].Status;
  401. j++;
  402. } else if ( pTempRegValues[i].FullValueName ) {
  403. ScepFree( pTempRegValues[i].FullValueName );
  404. }
  405. }
  406. ScepFree( pTempRegValues );
  407. *pValueCount = dCount;
  408. } else {
  409. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  410. *pValueCount = 0;
  411. }
  412. } else {
  413. //
  414. // no registry value from the GPO settings are found
  415. //
  416. ScepFreeRegistryValues( ppRegValues, *pValueCount );
  417. *ppRegValues = NULL;
  418. *pValueCount = 0;
  419. }
  420. }
  421. //
  422. // close the section
  423. //
  424. SceJetCloseSection(&hSection, TRUE);
  425. return(rc);
  426. }
  427. SCESTATUS
  428. ScepConfigureRegistryValues(
  429. IN PSCECONTEXT hProfile OPTIONAL,
  430. IN PSCE_REGISTRY_VALUE_INFO pRegValues,
  431. IN DWORD ValueCount,
  432. IN PSCE_ERROR_LOG_INFO *pErrLog,
  433. IN DWORD ConfigOptions,
  434. OUT PBOOL pAnythingSet
  435. )
  436. /* ++
  437. Routine Description:
  438. This routine configure registry values in the area of security
  439. policy.
  440. Arguments:
  441. pRegValues - The array of registry values to configure
  442. ValueCount - the number of values to configure
  443. Return value:
  444. SCESTATUS_SUCCESS
  445. SCESTATUS_NOT_ENOUGH_RESOURCE
  446. SCESTATUS_INVALID_PARAMETER
  447. SCESTATUS_OTHER_ERROR
  448. -- */
  449. {
  450. if ( !pRegValues || ValueCount == 0 ) {
  451. //
  452. // if no info to configure
  453. //
  454. return SCESTATUS_SUCCESS;
  455. }
  456. DWORD rc;
  457. SCESTATUS Saverc=SCESTATUS_SUCCESS;
  458. PWSTR pStart, pTemp, pValue;
  459. HKEY hKey=NULL;
  460. HKEY hKeyRoot;
  461. PSCESECTION hSectionDomain=NULL;
  462. PSCESECTION hSectionTattoo=NULL;
  463. SCE_REGISTRY_VALUE_INFO OneRegValue;
  464. if ( pAnythingSet )
  465. *pAnythingSet = FALSE;
  466. if ( (ConfigOptions & SCE_POLICY_TEMPLATE) && hProfile ) {
  467. ScepTattooOpenPolicySections(
  468. hProfile,
  469. szRegistryValues,
  470. &hSectionDomain,
  471. &hSectionTattoo
  472. );
  473. }
  474. for ( DWORD i=0; i<ValueCount; i++ ) {
  475. if ( !pRegValues[i].FullValueName ||
  476. !pRegValues[i].Value ) {
  477. //
  478. // no value to configure
  479. //
  480. continue;
  481. }
  482. ScepLogOutput3(2, 0, SCEDLL_SCP_CONFIGURE, pRegValues[i].FullValueName);
  483. //
  484. // look for the first \\
  485. //
  486. pStart = wcschr(pRegValues[i].FullValueName, L'\\') ;
  487. if ( !pStart ) {
  488. Saverc = SCESTATUS_INVALID_DATA;
  489. if ( pErrLog ) {
  490. ScepBuildErrorLogInfo(Saverc,pErrLog, SCEDLL_SCP_ERROR_CONFIGURE,
  491. pRegValues[i].FullValueName);
  492. } else {
  493. ScepLogOutput3(1, Saverc, SCEDLL_SCP_ERROR_CONFIGURE, pRegValues[i].FullValueName);
  494. }
  495. if ( ConfigOptions & SCE_RSOP_CALLBACK )
  496. ScepRsopLog(SCE_RSOP_REGISTRY_VALUE_INFO, Saverc, pRegValues[i].FullValueName, 0, 0);
  497. continue;
  498. }
  499. //
  500. // find the root key
  501. //
  502. if ( (7 == pStart-pRegValues[i].FullValueName) &&
  503. (0 == _wcsnicmp(L"MACHINE", pRegValues[i].FullValueName, 7)) ) {
  504. hKeyRoot = HKEY_LOCAL_MACHINE;
  505. } else if ( (5 == pStart-pRegValues[i].FullValueName) &&
  506. (0 == _wcsnicmp(L"USERS", pRegValues[i].FullValueName, 5)) ) {
  507. hKeyRoot = HKEY_USERS;
  508. } else if ( (12 == pStart-pRegValues[i].FullValueName) &&
  509. (0 == _wcsnicmp(L"CLASSES_ROOT", pRegValues[i].FullValueName, 12)) ) {
  510. hKeyRoot = HKEY_CLASSES_ROOT;
  511. } else {
  512. Saverc = SCESTATUS_INVALID_DATA;
  513. if ( pErrLog ) {
  514. ScepBuildErrorLogInfo(Saverc,pErrLog, SCEDLL_SCP_ERROR_CONFIGURE,
  515. pRegValues[i].FullValueName);
  516. } else {
  517. ScepLogOutput3(1, Saverc, SCEDLL_SCP_ERROR_CONFIGURE, pRegValues[i].FullValueName);
  518. }
  519. if ( ConfigOptions & SCE_RSOP_CALLBACK )
  520. ScepRsopLog(SCE_RSOP_REGISTRY_VALUE_INFO, Saverc, pRegValues[i].FullValueName, 0, 0);
  521. continue;
  522. }
  523. //
  524. // find the value name
  525. //
  526. pValue = pStart+1;
  527. do {
  528. pTemp = wcschr(pValue, L'\\');
  529. if ( pTemp ) {
  530. pValue = pTemp+1;
  531. }
  532. } while ( pTemp );
  533. if ( pValue == pStart+1 ) {
  534. Saverc = SCESTATUS_INVALID_DATA;
  535. if ( pErrLog ) {
  536. ScepBuildErrorLogInfo(Saverc,pErrLog, SCEDLL_SCP_ERROR_CONFIGURE,
  537. pRegValues[i].FullValueName);
  538. } else {
  539. ScepLogOutput3(1, Saverc, SCEDLL_SCP_ERROR_CONFIGURE, pRegValues[i].FullValueName);
  540. }
  541. if ( ConfigOptions & SCE_RSOP_CALLBACK )
  542. ScepRsopLog(SCE_RSOP_REGISTRY_VALUE_INFO, Saverc, pRegValues[i].FullValueName, 0, 0);
  543. continue;
  544. }
  545. //
  546. // terminate the subkey for now
  547. //
  548. *(pValue-1) = L'\0';
  549. //
  550. // set the value
  551. // always create the key if it does not exist.
  552. //
  553. rc = RegCreateKeyEx(hKeyRoot,
  554. pStart+1,
  555. 0,
  556. NULL,
  557. 0,
  558. KEY_READ | KEY_SET_VALUE,
  559. NULL,
  560. &hKey,
  561. NULL
  562. );
  563. if ( rc == ERROR_SUCCESS ||
  564. rc == ERROR_ALREADY_EXISTS ) {
  565. /*
  566. if(( rc = RegOpenKeyEx(hKeyRoot,
  567. pStart+1,
  568. 0,
  569. KEY_SET_VALUE,
  570. &hKey
  571. )) == ERROR_SUCCESS ) {
  572. */
  573. //
  574. // restore the char
  575. //
  576. *(pValue-1) = L'\\';
  577. OneRegValue.FullValueName = NULL;
  578. OneRegValue.Value = NULL;
  579. BOOL bLMSetting = FALSE;
  580. if ( (REG_DWORD == pRegValues[i].ValueType) &&
  581. _wcsicmp(L"MACHINE\\System\\CurrentControlSet\\Control\\Lsa\\LmCompatibilityLevel", pRegValues[i].FullValueName) == 0 ) {
  582. //
  583. // check if in setup upgrade
  584. //
  585. DWORD dwInSetup=0;
  586. DWORD dwUpgraded=0;
  587. ScepRegQueryIntValue(HKEY_LOCAL_MACHINE,
  588. TEXT("System\\Setup"),
  589. TEXT("SystemSetupInProgress"),
  590. &dwInSetup
  591. );
  592. if ( dwInSetup ) {
  593. //
  594. // if system is upgraded, the state is stored in registry
  595. // by SCE client at very beginning of GUI setup
  596. //
  597. ScepRegQueryIntValue(
  598. HKEY_LOCAL_MACHINE,
  599. SCE_ROOT_PATH,
  600. TEXT("SetupUpgraded"),
  601. (DWORD *)&dwUpgraded
  602. );
  603. if ( dwUpgraded ) {
  604. //
  605. // in setup upgrade, we need to do special check about
  606. // this setting
  607. //
  608. bLMSetting = TRUE;
  609. }
  610. }
  611. }
  612. //
  613. // if in policy propagation, query the existing value
  614. //
  615. if ( ( (ConfigOptions & SCE_POLICY_TEMPLATE) && hProfile ) ||
  616. bLMSetting ) {
  617. OneRegValue.FullValueName = pRegValues[i].FullValueName;
  618. OneRegValue.ValueType = pRegValues[i].ValueType;
  619. OneRegValue.Status = 0;
  620. DWORD rc2 = ScepAnalyzeOneRegistryValueNoValidate(
  621. hKey,
  622. pValue,
  623. NULL,
  624. SCEREG_VALUE_SYSTEM,
  625. &OneRegValue
  626. );
  627. if ( ERROR_SUCCESS != rc2 ) {
  628. if ( !bLMSetting ) {
  629. ScepLogOutput3(1, 0, SCESRV_POLICY_TATTOO_ERROR_QUERY, rc2, pRegValues[i].FullValueName);
  630. } else if ( ERROR_FILE_NOT_FOUND != rc2 ) {
  631. ScepLogOutput3(1, 0, SCESRV_SETUPUPD_ERROR_LMCOMPAT, rc2, pRegValues[i].FullValueName);
  632. }
  633. }
  634. }
  635. if ( REG_DWORD == pRegValues[i].ValueType ) {
  636. //
  637. // REG_DWORD type, value is a dword
  638. //
  639. LONG RegValue = _wtol(pRegValues[i].Value);
  640. if ( !bLMSetting || OneRegValue.Value == NULL ||
  641. _wtol(OneRegValue.Value) <= RegValue ) {
  642. rc = RegSetValueEx( hKey,
  643. pValue,
  644. 0,
  645. REG_DWORD,
  646. (BYTE *)&RegValue,
  647. sizeof(DWORD)
  648. );
  649. } else {
  650. //
  651. // for LMCompatibility level, if in setup, set this value only if
  652. // current system setting is less than configuration, or not defined
  653. //
  654. ScepLogOutput3(2, 0, SCESRV_SETUPUPD_IGNORE_LMCOMPAT, pRegValues[i].FullValueName);
  655. }
  656. } else if ( -1 == pRegValues[i].ValueType ) {
  657. //
  658. // delete the registry value
  659. //
  660. rc = RegDeleteValue(hKey, pValue);
  661. //
  662. // if the value doesn't exist, ignore the error
  663. //
  664. if ( ERROR_FILE_NOT_FOUND == rc )
  665. rc = ERROR_SUCCESS;
  666. } else {
  667. PBYTE pRegBytes=NULL;
  668. DWORD nLen;
  669. nLen = wcslen(pRegValues[i].Value);
  670. if ( REG_MULTI_SZ == pRegValues[i].ValueType || REG_QWORD == pRegValues[i].ValueType) {
  671. //
  672. // translate the comma delimited string to multi-sz string
  673. //
  674. //
  675. // LegalNoticeText is special cased i.e. \0 should be converted to \r\n
  676. // and commas should be unescaped before writing this value into the registry
  677. //
  678. BOOL bIsLegalNoticeText = FALSE;
  679. if ( !(REG_MULTI_SZ == pRegValues[i].ValueType &&
  680. (0 == _wcsicmp(szLegalNoticeTextKeyName, pRegValues[i].FullValueName ) ) ) ) {
  681. pRegBytes = (PBYTE)ScepAlloc(0, (nLen+2)*sizeof(WCHAR));
  682. if ( pRegBytes ) {
  683. wcscpy((PWSTR)pRegBytes, pRegValues[i].Value);
  684. ((PWSTR)pRegBytes)[nLen] = L'\0';
  685. ((PWSTR)pRegBytes)[nLen+1] = L'\0';
  686. ScepConvertMultiSzToDelim((PWSTR)pRegBytes,
  687. nLen+1,
  688. L',',
  689. L'\0'
  690. );
  691. } else {
  692. rc = ERROR_NOT_ENOUGH_MEMORY;
  693. }
  694. }
  695. else {
  696. DWORD dwCommaCount = 0;
  697. DWORD dwBytes;
  698. bIsLegalNoticeText = TRUE;
  699. for ( DWORD dwIndex = 0; dwIndex <= nLen; dwIndex++) {
  700. if ( pRegValues[i].Value[dwIndex] == L',' )
  701. dwCommaCount++;
  702. }
  703. dwBytes = (nLen + dwCommaCount + 2)*sizeof(WCHAR);
  704. pRegBytes = (PBYTE)ScepAlloc(0, dwBytes);
  705. if ( pRegBytes ) {
  706. memset(pRegBytes, '\0', dwBytes);
  707. //
  708. // unescape the "," and add \r\n wherever there is a ,
  709. //
  710. nLen = ScepUnescapeAndAddCRLF( pRegValues[i].Value, (PWSTR) pRegBytes);
  711. } else {
  712. rc = ERROR_NOT_ENOUGH_MEMORY;
  713. }
  714. }
  715. if ( rc == NO_ERROR ) {
  716. //
  717. // engine/UI treat LegalNoticeText as REG_MULTI_SZ but
  718. // we force it to be REG_SZ for compatibility sake
  719. //
  720. rc = RegSetValueEx( hKey,
  721. pValue,
  722. 0,
  723. bIsLegalNoticeText ? REG_SZ : pRegValues[i].ValueType,
  724. pRegBytes,
  725. (nLen+2)*sizeof(WCHAR)
  726. );
  727. ScepFree(pRegBytes);
  728. }
  729. } else if ( REG_BINARY == pRegValues[i].ValueType ) {
  730. if ( nLen > 0 ) {
  731. //
  732. // binary type, translate the unicode string to binary data
  733. // 4 bytes (2 wchars) to 1 byte
  734. //
  735. DWORD newLen;
  736. newLen = nLen/2;
  737. if ( nLen % 2 ) {
  738. newLen++; // pad a leading 0
  739. }
  740. pRegBytes = (PBYTE)ScepAlloc(0, newLen);
  741. if ( pRegBytes ) {
  742. BYTE dByte;
  743. for ( INT j=newLen-1; j>=0; j-- ) {
  744. if ( nLen % 2 ) {
  745. // odd number of chars
  746. dByte = (pRegValues[i].Value[j*2]-L'0') % 16;
  747. if ( j*2 >= 1 ) {
  748. dByte += ((pRegValues[i].Value[j*2-1]-L'0') % 16) * 16;
  749. }
  750. } else {
  751. // even number of chars
  752. dByte = (pRegValues[i].Value[j*2+1]-L'0') % 16;
  753. dByte += ((pRegValues[i].Value[j*2]-L'0') % 16) * 16;
  754. }
  755. pRegBytes[j] = dByte;
  756. }
  757. rc = RegSetValueEx( hKey,
  758. pValue,
  759. 0,
  760. REG_BINARY,
  761. pRegBytes,
  762. newLen
  763. );
  764. ScepFree(pRegBytes);
  765. } else {
  766. rc = ERROR_NOT_ENOUGH_MEMORY;
  767. }
  768. }
  769. } else {
  770. //
  771. // sz type, expand_sz
  772. //
  773. rc = RegSetValueEx( hKey,
  774. pValue,
  775. 0,
  776. pRegValues[i].ValueType,
  777. (BYTE *)(pRegValues[i].Value),
  778. (nLen)*sizeof(WCHAR)
  779. );
  780. }
  781. }
  782. //
  783. // manage the tattoo value
  784. //
  785. if ( (ConfigOptions & SCE_POLICY_TEMPLATE) && hProfile ) {
  786. //
  787. // if can't query system setting (OneRegValue.Value == NULL)
  788. // (may be because they are deleted e.g. demotion)
  789. // we still need to delete the tattoo values
  790. //
  791. ScepTattooManageOneRegistryValue(hSectionDomain,
  792. hSectionTattoo,
  793. pRegValues[i].FullValueName,
  794. 0,
  795. &OneRegValue,
  796. rc
  797. );
  798. }
  799. if ( OneRegValue.Value ) ScepFree(OneRegValue.Value);
  800. RegCloseKey( hKey );
  801. }
  802. if ( NO_ERROR != rc ) {
  803. if ( pErrLog ) {
  804. ScepBuildErrorLogInfo(rc,pErrLog, SCEDLL_ERROR_SET_INFO,
  805. pRegValues[i].FullValueName);
  806. }
  807. if ( ERROR_FILE_NOT_FOUND != rc &&
  808. ERROR_PATH_NOT_FOUND != rc ) {
  809. ScepLogOutput3(1, rc, SCEDLL_ERROR_SET_INFO, pRegValues[i].FullValueName);
  810. Saverc = ScepDosErrorToSceStatus(rc);
  811. }
  812. }
  813. if ( ConfigOptions & SCE_RSOP_CALLBACK )
  814. ScepRsopLog(SCE_RSOP_REGISTRY_VALUE_INFO, rc, pRegValues[i].FullValueName, 0, 0);
  815. if ( pAnythingSet ) {
  816. *pAnythingSet = TRUE;
  817. }
  818. }
  819. if ( hSectionDomain ) SceJetCloseSection(&hSectionDomain, TRUE);
  820. if ( hSectionTattoo ) SceJetCloseSection(&hSectionTattoo, TRUE);
  821. return(Saverc);
  822. }
  823. DWORD
  824. ScepUnescapeAndAddCRLF(
  825. IN PWSTR pszSource,
  826. IN OUT PWSTR pszDest
  827. )
  828. /* ++
  829. Routine Description:
  830. Primarily used just before configuration
  831. Unescapes commas i.e. a","\0b\0c\0\0 -> a,\0b\0c\0\0
  832. Also replaces , with \r\n
  833. Arguments:
  834. pszSource - The source string
  835. dwSourceChars - The number of chars in pszSource
  836. pszDest - The destination string
  837. Return value:
  838. Number of characters copied to the destination
  839. -- */
  840. {
  841. DWORD dwCharsCopied = 0;
  842. while (pszSource[0] != L'\0') {
  843. if (0 == wcsncmp(pszSource, L"\",\"", 3)) {
  844. pszDest[0] = L',';
  845. ++dwCharsCopied;
  846. ++pszDest;
  847. pszSource +=3;
  848. }
  849. else if (pszSource[0] == L',') {
  850. pszDest[0] = L'\r';
  851. pszDest[1] = L'\n';
  852. dwCharsCopied +=2;
  853. pszDest +=2 ;
  854. ++pszSource;
  855. }
  856. else {
  857. pszDest[0] = pszSource[0];
  858. ++dwCharsCopied;
  859. ++pszDest;
  860. ++pszSource;
  861. }
  862. }
  863. pszDest = L'\0';
  864. ++dwCharsCopied;
  865. return dwCharsCopied;
  866. }
  867. DWORD
  868. ScepEscapeAndRemoveCRLF(
  869. IN const PWSTR pszSource,
  870. IN const DWORD dwSourceSize,
  871. IN OUT PWSTR pszDest
  872. )
  873. /* ++
  874. Routine Description:
  875. Primarily used before analysis
  876. Escapes commas i.e. a,\0b\0c\0\0 -> a","\0b\0c\0\0
  877. Also replaces \r\n with ,
  878. This routine is the inverse of ScepUnescapeAndAddCRLF
  879. Arguments:
  880. pszSource - The source string
  881. dwSourceChars - The number of chars in pszSource
  882. pszDest - The destination string
  883. Return value:
  884. Number of characters copied to the destination
  885. -- */
  886. {
  887. DWORD dwSourceIndex = 0;
  888. DWORD dwCopiedChars = 0;
  889. while (dwSourceIndex < dwSourceSize) {
  890. if (0 == wcsncmp(pszSource + dwSourceIndex, L"\r\n", 2)) {
  891. pszDest[0] = L',';
  892. ++pszDest;
  893. ++dwCopiedChars;
  894. dwSourceIndex +=2;
  895. }
  896. else if (pszSource[dwSourceIndex] == L',') {
  897. pszDest[0] = L'"';
  898. pszDest[1] = L',';
  899. pszDest[2] = L'"';
  900. pszDest +=3 ;
  901. dwCopiedChars +=3 ;
  902. ++dwSourceIndex;
  903. }
  904. else {
  905. pszDest[0] = pszSource[dwSourceIndex];
  906. ++pszDest;
  907. ++dwCopiedChars;
  908. ++dwSourceIndex;
  909. }
  910. }
  911. pszDest = L'\0';
  912. return dwCopiedChars;
  913. }
  914. SCESTATUS
  915. ScepAnalyzeRegistryValues(
  916. IN PSCECONTEXT hProfile,
  917. IN DWORD dwAnalFlag,
  918. IN PSCE_PROFILE_INFO pSmpInfo
  919. )
  920. /* ++
  921. Routine Description:
  922. This routine analyze registry values in the area of security
  923. policy.
  924. Arguments:
  925. Return value:
  926. SCESTATUS_SUCCESS
  927. SCESTATUS_NOT_ENOUGH_RESOURCE
  928. SCESTATUS_INVALID_PARAMETER
  929. SCESTATUS_OTHER_ERROR
  930. -- */
  931. {
  932. if ( !pSmpInfo ) {
  933. return SCESTATUS_INVALID_PARAMETER;
  934. }
  935. if ( (dwAnalFlag != SCEREG_VALUE_SYSTEM) && !hProfile ) {
  936. return SCESTATUS_INVALID_PARAMETER;
  937. }
  938. SCESTATUS Saverc=SCESTATUS_SUCCESS;
  939. if ( dwAnalFlag != SCEREG_VALUE_ROLLBACK ) {
  940. Saverc = ScepEnumAllRegValues(
  941. &(pSmpInfo->RegValueCount),
  942. &(pSmpInfo->aRegValues)
  943. );
  944. }
  945. if ( Saverc != SCESTATUS_SUCCESS ) {
  946. return(Saverc);
  947. }
  948. if ( pSmpInfo->RegValueCount == 0 ||
  949. pSmpInfo->aRegValues == NULL ) {
  950. //
  951. // if no info to configure
  952. //
  953. return SCESTATUS_SUCCESS;
  954. }
  955. DWORD rc;
  956. DWORD i;
  957. PSCESECTION hSection=NULL;
  958. SCEJET_TABLE_TYPE tblType;
  959. if ( dwAnalFlag != SCEREG_VALUE_SYSTEM ) {
  960. //
  961. // query value from system doesn't require accessing the database
  962. //
  963. switch ( dwAnalFlag ) {
  964. case SCEREG_VALUE_SNAPSHOT:
  965. case SCEREG_VALUE_FILTER:
  966. case SCEREG_VALUE_ROLLBACK:
  967. tblType = SCEJET_TABLE_SMP;
  968. break;
  969. default:
  970. tblType = SCEJET_TABLE_SAP;
  971. break;
  972. }
  973. //
  974. // Prepare a new section
  975. // for delay filter mode, data is written to the SMP (local) table
  976. // when the setting is different from the effective setting (changed outside GPO)
  977. //
  978. Saverc = ScepStartANewSection(
  979. hProfile,
  980. &hSection,
  981. tblType,
  982. szRegistryValues
  983. );
  984. if ( Saverc != SCESTATUS_SUCCESS ) {
  985. ScepLogOutput3(1, ScepSceStatusToDosError(Saverc),
  986. SCEDLL_SAP_START_SECTION, (PWSTR)szRegistryValues);
  987. return(Saverc);
  988. }
  989. }
  990. for ( i=0; i<pSmpInfo->RegValueCount; i++ ) {
  991. if ( dwAnalFlag == SCEREG_VALUE_SYSTEM ) {
  992. //
  993. // mark the status field
  994. //
  995. (pSmpInfo->aRegValues)[i].Status = SCE_STATUS_ERROR_NOT_AVAILABLE;
  996. }
  997. if ( !((pSmpInfo->aRegValues)[i].FullValueName) ) {
  998. continue;
  999. }
  1000. ScepLogOutput3(2, 0, SCEDLL_SAP_ANALYZE, (pSmpInfo->aRegValues)[i].FullValueName);
  1001. rc = ScepAnalyzeOneRegistryValue(
  1002. hSection,
  1003. dwAnalFlag,
  1004. &((pSmpInfo->aRegValues)[i])
  1005. );
  1006. if ( SCESTATUS_INVALID_PARAMETER == rc ||
  1007. SCESTATUS_INVALID_DATA == rc ) {
  1008. continue;
  1009. }
  1010. if ( SCESTATUS_SUCCESS != rc ) {
  1011. Saverc = rc;
  1012. break;
  1013. }
  1014. }
  1015. //
  1016. // close the section
  1017. //
  1018. SceJetCloseSection( &hSection, TRUE);
  1019. return(Saverc);
  1020. }
  1021. SCESTATUS
  1022. ScepAnalyzeOneRegistryValue(
  1023. IN PSCESECTION hSection OPTIONAL,
  1024. IN DWORD dwAnalFlag,
  1025. IN OUT PSCE_REGISTRY_VALUE_INFO pOneRegValue
  1026. )
  1027. {
  1028. SCESTATUS Saverc=SCESTATUS_SUCCESS;
  1029. PWSTR pStart, pTemp, pValue;
  1030. HKEY hKey=NULL, hKeyRoot;
  1031. DWORD rc=0;
  1032. if ( pOneRegValue == NULL ||
  1033. pOneRegValue->FullValueName == NULL ) {
  1034. return(SCESTATUS_INVALID_DATA);
  1035. }
  1036. if ( hSection == NULL &&
  1037. (SCEREG_VALUE_ANALYZE == dwAnalFlag ||
  1038. SCEREG_VALUE_ROLLBACK == dwAnalFlag) ) {
  1039. return(SCESTATUS_INVALID_PARAMETER);
  1040. }
  1041. //
  1042. // look for the first \\
  1043. //
  1044. pStart = wcschr(pOneRegValue->FullValueName, L'\\') ;
  1045. if ( !pStart ) {
  1046. //
  1047. // if it's in snapshot mode, ignore bogus reg value names
  1048. //
  1049. Saverc = SCESTATUS_INVALID_DATA;
  1050. if ( SCEREG_VALUE_ANALYZE == dwAnalFlag ) {
  1051. //
  1052. // error analyzing the value, save it
  1053. //
  1054. ScepSaveRegistryValue(
  1055. hSection,
  1056. pOneRegValue->FullValueName,
  1057. pOneRegValue->ValueType,
  1058. NULL,
  1059. 0,
  1060. SCE_STATUS_ERROR_NOT_AVAILABLE
  1061. );
  1062. }
  1063. return(Saverc);
  1064. }
  1065. //
  1066. // find the root key
  1067. //
  1068. if ( (7 == pStart-pOneRegValue->FullValueName) &&
  1069. (0 == _wcsnicmp(L"MACHINE", pOneRegValue->FullValueName, 7)) ) {
  1070. hKeyRoot = HKEY_LOCAL_MACHINE;
  1071. } else if ( (5 == pStart-pOneRegValue->FullValueName) &&
  1072. (0 == _wcsnicmp(L"USERS", pOneRegValue->FullValueName, 5)) ) {
  1073. hKeyRoot = HKEY_USERS;
  1074. } else if ( (12 == pStart-pOneRegValue->FullValueName) &&
  1075. (0 == _wcsnicmp(L"CLASSES_ROOT", pOneRegValue->FullValueName, 12)) ) {
  1076. hKeyRoot = HKEY_CLASSES_ROOT;
  1077. } else {
  1078. //
  1079. // if it's in snapshot mode, ignore bogus reg value names
  1080. //
  1081. Saverc = SCESTATUS_INVALID_DATA;
  1082. if ( SCEREG_VALUE_ANALYZE == dwAnalFlag ) {
  1083. //
  1084. // error analyzing the value, save it
  1085. //
  1086. ScepSaveRegistryValue(
  1087. hSection,
  1088. pOneRegValue->FullValueName,
  1089. pOneRegValue->ValueType,
  1090. NULL,
  1091. 0,
  1092. SCE_STATUS_ERROR_NOT_AVAILABLE
  1093. );
  1094. }
  1095. return(Saverc);
  1096. }
  1097. //
  1098. // find the value name
  1099. //
  1100. pValue = pStart+1;
  1101. do {
  1102. pTemp = wcschr(pValue, L'\\');
  1103. if ( pTemp ) {
  1104. pValue = pTemp+1;
  1105. }
  1106. } while ( pTemp );
  1107. if ( pValue == pStart+1 ) {
  1108. //
  1109. // if it's in snapshot mode, ignore bogus reg value names
  1110. //
  1111. Saverc = SCESTATUS_INVALID_DATA;
  1112. if ( SCEREG_VALUE_ANALYZE == dwAnalFlag ) {
  1113. //
  1114. // error analyzing the value, save it
  1115. //
  1116. ScepSaveRegistryValue(
  1117. hSection,
  1118. pOneRegValue->FullValueName,
  1119. pOneRegValue->ValueType,
  1120. NULL,
  1121. 0,
  1122. SCE_STATUS_ERROR_NOT_AVAILABLE
  1123. );
  1124. }
  1125. return(Saverc);
  1126. }
  1127. //
  1128. // terminate the subkey for now
  1129. //
  1130. *(pValue-1) = L'\0';
  1131. if(( rc = RegOpenKeyEx(hKeyRoot,
  1132. pStart+1,
  1133. 0,
  1134. KEY_READ,
  1135. &hKey
  1136. )) == ERROR_SUCCESS ) {
  1137. //
  1138. // resotre the char
  1139. //
  1140. *(pValue-1) = L'\\';
  1141. rc = ScepAnalyzeOneRegistryValueNoValidate(hKey,
  1142. pValue,
  1143. hSection,
  1144. dwAnalFlag,
  1145. pOneRegValue
  1146. );
  1147. //
  1148. // close the key
  1149. //
  1150. RegCloseKey(hKey);
  1151. } else {
  1152. //
  1153. // error analyzing the value, or it doesn't exist, save it
  1154. //
  1155. if ( (SCEREG_VALUE_ANALYZE == dwAnalFlag) ||
  1156. (SCEREG_VALUE_ROLLBACK == dwAnalFlag) ) {
  1157. ScepSaveRegistryValue(
  1158. hSection,
  1159. pOneRegValue->FullValueName,
  1160. (SCEREG_VALUE_ANALYZE == dwAnalFlag) ? pOneRegValue->ValueType : -1,
  1161. NULL,
  1162. 0,
  1163. (SCEREG_VALUE_ANALYZE == dwAnalFlag) ? SCE_STATUS_ERROR_NOT_AVAILABLE : 0
  1164. );
  1165. }
  1166. if ( rc == ERROR_FILE_NOT_FOUND ||
  1167. rc == ERROR_PATH_NOT_FOUND ||
  1168. rc == ERROR_INVALID_HANDLE ||
  1169. rc == ERROR_ACCESS_DENIED ) {
  1170. rc = ERROR_SUCCESS;
  1171. }
  1172. }
  1173. if ( rc != NO_ERROR ) {
  1174. ScepLogOutput3(1, rc, SCEDLL_SAP_ERROR_ANALYZE, pOneRegValue->FullValueName);
  1175. Saverc = ScepDosErrorToSceStatus(rc);
  1176. }
  1177. return(Saverc);
  1178. }
  1179. DWORD
  1180. ScepAnalyzeOneRegistryValueNoValidate(
  1181. IN HKEY hKey,
  1182. IN PWSTR ValueName,
  1183. IN PSCESECTION hSection OPTIONAL,
  1184. IN DWORD dwAnalFlag,
  1185. IN OUT PSCE_REGISTRY_VALUE_INFO pOneRegValue
  1186. )
  1187. /*
  1188. Query and/or compare one registry value without validating the value name, etc.
  1189. The validation should be done outside of this routine.
  1190. This routine is primarily defined for sharing in both configuration and analysis.
  1191. */
  1192. {
  1193. if ( hKey == NULL || ValueName == NULL || pOneRegValue == NULL )
  1194. return(ERROR_INVALID_PARAMETER);
  1195. DWORD rc;
  1196. DWORD dSize=0;
  1197. DWORD RegType=pOneRegValue->ValueType;
  1198. DWORD RegData=0;
  1199. PWSTR strValue=NULL;
  1200. BOOL bIsLegalNoticeText = FALSE;
  1201. if ( SCEREG_VALUE_SYSTEM == dwAnalFlag ) {
  1202. //
  1203. // reset the status field, it's not error'ed
  1204. //
  1205. pOneRegValue->Status = 0;
  1206. }
  1207. if(( rc = RegQueryValueEx(hKey,
  1208. ValueName,
  1209. 0,
  1210. &RegType,
  1211. NULL,
  1212. &dSize
  1213. )) == ERROR_SUCCESS ) {
  1214. //
  1215. // we treat REG_DWORD_BIG_ENDIAN the same as REG_DWORD
  1216. //
  1217. if ( RegType == REG_DWORD_BIG_ENDIAN ) {
  1218. RegType = REG_DWORD;
  1219. }
  1220. if ( 0 == _wcsicmp( pOneRegValue->FullValueName, szLegalNoticeTextKeyName)) {
  1221. bIsLegalNoticeText = TRUE;
  1222. RegType = REG_MULTI_SZ;
  1223. } else if ( RegType != pOneRegValue->ValueType ) {
  1224. //
  1225. // if it's a wrong type, we assure it's not the value we found
  1226. //
  1227. rc = ERROR_FILE_NOT_FOUND;
  1228. }
  1229. if ( ERROR_SUCCESS == rc ) {
  1230. switch (RegType) {
  1231. case REG_DWORD:
  1232. dSize = sizeof(DWORD);
  1233. rc = RegQueryValueEx(hKey,
  1234. ValueName,
  1235. 0,
  1236. &RegType,
  1237. (BYTE *)&RegData,
  1238. &dSize
  1239. );
  1240. break;
  1241. default:
  1242. //
  1243. // can be REG_BINARY, REG_MULTI_SZ, REG_SZ, and REG_EXPAND_SZ
  1244. // everything else is treated as REG_SZ
  1245. //
  1246. strValue = (PWSTR)ScepAlloc(0, dSize + 4);
  1247. dSize += 2;
  1248. if ( strValue ) {
  1249. memset(strValue, 0, dSize + 4 - 2);
  1250. rc = RegQueryValueEx(hKey,
  1251. ValueName,
  1252. 0,
  1253. &RegType,
  1254. (BYTE *)strValue,
  1255. &dSize
  1256. );
  1257. if (bIsLegalNoticeText) {
  1258. RegType = REG_MULTI_SZ;
  1259. }
  1260. } else {
  1261. rc = ERROR_NOT_ENOUGH_MEMORY;
  1262. }
  1263. break;
  1264. }
  1265. }
  1266. }
  1267. if ( rc == NO_ERROR ) {
  1268. DWORD dwStatus = SCE_STATUS_NOT_CONFIGURED;
  1269. if ( SCEREG_VALUE_SNAPSHOT == dwAnalFlag ||
  1270. SCEREG_VALUE_ROLLBACK == dwAnalFlag )
  1271. dwStatus = 0;
  1272. switch ( RegType ) {
  1273. case REG_DWORD:
  1274. case REG_DWORD_BIG_ENDIAN:
  1275. if ( pOneRegValue->Value == NULL ||
  1276. (SCEREG_VALUE_SNAPSHOT == dwAnalFlag) ) {
  1277. if ( SCEREG_VALUE_SYSTEM == dwAnalFlag ) {
  1278. //
  1279. // add the value to OneRegValue buffer
  1280. //
  1281. rc = ScepSaveRegistryValueToBuffer(
  1282. REG_DWORD,
  1283. (PWSTR)&RegData,
  1284. sizeof(DWORD),
  1285. pOneRegValue
  1286. );
  1287. } else if ( SCEREG_VALUE_FILTER != dwAnalFlag ) {
  1288. //
  1289. // not configured, or snapshot the current value
  1290. //
  1291. rc = ScepSaveRegistryValue(
  1292. hSection,
  1293. pOneRegValue->FullValueName,
  1294. REG_DWORD,
  1295. (PWSTR)&RegData,
  1296. sizeof(DWORD),
  1297. dwStatus
  1298. );
  1299. } // else for the delay filter, only query the reg values configured
  1300. } else if ( (LONG)RegData != _wtol(pOneRegValue->Value) ) {
  1301. rc = ScepSaveRegistryValue(
  1302. hSection,
  1303. pOneRegValue->FullValueName,
  1304. REG_DWORD,
  1305. (PWSTR)&RegData,
  1306. sizeof(DWORD),
  1307. 0
  1308. );
  1309. }
  1310. break;
  1311. case REG_BINARY:
  1312. DWORD nLen;
  1313. if ( pOneRegValue->Value ) {
  1314. nLen = wcslen(pOneRegValue->Value);
  1315. } else {
  1316. nLen = 0;
  1317. }
  1318. if ( pOneRegValue->Value == NULL ||
  1319. (SCEREG_VALUE_SNAPSHOT == dwAnalFlag) ||
  1320. nLen == 0 ) {
  1321. if ( SCEREG_VALUE_SYSTEM == dwAnalFlag ) {
  1322. //
  1323. // add the value to OneRegValue buffer
  1324. //
  1325. rc = ScepSaveRegistryValueToBuffer(
  1326. RegType,
  1327. strValue,
  1328. dSize,
  1329. pOneRegValue
  1330. );
  1331. } else if ( SCEREG_VALUE_FILTER != dwAnalFlag ) {
  1332. //
  1333. // not configured, or snapshot the current value
  1334. //
  1335. rc = ScepSaveRegistryValue(
  1336. hSection,
  1337. pOneRegValue->FullValueName,
  1338. RegType,
  1339. strValue,
  1340. dSize,
  1341. dwStatus
  1342. );
  1343. }
  1344. } else if ( strValue ) {
  1345. DWORD newLen;
  1346. newLen = nLen/2;
  1347. if ( nLen % 2 ) {
  1348. newLen++; // pad a leading 0
  1349. }
  1350. PBYTE pRegBytes = (PBYTE)ScepAlloc(0, newLen);
  1351. if ( pRegBytes ) {
  1352. BYTE dByte;
  1353. for ( INT j=newLen-1; j>=0; j-- ) {
  1354. if ( nLen % 2 ) {
  1355. // odd number of chars
  1356. dByte = (pOneRegValue->Value[j*2]-L'0') % 16;
  1357. if ( j*2 >= 1 ) {
  1358. dByte += ((pOneRegValue->Value[j*2-1]-L'0') % 16) * 16;
  1359. }
  1360. } else {
  1361. // even number of chars
  1362. dByte = (pOneRegValue->Value[j*2+1]-L'0') % 16;
  1363. dByte += ((pOneRegValue->Value[j*2]-L'0') % 16) * 16;
  1364. }
  1365. pRegBytes[j] = dByte;
  1366. }
  1367. if ( memcmp(strValue, pRegBytes, dSize) == 0 ) {
  1368. //
  1369. // matched, do not do anything
  1370. //
  1371. } else {
  1372. //
  1373. // mismatched, save the binary data
  1374. //
  1375. rc = ScepSaveRegistryValue(
  1376. hSection,
  1377. pOneRegValue->FullValueName,
  1378. RegType,
  1379. strValue,
  1380. dSize,
  1381. 0
  1382. );
  1383. }
  1384. ScepFree(pRegBytes);
  1385. } else {
  1386. //
  1387. // out of memory
  1388. //
  1389. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1390. }
  1391. } else {
  1392. //
  1393. // mismatched, save the binary data
  1394. //
  1395. rc = ScepSaveRegistryValue(
  1396. hSection,
  1397. pOneRegValue->FullValueName,
  1398. RegType,
  1399. strValue,
  1400. dSize,
  1401. 0
  1402. );
  1403. }
  1404. break;
  1405. case REG_MULTI_SZ:
  1406. case REG_QWORD:
  1407. if ( strValue ) {
  1408. if ( !(RegType == REG_MULTI_SZ &&
  1409. (0 == _wcsicmp( pOneRegValue->FullValueName, szLegalNoticeTextKeyName) ) ) ) {
  1410. ScepConvertMultiSzToDelim(strValue, dSize/2, L'\0', L',');
  1411. }
  1412. else {
  1413. DWORD dwCommaCount = 0;
  1414. PWSTR strValueNew;
  1415. DWORD dwBytes;
  1416. for (DWORD dwIndex=0; dwIndex < dSize/2; dwIndex++) {
  1417. if ( strValue[dwIndex] == L',' )
  1418. dwCommaCount++;
  1419. }
  1420. dwBytes = (dSize/2+dwCommaCount * 2 + 1) * sizeof(WCHAR);
  1421. strValueNew = (PWSTR)ScepAlloc(0, dwBytes);
  1422. if (strValueNew) {
  1423. memset(strValueNew, '\0', dwBytes);
  1424. dSize = 2 + 2 * ScepEscapeAndRemoveCRLF( strValue, dSize/2, strValueNew);
  1425. ScepFree(strValue);
  1426. strValue = strValueNew;
  1427. }
  1428. else {
  1429. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1430. break;
  1431. }
  1432. }
  1433. }
  1434. // fall through
  1435. default:
  1436. if ( pOneRegValue->Value == NULL ||
  1437. (SCEREG_VALUE_SNAPSHOT == dwAnalFlag) ) {
  1438. if ( SCEREG_VALUE_SYSTEM == dwAnalFlag ) {
  1439. //
  1440. // add the value to OneRegValue buffer
  1441. //
  1442. rc = ScepSaveRegistryValueToBuffer(
  1443. RegType,
  1444. strValue,
  1445. dSize,
  1446. pOneRegValue
  1447. );
  1448. } else if ( SCEREG_VALUE_FILTER != dwAnalFlag ) {
  1449. rc = ScepSaveRegistryValue(
  1450. hSection,
  1451. pOneRegValue->FullValueName,
  1452. RegType,
  1453. strValue,
  1454. dSize,
  1455. dwStatus
  1456. );
  1457. }
  1458. } else if ( strValue && bIsLegalNoticeText &&
  1459. (pOneRegValue->ValueType != RegType)) {
  1460. //
  1461. // legalnotice text special case
  1462. // must be old template is used
  1463. // each comma is escaped with two quotes
  1464. //
  1465. DWORD Len = wcslen(pOneRegValue->Value);
  1466. PWSTR NewValue = (PWSTR)ScepAlloc(LPTR, Len*3*sizeof(WCHAR));
  1467. if ( NewValue ) {
  1468. ScepEscapeAndRemoveCRLF(pOneRegValue->Value, Len, NewValue);
  1469. if ( _wcsicmp(NewValue, strValue) != 0 ) {
  1470. //
  1471. // mismatched, save the item to the database
  1472. //
  1473. rc = ScepSaveRegistryValue(
  1474. hSection,
  1475. pOneRegValue->FullValueName,
  1476. RegType,
  1477. strValue,
  1478. dSize,
  1479. 0
  1480. );
  1481. }
  1482. ScepFree(NewValue);
  1483. } else {
  1484. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1485. }
  1486. } else if ( strValue &&
  1487. _wcsicmp(pOneRegValue->Value, strValue) == 0 ) {
  1488. //
  1489. // matched, do not do anything
  1490. //
  1491. } else {
  1492. //
  1493. // mismatched, save the item to the database
  1494. //
  1495. rc = ScepSaveRegistryValue(
  1496. hSection,
  1497. pOneRegValue->FullValueName,
  1498. RegType,
  1499. strValue,
  1500. dSize,
  1501. 0
  1502. );
  1503. }
  1504. break;
  1505. }
  1506. rc = ScepSceStatusToDosError(rc);
  1507. } else {
  1508. //
  1509. // error analyzing the value, or it doesn't exist, save it
  1510. // if the registry value doesn't exist, doesn't mean it's 0
  1511. // just log an "not available" status in this case
  1512. //
  1513. if ( (SCEREG_VALUE_ANALYZE == dwAnalFlag) ||
  1514. (SCEREG_VALUE_ROLLBACK == dwAnalFlag) ) {
  1515. ScepSaveRegistryValue(
  1516. hSection,
  1517. pOneRegValue->FullValueName,
  1518. (SCEREG_VALUE_ANALYZE == dwAnalFlag) ? pOneRegValue->ValueType : -1,
  1519. NULL,
  1520. 0,
  1521. (SCEREG_VALUE_ANALYZE == dwAnalFlag) ? SCE_STATUS_ERROR_NOT_AVAILABLE : 0
  1522. );
  1523. }
  1524. if ( rc == ERROR_FILE_NOT_FOUND ||
  1525. rc == ERROR_PATH_NOT_FOUND ||
  1526. rc == ERROR_INVALID_HANDLE ||
  1527. rc == ERROR_ACCESS_DENIED ) {
  1528. rc = ERROR_SUCCESS;
  1529. }
  1530. }
  1531. //
  1532. // free buffer
  1533. //
  1534. if ( strValue ) {
  1535. ScepFree(strValue);
  1536. strValue = NULL;
  1537. }
  1538. return(rc);
  1539. }
  1540. SCESTATUS
  1541. ScepSaveRegistryValue(
  1542. IN PSCESECTION hSection,
  1543. IN PWSTR Name,
  1544. IN DWORD RegType,
  1545. IN PWSTR CurrentValue,
  1546. IN DWORD CurrentBytes,
  1547. IN DWORD Status
  1548. )
  1549. /* ++
  1550. Routine Description:
  1551. This routine compares system settings in string with the baseline profile
  1552. settings. If there is mismatch or unknown, the entry is saved in the SAP
  1553. profile.
  1554. Arguments:
  1555. hSection - The section handle
  1556. Name - The entry name
  1557. RegType - the registry value type
  1558. CurrentValue - The current system setting
  1559. CurrentBytes - The length of the current setting
  1560. Status - the status of this registry vlue analyzed
  1561. Return Value:
  1562. SCESTATUS_SUCCESS
  1563. SCESTATUS_INVALID_PARAMETER
  1564. SCESTATUS returned from SceJetSetLine
  1565. -- */
  1566. {
  1567. SCESTATUS rc;
  1568. if ( Name == NULL )
  1569. return(SCESTATUS_INVALID_PARAMETER);
  1570. if ( CurrentValue == NULL &&
  1571. REG_DWORD == RegType &&
  1572. Status == 0 ) {
  1573. //
  1574. // only return if it's a DWORD type and saving for mismatch status
  1575. // for other types, NULL should be treated as ""
  1576. return(SCESTATUS_SUCCESS);
  1577. }
  1578. //
  1579. // build a buffer containing type and value
  1580. // note MULTI_SZ must be converted to null delimited
  1581. //
  1582. if ( REG_DWORD == RegType ) {
  1583. TCHAR StrValue[20];
  1584. memset(StrValue, '\0', 40);
  1585. *((CHAR *)StrValue) = (BYTE)RegType + '0';
  1586. if ( Status == 0) {
  1587. *((CHAR *)StrValue+1) = SCE_STATUS_MISMATCH + '0';
  1588. } else {
  1589. *((CHAR *)StrValue+1) = (BYTE)Status + '0';
  1590. }
  1591. StrValue[1] = L'\0';
  1592. if ( CurrentValue ) {
  1593. swprintf(StrValue+2, L"%d", *CurrentValue);
  1594. }
  1595. rc = SceJetSetLine( hSection, Name, FALSE, StrValue, (2+wcslen(StrValue+2))*2, 0);
  1596. } else {
  1597. PWSTR StrValue;
  1598. if ( (CurrentBytes % 2) && REG_BINARY == RegType ) {
  1599. StrValue = (PWSTR)ScepAlloc(0, CurrentBytes+9);
  1600. }
  1601. else {
  1602. StrValue = (PWSTR)ScepAlloc(0, CurrentBytes+8); // 4 wide chars: one for type, one delim, and two NULL
  1603. }
  1604. if ( StrValue ) {
  1605. memset(StrValue, 0, sizeof(StrValue));
  1606. *((CHAR *)StrValue) = (BYTE)RegType + '0';
  1607. if ( Status == 0) {
  1608. *((CHAR *)StrValue+1) = SCE_STATUS_MISMATCH + '0';
  1609. } else {
  1610. *((CHAR *)StrValue+1) = (BYTE)Status + '0';
  1611. }
  1612. StrValue[1] = L'\0';
  1613. if ( CurrentValue ) {
  1614. if (REG_BINARY == RegType && CurrentBytes == 1) {
  1615. swprintf(StrValue+2, L"%d", *CurrentValue);
  1616. }
  1617. else {
  1618. memcpy(StrValue+2, (PBYTE)CurrentValue, CurrentBytes);
  1619. }
  1620. }
  1621. if ( (CurrentBytes % 2) && REG_BINARY == RegType ) {
  1622. StrValue[CurrentBytes/2+3] = L'\0';
  1623. StrValue[CurrentBytes/2+4] = L'\0';
  1624. }
  1625. else {
  1626. StrValue[CurrentBytes/2+2] = L'\0';
  1627. StrValue[CurrentBytes/2+3] = L'\0';
  1628. }
  1629. if ( REG_MULTI_SZ == RegType || REG_QWORD == RegType ) {
  1630. //
  1631. // convert the , to null
  1632. //
  1633. ScepConvertMultiSzToDelim(StrValue+2, CurrentBytes/2, L',', L'\0');
  1634. }
  1635. if ( (CurrentBytes % 2) && REG_BINARY == RegType ) {
  1636. rc = SceJetSetLine( hSection, Name, FALSE, StrValue, CurrentBytes+7, 0);
  1637. }
  1638. else {
  1639. rc = SceJetSetLine( hSection, Name, FALSE, StrValue, CurrentBytes+6, 0);
  1640. }
  1641. ScepFree(StrValue);
  1642. } else {
  1643. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1644. }
  1645. }
  1646. switch (Status) {
  1647. case SCE_STATUS_ERROR_NOT_AVAILABLE:
  1648. ScepLogOutput3(2, 0, SCEDLL_STATUS_ERROR, Name);
  1649. break;
  1650. case SCE_STATUS_NOT_CONFIGURED:
  1651. ScepLogOutput3(2, 0, SCEDLL_STATUS_NC, Name);
  1652. break;
  1653. default:
  1654. ScepLogOutput3(2, 0, SCEDLL_STATUS_MISMATCH, Name);
  1655. break;
  1656. }
  1657. return(rc);
  1658. }
  1659. SCESTATUS
  1660. ScepSaveRegistryValueToBuffer(
  1661. IN DWORD RegType,
  1662. IN PWSTR Value,
  1663. IN DWORD dwBytes,
  1664. IN OUT PSCE_REGISTRY_VALUE_INFO pRegValues
  1665. )
  1666. /* ++
  1667. Routine Description:
  1668. This routine saves the registry value to the buffer
  1669. Arguments:
  1670. RegType - the registry value type
  1671. Value - The current system setting
  1672. dwBytes - The length of the current setting
  1673. pRegValues - the buffer for this registry value to save to
  1674. -- */
  1675. {
  1676. SCESTATUS rc=SCESTATUS_SUCCESS;
  1677. if ( pRegValues == NULL ) {
  1678. return(SCESTATUS_INVALID_PARAMETER);
  1679. }
  1680. if ( Value == NULL || dwBytes == 0 ) {
  1681. // nothing to save
  1682. return(SCESTATUS_SUCCESS);
  1683. }
  1684. //
  1685. // build a buffer containing type and value
  1686. // note MULTI_SZ must be converted to null delimited
  1687. //
  1688. if ( REG_DWORD == RegType ) {
  1689. TCHAR StrValue[20];
  1690. DWORD *pdwValue = (DWORD *)Value;
  1691. memset(StrValue, '\0', 40);
  1692. _ultow(*pdwValue, StrValue, 10);
  1693. PWSTR pValue = (PWSTR)ScepAlloc(0, (wcslen(StrValue)+1)*2);
  1694. if ( pValue ) {
  1695. wcscpy(pValue, StrValue);
  1696. pRegValues->Value = pValue;
  1697. pRegValues->ValueType = RegType;
  1698. } else {
  1699. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1700. }
  1701. } else {
  1702. PWSTR StrValue;
  1703. if ( (dwBytes % 2) && REG_BINARY == RegType ) {
  1704. StrValue = (PWSTR)ScepAlloc(LPTR, dwBytes+5);
  1705. } else {
  1706. StrValue = (PWSTR)ScepAlloc(LPTR, dwBytes+4); // 2 wide chars: two NULL
  1707. }
  1708. if ( StrValue ) {
  1709. if (REG_BINARY == RegType && dwBytes == 1) {
  1710. swprintf(StrValue, L"%d", *Value);
  1711. } else {
  1712. memcpy(StrValue, (PBYTE)Value, dwBytes);
  1713. }
  1714. if ( (dwBytes % 2) && REG_BINARY == RegType ) {
  1715. StrValue[dwBytes/2+1] = L'\0';
  1716. StrValue[dwBytes/2+2] = L'\0';
  1717. }
  1718. else {
  1719. StrValue[dwBytes/2+0] = L'\0';
  1720. StrValue[dwBytes/2+1] = L'\0';
  1721. }
  1722. pRegValues->Value = StrValue;
  1723. pRegValues->ValueType = RegType;
  1724. } else {
  1725. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1726. }
  1727. }
  1728. return(rc);
  1729. }
  1730. SCESTATUS
  1731. ScepEnumAllRegValues(
  1732. IN OUT PDWORD pCount,
  1733. IN OUT PSCE_REGISTRY_VALUE_INFO *paRegValues
  1734. )
  1735. /*
  1736. Routine Description:
  1737. Enumerate all registry values supported by SCE from registry.
  1738. Arguments:
  1739. pCount - the number of reg values to output
  1740. paRegValues - the array of registry values to output
  1741. Return Value:
  1742. */
  1743. {
  1744. DWORD Win32Rc;
  1745. HKEY hKey=NULL;
  1746. PSCE_NAME_STATUS_LIST pnsList=NULL;
  1747. DWORD nAdded=0;
  1748. Win32Rc = RegOpenKeyEx(
  1749. HKEY_LOCAL_MACHINE,
  1750. SCE_ROOT_REGVALUE_PATH,
  1751. 0,
  1752. KEY_READ,
  1753. &hKey
  1754. );
  1755. DWORD cSubKeys = 0;
  1756. DWORD nMaxLen;
  1757. if ( Win32Rc == ERROR_SUCCESS ) {
  1758. //
  1759. // enumerate all subkeys of the key
  1760. //
  1761. Win32Rc = RegQueryInfoKey (
  1762. hKey,
  1763. NULL,
  1764. NULL,
  1765. NULL,
  1766. &cSubKeys,
  1767. &nMaxLen,
  1768. NULL,
  1769. NULL,
  1770. NULL,
  1771. NULL,
  1772. NULL,
  1773. NULL
  1774. );
  1775. }
  1776. if ( Win32Rc == ERROR_SUCCESS && cSubKeys > 0 ) {
  1777. PWSTR szName = (PWSTR)ScepAlloc(0, (nMaxLen+2)*sizeof(WCHAR));
  1778. if ( !szName ) {
  1779. Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
  1780. } else {
  1781. DWORD BufSize;
  1782. DWORD index = 0;
  1783. do {
  1784. BufSize = nMaxLen+1;
  1785. Win32Rc = RegEnumKeyEx(
  1786. hKey,
  1787. index,
  1788. szName,
  1789. &BufSize,
  1790. NULL,
  1791. NULL,
  1792. NULL,
  1793. NULL);
  1794. if ( ERROR_SUCCESS == Win32Rc ) {
  1795. index++;
  1796. //
  1797. // get the full registry key name and Valuetype
  1798. //
  1799. cSubKeys = REG_SZ;
  1800. //
  1801. // query ValueType, if error, default REG_SZ
  1802. //
  1803. ScepRegQueryIntValue( hKey,
  1804. szName,
  1805. SCE_REG_VALUE_TYPE,
  1806. &cSubKeys
  1807. );
  1808. if ( cSubKeys < REG_SZ || cSubKeys > REG_MULTI_SZ ) {
  1809. cSubKeys = REG_SZ;
  1810. }
  1811. //
  1812. // convert the path name
  1813. //
  1814. ScepConvertMultiSzToDelim(szName, BufSize, L'/', L'\\');
  1815. //
  1816. // compare with the input array, if not exist,
  1817. // add it
  1818. //
  1819. for ( DWORD i=0; i<*pCount; i++ ) {
  1820. if ( (*paRegValues)[i].FullValueName &&
  1821. _wcsicmp(szName, (*paRegValues)[i].FullValueName) == 0 ) {
  1822. break;
  1823. }
  1824. }
  1825. if ( i >= *pCount ) {
  1826. //
  1827. // did not find a match, add it
  1828. //
  1829. if ( SCESTATUS_SUCCESS != ScepAddToNameStatusList(&pnsList,
  1830. szName,
  1831. BufSize,
  1832. cSubKeys) ) {
  1833. Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
  1834. break;
  1835. }
  1836. nAdded++;
  1837. }
  1838. } else if ( ERROR_NO_MORE_ITEMS != Win32Rc ) {
  1839. break;
  1840. }
  1841. } while ( Win32Rc != ERROR_NO_MORE_ITEMS );
  1842. if ( Win32Rc == ERROR_NO_MORE_ITEMS ) {
  1843. Win32Rc = ERROR_SUCCESS;
  1844. }
  1845. //
  1846. // free the enumeration buffer
  1847. //
  1848. ScepFree(szName);
  1849. }
  1850. }
  1851. if ( hKey ) {
  1852. RegCloseKey(hKey);
  1853. }
  1854. if ( ERROR_SUCCESS == Win32Rc ) {
  1855. //
  1856. // add the name list to the output arrays
  1857. //
  1858. DWORD nNewCount = *pCount + nAdded;
  1859. PSCE_REGISTRY_VALUE_INFO aNewArray;
  1860. if ( nNewCount ) {
  1861. aNewArray = (PSCE_REGISTRY_VALUE_INFO)ScepAlloc(0, nNewCount*sizeof(SCE_REGISTRY_VALUE_INFO));
  1862. if ( aNewArray ) {
  1863. DWORD i;
  1864. for ( i=0; i<*pCount; i++ ) {
  1865. aNewArray[i].FullValueName = (*paRegValues)[i].FullValueName;
  1866. aNewArray[i].Value = (*paRegValues)[i].Value;
  1867. aNewArray[i].ValueType = (*paRegValues)[i].ValueType;
  1868. }
  1869. i=0;
  1870. for ( PSCE_NAME_STATUS_LIST pns=pnsList;
  1871. pns; pns=pns->Next ) {
  1872. if ( pns->Name && i < nAdded ) {
  1873. aNewArray[*pCount+i].FullValueName = pns->Name;
  1874. pns->Name = NULL;
  1875. aNewArray[*pCount+i].Value = NULL;
  1876. aNewArray[*pCount+i].ValueType = pns->Status;
  1877. i++;
  1878. }
  1879. }
  1880. //
  1881. // free the original array
  1882. // all components in the array are already transferred to the new array
  1883. //
  1884. ScepFree(*paRegValues);
  1885. *pCount = nNewCount;
  1886. *paRegValues = aNewArray;
  1887. } else {
  1888. Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
  1889. }
  1890. }
  1891. }
  1892. if ( ERROR_FILE_NOT_FOUND == Win32Rc ||
  1893. ERROR_PATH_NOT_FOUND == Win32Rc ) {
  1894. //
  1895. // no value has been registered
  1896. //
  1897. Win32Rc = ERROR_SUCCESS;
  1898. }
  1899. //
  1900. // free the name status list
  1901. //
  1902. SceFreeMemory(pnsList, SCE_STRUCT_NAME_STATUS_LIST);
  1903. return( ScepDosErrorToSceStatus(Win32Rc) );
  1904. }