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.

5498 lines
132 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. common.cpp
  5. Abstract:
  6. Shared APIs
  7. Author:
  8. Jin Huang
  9. Revision History:
  10. jinhuang 23-Jan-1998 merged from multiple modules
  11. --*/
  12. #include "headers.h"
  13. #include <alloca.h>
  14. #if DBG
  15. DEFINE_DEBUG2(Sce);
  16. DEBUG_KEY SceDebugKeys[] = {{DEB_ERROR, "Error"},
  17. {DEB_WARN, "Warn"},
  18. {DEB_TRACE, "Trace"},
  19. {0, NULL}};
  20. VOID
  21. DebugInitialize()
  22. {
  23. SceInitDebug(SceDebugKeys);
  24. }
  25. VOID
  26. DebugUninit()
  27. {
  28. SceUnloadDebug();
  29. }
  30. #endif // DBG
  31. HINSTANCE MyModuleHandle=NULL;
  32. HANDLE hEventLog = NULL;
  33. TCHAR EventSource[64];
  34. const TCHAR c_szCRLF[] = TEXT("\r\n");
  35. #define RIGHT_DS_CREATE_CHILD ACTRL_DS_CREATE_CHILD
  36. #define RIGHT_DS_DELETE_CHILD ACTRL_DS_DELETE_CHILD
  37. #define RIGHT_DS_DELETE_SELF DELETE
  38. #define RIGHT_DS_LIST_CONTENTS ACTRL_DS_LIST
  39. #define RIGHT_DS_SELF_WRITE ACTRL_DS_SELF
  40. #define RIGHT_DS_READ_PROPERTY ACTRL_DS_READ_PROP
  41. #define RIGHT_DS_WRITE_PROPERTY ACTRL_DS_WRITE_PROP
  42. //
  43. // defines for DSDIT, DSLOG, SYSVOL registry path
  44. //
  45. #define szNetlogonKey TEXT("System\\CurrentControlSet\\Services\\Netlogon\\Parameters")
  46. #define szNTDSKey TEXT("System\\CurrentControlSet\\Services\\NTDS\\Parameters")
  47. #define szSetupKey TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Setup")
  48. #define szSysvolValue TEXT("SysVol")
  49. #define szDSDITValue TEXT("DSA Working Directory")
  50. #define szDSLOGValue TEXT("Database log files path")
  51. #define szBootDriveValue TEXT("BootDir")
  52. //
  53. // Define the generic rights
  54. //
  55. // generic read
  56. #define GENERIC_READ_MAPPING ((STANDARD_RIGHTS_READ) | \
  57. (ACTRL_DS_LIST) | \
  58. (ACTRL_DS_READ_PROP))
  59. // generic execute
  60. #define GENERIC_EXECUTE_MAPPING ((STANDARD_RIGHTS_EXECUTE) | \
  61. (ACTRL_DS_LIST))
  62. // generic right
  63. #define GENERIC_WRITE_MAPPING ((STANDARD_RIGHTS_WRITE) | \
  64. (ACTRL_DS_SELF) | \
  65. (ACTRL_DS_WRITE_PROP))
  66. // generic all
  67. #define GENERIC_ALL_MAPPING ((STANDARD_RIGHTS_REQUIRED) | \
  68. (ACTRL_DS_CREATE_CHILD) | \
  69. (ACTRL_DS_DELETE_CHILD) | \
  70. (ACTRL_DS_READ_PROP) | \
  71. (ACTRL_DS_WRITE_PROP) | \
  72. (ACTRL_DS_LIST) | \
  73. (ACTRL_DS_SELF))
  74. GENERIC_MAPPING DsGenMap = {
  75. GENERIC_READ_MAPPING,
  76. GENERIC_WRITE_MAPPING,
  77. GENERIC_EXECUTE_MAPPING,
  78. GENERIC_ALL_MAPPING
  79. };
  80. DWORD
  81. ScepCompareExplicitAcl(
  82. IN SE_OBJECT_TYPE ObjectType,
  83. IN BOOL IsContainer,
  84. IN PACL pAcl1,
  85. IN PACL pAcl2,
  86. OUT PBOOL pDifferent
  87. );
  88. NTSTATUS
  89. ScepAnyExplicitAcl(
  90. IN PACL Acl,
  91. IN DWORD Processed,
  92. OUT PBOOL pExist
  93. );
  94. BOOL
  95. ScepEqualAce(
  96. IN SE_OBJECT_TYPE ObjectType,
  97. IN BOOL IsContainer,
  98. IN ACE_HEADER *pAce1,
  99. IN ACE_HEADER *pAce2
  100. );
  101. DWORD
  102. ScepGetCurrentUserProfilePath(
  103. OUT PWSTR *ProfilePath
  104. );
  105. DWORD
  106. ScepGetUsersProfileName(
  107. IN UNICODE_STRING AssignedProfile,
  108. IN PSID AccountSid,
  109. IN BOOL bDefault,
  110. OUT PWSTR *UserProfilePath
  111. );
  112. BOOL
  113. ScepConvertSDDLAceType(
  114. LPTSTR pszValue,
  115. PCWSTR szSearchFor, // only two letters are allowed
  116. PCWSTR szReplace
  117. );
  118. BOOL
  119. ScepConvertSDDLSid(
  120. LPTSTR pszValue,
  121. PCWSTR szSearchFor, // only two letters are allowed
  122. PCWSTR szReplace
  123. );
  124. NTSTATUS
  125. ScepConvertAclBlobToAdl(
  126. IN SE_OBJECT_TYPE ObjectType,
  127. IN BOOL IsContainer,
  128. IN PACL pAcl,
  129. OUT DWORD *pdwAceNumber,
  130. OUT BOOL *pbAclNoExplicitAces,
  131. OUT PSCEP_ADL_NODE *hTable
  132. );
  133. DWORD
  134. ScepAdlLookupAdd(
  135. IN SE_OBJECT_TYPE ObjectType,
  136. IN BOOL IsContainer,
  137. IN ACE_HEADER *pAce,
  138. OUT PSCEP_ADL_NODE *hTable
  139. );
  140. PSCEP_ADL_NODE
  141. ScepAdlLookup(
  142. IN ACE_HEADER *pAce,
  143. IN PSCEP_ADL_NODE *hTable
  144. );
  145. DWORD
  146. ScepAddToAdlList(
  147. IN SE_OBJECT_TYPE ObjectType,
  148. IN BOOL IsContainer,
  149. IN ACE_HEADER *pAce,
  150. OUT PSCEP_ADL_NODE *pAdlList
  151. );
  152. VOID
  153. ScepAdlMergeMasks(
  154. IN SE_OBJECT_TYPE ObjectType,
  155. IN BOOL IsContainer,
  156. IN ACE_HEADER *pAce,
  157. IN PSCEP_ADL_NODE pNode
  158. );
  159. BOOL
  160. ScepEqualAdls(
  161. IN PSCEP_ADL_NODE *hTable1,
  162. IN PSCEP_ADL_NODE *hTable2
  163. );
  164. VOID
  165. ScepFreeAdl(
  166. IN PSCEP_ADL_NODE *hTable
  167. );
  168. SCESTATUS
  169. ScepFreeAdlList(
  170. IN PSCEP_ADL_NODE pAdlList
  171. );
  172. BOOL
  173. ScepEqualSid(
  174. IN PISID pSid1,
  175. IN PISID pSid2
  176. );
  177. PWSTR
  178. ScepMultiSzWcsstr(
  179. PWSTR pszStringToSearchIn,
  180. PWSTR pszStringToSearchFor
  181. );
  182. //
  183. // function definitions
  184. //
  185. SCESTATUS
  186. WINAPI
  187. SceSvcpGetInformationTemplate(
  188. IN HINF hInf,
  189. IN PCWSTR ServiceName,
  190. IN PCWSTR Key OPTIONAL,
  191. OUT PSCESVC_CONFIGURATION_INFO *ServiceInfo
  192. )
  193. {
  194. SCESTATUS rc=SCESTATUS_SUCCESS;
  195. if ( hInf == NULL || hInf == INVALID_HANDLE_VALUE ||
  196. ServiceName == NULL || ServiceInfo == NULL ) {
  197. return(SCESTATUS_INVALID_PARAMETER);
  198. }
  199. LONG nCount=0;
  200. if ( Key == NULL ) {
  201. //
  202. // get the entire section count
  203. //
  204. nCount = SetupGetLineCount(hInf, ServiceName);
  205. if ( nCount <= 0 ) {
  206. //
  207. // the section is not there, or nothing in the section
  208. //
  209. rc =SCESTATUS_RECORD_NOT_FOUND;
  210. }
  211. } else {
  212. nCount = 1;
  213. }
  214. if ( rc == SCESTATUS_SUCCESS ) {
  215. //
  216. // allocate buffer for the section
  217. //
  218. *ServiceInfo = (PSCESVC_CONFIGURATION_INFO)ScepAlloc(LMEM_FIXED,
  219. sizeof(SCESVC_CONFIGURATION_INFO));
  220. if ( *ServiceInfo == NULL ) {
  221. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  222. } else {
  223. (*ServiceInfo)->Lines =
  224. (PSCESVC_CONFIGURATION_LINE)ScepAlloc(LMEM_ZEROINIT,
  225. nCount*sizeof(SCESVC_CONFIGURATION_LINE));
  226. if ( (*ServiceInfo)->Lines == NULL ) {
  227. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  228. ScepFree(*ServiceInfo);
  229. *ServiceInfo = NULL;
  230. } else {
  231. (*ServiceInfo)->Count = nCount;
  232. }
  233. }
  234. }
  235. if ( rc == SCESTATUS_SUCCESS ) {
  236. //
  237. // get each line in the section, nor a single key now
  238. //
  239. INFCONTEXT InfLine;
  240. DWORD LineLen, Len, KeyLen, DataSize;
  241. DWORD i, cFields;
  242. DWORD LineCount=0;
  243. PWSTR Keyname=NULL, Strvalue=NULL;
  244. //
  245. // look for the first line in the Servi ceName section
  246. //
  247. if(SetupFindFirstLine(hInf,ServiceName,NULL,&InfLine)) {
  248. do {
  249. //
  250. // read each line in the section and append to the end of the buffer
  251. // note: the required size returned from SetupGetStringField already
  252. // has one more character space.
  253. //
  254. rc = SCESTATUS_INVALID_DATA;
  255. if ( SetupGetStringField(&InfLine, 0, NULL, 0, &KeyLen) ) {
  256. Keyname = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (KeyLen+1)*sizeof(WCHAR));
  257. if ( Keyname != NULL ) {
  258. if ( SetupGetStringField(&InfLine, 0, Keyname, KeyLen, NULL) ) {
  259. //
  260. // Got key name, compare with Key if specified.
  261. //
  262. if ( Key == NULL || _wcsicmp(Keyname, Key) == 0 ) {
  263. cFields = SetupGetFieldCount( &InfLine );
  264. LineLen = 0;
  265. Len = 0;
  266. rc = SCESTATUS_SUCCESS;
  267. //
  268. // count total number of characters for the value
  269. //
  270. for ( i=0; i<cFields; i++) {
  271. if( SetupGetStringField(&InfLine,i+1,NULL,0,&DataSize) ) {
  272. LineLen += (DataSize + 1);
  273. } else {
  274. rc = SCESTATUS_INVALID_DATA;
  275. break;
  276. }
  277. }
  278. if ( rc == SCESTATUS_SUCCESS ) {
  279. Strvalue = (PWSTR)ScepAlloc( LMEM_ZEROINIT,
  280. (LineLen+1)*sizeof(WCHAR) );
  281. if( Strvalue != NULL ) {
  282. for ( i=0; i<cFields; i++) {
  283. if ( !SetupGetStringField(&InfLine, i+1,
  284. Strvalue+Len, LineLen-Len, &DataSize) ) {
  285. rc = SCESTATUS_INVALID_DATA;
  286. break;
  287. }
  288. if ( i == cFields-1)
  289. *(Strvalue+Len+DataSize-1) = L'\0';
  290. else
  291. *(Strvalue+Len+DataSize-1) = L',';
  292. Len += DataSize;
  293. }
  294. if ( rc == SCESTATUS_SUCCESS ) {
  295. //
  296. // everything is successful
  297. //
  298. (*ServiceInfo)->Lines[LineCount].Key = Keyname;
  299. (*ServiceInfo)->Lines[LineCount].Value = Strvalue;
  300. (*ServiceInfo)->Lines[LineCount].ValueLen = LineLen*sizeof(WCHAR);
  301. Keyname = NULL;
  302. Strvalue = NULL;
  303. rc = SCESTATUS_SUCCESS;
  304. LineCount++;
  305. if ( Key != NULL ) {
  306. break; // break the do while loop because the exact match for the key is found
  307. }
  308. } else {
  309. ScepFree( Strvalue );
  310. Strvalue = NULL;
  311. }
  312. } else
  313. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  314. }
  315. } else {
  316. //
  317. // did not find the right key, go to next line
  318. //
  319. rc = SCESTATUS_SUCCESS;
  320. }
  321. }
  322. if ( Keyname != NULL ) {
  323. ScepFree(Keyname);
  324. Keyname = NULL;
  325. }
  326. } else {
  327. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  328. }
  329. }
  330. if ( rc != SCESTATUS_SUCCESS ) {
  331. break;
  332. }
  333. } while ( SetupFindNextLine(&InfLine,&InfLine) );
  334. } else {
  335. rc = SCESTATUS_RECORD_NOT_FOUND;
  336. }
  337. //
  338. // if no exact match for the key is found, return the error code
  339. //
  340. if ( rc == SCESTATUS_SUCCESS && Key != NULL && LineCount == 0 ) {
  341. rc = SCESTATUS_RECORD_NOT_FOUND;
  342. }
  343. }
  344. if ( rc != SCESTATUS_SUCCESS && *ServiceInfo != NULL ) {
  345. //
  346. // free ServiceInfo
  347. //
  348. PSCESVC_CONFIGURATION_LINE Lines;
  349. Lines = ((PSCESVC_CONFIGURATION_INFO)(*ServiceInfo))->Lines;
  350. for ( DWORD i=0; i<((PSCESVC_CONFIGURATION_INFO)(*ServiceInfo))->Count; i++) {
  351. if ( Lines[i].Key != NULL ) {
  352. ScepFree(Lines[i].Key);
  353. }
  354. if ( Lines[i].Value != NULL ) {
  355. ScepFree(Lines[i].Value);
  356. }
  357. }
  358. ScepFree(Lines);
  359. ScepFree(*ServiceInfo);
  360. *ServiceInfo = NULL;
  361. }
  362. return(rc);
  363. }
  364. DWORD
  365. ScepAddToNameList(
  366. OUT PSCE_NAME_LIST *pNameList,
  367. IN PWSTR Name,
  368. IN ULONG Len
  369. )
  370. /* ++
  371. Routine Description:
  372. This routine adds a name (wchar) to the name list. The new added
  373. node is always placed as the head of the list for performance reason.
  374. Arguments:
  375. pNameList - The address of the name list to add to.
  376. Name - The name to add
  377. Len - number of wchars in Name
  378. Return value:
  379. Win32 error code
  380. -- */
  381. {
  382. PSCE_NAME_LIST pList=NULL;
  383. ULONG Length=Len;
  384. //
  385. // check arguments
  386. //
  387. if ( pNameList == NULL )
  388. return(ERROR_INVALID_PARAMETER);
  389. if ( Name == NULL )
  390. return(NO_ERROR);
  391. if ( Len == 0 )
  392. Length = wcslen(Name);
  393. if ( Length == 0 )
  394. return(NO_ERROR);
  395. //
  396. // allocate a new node
  397. //
  398. pList = (PSCE_NAME_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_LIST));
  399. if ( pList == NULL )
  400. return(ERROR_NOT_ENOUGH_MEMORY);
  401. pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Length+1)*sizeof(TCHAR));
  402. if ( pList->Name == NULL ) {
  403. ScepFree(pList);
  404. return(ERROR_NOT_ENOUGH_MEMORY);
  405. }
  406. //
  407. // add the node to the front of the list and link its next to the old list
  408. //
  409. wcsncpy(pList->Name, Name, Length);
  410. pList->Next = *pNameList;
  411. *pNameList = pList;
  412. return(NO_ERROR);
  413. }
  414. SCESTATUS
  415. ScepBuildErrorLogInfo(
  416. IN DWORD rc,
  417. OUT PSCE_ERROR_LOG_INFO *errlog,
  418. IN UINT nId,
  419. // IN PCWSTR fmt,
  420. ...
  421. )
  422. /* ++
  423. Routine Description:
  424. This routine add the error information to the end of error log info list
  425. (errlog). The error information is stored in SCE_ERROR_LOG_INFO structure.
  426. Arguments:
  427. rc - Win32 error code
  428. errlog - the error log info list head
  429. fmt - a format string
  430. ... - variable arguments
  431. Return value:
  432. SCESTATUS error code
  433. -- */
  434. {
  435. PSCE_ERROR_LOG_INFO pNode;
  436. PSCE_ERROR_LOG_INFO pErr;
  437. DWORD bufferSize;
  438. PWSTR buf=NULL;
  439. va_list args;
  440. WCHAR szTempString[256];
  441. //
  442. // check arguments
  443. //
  444. // if ( errlog == NULL || fmt == NULL )
  445. if ( errlog == NULL || nId == 0 )
  446. return(SCESTATUS_SUCCESS);
  447. szTempString[0] = L'\0';
  448. LoadString( MyModuleHandle,
  449. nId,
  450. szTempString,
  451. 256
  452. );
  453. if ( szTempString[0] == L'\0' )
  454. return(SCESTATUS_SUCCESS);
  455. SafeAllocaAllocate( buf, SCE_BUF_LEN*sizeof(WCHAR) );
  456. if ( buf == NULL ) {
  457. return(SCESTATUS_NOT_ENOUGH_RESOURCE);
  458. }
  459. va_start( args, nId );
  460. vswprintf( buf, szTempString, args );
  461. va_end( args );
  462. bufferSize = wcslen(buf);
  463. //
  464. // no error information to be stored. return
  465. //
  466. SCESTATUS rCode=SCESTATUS_SUCCESS;
  467. if ( bufferSize != 0 ) {
  468. //
  469. // allocate memory and store error information in pNode->buffer
  470. //
  471. pNode = (PSCE_ERROR_LOG_INFO)ScepAlloc( 0, sizeof(SCE_ERROR_LOG_INFO) );
  472. if ( pNode != NULL ) {
  473. pNode->buffer = (LPTSTR)ScepAlloc( 0, (bufferSize+1)*sizeof(TCHAR) );
  474. if ( pNode->buffer != NULL ) {
  475. //
  476. // Error information is in "SystemMessage : Caller'sMessage" format
  477. //
  478. pNode->buffer[0] = L'\0';
  479. wcscpy(pNode->buffer, buf);
  480. pNode->rc = rc;
  481. pNode->next = NULL;
  482. //
  483. // link it to the list
  484. //
  485. if ( *errlog == NULL )
  486. //
  487. // This is the first node in the error log information list
  488. //
  489. *errlog = pNode;
  490. else {
  491. //
  492. // find the last node in the list
  493. //
  494. for ( pErr=*errlog; pErr->next; pErr = pErr->next );
  495. pErr->next = pNode;
  496. }
  497. } else {
  498. ScepFree(pNode);
  499. rCode = SCESTATUS_NOT_ENOUGH_RESOURCE;
  500. }
  501. } else {
  502. rCode = SCESTATUS_NOT_ENOUGH_RESOURCE;
  503. }
  504. }
  505. SafeAllocaFree( buf );
  506. return(rc);
  507. }
  508. DWORD
  509. ScepRegQueryIntValue(
  510. IN HKEY hKeyRoot,
  511. IN PWSTR SubKey,
  512. IN PWSTR ValueName,
  513. OUT DWORD *Value
  514. )
  515. /* ++
  516. Routine Description:
  517. This routine queries a REG_DWORD value from a value name/subkey.
  518. Arguments:
  519. hKeyRoot - root
  520. SubKey - key path
  521. ValueName - name of the value
  522. Value - the output value for the ValueName
  523. Return values:
  524. Win32 error code
  525. -- */
  526. {
  527. DWORD Rcode;
  528. DWORD RegType;
  529. DWORD dSize=0;
  530. HKEY hKey=NULL;
  531. if(( Rcode = RegOpenKeyEx(hKeyRoot,
  532. SubKey,
  533. 0,
  534. KEY_READ,
  535. &hKey
  536. )) == ERROR_SUCCESS ) {
  537. if(( Rcode = RegQueryValueEx(hKey,
  538. ValueName,
  539. 0,
  540. &RegType,
  541. NULL,
  542. &dSize
  543. )) == ERROR_SUCCESS ) {
  544. switch (RegType) {
  545. case REG_DWORD:
  546. case REG_DWORD_BIG_ENDIAN:
  547. Rcode = RegQueryValueEx(hKey,
  548. ValueName,
  549. 0,
  550. &RegType,
  551. (BYTE *)Value,
  552. &dSize
  553. );
  554. if ( Rcode != ERROR_SUCCESS ) {
  555. if ( Value != NULL )
  556. *Value = 0;
  557. }
  558. break;
  559. default:
  560. Rcode = ERROR_INVALID_DATATYPE;
  561. break;
  562. }
  563. }
  564. }
  565. if( hKey )
  566. RegCloseKey( hKey );
  567. return(Rcode);
  568. }
  569. DWORD
  570. ScepRegSetIntValue(
  571. IN HKEY hKeyRoot,
  572. IN PWSTR SubKey,
  573. IN PWSTR ValueName,
  574. IN DWORD Value
  575. )
  576. /* ++
  577. Routine Description:
  578. This routine sets a REG_DWORD value to a value name/subkey.
  579. Arguments:
  580. hKeyRoot - root
  581. SubKey - key path
  582. ValueName - name of the value
  583. Value - the value to set
  584. Return values:
  585. Win32 error code
  586. -- */
  587. {
  588. DWORD Rcode;
  589. HKEY hKey=NULL;
  590. if(( Rcode = RegOpenKeyEx(hKeyRoot,
  591. SubKey,
  592. 0,
  593. KEY_SET_VALUE,
  594. &hKey
  595. )) == ERROR_SUCCESS ) {
  596. Rcode = RegSetValueEx( hKey,
  597. ValueName,
  598. 0,
  599. REG_DWORD,
  600. (BYTE *)&Value,
  601. 4
  602. );
  603. }
  604. if( hKey )
  605. RegCloseKey( hKey );
  606. return(Rcode);
  607. }
  608. DWORD
  609. ScepRegQueryBinaryValue(
  610. IN HKEY hKeyRoot,
  611. IN PWSTR SubKey,
  612. IN PWSTR ValueName,
  613. OUT PBYTE *ppValue
  614. )
  615. /* ++
  616. Routine Description:
  617. This routine queries a REG_BINARY value from a value name/subkey.
  618. Arguments:
  619. hKeyRoot - root
  620. SubKey - key path
  621. ValueName - name of the value
  622. Value - the output value for the ValueName
  623. Return values:
  624. Win32 error code
  625. -- */
  626. {
  627. DWORD Rcode;
  628. DWORD RegType;
  629. DWORD dSize=0;
  630. HKEY hKey=NULL;
  631. if(( Rcode = RegOpenKeyEx(hKeyRoot,
  632. SubKey,
  633. 0,
  634. KEY_READ,
  635. &hKey
  636. )) == ERROR_SUCCESS ) {
  637. // get the size since it is free form binary
  638. if(( Rcode = RegQueryValueEx(hKey,
  639. ValueName,
  640. 0,
  641. &RegType,
  642. NULL,
  643. &dSize
  644. )) == ERROR_SUCCESS ) {
  645. switch (RegType) {
  646. case REG_BINARY:
  647. //need to free this outside
  648. if (ppValue)
  649. *ppValue = ( PBYTE )ScepAlloc( 0, sizeof(BYTE) * dSize);
  650. Rcode = RegQueryValueEx(hKey,
  651. ValueName,
  652. 0,
  653. &RegType,
  654. ( PBYTE ) *ppValue,
  655. &dSize
  656. );
  657. if ( Rcode != ERROR_SUCCESS ) {
  658. if ( *ppValue != NULL )
  659. **ppValue = (BYTE)0;
  660. }
  661. break;
  662. default:
  663. Rcode = ERROR_INVALID_DATATYPE;
  664. break;
  665. }
  666. }
  667. }
  668. if( hKey )
  669. RegCloseKey( hKey );
  670. return(Rcode);
  671. }
  672. DWORD
  673. ScepRegSetValue(
  674. IN HKEY hKeyRoot,
  675. IN PWSTR SubKey,
  676. IN PWSTR ValueName,
  677. IN DWORD RegType,
  678. IN BYTE *Value,
  679. IN DWORD ValueLen
  680. )
  681. /* ++
  682. Routine Description:
  683. This routine sets a string value to a value name/subkey.
  684. Arguments:
  685. hKeyRoot - root
  686. SubKey - key path
  687. ValueName - name of the value
  688. Value - the value to set
  689. ValueLen - The number of bytes in Value
  690. Return values:
  691. Win32 error code
  692. -- */
  693. {
  694. DWORD Rcode;
  695. DWORD NewKey;
  696. HKEY hKey=NULL;
  697. SECURITY_ATTRIBUTES SecurityAttributes;
  698. PSECURITY_DESCRIPTOR SecurityDescriptor=NULL;
  699. if(( Rcode = RegOpenKeyEx(hKeyRoot,
  700. SubKey,
  701. 0,
  702. KEY_SET_VALUE,
  703. &hKey
  704. )) != ERROR_SUCCESS ) {
  705. SecurityAttributes.nLength = sizeof( SECURITY_ATTRIBUTES );
  706. SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
  707. SecurityAttributes.bInheritHandle = FALSE;
  708. Rcode = RegCreateKeyEx(
  709. hKeyRoot,
  710. SubKey,
  711. 0,
  712. NULL, // LPTSTR lpClass,
  713. REG_OPTION_NON_VOLATILE,
  714. KEY_WRITE, // KEY_SET_VALUE,
  715. NULL, // &SecurityAttributes,
  716. &hKey,
  717. &NewKey
  718. );
  719. }
  720. if ( Rcode == ERROR_SUCCESS ) {
  721. Rcode = RegSetValueEx( hKey,
  722. ValueName,
  723. 0,
  724. RegType,
  725. Value,
  726. ValueLen
  727. );
  728. }
  729. if( hKey )
  730. RegCloseKey( hKey );
  731. return(Rcode);
  732. }
  733. DWORD
  734. ScepRegQueryValue(
  735. IN HKEY hKeyRoot,
  736. IN PWSTR SubKey,
  737. IN PCWSTR ValueName,
  738. OUT PVOID *Value,
  739. OUT LPDWORD pRegType
  740. )
  741. /* ++
  742. Routine Description:
  743. This routine queries a REG_SZ value from a value name/subkey.
  744. The output buffer is allocated if it is NULL. It must be freed
  745. by LocalFree
  746. Arguments:
  747. hKeyRoot - root
  748. SubKey - key path
  749. ValueName - name of the value
  750. Value - the output string for the ValueName
  751. Return values:
  752. Win32 error code
  753. -- */
  754. {
  755. DWORD Rcode;
  756. DWORD dSize=0;
  757. HKEY hKey=NULL;
  758. BOOL FreeMem=FALSE;
  759. if ( SubKey == NULL || ValueName == NULL ||
  760. Value == NULL || pRegType == NULL ) {
  761. return(SCESTATUS_INVALID_PARAMETER);
  762. }
  763. if(( Rcode = RegOpenKeyEx(hKeyRoot,
  764. SubKey,
  765. 0,
  766. KEY_READ,
  767. &hKey
  768. )) == ERROR_SUCCESS ) {
  769. if(( Rcode = RegQueryValueEx(hKey,
  770. ValueName,
  771. 0,
  772. pRegType,
  773. NULL,
  774. &dSize
  775. )) == ERROR_SUCCESS ) {
  776. switch (*pRegType) {
  777. /*
  778. case REG_DWORD:
  779. case REG_DWORD_BIG_ENDIAN:
  780. Rcode = RegQueryValueEx(hKey,
  781. ValueName,
  782. 0,
  783. pRegType,
  784. (BYTE *)(*Value),
  785. &dSize
  786. );
  787. if ( Rcode != ERROR_SUCCESS ) {
  788. if ( *Value != NULL )
  789. *((BYTE *)(*Value)) = 0;
  790. }
  791. break;
  792. */
  793. case REG_SZ:
  794. case REG_EXPAND_SZ:
  795. case REG_MULTI_SZ:
  796. if ( *Value == NULL ) {
  797. *Value = (PVOID)ScepAlloc( LMEM_ZEROINIT, (dSize+1)*sizeof(TCHAR));
  798. FreeMem = TRUE;
  799. }
  800. if ( *Value == NULL ) {
  801. Rcode = ERROR_NOT_ENOUGH_MEMORY;
  802. } else {
  803. Rcode = RegQueryValueEx(hKey,
  804. ValueName,
  805. 0,
  806. pRegType,
  807. (BYTE *)(*Value),
  808. &dSize
  809. );
  810. if ( Rcode != ERROR_SUCCESS && FreeMem ) {
  811. ScepFree(*Value);
  812. *Value = NULL;
  813. }
  814. }
  815. break;
  816. default:
  817. Rcode = ERROR_INVALID_DATATYPE;
  818. break;
  819. }
  820. }
  821. }
  822. if( hKey )
  823. RegCloseKey( hKey );
  824. return(Rcode);
  825. }
  826. DWORD
  827. ScepRegDeleteValue(
  828. IN HKEY hKeyRoot,
  829. IN PWSTR SubKey,
  830. IN PWSTR ValueName
  831. )
  832. /* ++
  833. Routine Description:
  834. This routine delete the reg value
  835. Arguments:
  836. hKeyRoot - root
  837. SubKey - key path
  838. ValueName - name of the value
  839. Return values:
  840. Win32 error code
  841. -- */
  842. {
  843. DWORD Rcode;
  844. HKEY hKey=NULL;
  845. if(( Rcode = RegOpenKeyEx(hKeyRoot,
  846. SubKey,
  847. 0,
  848. KEY_READ | KEY_WRITE,
  849. &hKey
  850. )) == ERROR_SUCCESS ) {
  851. Rcode = RegDeleteValue(hKey, ValueName);
  852. }
  853. if( hKey )
  854. RegCloseKey( hKey );
  855. return(Rcode);
  856. }
  857. SCESTATUS
  858. ScepCreateDirectory(
  859. IN PCWSTR ProfileLocation,
  860. IN BOOL FileOrDir,
  861. PSECURITY_DESCRIPTOR pSecurityDescriptor OPTIONAL
  862. )
  863. /* ++
  864. Routine Description:
  865. This routine creates directory(ies) as specified in the ProfileLocation.
  866. Arguments:
  867. ProfileLocation - The directory (full path) to create
  868. FileOrDir - TRUE = Dir name, FALSE = file name
  869. pSecurityDescriptor - The secrity descriptor for the directories to create.
  870. If it is NULL, then the parent directory's inherit
  871. security descriptor is used.
  872. Return Value:
  873. SCESTATUS_SUCCESS
  874. SCESTATUS_INVALID_PARAMETER
  875. SCESTATUS_NOT_ENOUGH_RESOURCE
  876. SCESTATUS_OTHER_ERROR
  877. -- */
  878. {
  879. PWSTR Buffer=NULL;
  880. PWSTR pTemp=NULL;
  881. DWORD Len=0;
  882. SCESTATUS rc;
  883. SECURITY_ATTRIBUTES sa;
  884. if ( ProfileLocation == NULL ) {
  885. return(SCESTATUS_INVALID_PARAMETER);
  886. }
  887. if ( wcsncmp(ProfileLocation,L"\\\\?\\",4) == 0 ) {
  888. pTemp = (PWSTR)ProfileLocation+4;
  889. } else {
  890. pTemp = (PWSTR)ProfileLocation;
  891. }
  892. //
  893. // skip the first '\\' for example, c:\winnt
  894. //
  895. pTemp = wcschr(pTemp, L'\\');
  896. if ( pTemp == NULL ) {
  897. if ( ProfileLocation[1] == L':' ) {
  898. return(SCESTATUS_SUCCESS);
  899. } else {
  900. return(SCESTATUS_INVALID_PARAMETER);
  901. }
  902. } else if ( *(pTemp+1) == L'\\' ) {
  903. //
  904. // there is a machine name here
  905. //
  906. pTemp = wcschr(pTemp+2, L'\\');
  907. if ( pTemp == NULL ) {
  908. //
  909. // just a machine name, invalid
  910. //
  911. return(SCESTATUS_INVALID_PARAMETER);
  912. } else {
  913. //
  914. // look for the share name end
  915. //
  916. pTemp = wcschr(pTemp+1, L'\\');
  917. if ( pTemp == NULL ) {
  918. //
  919. // no directory is specified
  920. //
  921. return(SCESTATUS_INVALID_PARAMETER);
  922. }
  923. }
  924. }
  925. //
  926. // Make a copy of the profile location
  927. //
  928. Buffer = (PWSTR)ScepAlloc( 0, (wcslen(ProfileLocation)+1)*sizeof(WCHAR));
  929. if ( Buffer == NULL ) {
  930. return(SCESTATUS_NOT_ENOUGH_RESOURCE);
  931. }
  932. wcscpy( Buffer, ProfileLocation );
  933. //
  934. // Looping to find the next '\\'
  935. //
  936. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  937. sa.lpSecurityDescriptor = (LPVOID)pSecurityDescriptor;
  938. sa.bInheritHandle = FALSE;
  939. do {
  940. pTemp = wcschr( pTemp+1, L'\\');
  941. if ( pTemp != NULL ) {
  942. Len = (DWORD)(pTemp - ProfileLocation);
  943. Buffer[Len] = L'\0';
  944. } else if ( FileOrDir )
  945. Len = 0; // dir name
  946. else
  947. break; // file name. DO NOT create directory for the file name part
  948. //
  949. // should make a security descriptor and set
  950. //
  951. if ( CreateDirectory(
  952. Buffer,
  953. &sa
  954. ) == FALSE ) {
  955. if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
  956. rc = ScepDosErrorToSceStatus(GetLastError());
  957. goto Done;
  958. }
  959. }
  960. if ( Len != 0 )
  961. Buffer[Len] = L'\\';
  962. } while ( pTemp != NULL );
  963. rc = SCESTATUS_SUCCESS;
  964. Done:
  965. ScepFree(Buffer);
  966. return(rc);
  967. }
  968. DWORD
  969. ScepSceStatusToDosError(
  970. IN SCESTATUS SceStatus
  971. )
  972. // converts SCESTATUS error code to dos error defined in winerror.h
  973. {
  974. switch(SceStatus) {
  975. case SCESTATUS_SUCCESS:
  976. return(NO_ERROR);
  977. case SCESTATUS_OTHER_ERROR:
  978. return(ERROR_EXTENDED_ERROR);
  979. case SCESTATUS_INVALID_PARAMETER:
  980. return(ERROR_INVALID_PARAMETER);
  981. case SCESTATUS_RECORD_NOT_FOUND:
  982. return(ERROR_NO_MORE_ITEMS);
  983. case SCESTATUS_NO_MAPPING:
  984. return(ERROR_NONE_MAPPED);
  985. case SCESTATUS_TRUST_FAIL:
  986. return(ERROR_TRUSTED_DOMAIN_FAILURE);
  987. case SCESTATUS_INVALID_DATA:
  988. return(ERROR_INVALID_DATA);
  989. case SCESTATUS_OBJECT_EXIST:
  990. return(ERROR_FILE_EXISTS);
  991. case SCESTATUS_BUFFER_TOO_SMALL:
  992. return(ERROR_INSUFFICIENT_BUFFER);
  993. case SCESTATUS_PROFILE_NOT_FOUND:
  994. return(ERROR_FILE_NOT_FOUND);
  995. case SCESTATUS_BAD_FORMAT:
  996. return(ERROR_BAD_FORMAT);
  997. case SCESTATUS_NOT_ENOUGH_RESOURCE:
  998. return(ERROR_NOT_ENOUGH_MEMORY);
  999. case SCESTATUS_ACCESS_DENIED:
  1000. return(ERROR_ACCESS_DENIED);
  1001. case SCESTATUS_CANT_DELETE:
  1002. return(ERROR_CURRENT_DIRECTORY);
  1003. case SCESTATUS_PREFIX_OVERFLOW:
  1004. return(ERROR_BUFFER_OVERFLOW);
  1005. case SCESTATUS_ALREADY_RUNNING:
  1006. return(ERROR_SERVICE_ALREADY_RUNNING);
  1007. case SCESTATUS_SERVICE_NOT_SUPPORT:
  1008. return(ERROR_NOT_SUPPORTED);
  1009. case SCESTATUS_MOD_NOT_FOUND:
  1010. return(ERROR_MOD_NOT_FOUND);
  1011. case SCESTATUS_EXCEPTION_IN_SERVER:
  1012. return(ERROR_EXCEPTION_IN_SERVICE);
  1013. case SCESTATUS_JET_DATABASE_ERROR:
  1014. return(ERROR_DATABASE_FAILURE);
  1015. case SCESTATUS_TIMEOUT:
  1016. return(ERROR_TIMEOUT);
  1017. case SCESTATUS_PENDING_IGNORE:
  1018. return(ERROR_IO_PENDING);
  1019. case SCESTATUS_SPECIAL_ACCOUNT:
  1020. return(ERROR_SPECIAL_ACCOUNT);
  1021. default:
  1022. return(ERROR_EXTENDED_ERROR);
  1023. }
  1024. }
  1025. SCESTATUS
  1026. ScepDosErrorToSceStatus(
  1027. DWORD rc
  1028. )
  1029. {
  1030. switch(rc) {
  1031. case NO_ERROR:
  1032. return(SCESTATUS_SUCCESS);
  1033. case ERROR_INVALID_PARAMETER:
  1034. case RPC_S_INVALID_STRING_BINDING:
  1035. case RPC_S_INVALID_BINDING:
  1036. case RPC_X_NULL_REF_POINTER:
  1037. return(SCESTATUS_INVALID_PARAMETER);
  1038. case ERROR_INVALID_DATA:
  1039. return(SCESTATUS_INVALID_DATA);
  1040. case ERROR_FILE_NOT_FOUND:
  1041. case ERROR_PATH_NOT_FOUND:
  1042. case ERROR_BAD_NETPATH:
  1043. return(SCESTATUS_PROFILE_NOT_FOUND);
  1044. case ERROR_ACCESS_DENIED:
  1045. case ERROR_SHARING_VIOLATION:
  1046. case ERROR_LOCK_VIOLATION:
  1047. case ERROR_NETWORK_ACCESS_DENIED:
  1048. case ERROR_CANT_ACCESS_FILE:
  1049. case RPC_S_SERVER_TOO_BUSY:
  1050. return(SCESTATUS_ACCESS_DENIED);
  1051. case ERROR_NOT_ENOUGH_MEMORY:
  1052. case ERROR_OUTOFMEMORY:
  1053. case RPC_S_OUT_OF_RESOURCES:
  1054. return(SCESTATUS_NOT_ENOUGH_RESOURCE);
  1055. case ERROR_BAD_FORMAT:
  1056. return(SCESTATUS_BAD_FORMAT);
  1057. case ERROR_CURRENT_DIRECTORY:
  1058. return(SCESTATUS_CANT_DELETE);
  1059. case ERROR_SECTOR_NOT_FOUND:
  1060. case ERROR_SERVICE_DOES_NOT_EXIST:
  1061. case ERROR_RESOURCE_DATA_NOT_FOUND:
  1062. case ERROR_NO_MORE_ITEMS:
  1063. return(SCESTATUS_RECORD_NOT_FOUND);
  1064. case ERROR_NO_TRUST_LSA_SECRET:
  1065. case ERROR_NO_TRUST_SAM_ACCOUNT:
  1066. case ERROR_TRUSTED_DOMAIN_FAILURE:
  1067. case ERROR_TRUSTED_RELATIONSHIP_FAILURE:
  1068. case ERROR_TRUST_FAILURE:
  1069. return(SCESTATUS_TRUST_FAIL);
  1070. case ERROR_NONE_MAPPED:
  1071. return(SCESTATUS_NO_MAPPING);
  1072. case ERROR_DUP_NAME:
  1073. case ERROR_FILE_EXISTS:
  1074. return(SCESTATUS_OBJECT_EXIST);
  1075. case ERROR_BUFFER_OVERFLOW:
  1076. return(SCESTATUS_PREFIX_OVERFLOW);
  1077. case ERROR_INSUFFICIENT_BUFFER:
  1078. case RPC_S_STRING_TOO_LONG:
  1079. return(SCESTATUS_BUFFER_TOO_SMALL);
  1080. case ERROR_SERVICE_ALREADY_RUNNING:
  1081. return(SCESTATUS_ALREADY_RUNNING);
  1082. case ERROR_NOT_SUPPORTED:
  1083. case RPC_S_INVALID_NET_ADDR:
  1084. case RPC_S_NO_ENDPOINT_FOUND:
  1085. case RPC_S_SERVER_UNAVAILABLE:
  1086. case RPC_S_CANNOT_SUPPORT:
  1087. return(SCESTATUS_SERVICE_NOT_SUPPORT);
  1088. case ERROR_MOD_NOT_FOUND:
  1089. case ERROR_PROC_NOT_FOUND:
  1090. return(SCESTATUS_MOD_NOT_FOUND);
  1091. case ERROR_EXCEPTION_IN_SERVICE:
  1092. return(SCESTATUS_EXCEPTION_IN_SERVER);
  1093. case ERROR_DATABASE_FAILURE:
  1094. return(SCESTATUS_JET_DATABASE_ERROR);
  1095. case ERROR_TIMEOUT:
  1096. return(SCESTATUS_TIMEOUT);
  1097. case ERROR_IO_PENDING:
  1098. return(SCESTATUS_PENDING_IGNORE);
  1099. case ERROR_SPECIAL_ACCOUNT:
  1100. case ERROR_PASSWORD_RESTRICTION:
  1101. return(SCESTATUS_SPECIAL_ACCOUNT);
  1102. default:
  1103. return(SCESTATUS_OTHER_ERROR);
  1104. }
  1105. }
  1106. SCESTATUS
  1107. ScepChangeAclRevision(
  1108. IN PSECURITY_DESCRIPTOR pSD,
  1109. IN BYTE NewRevision
  1110. )
  1111. /*
  1112. Change AclRevision to the NewRevision.
  1113. This routine is made for backward compatility because NT4 does not support
  1114. the new ACL_REVISION_DS.
  1115. */
  1116. {
  1117. BOOLEAN bPresent=FALSE;
  1118. BOOLEAN bDefault=FALSE;
  1119. PACL pAcl=NULL;
  1120. NTSTATUS NtStatus;
  1121. if ( pSD ) {
  1122. //
  1123. // change acl revision on DACL
  1124. //
  1125. NtStatus = RtlGetDaclSecurityDescriptor (
  1126. pSD,
  1127. &bPresent,
  1128. &pAcl,
  1129. &bDefault
  1130. );
  1131. if ( NT_SUCCESS(NtStatus) && bPresent && pAcl ) {
  1132. pAcl->AclRevision = NewRevision;
  1133. }
  1134. //
  1135. // change acl revision on SACL
  1136. //
  1137. pAcl = NULL;
  1138. bPresent = FALSE;
  1139. NtStatus = RtlGetSaclSecurityDescriptor (
  1140. pSD,
  1141. &bPresent,
  1142. &pAcl,
  1143. &bDefault
  1144. );
  1145. if ( NT_SUCCESS(NtStatus) && bPresent && pAcl ) {
  1146. pAcl->AclRevision = NewRevision;
  1147. }
  1148. }
  1149. return(SCESTATUS_SUCCESS);
  1150. }
  1151. BOOL
  1152. ScepEqualSid(
  1153. IN PISID pSid1,
  1154. IN PISID pSid2
  1155. )
  1156. {
  1157. if ( pSid1 == NULL && pSid2 == NULL )
  1158. return(TRUE);
  1159. if ( pSid1 == NULL || pSid2 == NULL )
  1160. return(FALSE);
  1161. return (EqualSid((PSID)pSid1, (PSID)pSid2) ? TRUE: FALSE);
  1162. }
  1163. BOOL
  1164. ScepEqualGuid(
  1165. IN GUID *Guid1,
  1166. IN GUID *Guid2
  1167. )
  1168. {
  1169. if ( Guid1 == NULL && Guid2 == NULL )
  1170. return(TRUE);
  1171. if ( Guid1 == NULL || Guid2 == NULL )
  1172. return(FALSE);
  1173. /*
  1174. if ( Guid1->Data1 != Guid2->Data1 ||
  1175. Guid1->Data2 != Guid2->Data2 ||
  1176. Guid1->Data3 != Guid2->Data3 ||
  1177. *((DWORD *)(Guid1->Data4)) != *((DWORD *)(Guid2->Data4)) ||
  1178. *((DWORD *)(Guid1->Data4)+1) != *((DWORD *)(Guid2->Data4)+1) )
  1179. return(FALSE);
  1180. return(TRUE);
  1181. */
  1182. return (!memcmp(Guid1, Guid2, sizeof(GUID)));
  1183. }
  1184. SCESTATUS
  1185. ScepAddToGroupMembership(
  1186. OUT PSCE_GROUP_MEMBERSHIP *pGroupMembership,
  1187. IN PWSTR Keyname,
  1188. IN DWORD KeyLen,
  1189. IN PSCE_NAME_LIST pMembers,
  1190. IN DWORD ValueType,
  1191. IN BOOL bCheckDup,
  1192. IN BOOL bReplaceList
  1193. )
  1194. {
  1195. PSCE_GROUP_MEMBERSHIP pGroup=NULL;
  1196. SCESTATUS rc=SCESTATUS_SUCCESS;
  1197. if ( pGroupMembership == NULL || Keyname == NULL ||
  1198. KeyLen <= 0 ) {
  1199. return(SCESTATUS_INVALID_PARAMETER);
  1200. }
  1201. //
  1202. // find if the group is already defined
  1203. //
  1204. if ( bCheckDup ) {
  1205. for ( pGroup=*pGroupMembership; pGroup != NULL; pGroup=pGroup->Next ) {
  1206. if ( _wcsnicmp( pGroup->GroupName, Keyname, KeyLen) == 0 &&
  1207. pGroup->GroupName[KeyLen] == L'\0' )
  1208. break;
  1209. }
  1210. }
  1211. if ( pGroup == NULL ) {
  1212. // not found. create a new node
  1213. pGroup = (PSCE_GROUP_MEMBERSHIP)ScepAlloc( LMEM_ZEROINIT,
  1214. sizeof(SCE_GROUP_MEMBERSHIP) );
  1215. if ( pGroup != NULL ) {
  1216. pGroup->GroupName = (PWSTR)ScepAlloc( LMEM_ZEROINIT,
  1217. (KeyLen+1)*sizeof(WCHAR) );
  1218. if (pGroup->GroupName != NULL) {
  1219. wcsncpy( pGroup->GroupName, Keyname, KeyLen );
  1220. pGroup->Next = *pGroupMembership;
  1221. pGroup->Status = SCE_GROUP_STATUS_NC_MEMBERS | SCE_GROUP_STATUS_NC_MEMBEROF;
  1222. *pGroupMembership = pGroup;
  1223. } else {
  1224. ScepFree(pGroup);
  1225. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1226. }
  1227. } else
  1228. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1229. }
  1230. if ( rc == SCESTATUS_SUCCESS ) {
  1231. if ( ValueType == 0 ) {
  1232. if ( bReplaceList ) {
  1233. ScepFreeNameList(pGroup->pMembers);
  1234. pGroup->pMembers = pMembers;
  1235. } else if ( pGroup->pMembers == NULL )
  1236. pGroup->pMembers = pMembers;
  1237. pGroup->Status &= ~SCE_GROUP_STATUS_NC_MEMBERS;
  1238. } else {
  1239. if ( bReplaceList ) {
  1240. ScepFreeNameList(pGroup->pMemberOf);
  1241. pGroup->pMemberOf = pMembers;
  1242. } else if ( pGroup->pMemberOf == NULL )
  1243. pGroup->pMemberOf = pMembers;
  1244. pGroup->Status &= ~SCE_GROUP_STATUS_NC_MEMBEROF;
  1245. }
  1246. }
  1247. return(rc);
  1248. }
  1249. DWORD
  1250. ScepAddOneServiceToList(
  1251. IN LPWSTR lpServiceName,
  1252. IN LPWSTR lpDisplayName,
  1253. IN DWORD ServiceStatus,
  1254. IN PVOID pGeneral OPTIONAL,
  1255. IN SECURITY_INFORMATION SeInfo,
  1256. IN BOOL bSecurity,
  1257. OUT PSCE_SERVICES *pServiceList
  1258. )
  1259. /*
  1260. Routine Description:
  1261. Add service name, startup status, security descriptor or a engine name
  1262. to the service list. The service list must be freed using SceFreePSCE_SERVICES
  1263. Arguments:
  1264. lpServiceName - The service name
  1265. ServiceStatus - The startup status of the service
  1266. pGeneral - The security descriptor or the engine dll name, decided by
  1267. bSecurity
  1268. bSecurity - TRUE = a security descriptor is passed in pGeneral
  1269. FALSE = a engine dll name is passed in pGeneral
  1270. pServiceList - The service list to output
  1271. Return Value:
  1272. ERROR_SUCCESS
  1273. Win32 errors
  1274. */
  1275. {
  1276. if ( NULL == lpServiceName || pServiceList == NULL ) {
  1277. return(ERROR_INVALID_PARAMETER);
  1278. }
  1279. PSCE_SERVICES pServiceNode;
  1280. DWORD rc=ERROR_SUCCESS;
  1281. //
  1282. // allocate a service node
  1283. //
  1284. pServiceNode = (PSCE_SERVICES)LocalAlloc(LMEM_ZEROINIT, sizeof(SCE_SERVICES));
  1285. if ( pServiceNode != NULL ) {
  1286. //
  1287. // allocate buffer for ServiceName
  1288. //
  1289. pServiceNode->ServiceName = (PWSTR)LocalAlloc(LMEM_FIXED,
  1290. (wcslen(lpServiceName) + 1)*sizeof(WCHAR));
  1291. if ( NULL != pServiceNode->ServiceName ) {
  1292. //
  1293. // fill the service node
  1294. //
  1295. if ( lpDisplayName != NULL ) {
  1296. pServiceNode->DisplayName = (PWSTR)LocalAlloc(LMEM_FIXED,
  1297. (wcslen(lpDisplayName) + 1)*sizeof(WCHAR));
  1298. if ( pServiceNode->DisplayName != NULL ) {
  1299. wcscpy(pServiceNode->DisplayName, lpDisplayName);
  1300. } else {
  1301. rc = ERROR_NOT_ENOUGH_MEMORY;
  1302. }
  1303. } else
  1304. pServiceNode->DisplayName = NULL;
  1305. if ( rc == NO_ERROR ) {
  1306. wcscpy(pServiceNode->ServiceName, lpServiceName);
  1307. pServiceNode->Status = 0;
  1308. pServiceNode->Startup = (BYTE)ServiceStatus;
  1309. if ( bSecurity ) {
  1310. //
  1311. // security descriptor
  1312. //
  1313. pServiceNode->General.pSecurityDescriptor = (PSECURITY_DESCRIPTOR)pGeneral;
  1314. pServiceNode->SeInfo = SeInfo;
  1315. } else {
  1316. //
  1317. // service engine name
  1318. //
  1319. pServiceNode->General.ServiceEngineName = (PWSTR)pGeneral;
  1320. }
  1321. //
  1322. // link to the list
  1323. //
  1324. pServiceNode->Next = *pServiceList;
  1325. *pServiceList = pServiceNode;
  1326. } else {
  1327. LocalFree(pServiceNode->ServiceName);
  1328. }
  1329. } else
  1330. rc = ERROR_NOT_ENOUGH_MEMORY;
  1331. if ( rc != ERROR_SUCCESS ) {
  1332. LocalFree(pServiceNode);
  1333. }
  1334. } else
  1335. rc = ERROR_NOT_ENOUGH_MEMORY;
  1336. return(rc);
  1337. }
  1338. DWORD
  1339. ScepIsAdminLoggedOn(
  1340. OUT PBOOL bpAdminLogon
  1341. )
  1342. {
  1343. HANDLE Token;
  1344. NTSTATUS NtStatus;
  1345. SID_IDENTIFIER_AUTHORITY IdAuth=SECURITY_NT_AUTHORITY;
  1346. PSID AdminsSid=NULL;
  1347. if ( bpAdminLogon == NULL ) {
  1348. return(ERROR_INVALID_PARAMETER);
  1349. }
  1350. *bpAdminLogon = FALSE;
  1351. if (!OpenThreadToken( GetCurrentThread(),
  1352. TOKEN_QUERY | TOKEN_DUPLICATE,
  1353. FALSE,
  1354. &Token)) {
  1355. if (!OpenProcessToken( GetCurrentProcess(),
  1356. TOKEN_QUERY | TOKEN_DUPLICATE,
  1357. &Token))
  1358. return(GetLastError());
  1359. }
  1360. //
  1361. // Parepare AdminsSid
  1362. //
  1363. NtStatus = RtlAllocateAndInitializeSid(
  1364. &IdAuth,
  1365. 2,
  1366. SECURITY_BUILTIN_DOMAIN_RID,
  1367. DOMAIN_ALIAS_RID_ADMINS,
  1368. 0,
  1369. 0,
  1370. 0,
  1371. 0,
  1372. 0,
  1373. 0,
  1374. &AdminsSid );
  1375. DWORD rc32 = RtlNtStatusToDosError(NtStatus);
  1376. if (NT_SUCCESS(NtStatus) ) {
  1377. //
  1378. // use the CheckTokenMembership API which handles the group attributes
  1379. //
  1380. HANDLE NewToken;
  1381. if ( DuplicateToken( Token, SecurityImpersonation, &NewToken )) {
  1382. if ( FALSE == CheckTokenMembership(
  1383. NewToken,
  1384. AdminsSid,
  1385. bpAdminLogon
  1386. ) ) {
  1387. //
  1388. // error occured when checking membership, assume it is not a member
  1389. //
  1390. *bpAdminLogon = FALSE;
  1391. rc32 = GetLastError();
  1392. }
  1393. CloseHandle(NewToken);
  1394. } else {
  1395. rc32 = GetLastError();
  1396. }
  1397. #if 0
  1398. DWORD i;
  1399. DWORD ReturnLen, NewLen;
  1400. PVOID Info=NULL;
  1401. //
  1402. // check groups
  1403. //
  1404. NtStatus = NtQueryInformationToken (
  1405. Token,
  1406. TokenGroups,
  1407. NULL,
  1408. 0,
  1409. &ReturnLen
  1410. );
  1411. if ( NtStatus == STATUS_BUFFER_TOO_SMALL ) {
  1412. //
  1413. // allocate buffer
  1414. //
  1415. Info = ScepAlloc(0, ReturnLen+1);
  1416. if ( Info != NULL ) {
  1417. NtStatus = NtQueryInformationToken (
  1418. Token,
  1419. TokenGroups,
  1420. Info,
  1421. ReturnLen,
  1422. &NewLen
  1423. );
  1424. if ( NT_SUCCESS(NtStatus) ) {
  1425. for ( i = 0; i<((PTOKEN_GROUPS)Info)->GroupCount; i++) {
  1426. //
  1427. // check each group sid
  1428. //
  1429. if ( ((PTOKEN_GROUPS)Info)->Groups[i].Sid != NULL &&
  1430. RtlEqualSid(((PTOKEN_GROUPS)Info)->Groups[i].Sid, AdminsSid) ) {
  1431. *bpAdminLogon = TRUE;
  1432. break;
  1433. }
  1434. }
  1435. }
  1436. ScepFree(Info);
  1437. }
  1438. }
  1439. rc32 = RtlNtStatusToDosError(NtStatus);
  1440. #endif
  1441. //
  1442. // Free administrators Sid
  1443. //
  1444. RtlFreeSid(AdminsSid);
  1445. }
  1446. CloseHandle(Token);
  1447. return(rc32);
  1448. }
  1449. DWORD
  1450. ScepGetProfileSetting(
  1451. IN PCWSTR ValueName,
  1452. IN BOOL bAdminLogon,
  1453. OUT PWSTR *Setting
  1454. )
  1455. /*
  1456. Routine Description:
  1457. This routine returns JET profile setting for the ValueName from registry.
  1458. If there is no setting in registry (e.g., first time), a default setting
  1459. for the ValueName will be built. The output Setting string must be freed
  1460. by LocalFree after its use.
  1461. Arguments:
  1462. ValueName - The registry value name to retrieve
  1463. bAdminLogon - The flag to indicate if logged on user is admin equivalent
  1464. Setting - the ouptut buffer
  1465. Return Value:
  1466. Win32 error codes
  1467. */
  1468. {
  1469. DWORD RegType;
  1470. DWORD rc;
  1471. PWSTR SysRoot=NULL;
  1472. PWSTR ProfilePath=NULL;
  1473. TCHAR TempName[256];
  1474. if ( ValueName == NULL || Setting == NULL ) {
  1475. return( ERROR_INVALID_PARAMETER );
  1476. }
  1477. *Setting = NULL;
  1478. if (bAdminLogon ) {
  1479. if ( _wcsicmp(L"DefaultProfile", ValueName ) == 0 ) {
  1480. //
  1481. // do not query the system database name in registry
  1482. //
  1483. rc = ERROR_FILE_NOT_FOUND;
  1484. } else {
  1485. rc = ScepRegQueryValue(
  1486. HKEY_LOCAL_MACHINE,
  1487. SCE_ROOT_PATH,
  1488. ValueName,
  1489. (PVOID *)Setting,
  1490. &RegType
  1491. );
  1492. }
  1493. } else {
  1494. HKEY hCurrentUser=NULL;
  1495. //
  1496. // the HKEY_CURRENT_USER may be linked to .default
  1497. // depends on the current calling process
  1498. //
  1499. rc =RegOpenCurrentUser(
  1500. KEY_READ,
  1501. &hCurrentUser
  1502. );
  1503. if ( rc != NO_ERROR ) {
  1504. hCurrentUser = NULL;
  1505. }
  1506. rc = ScepRegQueryValue(
  1507. hCurrentUser ? hCurrentUser : HKEY_CURRENT_USER,
  1508. SCE_ROOT_PATH,
  1509. ValueName,
  1510. (PVOID *)Setting,
  1511. &RegType
  1512. );
  1513. if ( hCurrentUser ) {
  1514. // close it
  1515. RegCloseKey(hCurrentUser);
  1516. }
  1517. }
  1518. //
  1519. // if registry type is not REG_SZ or REG_EXPAND_SZ,
  1520. // return status won't be SUCCESS
  1521. //
  1522. if ( rc != NO_ERROR ) {
  1523. //
  1524. // use the default
  1525. //
  1526. RegType = 0;
  1527. rc = ScepGetNTDirectory( &SysRoot, &RegType, SCE_FLAG_WINDOWS_DIR );
  1528. if ( rc == NO_ERROR ) {
  1529. if ( SysRoot != NULL ) {
  1530. if ( bAdminLogon ) {
  1531. //
  1532. // default location is %SystemRoot%\Security\Database\secedit.sdb
  1533. //
  1534. wcscpy(TempName, L"\\Security\\Database\\secedit.sdb");
  1535. RegType += wcslen(TempName)+1;
  1536. *Setting = (PWSTR)ScepAlloc( 0, RegType*sizeof(WCHAR));
  1537. if ( *Setting != NULL ) {
  1538. swprintf(*Setting, L"%s%s", SysRoot, TempName );
  1539. *(*Setting+RegType-1) = L'\0';
  1540. /*
  1541. // do not save system database name
  1542. // set this value as the default profile name for administrators
  1543. //
  1544. ScepRegSetValue(
  1545. HKEY_LOCAL_MACHINE,
  1546. SCE_ROOT_PATH,
  1547. (PWSTR)ValueName,
  1548. REG_SZ,
  1549. (BYTE *)(*Setting),
  1550. (RegType-1)*sizeof(WCHAR)
  1551. );
  1552. */
  1553. } else
  1554. rc = ERROR_NOT_ENOUGH_MEMORY;
  1555. } else {
  1556. //
  1557. // default location is <UserProfilesDirectory>\Profiles\<User>\secedit.sdb
  1558. // on NT5, it will be %SystemDrive%\Users\Profiles...
  1559. // on NT4, it is %SystemRoot%\Profiles...
  1560. // GetCurrentUserProfilePath already handles NT4/NT5 difference
  1561. //
  1562. rc = ScepGetCurrentUserProfilePath(&ProfilePath);
  1563. if ( rc == NO_ERROR && ProfilePath != NULL ) {
  1564. //
  1565. // get the current user profile path
  1566. //
  1567. wcscpy(TempName, L"\\secedit.sdb");
  1568. *Setting = (PWSTR)ScepAlloc(0, (wcslen(ProfilePath)+wcslen(TempName)+1)*sizeof(WCHAR));
  1569. if ( *Setting != NULL ) {
  1570. swprintf(*Setting, L"%s%s\0", ProfilePath,TempName );
  1571. } else
  1572. rc = ERROR_NOT_ENOUGH_MEMORY;
  1573. ScepFree(ProfilePath);
  1574. } else {
  1575. rc = NO_ERROR;
  1576. wcscpy(TempName, L"\\Profiles\\secedit.sdb");
  1577. #if _WINNT_WIN32>=0x0500
  1578. //
  1579. // default to <ProfilesDirectory>\Profiles
  1580. // get the profiles directory first
  1581. //
  1582. RegType = 0;
  1583. GetProfilesDirectory(NULL, &RegType);
  1584. if ( RegType ) {
  1585. //
  1586. // allocate the total buffer
  1587. //
  1588. RegType += wcslen(TempName);
  1589. *Setting = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (RegType+1)*sizeof(WCHAR));
  1590. if ( *Setting ) {
  1591. //
  1592. // call to get the profiles directory again
  1593. //
  1594. if ( GetProfilesDirectory(*Setting, &RegType) ) {
  1595. wcscat(*Setting, TempName );
  1596. } else {
  1597. rc = GetLastError();
  1598. ScepFree(*Setting);
  1599. *Setting = NULL;
  1600. }
  1601. } else {
  1602. rc = ERROR_NOT_ENOUGH_MEMORY;
  1603. }
  1604. } else {
  1605. rc = GetLastError();
  1606. }
  1607. #else
  1608. //
  1609. // default to %SystemRoot%\Profiles
  1610. //
  1611. RegType += wcslen(TempName)+1;
  1612. *Setting = (PWSTR)ScepAlloc( 0, RegType*sizeof(WCHAR));
  1613. if ( *Setting != NULL ) {
  1614. swprintf(*Setting, L"%s%s", SysRoot,TempName );
  1615. *(*Setting+RegType-1) = L'\0';
  1616. rc = ERROR_SUCCESS;
  1617. } else {
  1618. rc = ERROR_NOT_ENOUGH_MEMORY;
  1619. }
  1620. #endif
  1621. }
  1622. }
  1623. ScepFree(SysRoot);
  1624. } else
  1625. rc = ERROR_INVALID_DATA;
  1626. }
  1627. }
  1628. return(rc);
  1629. }
  1630. DWORD
  1631. ScepCompareObjectSecurity(
  1632. IN SE_OBJECT_TYPE ObjectType,
  1633. IN BOOL IsContainer,
  1634. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1635. IN PSECURITY_DESCRIPTOR ProfileSD,
  1636. IN SECURITY_INFORMATION ProfileSeInfo,
  1637. OUT PBYTE IsDifferent
  1638. )
  1639. /* ++
  1640. Routine Description:
  1641. Compare two security descriptors
  1642. Arguments:
  1643. ObjectType - the object type
  1644. pSecurityDescriptor - The security descriptor of current object's setting
  1645. ProfileSD - security descriptor specified in the template
  1646. ProfileSeInfo - security information specified in the template
  1647. Return value:
  1648. SCESTATUS error codes
  1649. ++ */
  1650. {
  1651. BOOL Different=FALSE;
  1652. BOOL DifPermOrAudit;
  1653. DWORD rc=ERROR_SUCCESS;
  1654. PSID pSid1=NULL;
  1655. PSID pSid2=NULL;
  1656. BOOLEAN tFlag;
  1657. BOOLEAN aclPresent;
  1658. PACL pAcl1=NULL;
  1659. PACL pAcl2=NULL;
  1660. SECURITY_DESCRIPTOR_CONTROL Control1;
  1661. SECURITY_DESCRIPTOR_CONTROL Control2;
  1662. DWORD Win32rc;
  1663. BYTE Status=0;
  1664. if ( IsDifferent == NULL ) {
  1665. return(SCESTATUS_INVALID_PARAMETER);
  1666. }
  1667. if ( pSecurityDescriptor == NULL &&
  1668. ProfileSD == NULL ) {
  1669. if ( IsDifferent ) {
  1670. *IsDifferent = SCE_STATUS_MISMATCH;
  1671. }
  1672. return(rc);
  1673. }
  1674. if ( IsDifferent ) {
  1675. *IsDifferent = 0;
  1676. }
  1677. //
  1678. // if ProfileSD is specified and protection does not match SystemSD, then mismatch
  1679. // don't care if ProfileSD is not specified
  1680. //
  1681. if ( pSecurityDescriptor == NULL || !NT_SUCCESS(RtlGetControlSecurityDescriptor (
  1682. pSecurityDescriptor,
  1683. &Control1,
  1684. &Win32rc // temp use
  1685. ))) {
  1686. Control1 = 0;
  1687. }
  1688. if ( ProfileSD == NULL || !NT_SUCCESS(RtlGetControlSecurityDescriptor (
  1689. ProfileSD,
  1690. &Control2,
  1691. &Win32rc // temp use
  1692. ))) {
  1693. Control2 = 0;
  1694. }
  1695. if ((Control1 & SE_DACL_PROTECTED) != (Control2 & SE_DACL_PROTECTED)) {
  1696. Different = TRUE;
  1697. Status |= SCE_STATUS_PERMISSION_MISMATCH;
  1698. }
  1699. if ((Control1 & SE_SACL_PROTECTED) != (Control2 & SE_SACL_PROTECTED)) {
  1700. Different = TRUE;
  1701. Status |= SCE_STATUS_AUDIT_MISMATCH;
  1702. }
  1703. //
  1704. // Compare two security descriptors
  1705. //
  1706. if ( ProfileSeInfo & OWNER_SECURITY_INFORMATION ) {
  1707. if ( pSecurityDescriptor == NULL ||
  1708. !NT_SUCCESS( RtlGetOwnerSecurityDescriptor(
  1709. pSecurityDescriptor,
  1710. &pSid1,
  1711. &tFlag)
  1712. ) ) {
  1713. pSid1 = NULL;
  1714. }
  1715. if ( ProfileSD == NULL ||
  1716. !NT_SUCCESS( RtlGetOwnerSecurityDescriptor(
  1717. ProfileSD,
  1718. &pSid2,
  1719. &tFlag)
  1720. ) ) {
  1721. pSid2 = NULL;
  1722. }
  1723. if ( (pSid1 == NULL && pSid2 != NULL) ||
  1724. (pSid1 != NULL && pSid2 == NULL) ||
  1725. (pSid1 != NULL && pSid2 != NULL && !EqualSid(pSid1, pSid2)) ) {
  1726. Different = TRUE;
  1727. }
  1728. }
  1729. #if 0
  1730. //
  1731. // Get Group address
  1732. //
  1733. if ( ProfileSeInfo & GROUP_SECURITY_INFORMATION ) {
  1734. pSid1 = NULL;
  1735. pSid2 = NULL;
  1736. if ( pSecurityDescriptor == NULL ||
  1737. !NT_SUCCESS( RtlGetGroupSecurityDescriptor(
  1738. pSecurityDescriptor,
  1739. &pSid1,
  1740. &tFlag)
  1741. ) ) {
  1742. pSid1 = NULL;
  1743. }
  1744. if ( ProfileSD == NULL ||
  1745. !NT_SUCCESS( RtlGetGroupSecurityDescriptor(
  1746. ProfileSD,
  1747. &pSid2,
  1748. &tFlag)
  1749. ) ) {
  1750. pSid2 = NULL;
  1751. }
  1752. if ( (pSid1 == NULL && pSid2 != NULL) ||
  1753. (pSid1 != NULL && pSid2 == NULL) ||
  1754. (pSid1 != NULL && pSid2 != NULL && !EqualSid(pSid1, pSid2)) ) {
  1755. Different = TRUE;
  1756. }
  1757. }
  1758. #endif
  1759. //
  1760. // Get DACL address
  1761. //
  1762. if ( !(Status & SCE_STATUS_PERMISSION_MISMATCH) && (ProfileSeInfo & DACL_SECURITY_INFORMATION) ) {
  1763. if ( pSecurityDescriptor == NULL ||
  1764. !NT_SUCCESS( RtlGetDaclSecurityDescriptor(
  1765. pSecurityDescriptor,
  1766. &aclPresent,
  1767. &pAcl1,
  1768. &tFlag)
  1769. ) ) {
  1770. pAcl1 = NULL;
  1771. } else if ( !aclPresent )
  1772. pAcl1 = NULL;
  1773. if ( ProfileSD == NULL ||
  1774. !NT_SUCCESS( RtlGetDaclSecurityDescriptor(
  1775. ProfileSD,
  1776. &aclPresent,
  1777. &pAcl2,
  1778. &tFlag)
  1779. ) ) {
  1780. pAcl2 = NULL;
  1781. } else if ( !aclPresent )
  1782. pAcl2 = NULL;
  1783. //
  1784. // compare two ACLs
  1785. //
  1786. DifPermOrAudit = FALSE;
  1787. rc = ScepCompareExplicitAcl( ObjectType, IsContainer, pAcl1, pAcl2, &DifPermOrAudit );
  1788. if ( rc != ERROR_SUCCESS ) {
  1789. goto Done;
  1790. }
  1791. if ( DifPermOrAudit ) {
  1792. Different = TRUE;
  1793. Status |= SCE_STATUS_PERMISSION_MISMATCH;
  1794. }
  1795. }
  1796. //
  1797. // Get SACL address
  1798. //
  1799. if ( !(Status & SCE_STATUS_AUDIT_MISMATCH) && (ProfileSeInfo & SACL_SECURITY_INFORMATION) ) {
  1800. pAcl1 = NULL;
  1801. pAcl2 = NULL;
  1802. if ( pSecurityDescriptor == NULL ||
  1803. !NT_SUCCESS( RtlGetSaclSecurityDescriptor(
  1804. pSecurityDescriptor,
  1805. &aclPresent,
  1806. &pAcl1,
  1807. &tFlag)
  1808. ) ) {
  1809. pAcl1 = NULL;
  1810. } else if ( !aclPresent )
  1811. pAcl1 = NULL;
  1812. if ( ProfileSD == NULL ||
  1813. !NT_SUCCESS( RtlGetSaclSecurityDescriptor(
  1814. ProfileSD,
  1815. &aclPresent,
  1816. &pAcl2,
  1817. &tFlag)
  1818. ) ) {
  1819. pAcl2 = NULL;
  1820. } else if ( !aclPresent )
  1821. pAcl2 = NULL;
  1822. //
  1823. // compare two ACLs
  1824. //
  1825. DifPermOrAudit = FALSE;
  1826. rc = ScepCompareExplicitAcl( ObjectType, IsContainer, pAcl1, pAcl2, &DifPermOrAudit );
  1827. if ( rc != ERROR_SUCCESS ) {
  1828. goto Done;
  1829. }
  1830. if ( DifPermOrAudit ) {
  1831. Different = TRUE;
  1832. Status |= SCE_STATUS_AUDIT_MISMATCH;
  1833. }
  1834. }
  1835. if ( IsDifferent && Different ) {
  1836. *IsDifferent = SCE_STATUS_MISMATCH;
  1837. if ( Status ) {
  1838. *IsDifferent |= Status;
  1839. }
  1840. }
  1841. Done:
  1842. return(rc);
  1843. }
  1844. DWORD
  1845. ScepCompareExplicitAcl(
  1846. IN SE_OBJECT_TYPE ObjectType,
  1847. IN BOOL IsContainer,
  1848. IN PACL pAcl1,
  1849. IN PACL pAcl2,
  1850. OUT PBOOL pDifferent
  1851. )
  1852. /*
  1853. Routine Description:
  1854. This routine compares explicit aces of two ACLs for exact match. Exact
  1855. match means: same access type, same inheritance flag, same access mask,
  1856. same GUID/Object GUID (if available), and same SID.
  1857. Inherited aces (INHERITED_ACE is set) are ignored.
  1858. Arguments:
  1859. pAcl1 - The first ACL
  1860. pAcl2 - The 2nd ACL
  1861. pDifferent - The output flag to indicate different
  1862. Return Value:
  1863. Win32 error codes
  1864. */
  1865. {
  1866. NTSTATUS NtStatus=STATUS_SUCCESS;
  1867. DWORD dwAcl1AceCount, dwAcl2AceCount;
  1868. ACE_HEADER *pAce1=NULL;
  1869. ACE_HEADER *pAce2=NULL;
  1870. PSCEP_ADL_NODE hTable1 [SCEP_ADL_HTABLE_SIZE];
  1871. PSCEP_ADL_NODE hTable2 [SCEP_ADL_HTABLE_SIZE];
  1872. memset(hTable1, NULL, SCEP_ADL_HTABLE_SIZE * sizeof(PSCEP_ADL_NODE) );
  1873. memset(hTable2, NULL, SCEP_ADL_HTABLE_SIZE * sizeof(PSCEP_ADL_NODE) );
  1874. *pDifferent = FALSE;
  1875. //
  1876. // if pAcl1 is NULL, pAcl2 should have 0 explicit Ace
  1877. //
  1878. if ( pAcl1 == NULL ) {
  1879. NtStatus = ScepAnyExplicitAcl( pAcl2, 0, pDifferent );
  1880. return(RtlNtStatusToDosError(NtStatus));
  1881. }
  1882. //
  1883. // if pAcl2 is NULL, pAcl1 should have 0 explicit Ace
  1884. //
  1885. if ( pAcl2 == NULL ) {
  1886. NtStatus = ScepAnyExplicitAcl( pAcl1, 0, pDifferent );
  1887. return(RtlNtStatusToDosError(NtStatus));
  1888. }
  1889. //
  1890. // both ACLs are not NULL
  1891. //
  1892. BOOL bAcl1NoExplicitAces;
  1893. BOOL bAcl2NoExplicitAces;
  1894. dwAcl1AceCount = 0;
  1895. dwAcl2AceCount = 0;
  1896. while ( dwAcl1AceCount < pAcl1->AceCount || dwAcl2AceCount < pAcl2->AceCount) {
  1897. //
  1898. // convert Acl1 into Access Description Language and insert into htable for this blob
  1899. // blob is defined as a contiguous AceList of same type
  1900. //
  1901. bAcl1NoExplicitAces = TRUE;
  1902. if (dwAcl1AceCount < pAcl1->AceCount) {
  1903. NtStatus = ScepConvertAclBlobToAdl(ObjectType,
  1904. IsContainer,
  1905. pAcl1,
  1906. &dwAcl1AceCount,
  1907. &bAcl1NoExplicitAces,
  1908. hTable1);
  1909. if ( !NT_SUCCESS(NtStatus) )
  1910. goto Done;
  1911. }
  1912. //
  1913. // convert Acl2 into Access Description Language and insert into htable for this blob
  1914. //
  1915. bAcl2NoExplicitAces = TRUE;
  1916. if (dwAcl2AceCount < pAcl2->AceCount) {
  1917. NtStatus = ScepConvertAclBlobToAdl(ObjectType,
  1918. IsContainer,
  1919. pAcl2,
  1920. &dwAcl2AceCount,
  1921. &bAcl2NoExplicitAces,
  1922. hTable2);
  1923. if ( !NT_SUCCESS(NtStatus) )
  1924. goto Done;
  1925. }
  1926. //
  1927. // compare Adls for Acl1 and Acl2 blobs
  1928. // if after ignoring INHERITED_ACES, one Acl has no aces and the other has, then bAcl1NoExplicitAces != bAcl2NoExplicitAces
  1929. //
  1930. if (bAcl1NoExplicitAces != bAcl2NoExplicitAces || !ScepEqualAdls(hTable1, hTable2) ) {
  1931. *pDifferent = TRUE;
  1932. ScepFreeAdl(hTable1);
  1933. ScepFreeAdl(hTable2);
  1934. return(ERROR_SUCCESS);
  1935. }
  1936. //
  1937. // need to reuse hTables for next blobs
  1938. //
  1939. ScepFreeAdl(hTable1);
  1940. ScepFreeAdl(hTable2);
  1941. //
  1942. // the Adls are equal - so continue with next blobs for Acl1 and Acl2
  1943. //
  1944. }
  1945. Done:
  1946. //
  1947. // free in case goto was taken
  1948. //
  1949. ScepFreeAdl(hTable1);
  1950. ScepFreeAdl(hTable2);
  1951. return(RtlNtStatusToDosError(NtStatus));
  1952. }
  1953. NTSTATUS
  1954. ScepConvertAclBlobToAdl(
  1955. IN SE_OBJECT_TYPE ObjectType,
  1956. IN BOOL IsContainer,
  1957. IN PACL pAcl,
  1958. OUT DWORD *pdwAceNumber,
  1959. OUT BOOL *pbAclNoExplicitAces,
  1960. OUT PSCEP_ADL_NODE *hTable
  1961. )
  1962. /*
  1963. Routine Description:
  1964. This routine builds the Adl for a contiguous block of same type aces.
  1965. Inherited aces (INHERITED_ACE is set) are ignored.
  1966. Arguments:
  1967. IN ObjectType - the type of object, passed on to other functions
  1968. IN IsContainer - whether container or not, passed on to other functions
  1969. IN pAcl - the Acl to be converted to Adl
  1970. OUT pdwAceNumber - running count of the aces considered
  1971. OUT pbAclNoExplicitAces - whether there were explicit aces (if FALSE, there is at leat one explicit ace)
  1972. OUT hTable - the Adl structure for this Acl
  1973. Return Value:
  1974. Win32 error codes
  1975. */
  1976. {
  1977. NTSTATUS NtStatus=STATUS_SUCCESS;
  1978. ACE_HEADER *pAce=NULL;
  1979. if (pAcl == NULL || pdwAceNumber == NULL ||
  1980. hTable == NULL || pbAclNoExplicitAces == NULL) {
  1981. return (STATUS_INVALID_PARAMETER);
  1982. }
  1983. DWORD dwAceNumber = *pdwAceNumber;
  1984. NtStatus = RtlGetAce(pAcl, dwAceNumber, (PVOID *)&pAce);
  1985. if ( !NT_SUCCESS(NtStatus) )
  1986. goto Done;
  1987. //
  1988. // get the first non INHERITED_ACE
  1989. //
  1990. while ( (pAce->AceFlags & INHERITED_ACE) && (++dwAceNumber < pAcl->AceCount) ) {
  1991. NtStatus = RtlGetAce(pAcl, dwAceNumber, (PVOID *)&pAce);
  1992. if ( !NT_SUCCESS(NtStatus) )
  1993. goto Done;
  1994. }
  1995. if ( !(pAce->AceFlags & INHERITED_ACE) ) {
  1996. UCHAR AclAceType;
  1997. *pbAclNoExplicitAces = FALSE;
  1998. AclAceType = pAce->AceType;
  1999. //
  2000. // in a blob of AclAceType
  2001. //
  2002. while ( (pAce->AceType == AclAceType) && (dwAceNumber < pAcl->AceCount) ) {
  2003. if (NO_ERROR != ScepAdlLookupAdd(ObjectType, IsContainer, pAce, hTable)){
  2004. NtStatus = STATUS_NO_MEMORY;
  2005. goto Done;
  2006. }
  2007. //
  2008. // get the next ace in Acl
  2009. //
  2010. if (++dwAceNumber < pAcl->AceCount) {
  2011. //
  2012. // skip INHERITED_ACEs if any except if AceType changes
  2013. //
  2014. do {
  2015. NtStatus = RtlGetAce(pAcl, dwAceNumber, (PVOID *)&pAce);
  2016. if ( !NT_SUCCESS(NtStatus) )
  2017. goto Done;
  2018. //
  2019. // if AceType changes (e.g. from A to D) we quit building the Adl
  2020. // irrespective of whether it is an INHERITED_ACE
  2021. //
  2022. if (pAce->AceType != AclAceType)
  2023. break;
  2024. } while ( (pAce->AceFlags & INHERITED_ACE) && (++dwAceNumber < pAcl->AceCount) );
  2025. }
  2026. }
  2027. }
  2028. Done:
  2029. //
  2030. // update the running count of aces for this Acl
  2031. //
  2032. *pdwAceNumber = dwAceNumber;
  2033. return(NtStatus);
  2034. }
  2035. BOOL
  2036. ScepEqualAdls(
  2037. IN PSCEP_ADL_NODE *hTable1,
  2038. IN PSCEP_ADL_NODE *hTable2
  2039. )
  2040. /*
  2041. Routine Description:
  2042. This routine compares rwo Adls - if the Adls are equal, the hTables will be laid out in the same
  2043. fashion since hashing function is the same. Two Adls are equal iff they match all of the below
  2044. (a) SID, GIUD1, GIUD2
  2045. (b) AceType
  2046. (c) All the masks
  2047. Arguments:
  2048. IN hTable1 - the first Adl hash table
  2049. IN hTable2 - the secomd Adl hash table
  2050. Return Value:
  2051. BOOL - true if equal
  2052. */
  2053. {
  2054. PSCEP_ADL_NODE pNode1 = NULL;
  2055. PSCEP_ADL_NODE pNode2 = NULL;
  2056. //
  2057. // the Adls should be the same if superimposed over each other since they use the same hash etc.
  2058. //
  2059. for (DWORD numBucket = 0; numBucket < SCEP_ADL_HTABLE_SIZE; numBucket++) {
  2060. //
  2061. // walk each bucket, marching pointers in pairs
  2062. //
  2063. pNode1 = hTable1[numBucket];
  2064. pNode2 = hTable2[numBucket];
  2065. while (pNode1 && pNode2) {
  2066. if ( pNode1->AceType != pNode2->AceType ||
  2067. pNode1->dwEffectiveMask != pNode2->dwEffectiveMask ||
  2068. pNode1->dw_CI_IO_Mask != pNode2->dw_CI_IO_Mask ||
  2069. pNode1->dw_OI_IO_Mask != pNode2->dw_OI_IO_Mask ||
  2070. pNode1->dw_NP_CI_IO_Mask != pNode2->dw_NP_CI_IO_Mask ||
  2071. !ScepEqualSid(pNode1->pSid, pNode2->pSid) ||
  2072. !ScepEqualGuid(pNode1->pGuidObjectType, pNode2->pGuidObjectType) ||
  2073. !ScepEqualGuid(pNode1->pGuidInheritedObjectType, pNode2->pGuidInheritedObjectType) ) {
  2074. return FALSE;
  2075. }
  2076. pNode1 = pNode1->Next;
  2077. pNode2 = pNode2->Next;
  2078. }
  2079. if (pNode1 == NULL && pNode2 != NULL ||
  2080. pNode1 != NULL && pNode2 == NULL) {
  2081. return FALSE;
  2082. }
  2083. }
  2084. return(TRUE);
  2085. }
  2086. DWORD
  2087. ScepAdlLookupAdd(
  2088. IN SE_OBJECT_TYPE ObjectType,
  2089. IN BOOL IsContainer,
  2090. IN ACE_HEADER *pAce,
  2091. OUT PSCEP_ADL_NODE *hTable
  2092. )
  2093. /*
  2094. Routine Description:
  2095. This routine adds and initializes a new entry in the hTable for pAce->Sid or merges the
  2096. existing access masks if pAce->Sid already exists
  2097. Arguments:
  2098. IN ObjectType - the type of object, passed on to other functions
  2099. IN IsContainer - whether container or not, passed on to other functions
  2100. IN pAce - the ace to be parsed into the Adl hTable
  2101. OUT hTable - the hTable for this Adl
  2102. Return Value:
  2103. Dos error codes
  2104. */
  2105. {
  2106. DWORD rc = NO_ERROR;
  2107. PISID pSid = NULL;
  2108. PSCEP_ADL_NODE pNode = NULL;
  2109. if (pAce == NULL || hTable == NULL)
  2110. return ERROR_INVALID_PARAMETER;
  2111. switch ( pAce->AceType ) {
  2112. case ACCESS_ALLOWED_ACE_TYPE:
  2113. case ACCESS_DENIED_ACE_TYPE:
  2114. case SYSTEM_AUDIT_ACE_TYPE:
  2115. case SYSTEM_ALARM_ACE_TYPE:
  2116. pSid = (PISID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
  2117. break;
  2118. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2119. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2120. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2121. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  2122. pSid = (PISID)ScepObjectAceObjectType(pAce);
  2123. break;
  2124. default:
  2125. // should not get in here taken care of just after switch
  2126. ;
  2127. }
  2128. if (pSid == NULL)
  2129. return(ERROR_INVALID_PARAMETER);
  2130. pNode = ScepAdlLookup(pAce, hTable);
  2131. //
  2132. // hashed by last subauthority of SID - will need to change this if too many collisions in hTable
  2133. // once mapped to a bucket, for exact match, have to match the triple <SID,GUID1,GUID2>
  2134. //
  2135. if (pNode == NULL)
  2136. //
  2137. // seeing this triple <SID, GUID1, GUID2> for the first time
  2138. //
  2139. rc = ScepAddToAdlList( ObjectType,
  2140. IsContainer,
  2141. pAce,
  2142. &hTable[(pSid->SubAuthority[pSid->SubAuthorityCount - 1] % SCEP_ADL_HTABLE_SIZE)]
  2143. );
  2144. else
  2145. //
  2146. // already exists so simply merge the masks
  2147. //
  2148. ScepAdlMergeMasks(ObjectType,
  2149. IsContainer,
  2150. pAce,
  2151. pNode
  2152. );
  2153. return rc;
  2154. }
  2155. PSCEP_ADL_NODE
  2156. ScepAdlLookup(
  2157. IN ACE_HEADER *pAce,
  2158. IN PSCEP_ADL_NODE *hTable
  2159. )
  2160. /*
  2161. Routine Description:
  2162. This routine searches searches the Adl hTable for the converted pAce's entry and returns
  2163. a pointer to it if present, else returns NULL
  2164. Arguments:
  2165. IN pAce - the Ace to convert to <SID,GUID1,GUID2> and search for
  2166. IN hTable - the Adl in which pAce might exist
  2167. Return Value:
  2168. The node corresponding to pAce if it found, else NULL
  2169. */
  2170. {
  2171. PSCEP_ADL_NODE pNode;
  2172. PISID pSid = NULL;
  2173. GUID *pGuidObjectType = NULL;
  2174. GUID *pGuidInheritedObjectType = NULL;
  2175. switch ( pAce->AceType ) {
  2176. case ACCESS_ALLOWED_ACE_TYPE:
  2177. case ACCESS_DENIED_ACE_TYPE:
  2178. case SYSTEM_AUDIT_ACE_TYPE:
  2179. case SYSTEM_ALARM_ACE_TYPE:
  2180. pSid = (PISID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
  2181. break;
  2182. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2183. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2184. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2185. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  2186. pSid = (PISID)ScepObjectAceObjectType(pAce);
  2187. pGuidObjectType = ScepObjectAceObjectType(pAce);
  2188. pGuidInheritedObjectType = ScepObjectAceInheritedObjectType(pAce);
  2189. break;
  2190. default:
  2191. // should not get in here since filtered out by caller ScepAdlLookupAdd()
  2192. // in any case we do a check right after thsi switch
  2193. ;
  2194. }
  2195. //
  2196. // there might be something better we can do to handle this case
  2197. //
  2198. if (pSid == NULL)
  2199. return NULL;
  2200. for (pNode = hTable[(pSid->SubAuthority[pSid->SubAuthorityCount - 1] % SCEP_ADL_HTABLE_SIZE)];
  2201. pNode != NULL; pNode = pNode->Next){
  2202. if ( ScepEqualSid(pNode->pSid, pSid) &&
  2203. ScepEqualGuid(pNode->pGuidObjectType, pGuidObjectType) &&
  2204. ScepEqualGuid(pNode->pGuidInheritedObjectType, pGuidInheritedObjectType) ) {
  2205. return pNode;
  2206. }
  2207. }
  2208. return NULL;
  2209. }
  2210. DWORD
  2211. ScepAddToAdlList(
  2212. IN SE_OBJECT_TYPE ObjectType,
  2213. IN BOOL IsContainer,
  2214. IN ACE_HEADER *pAce,
  2215. OUT PSCEP_ADL_NODE *pAdlList
  2216. )
  2217. /*
  2218. Routine Description:
  2219. This routine adds an ace to the head of the bucket into which pAce->Sid hashes (pAdlList)
  2220. Arguments:
  2221. IN ObjectType - the type of object, passed on to other functions
  2222. IN IsContainer - whether container or not, passed on to other functions
  2223. IN pAce - the Ace to convert and add
  2224. OUT pAdlList - head of the bucket into which pAce->Sid hashes into
  2225. Return Value:
  2226. Dos error code
  2227. */
  2228. {
  2229. PSCEP_ADL_NODE pNode=NULL;
  2230. //
  2231. // check arguments
  2232. //
  2233. if ( pAdlList == NULL || pAce == NULL )
  2234. return(ERROR_INVALID_PARAMETER);
  2235. //
  2236. // allocate a new node
  2237. //
  2238. pNode = (PSCEP_ADL_NODE)ScepAlloc( (UINT)0, sizeof(SCEP_ADL_NODE));
  2239. if ( pNode == NULL )
  2240. return(ERROR_NOT_ENOUGH_MEMORY);
  2241. pNode->pSid = NULL;
  2242. pNode->pGuidObjectType = NULL;
  2243. pNode->pGuidInheritedObjectType = NULL;
  2244. pNode->AceType = pAce->AceType;
  2245. pNode->Next = NULL;
  2246. //
  2247. // initialize the node with fields from pAce
  2248. //
  2249. switch ( pAce->AceType ) {
  2250. case ACCESS_ALLOWED_ACE_TYPE:
  2251. case ACCESS_DENIED_ACE_TYPE:
  2252. case SYSTEM_AUDIT_ACE_TYPE:
  2253. case SYSTEM_ALARM_ACE_TYPE:
  2254. pNode->pSid = (PISID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
  2255. break;
  2256. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2257. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2258. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2259. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  2260. pNode->pSid = (PISID)ScepObjectAceObjectType(pAce);
  2261. pNode->pGuidObjectType = ScepObjectAceObjectType(pAce);
  2262. pNode->pGuidInheritedObjectType = ScepObjectAceInheritedObjectType(pAce);
  2263. break;
  2264. default:
  2265. // should not get in here since filtered out by caller ScepAdlLookupAdd()
  2266. ScepFree(pNode);
  2267. return(ERROR_INVALID_PARAMETER);
  2268. ;
  2269. }
  2270. //
  2271. // initialize all masks for this node
  2272. //
  2273. pNode->dwEffectiveMask = 0;
  2274. pNode->dw_CI_IO_Mask = 0;
  2275. pNode->dw_OI_IO_Mask = 0;
  2276. pNode->dw_NP_CI_IO_Mask = 0;
  2277. ScepAdlMergeMasks(ObjectType,
  2278. IsContainer,
  2279. pAce,
  2280. pNode
  2281. );
  2282. //
  2283. // add the node to the front of the list and link its next to the old list
  2284. //
  2285. pNode->Next = *pAdlList;
  2286. *pAdlList = pNode;
  2287. return(NO_ERROR);
  2288. }
  2289. VOID
  2290. ScepAdlMergeMasks(
  2291. IN SE_OBJECT_TYPE ObjectType,
  2292. IN BOOL IsContainer,
  2293. IN ACE_HEADER *pAce,
  2294. IN PSCEP_ADL_NODE pNode
  2295. )
  2296. /*
  2297. Routine Description:
  2298. The actual routine that merges the masks from pAce onto pNode
  2299. Arguments:
  2300. IN ObjectType - the type of object, passed on to other functions
  2301. IN IsContainer - whether container or not, passed on to other functions
  2302. IN pAce - the Ace to extract flags and OR with (source)
  2303. IN pNode - the Adl node to update masks (target)
  2304. Return Value:
  2305. Nothing
  2306. */
  2307. {
  2308. DWORD dwMask = 0;
  2309. switch ( pAce->AceType ) {
  2310. case ACCESS_ALLOWED_ACE_TYPE:
  2311. case ACCESS_DENIED_ACE_TYPE:
  2312. case SYSTEM_AUDIT_ACE_TYPE:
  2313. case SYSTEM_ALARM_ACE_TYPE:
  2314. dwMask = ((PACCESS_ALLOWED_ACE)pAce)->Mask;
  2315. break;
  2316. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2317. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2318. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2319. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  2320. dwMask = ((PACCESS_ALLOWED_OBJECT_ACE)pAce)->Mask;
  2321. break;
  2322. default:
  2323. // should not get in here since filtered out by all callers (3 deep)
  2324. ;
  2325. }
  2326. //
  2327. // if generic bits present, get the object specific masks
  2328. //
  2329. if ( dwMask & (GENERIC_READ |
  2330. GENERIC_WRITE |
  2331. GENERIC_EXECUTE |
  2332. GENERIC_ALL)) {
  2333. switch ( ObjectType ) {
  2334. case SE_DS_OBJECT:
  2335. RtlMapGenericMask (
  2336. &dwMask,
  2337. &DsGenMap
  2338. );
  2339. break;
  2340. case SE_SERVICE:
  2341. RtlMapGenericMask (
  2342. &dwMask,
  2343. &SvcGenMap
  2344. );
  2345. break;
  2346. case SE_REGISTRY_KEY:
  2347. RtlMapGenericMask (
  2348. &dwMask,
  2349. &KeyGenericMapping
  2350. );
  2351. break;
  2352. case SE_FILE_OBJECT:
  2353. RtlMapGenericMask (
  2354. &dwMask,
  2355. &FileGenericMapping
  2356. );
  2357. break;
  2358. default:
  2359. // if this happens, dwMask is not mapped to object specific bits
  2360. ;
  2361. }
  2362. }
  2363. //
  2364. // effective mask is updated for non-IO aces only
  2365. //
  2366. if ( !(pAce->AceFlags & INHERIT_ONLY_ACE) ) {
  2367. pNode->dwEffectiveMask |= dwMask;
  2368. }
  2369. //
  2370. // for non-containers, we don't care about the CI, OI masks (to simulate config)
  2371. //
  2372. if (IsContainer) {
  2373. //
  2374. // if NP, we only care about CI
  2375. // else we care about CI, OI
  2376. //
  2377. if (pAce->AceFlags & NO_PROPAGATE_INHERIT_ACE) {
  2378. if (pAce->AceFlags & CONTAINER_INHERIT_ACE) {
  2379. pNode->dw_NP_CI_IO_Mask |= dwMask;
  2380. }
  2381. } else {
  2382. if ( (pAce->AceFlags & CONTAINER_INHERIT_ACE) )
  2383. pNode->dw_CI_IO_Mask |= dwMask;
  2384. if ( !(ObjectType & SE_REGISTRY_KEY) && (pAce->AceFlags & OBJECT_INHERIT_ACE) )
  2385. pNode->dw_OI_IO_Mask |= dwMask;
  2386. }
  2387. }
  2388. return;
  2389. }
  2390. VOID
  2391. ScepFreeAdl(
  2392. IN PSCEP_ADL_NODE *hTable
  2393. )
  2394. /*
  2395. Routine Description:
  2396. This routine frees the linked lists of nodes (buckets) and reset's them for further use
  2397. Arguments:
  2398. IN hTable - the hash-table to free
  2399. Return Value:
  2400. Nothing
  2401. */
  2402. {
  2403. if (hTable) {
  2404. for (UINT bucketNum = 0; bucketNum < SCEP_ADL_HTABLE_SIZE; bucketNum++ ) {
  2405. ScepFreeAdlList(hTable[bucketNum]);
  2406. hTable[bucketNum] = NULL;
  2407. }
  2408. }
  2409. }
  2410. SCESTATUS
  2411. ScepFreeAdlList(
  2412. IN PSCEP_ADL_NODE pAdlList
  2413. )
  2414. /*
  2415. Routine Description:
  2416. This is the actual routine that frees the linked lists of nodes (buckets)
  2417. Arguments:
  2418. IN pAdlList - head of bucket to free
  2419. Return Value:
  2420. Nothing
  2421. */
  2422. {
  2423. PSCEP_ADL_NODE pCurAdlNode;
  2424. PSCEP_ADL_NODE pTempNode;
  2425. SCESTATUS rc=SCESTATUS_SUCCESS;
  2426. if ( pAdlList == NULL )
  2427. return(rc);
  2428. pCurAdlNode = pAdlList;
  2429. while ( pCurAdlNode != NULL ) {
  2430. pTempNode = pCurAdlNode;
  2431. pCurAdlNode = pCurAdlNode->Next;
  2432. __try {
  2433. ScepFree( pTempNode );
  2434. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2435. rc = SCESTATUS_INVALID_PARAMETER;
  2436. }
  2437. }
  2438. return(rc);
  2439. }
  2440. NTSTATUS
  2441. ScepAnyExplicitAcl(
  2442. IN PACL Acl,
  2443. IN DWORD Processed,
  2444. OUT PBOOL pExist
  2445. )
  2446. /*
  2447. Routine Description:
  2448. This routine detects if there is any explicit ace in the Acl. The DWORD
  2449. Processed is a bit mask of the aces already checked.
  2450. Arguments:
  2451. Acl - The Acl
  2452. Processed - The bit mask for the processed aces (so it won't be checked again)
  2453. pExist - The output flag to indicate if there is any explicit ace
  2454. Return Value:
  2455. NTSTATUS
  2456. */
  2457. {
  2458. NTSTATUS NtStatus=STATUS_SUCCESS;
  2459. DWORD j;
  2460. ACE_HEADER *pAce=NULL;
  2461. //
  2462. // check output argument
  2463. //
  2464. if ( pExist == NULL )
  2465. return(STATUS_INVALID_PARAMETER);
  2466. *pExist = FALSE;
  2467. if ( Acl == NULL )
  2468. return(NtStatus);
  2469. for ( j=0; j<Acl->AceCount; j++ ) {
  2470. if ( Processed & (1 << j) )
  2471. continue;
  2472. NtStatus = RtlGetAce(Acl, j, (PVOID *)&pAce);
  2473. if ( !NT_SUCCESS(NtStatus) )
  2474. return(NtStatus);
  2475. if ( pAce == NULL )
  2476. continue;
  2477. if ( !(pAce->AceFlags & INHERITED_ACE) ) {
  2478. //
  2479. // find a explicit Ace in Acl
  2480. //
  2481. *pExist = TRUE;
  2482. break;
  2483. }
  2484. }
  2485. return(NtStatus);
  2486. }
  2487. BOOL
  2488. ScepEqualAce(
  2489. IN SE_OBJECT_TYPE ObjectType,
  2490. IN BOOL IsContainer,
  2491. IN ACE_HEADER *pAce1,
  2492. IN ACE_HEADER *pAce2
  2493. )
  2494. // compare two aces for exact match. The return BOOL value indicates the
  2495. // match or not
  2496. {
  2497. PSID pSid1=NULL, pSid2=NULL;
  2498. ACCESS_MASK Access1=0, Access2=0;
  2499. if ( pAce1 == NULL && pAce2 == NULL )
  2500. return(TRUE);
  2501. if ( pAce1 == NULL || pAce2 == NULL )
  2502. return(FALSE);
  2503. //
  2504. // compare ace access type
  2505. //
  2506. if ( pAce1->AceType != pAce2->AceType )
  2507. return(FALSE);
  2508. if ( IsContainer ) {
  2509. //
  2510. // compare ace inheritance flag
  2511. //
  2512. if ( pAce1->AceFlags != pAce2->AceFlags )
  2513. return(FALSE);
  2514. }
  2515. switch ( pAce1->AceType ) {
  2516. case ACCESS_ALLOWED_ACE_TYPE:
  2517. case ACCESS_DENIED_ACE_TYPE:
  2518. case SYSTEM_AUDIT_ACE_TYPE:
  2519. case SYSTEM_ALARM_ACE_TYPE:
  2520. pSid1 = (PSID)&((PACCESS_ALLOWED_ACE)pAce1)->SidStart;
  2521. pSid2 = (PSID)&((PACCESS_ALLOWED_ACE)pAce2)->SidStart;
  2522. Access1 = ((PACCESS_ALLOWED_ACE)pAce1)->Mask;
  2523. Access2 = ((PACCESS_ALLOWED_ACE)pAce2)->Mask;
  2524. break;
  2525. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  2526. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  2527. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  2528. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  2529. if ( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags !=
  2530. ((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->Flags ) {
  2531. return(FALSE);
  2532. }
  2533. if ( ( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags & ACE_OBJECT_TYPE_PRESENT ) ||
  2534. ( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT ) ) {
  2535. //
  2536. // at least one GUID exists
  2537. //
  2538. if ( !ScepEqualGuid( (GUID *)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->ObjectType,
  2539. (GUID *)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->ObjectType ) ) {
  2540. return(FALSE);
  2541. }
  2542. if ( ( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags & ACE_OBJECT_TYPE_PRESENT ) &&
  2543. ( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT ) ) {
  2544. //
  2545. // the second GUID also exists
  2546. //
  2547. if ( !ScepEqualGuid( (GUID *)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->InheritedObjectType,
  2548. (GUID *)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->InheritedObjectType) ) {
  2549. return(FALSE);
  2550. }
  2551. pSid1 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->SidStart;
  2552. pSid2 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->SidStart;
  2553. } else {
  2554. pSid1 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->InheritedObjectType;
  2555. pSid2 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->InheritedObjectType;
  2556. }
  2557. } else {
  2558. //
  2559. // none of the GUID exists
  2560. //
  2561. pSid1 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->ObjectType;
  2562. pSid2 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->ObjectType;
  2563. }
  2564. Access1 = ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Mask;
  2565. Access2 = ((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->Mask;
  2566. break;
  2567. default:
  2568. return(FALSE); // not recognized Ace type
  2569. }
  2570. if ( pSid1 == NULL || pSid2 == NULL )
  2571. //
  2572. // no Sid, ignore the Ace
  2573. //
  2574. return(FALSE);
  2575. //
  2576. // compare the sids
  2577. //
  2578. if ( !EqualSid(pSid1, pSid2) )
  2579. return(FALSE);
  2580. //
  2581. // access mask
  2582. //
  2583. // Translation is already done when calculating security descriptor
  2584. // for file objects and registry objects
  2585. //
  2586. if ( Access1 != Access2 ) {
  2587. switch ( ObjectType ) {
  2588. case SE_DS_OBJECT:
  2589. //
  2590. // convert access mask of Access2 (from ProfileSD) for ds objects
  2591. //
  2592. RtlMapGenericMask (
  2593. &Access2,
  2594. &DsGenMap
  2595. );
  2596. if ( Access1 != Access2)
  2597. return(FALSE);
  2598. break;
  2599. case SE_SERVICE:
  2600. RtlMapGenericMask (
  2601. &Access2,
  2602. &SvcGenMap
  2603. );
  2604. if ( Access1 != Access2)
  2605. return(FALSE);
  2606. break;
  2607. case SE_REGISTRY_KEY:
  2608. RtlMapGenericMask (
  2609. &Access2,
  2610. &KeyGenericMapping
  2611. );
  2612. if ( Access1 != Access2)
  2613. return(FALSE);
  2614. break;
  2615. case SE_FILE_OBJECT:
  2616. RtlMapGenericMask (
  2617. &Access2,
  2618. &FileGenericMapping
  2619. );
  2620. if ( Access1 != Access2)
  2621. return(FALSE);
  2622. break;
  2623. default:
  2624. return(FALSE);
  2625. }
  2626. }
  2627. return(TRUE);
  2628. }
  2629. SCESTATUS
  2630. ScepAddToNameStatusList(
  2631. OUT PSCE_NAME_STATUS_LIST *pNameList,
  2632. IN PWSTR Name,
  2633. IN ULONG Len,
  2634. IN DWORD Status
  2635. )
  2636. /* ++
  2637. Routine Description:
  2638. This routine adds a name (wchar) and a status to the name list.
  2639. Arguments:
  2640. pNameList - The name list to add to.
  2641. Name - The name to add
  2642. Len - number of wchars to add
  2643. Status - The value for the status field
  2644. Return value:
  2645. Win32 error code
  2646. -- */
  2647. {
  2648. PSCE_NAME_STATUS_LIST pList=NULL;
  2649. ULONG Length=Len;
  2650. if ( pNameList == NULL )
  2651. return(ERROR_INVALID_PARAMETER);
  2652. if ( Name != NULL && Name[0] && Len == 0 )
  2653. Length = wcslen(Name) + 1;
  2654. // if ( Length <= 1)
  2655. // return(NO_ERROR);
  2656. pList = (PSCE_NAME_STATUS_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_STATUS_LIST));
  2657. if ( pList == NULL )
  2658. return(ERROR_NOT_ENOUGH_MEMORY);
  2659. if ( Name != NULL && Name[0] ) {
  2660. pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Length+1)*sizeof(TCHAR));
  2661. if ( pList->Name == NULL ) {
  2662. ScepFree(pList);
  2663. return(ERROR_NOT_ENOUGH_MEMORY);
  2664. }
  2665. wcsncpy(pList->Name, Name, Length);
  2666. } else
  2667. pList->Name = NULL;
  2668. pList->Status = Status;
  2669. pList->Next = *pNameList;
  2670. *pNameList = pList;
  2671. return(NO_ERROR);
  2672. }
  2673. DWORD
  2674. ScepAddToObjectList(
  2675. OUT PSCE_OBJECT_LIST *pNameList,
  2676. IN PWSTR Name,
  2677. IN ULONG Len,
  2678. IN BOOL IsContainer,
  2679. IN BYTE Status,
  2680. IN DWORD Count,
  2681. IN BYTE byFlags
  2682. )
  2683. /* ++
  2684. Routine Description:
  2685. This routine adds a name (wchar), a status, and a count to the name list.
  2686. Arguments:
  2687. pNameList - The name list to add to.
  2688. Name - The name to add
  2689. Len - number of wchars to add
  2690. Status - The value for the status field
  2691. Count - The value for the count field
  2692. byFlags - SCE_CHECK_DUP do not add for duplicates
  2693. SCE_INCREASE_COUNT increase count by 1
  2694. Return value:
  2695. Win32 error code
  2696. -- */
  2697. {
  2698. PSCE_OBJECT_LIST pList=NULL;
  2699. ULONG Length=Len;
  2700. if ( pNameList == NULL )
  2701. return(ERROR_INVALID_PARAMETER);
  2702. if ( Name == NULL )
  2703. return(NO_ERROR);
  2704. if ( Len == 0 )
  2705. Length = wcslen(Name);
  2706. if ( Length < 1)
  2707. return(NO_ERROR);
  2708. if ( byFlags & SCE_CHECK_DUP ) {
  2709. for ( pList = *pNameList; pList != NULL; pList = pList->Next ) {
  2710. if ( _wcsnicmp( pList->Name, Name, Length) == 0 &&
  2711. pList->Name[Length] == L'\0') {
  2712. break;
  2713. }
  2714. }
  2715. if ( NULL != pList ) {
  2716. //
  2717. // already exist. return
  2718. //
  2719. if ( (byFlags & SCE_INCREASE_COUNT) && 0 == pList->Count ) {
  2720. pList->Count++;
  2721. }
  2722. return(NO_ERROR);
  2723. }
  2724. }
  2725. pList = (PSCE_OBJECT_LIST)ScepAlloc( (UINT)0, sizeof(SCE_OBJECT_LIST));
  2726. if ( pList == NULL )
  2727. return(ERROR_NOT_ENOUGH_MEMORY);
  2728. pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Length+1)*sizeof(TCHAR));
  2729. if ( pList->Name == NULL ) {
  2730. ScepFree(pList);
  2731. return(ERROR_NOT_ENOUGH_MEMORY);
  2732. }
  2733. wcsncpy(pList->Name, Name, Length);
  2734. pList->Status = Status;
  2735. pList->IsContainer = IsContainer;
  2736. if ( byFlags & SCE_INCREASE_COUNT && 0 == Count )
  2737. pList->Count = 1;
  2738. else
  2739. pList->Count = Count;
  2740. pList->Next = *pNameList;
  2741. *pNameList = pList;
  2742. return(NO_ERROR);
  2743. }
  2744. DWORD
  2745. ScepGetNTDirectory(
  2746. IN PWSTR *ppDirectory,
  2747. IN PDWORD pDirSize,
  2748. IN DWORD Flag
  2749. )
  2750. /*
  2751. Routine Description:
  2752. This routine retrieves windows directory location or system directory
  2753. location based on the input Flag. The output directory location must
  2754. be freed by LocalFree after use.
  2755. Arguments:
  2756. ppDirectory - the output buffer holding the directory location.
  2757. pDirSize - The returned number of wchars of the output buffer
  2758. Flag - Flag to indicate directory
  2759. 1 = Windows directory
  2760. 2 = System directory
  2761. Return Value:
  2762. Win32 error codes
  2763. */
  2764. {
  2765. DWORD dSize=0;
  2766. DWORD rc=0;
  2767. PWSTR pSubKey=NULL;
  2768. PWSTR pValName=NULL;
  2769. if ( ppDirectory == NULL )
  2770. return(ERROR_INVALID_PARAMETER);
  2771. switch ( Flag ) {
  2772. case SCE_FLAG_WINDOWS_DIR: // windows directory
  2773. dSize=GetSystemWindowsDirectory( *ppDirectory, 0 );
  2774. break;
  2775. case SCE_FLAG_SYSTEM_DIR: // system directory
  2776. dSize=GetSystemDirectory( *ppDirectory, 0 );
  2777. break;
  2778. case SCE_FLAG_DSDIT_DIR: // DS working directory
  2779. case SCE_FLAG_DSLOG_DIR: // DS database log files directory
  2780. case SCE_FLAG_SYSVOL_DIR: // Sysvol directory
  2781. case SCE_FLAG_BOOT_DRIVE: // boot drive
  2782. // get the appropriate registry path and value name
  2783. if ( SCE_FLAG_SYSVOL_DIR == Flag ) {
  2784. pSubKey = szNetlogonKey;
  2785. pValName = szSysvolValue;
  2786. } else if ( SCE_FLAG_BOOT_DRIVE == Flag ) {
  2787. pSubKey = szSetupKey;
  2788. pValName = szBootDriveValue;
  2789. } else {
  2790. pSubKey = szNTDSKey;
  2791. if ( SCE_FLAG_DSDIT_DIR == Flag ) {
  2792. pValName = szDSDITValue;
  2793. } else {
  2794. pValName = szDSLOGValue;
  2795. }
  2796. }
  2797. //
  2798. // query the value.
  2799. // if this function is executed on a non DC, this function will fail
  2800. // possibly with ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND
  2801. // which in turn fails the translation.
  2802. //
  2803. DWORD RegType;
  2804. rc = ScepRegQueryValue(
  2805. HKEY_LOCAL_MACHINE,
  2806. pSubKey,
  2807. pValName,
  2808. (PVOID *)ppDirectory,
  2809. &RegType
  2810. );
  2811. if ( rc == ERROR_SUCCESS && RegType != REG_SZ ) {
  2812. rc = ERROR_FILE_NOT_FOUND;
  2813. }
  2814. if ( rc == ERROR_SUCCESS && *ppDirectory ) {
  2815. if ( Flag == SCE_FLAG_SYSVOL_DIR ) {
  2816. //
  2817. // for sysvol path, it will look like d:\winnt\sysvol\sysvol.
  2818. // we need to remove the last sysvol from this variable
  2819. //
  2820. PWSTR pTemp = ScepWcstrr(*ppDirectory, L"\\sysvol");
  2821. if ( pTemp && (pTemp != *ppDirectory) &&
  2822. _wcsnicmp(pTemp-7, L"\\sysvol",7 ) == 0 ) {
  2823. // terminate the string here
  2824. *pTemp = L'\0';
  2825. }
  2826. }
  2827. dSize = wcslen(*ppDirectory);
  2828. }
  2829. break;
  2830. default: // invalid
  2831. return(ERROR_INVALID_PARAMETER);
  2832. break;
  2833. }
  2834. if ( dSize > 0 &&
  2835. ( SCE_FLAG_WINDOWS_DIR == Flag ||
  2836. SCE_FLAG_SYSTEM_DIR == Flag ) ) {
  2837. *ppDirectory = (PWSTR)ScepAlloc(LMEM_ZEROINIT, (dSize+1)*sizeof(WCHAR));
  2838. if ( *ppDirectory == NULL )
  2839. return(ERROR_NOT_ENOUGH_MEMORY);
  2840. switch ( Flag ) {
  2841. case SCE_FLAG_WINDOWS_DIR: // windows directory
  2842. dSize=GetSystemWindowsDirectory( *ppDirectory, dSize );
  2843. break;
  2844. case SCE_FLAG_SYSTEM_DIR: // system directory
  2845. dSize=GetSystemDirectory( *ppDirectory, dSize );
  2846. break;
  2847. }
  2848. }
  2849. *pDirSize = dSize;
  2850. if ( dSize == 0 ) {
  2851. if ( *ppDirectory != NULL )
  2852. ScepFree(*ppDirectory);
  2853. *ppDirectory = NULL;
  2854. if ( rc ) {
  2855. return(rc);
  2856. } else if ( NO_ERROR == GetLastError() )
  2857. return(ERROR_INVALID_DATA);
  2858. else
  2859. return(GetLastError());
  2860. } else
  2861. _wcsupr(*ppDirectory);
  2862. return(NO_ERROR);
  2863. }
  2864. DWORD
  2865. ScepGetCurrentUserProfilePath(
  2866. OUT PWSTR *ProfilePath
  2867. )
  2868. {
  2869. HANDLE Token;
  2870. NTSTATUS NtStatus;
  2871. DWORD rc;
  2872. PVOID Info=NULL;
  2873. DWORD ReturnLen, NewLen;
  2874. UNICODE_STRING ProfileName;
  2875. if (!OpenThreadToken( GetCurrentThread(),
  2876. TOKEN_QUERY,
  2877. FALSE,
  2878. &Token)) {
  2879. if (!OpenProcessToken( GetCurrentProcess(),
  2880. TOKEN_QUERY,
  2881. &Token))
  2882. return(GetLastError());
  2883. }
  2884. //
  2885. // get token user
  2886. //
  2887. NtStatus = NtQueryInformationToken (
  2888. Token,
  2889. TokenUser,
  2890. NULL,
  2891. 0,
  2892. &ReturnLen
  2893. );
  2894. if ( NtStatus == STATUS_BUFFER_TOO_SMALL ) {
  2895. //
  2896. // allocate buffer
  2897. //
  2898. Info = ScepAlloc(0, ReturnLen+1);
  2899. if ( Info != NULL ) {
  2900. NtStatus = NtQueryInformationToken (
  2901. Token,
  2902. TokenUser,
  2903. Info,
  2904. ReturnLen,
  2905. &NewLen
  2906. );
  2907. if ( NT_SUCCESS(NtStatus) ) {
  2908. ProfileName.Length = 0;
  2909. rc = ScepGetUsersProfileName(
  2910. ProfileName,
  2911. ((PTOKEN_USER)Info)->User.Sid,
  2912. FALSE,
  2913. ProfilePath
  2914. );
  2915. } else
  2916. rc = RtlNtStatusToDosError(NtStatus);
  2917. ScepFree(Info);
  2918. } else {
  2919. rc = ERROR_NOT_ENOUGH_MEMORY;
  2920. }
  2921. } else
  2922. rc = RtlNtStatusToDosError(NtStatus);
  2923. CloseHandle(Token);
  2924. return(rc);
  2925. }
  2926. DWORD
  2927. ScepGetUsersProfileName(
  2928. IN UNICODE_STRING AssignedProfile,
  2929. IN PSID AccountSid,
  2930. IN BOOL bDefault,
  2931. OUT PWSTR *UserProfilePath
  2932. )
  2933. {
  2934. DWORD rc=ERROR_INVALID_PARAMETER;
  2935. SID_IDENTIFIER_AUTHORITY *a;
  2936. DWORD Len, i, j;
  2937. WCHAR KeyName[356];
  2938. PWSTR StrValue=NULL;
  2939. PWSTR SystemRoot=NULL;
  2940. DWORD DirSize=0;
  2941. if ( AssignedProfile.Length > 0 && AssignedProfile.Buffer != NULL ) {
  2942. //
  2943. // use the assigned profile
  2944. //
  2945. *UserProfilePath = (PWSTR)ScepAlloc( LMEM_ZEROINIT, AssignedProfile.Length+2);
  2946. if ( *UserProfilePath == NULL )
  2947. return(ERROR_NOT_ENOUGH_MEMORY);
  2948. wcsncpy(*UserProfilePath, AssignedProfile.Buffer, AssignedProfile.Length/2);
  2949. return(NO_ERROR);
  2950. }
  2951. if ( AccountSid != NULL ) {
  2952. //
  2953. // look for this user's ProfileImageName in ProfileList in registry
  2954. // if this user logged on the system once
  2955. //
  2956. memset(KeyName, '\0', 356*sizeof(WCHAR));
  2957. swprintf(KeyName, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
  2958. Len = wcslen(KeyName);
  2959. a = RtlIdentifierAuthoritySid(AccountSid);
  2960. swprintf(KeyName+Len, L"S-1-");
  2961. for ( i=0; i<6; i++ ) {
  2962. if ( a -> Value[i] > 0 )
  2963. break;
  2964. }
  2965. for ( j=i; j<6; j++) {
  2966. swprintf(KeyName+Len, L"%s%d", KeyName+Len, a -> Value[j]);
  2967. }
  2968. for (i = 0; i < *RtlSubAuthorityCountSid(AccountSid); i++) {
  2969. swprintf(KeyName+Len, L"%s-%d", KeyName+Len, *RtlSubAuthoritySid(AccountSid, i));
  2970. }
  2971. //
  2972. // now the registry full path name for the user profile is built into KeyName
  2973. //
  2974. rc = ScepRegQueryValue(
  2975. HKEY_LOCAL_MACHINE,
  2976. KeyName,
  2977. L"ProfileImagePath",
  2978. (PVOID *)&StrValue,
  2979. &Len
  2980. );
  2981. if ( rc == NO_ERROR && StrValue != NULL ) {
  2982. //
  2983. // translatethe name to expand environment variables
  2984. //
  2985. DirSize = ExpandEnvironmentStrings(StrValue, NULL, 0);
  2986. if ( DirSize ) {
  2987. *UserProfilePath = (PWSTR)ScepAlloc(0, (DirSize+1)*sizeof(WCHAR));
  2988. if ( *UserProfilePath ) {
  2989. if ( !ExpandEnvironmentStrings(StrValue, *UserProfilePath, DirSize) ) {
  2990. // error occurs
  2991. rc = GetLastError();
  2992. ScepFree(*UserProfilePath);
  2993. *UserProfilePath = NULL;
  2994. }
  2995. } else {
  2996. rc = ERROR_NOT_ENOUGH_MEMORY;
  2997. }
  2998. } else {
  2999. rc = GetLastError();
  3000. }
  3001. ScepFree(StrValue);
  3002. return(rc);
  3003. }
  3004. }
  3005. if ( StrValue ) {
  3006. ScepFree(StrValue);
  3007. StrValue = NULL;
  3008. }
  3009. //
  3010. // if user is not assigned a profile explicitly, and there is no
  3011. // profile created (under ProfileList), take the default profile
  3012. //
  3013. if ( bDefault ) {
  3014. rc = NO_ERROR;
  3015. #if _WINNT_WIN32>=0x0500
  3016. //
  3017. // Take the default user profile
  3018. //
  3019. DirSize = 355;
  3020. GetDefaultUserProfileDirectory(KeyName, &DirSize);
  3021. if ( DirSize ) {
  3022. //
  3023. // length of "\\NTUSER.DAT" is 11
  3024. //
  3025. *UserProfilePath = (PWSTR)ScepAlloc( 0, (DirSize+12)*sizeof(WCHAR));
  3026. if ( *UserProfilePath ) {
  3027. if ( DirSize > 355 ) {
  3028. //
  3029. // KeyName buffer is not enough, call again
  3030. //
  3031. Len = DirSize;
  3032. if ( !GetDefaultUserProfileDirectory(*UserProfilePath, &Len) ) {
  3033. //
  3034. // error occurs, free the buffer
  3035. //
  3036. rc = GetLastError();
  3037. ScepFree(*UserProfilePath);
  3038. *UserProfilePath = NULL;
  3039. }
  3040. } else {
  3041. //
  3042. // KeyName contains the directory
  3043. //
  3044. wcscpy(*UserProfilePath, KeyName);
  3045. (*UserProfilePath)[DirSize] = L'\0';
  3046. }
  3047. //
  3048. // append NTUSER.DAT to the end
  3049. //
  3050. if ( NO_ERROR == rc ) {
  3051. wcscat(*UserProfilePath, L"\\NTUSER.DAT");
  3052. }
  3053. } else {
  3054. rc = ERROR_NOT_ENOUGH_MEMORY;
  3055. }
  3056. } else {
  3057. rc = GetLastError();
  3058. }
  3059. #else
  3060. //
  3061. // for NT4: Take the default user profile
  3062. //
  3063. rc = ScepGetNTDirectory( &SystemRoot, &DirSize, SCE_FLAG_WINDOWS_DIR );
  3064. if ( NO_ERROR == rc ) {
  3065. //
  3066. // string to append to the %SystemRoot%
  3067. //
  3068. wcscpy(KeyName, L"\\Profiles\\Default User\\NTUSER.DAT");
  3069. Len = wcslen(KeyName);
  3070. *UserProfilePath = (PWSTR)ScepAlloc( 0, (DirSize+Len+1)*sizeof(WCHAR));
  3071. if ( *UserProfilePath == NULL ) {
  3072. rc = ERROR_NOT_ENOUGH_MEMORY;
  3073. } else {
  3074. swprintf( *UserProfilePath, L"%s%s", SystemRoot, KeyName);
  3075. }
  3076. }
  3077. if ( SystemRoot != NULL )
  3078. ScepFree( SystemRoot);
  3079. #endif
  3080. }
  3081. return(rc);
  3082. }
  3083. DWORD
  3084. SceAdjustPrivilege(
  3085. IN ULONG Priv,
  3086. IN BOOL Enable,
  3087. IN HANDLE TokenToAdjust
  3088. )
  3089. /* ++
  3090. Routine Description:
  3091. This routine enable/disable the specified privilege (Priv) to the current process.
  3092. Arguments:
  3093. Priv - The privilege to adjust
  3094. Enable - TRUE = enable, FALSE = disable
  3095. TokenToAdjust - The Token of current thread/process. It is optional
  3096. Return value:
  3097. Win32 error code
  3098. -- */
  3099. {
  3100. HANDLE Token;
  3101. NTSTATUS Status;
  3102. TOKEN_PRIVILEGES Privs;
  3103. if ( TokenToAdjust == NULL ) {
  3104. if (!OpenThreadToken( GetCurrentThread(),
  3105. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  3106. FALSE,
  3107. &Token)) {
  3108. if (!OpenProcessToken( GetCurrentProcess(),
  3109. TOKEN_ADJUST_PRIVILEGES,
  3110. &Token))
  3111. return(GetLastError());
  3112. }
  3113. } else
  3114. Token = TokenToAdjust;
  3115. //
  3116. // Token_privileges contains enough room for one privilege.
  3117. //
  3118. Privs.PrivilegeCount = 1;
  3119. Privs.Privileges[0].Luid = RtlConvertUlongToLuid(Priv); // RtlConvertLongToLuid(Priv);
  3120. Privs.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
  3121. Status = NtAdjustPrivilegesToken(Token,
  3122. FALSE,
  3123. &Privs,
  3124. 0,
  3125. NULL,
  3126. 0);
  3127. if (TokenToAdjust == NULL )
  3128. CloseHandle(Token);
  3129. return (RtlNtStatusToDosError( Status ) );
  3130. }
  3131. DWORD
  3132. ScepGetEnvStringSize(
  3133. IN LPVOID peb
  3134. )
  3135. {
  3136. if ( !peb ) {
  3137. return 0;
  3138. }
  3139. DWORD dwSize=0;
  3140. LPTSTR pTemp=(LPTSTR)peb;
  3141. DWORD Len;
  3142. while ( *pTemp ) {
  3143. Len = wcslen(pTemp);
  3144. dwSize += Len+1;
  3145. pTemp += Len+1;
  3146. };
  3147. dwSize++;
  3148. return dwSize*sizeof(WCHAR);
  3149. }
  3150. //*************************************************************
  3151. // Routines to handle events
  3152. //*************************************************************
  3153. BOOL InitializeEvents (
  3154. IN LPTSTR EventSourceName
  3155. )
  3156. /*++
  3157. Routine Description:
  3158. Opens the event log
  3159. Arguments:
  3160. EventSourceName - the event's source name (usually dll or exe's name)
  3161. Return:
  3162. TRUE if successful
  3163. FALSE if an error occurs
  3164. --*/
  3165. {
  3166. if ( hEventLog ) {
  3167. //
  3168. // already initialized
  3169. //
  3170. return TRUE;
  3171. }
  3172. //
  3173. // Open the event source
  3174. //
  3175. if ( EventSourceName ) {
  3176. wcscpy(EventSource, EventSourceName);
  3177. hEventLog = RegisterEventSource(NULL, EventSource);
  3178. if (hEventLog) {
  3179. return TRUE;
  3180. }
  3181. } else {
  3182. EventSource[0] = L'\0';
  3183. }
  3184. return FALSE;
  3185. }
  3186. int
  3187. LogEvent(
  3188. IN HINSTANCE hInstance,
  3189. IN DWORD LogLevel,
  3190. IN DWORD dwEventID,
  3191. IN UINT idMsg,
  3192. ...)
  3193. /*++
  3194. Routine Description:
  3195. Logs a verbose event to the event log
  3196. Arguments:
  3197. hInstance - the resource dll instance
  3198. bLogLevel - the severity level of the log
  3199. STATUS_SEVERITY_INFORMATIONAL
  3200. STATUS_SEVERITY_WARNING
  3201. STATUS_SEVERITY_ERROR
  3202. dwEventID - the event ID (defined in uevents.mc)
  3203. idMsg - Message id
  3204. Return:
  3205. TRUE if successful
  3206. FALSE if an error occurs
  3207. --*/
  3208. {
  3209. TCHAR szMsg[MAX_PATH];
  3210. TCHAR szErrorMsg[2*MAX_PATH+40];
  3211. LPTSTR aStrings[2];
  3212. WORD wType;
  3213. va_list marker;
  3214. //
  3215. // Check for the event log being open.
  3216. //
  3217. if (!hEventLog ) {
  3218. if ( EventSource[0] == L'\0' ||
  3219. !InitializeEvents(EventSource)) {
  3220. return -1;
  3221. }
  3222. }
  3223. //
  3224. // Load the message
  3225. //
  3226. if (idMsg != 0) {
  3227. if (!LoadString (hInstance, idMsg, szMsg, MAX_PATH)) {
  3228. return -1;
  3229. }
  3230. } else {
  3231. lstrcpy (szMsg, TEXT("%s"));
  3232. }
  3233. //
  3234. // Plug in the arguments
  3235. //
  3236. szErrorMsg[0] = L'\0';
  3237. va_start(marker, idMsg);
  3238. __try {
  3239. wvsprintf(szErrorMsg, szMsg, marker);
  3240. } __except(EXCEPTION_EXECUTE_HANDLER) {
  3241. }
  3242. va_end(marker);
  3243. //
  3244. // Report the event to the eventlog
  3245. //
  3246. aStrings[0] = szErrorMsg;
  3247. switch (LogLevel) {
  3248. case STATUS_SEVERITY_WARNING:
  3249. wType = EVENTLOG_WARNING_TYPE;
  3250. break;
  3251. case STATUS_SEVERITY_ERROR:
  3252. wType = EVENTLOG_ERROR_TYPE;
  3253. break;
  3254. default:
  3255. wType = EVENTLOG_INFORMATION_TYPE;
  3256. break;
  3257. }
  3258. if (!ReportEvent(hEventLog,
  3259. wType,
  3260. 0,
  3261. dwEventID,
  3262. NULL,
  3263. 1,
  3264. 0,
  3265. (LPCTSTR *)aStrings,
  3266. NULL) ) {
  3267. return 1;
  3268. }
  3269. return 0;
  3270. }
  3271. int
  3272. LogEventAndReport(
  3273. IN HINSTANCE hInstance,
  3274. IN LPTSTR LogFileName,
  3275. IN DWORD LogLevel,
  3276. IN DWORD dwEventID,
  3277. IN UINT idMsg,
  3278. ...)
  3279. /*++
  3280. Routine Description:
  3281. Logs a verbose event to the event log and logs
  3282. Arguments:
  3283. hInstance - the resource dll handle
  3284. LofFileName - the log file also reported to
  3285. bLogLevel - the severity level of the log
  3286. STATUS_SEVERITY_INFORMATIONAL
  3287. STATUS_SEVERITY_WARNING
  3288. STATUS_SEVERITY_ERROR
  3289. dwEventID - the event ID (defined in uevents.mc)
  3290. idMsg - Message id
  3291. Return:
  3292. TRUE if successful
  3293. FALSE if an error occurs
  3294. --*/
  3295. {
  3296. TCHAR szMsg[MAX_PATH];
  3297. TCHAR szErrorMsg[2*MAX_PATH+40];
  3298. LPTSTR aStrings[2];
  3299. WORD wType;
  3300. va_list marker;
  3301. //
  3302. // Load the message
  3303. //
  3304. if (idMsg != 0) {
  3305. if (!LoadString (hInstance, idMsg, szMsg, MAX_PATH)) {
  3306. return -1;
  3307. }
  3308. } else {
  3309. lstrcpy (szMsg, TEXT("%s"));
  3310. }
  3311. HANDLE hFile = INVALID_HANDLE_VALUE;
  3312. if ( LogFileName ) {
  3313. hFile = CreateFile(LogFileName,
  3314. GENERIC_WRITE,
  3315. FILE_SHARE_READ,
  3316. NULL,
  3317. OPEN_ALWAYS,
  3318. FILE_ATTRIBUTE_NORMAL,
  3319. NULL);
  3320. if (hFile != INVALID_HANDLE_VALUE) {
  3321. DWORD dwBytesWritten;
  3322. SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
  3323. BYTE TmpBuf[3];
  3324. TmpBuf[0] = 0xFF;
  3325. TmpBuf[1] = 0xFE;
  3326. TmpBuf[2] = 0;
  3327. WriteFile (hFile, (LPCVOID)TmpBuf, 2,
  3328. &dwBytesWritten,
  3329. NULL);
  3330. SetFilePointer (hFile, 0, NULL, FILE_END);
  3331. }
  3332. }
  3333. //
  3334. // Check for the event log being open.
  3335. //
  3336. if (!hEventLog && dwEventID > 0 ) {
  3337. if ( EventSource[0] == L'\0' ||
  3338. !InitializeEvents(EventSource)) {
  3339. if ( INVALID_HANDLE_VALUE == hFile ) {
  3340. return -1; // no event log and the log file can't be opened
  3341. }
  3342. }
  3343. }
  3344. //
  3345. // Plug in the arguments
  3346. //
  3347. szErrorMsg[0] = L'\0';
  3348. va_start(marker, idMsg);
  3349. __try {
  3350. wvsprintf(szErrorMsg, szMsg, marker);
  3351. } __except(EXCEPTION_EXECUTE_HANDLER) {
  3352. }
  3353. va_end(marker);
  3354. //
  3355. // Report the event to the eventlog
  3356. //
  3357. int iRet = 0;
  3358. if ( hEventLog && dwEventID > 0 ) {
  3359. aStrings[0] = szErrorMsg;
  3360. switch (LogLevel) {
  3361. case STATUS_SEVERITY_WARNING:
  3362. wType = EVENTLOG_WARNING_TYPE;
  3363. break;
  3364. case STATUS_SEVERITY_ERROR:
  3365. wType = EVENTLOG_ERROR_TYPE;
  3366. break;
  3367. default:
  3368. wType = EVENTLOG_INFORMATION_TYPE;
  3369. break;
  3370. }
  3371. if (!ReportEvent(hEventLog,
  3372. wType,
  3373. 0,
  3374. dwEventID,
  3375. NULL,
  3376. 1,
  3377. 0,
  3378. (LPCTSTR *)aStrings,
  3379. NULL) ) {
  3380. iRet = 1;
  3381. }
  3382. }
  3383. if ( INVALID_HANDLE_VALUE != hFile ) {
  3384. //
  3385. // Log to the log file
  3386. //
  3387. ScepWriteSingleUnicodeLog(hFile, FALSE, L"\r\n");
  3388. ScepWriteSingleUnicodeLog(hFile, TRUE, szErrorMsg );
  3389. CloseHandle(hFile);
  3390. }
  3391. return iRet;
  3392. }
  3393. BOOL
  3394. ShutdownEvents (void)
  3395. /*++
  3396. Routine Description:
  3397. Stops the event log
  3398. Arguments:
  3399. None
  3400. Return:
  3401. TRUE if successful
  3402. FALSE if an error occurs
  3403. --*/
  3404. {
  3405. BOOL bRetVal = TRUE;
  3406. HANDLE hTemp = hEventLog;
  3407. hEventLog = NULL;
  3408. if (hTemp) {
  3409. bRetVal = DeregisterEventSource(hTemp);
  3410. }
  3411. EventSource[0] = L'\0';
  3412. return bRetVal;
  3413. }
  3414. SCESTATUS
  3415. ScepConvertToSDDLFormat(
  3416. IN LPTSTR pszValue,
  3417. IN DWORD Len
  3418. )
  3419. {
  3420. if ( pszValue == NULL || Len == 0 ) {
  3421. return SCESTATUS_INVALID_PARAMETER;
  3422. }
  3423. ScepConvertSDDLSid(pszValue, L"DA", L"BA");
  3424. ScepConvertSDDLSid(pszValue, L"RP", L"RE");
  3425. ScepConvertSDDLAceType(pszValue, L"SA", L"AU");
  3426. ScepConvertSDDLAceType(pszValue, L"SM", L"AL");
  3427. ScepConvertSDDLAceType(pszValue, L"OM", L"OL");
  3428. return SCESTATUS_SUCCESS;
  3429. }
  3430. BOOL
  3431. ScepConvertSDDLSid(
  3432. LPTSTR pszValue,
  3433. PCWSTR szSearchFor, // only two letters are allowed
  3434. PCWSTR szReplace
  3435. )
  3436. {
  3437. PWSTR pTemp = pszValue;
  3438. DWORD i;
  3439. while ( pTemp && *pTemp != L'\0' ) {
  3440. pTemp = wcsstr(pTemp, szSearchFor);
  3441. if ( pTemp != NULL ) {
  3442. //
  3443. // find the first non space char
  3444. // must be : or ;
  3445. //
  3446. i=1;
  3447. while ( pTemp-i > pszValue && *(pTemp-i) == L' ' ) {
  3448. i++;
  3449. }
  3450. if ( pTemp-i > pszValue &&
  3451. ( *(pTemp-i) == L':' || *(pTemp-i) == L';') ) {
  3452. //
  3453. // find the next non space char
  3454. // must be ), O:, G:, D:, S:
  3455. //
  3456. i=2;
  3457. while ( *(pTemp+i) == L' ' ) {
  3458. i++;
  3459. }
  3460. if ( *(pTemp+i) == L')' ||
  3461. ( *(pTemp+i) != L'\0' && *(pTemp+i+1) == L':')) {
  3462. //
  3463. // find one, replace it
  3464. //
  3465. *pTemp = szReplace[0];
  3466. *(pTemp+1) = szReplace[1];
  3467. }
  3468. pTemp += 2;
  3469. } else {
  3470. //
  3471. // this is not a one to convert
  3472. //
  3473. pTemp += 2;
  3474. }
  3475. }
  3476. }
  3477. return TRUE;
  3478. }
  3479. BOOL
  3480. ScepConvertSDDLAceType(
  3481. LPTSTR pszValue,
  3482. PCWSTR szSearchFor, // only two letters are allowed
  3483. PCWSTR szReplace
  3484. )
  3485. {
  3486. PWSTR pTemp = pszValue;
  3487. DWORD i;
  3488. while ( pTemp && *pTemp != L'\0' ) {
  3489. pTemp = wcsstr(pTemp, szSearchFor);
  3490. if ( pTemp != NULL ) {
  3491. //
  3492. // find the first non space char
  3493. // must be (
  3494. //
  3495. i=1;
  3496. while ( pTemp-i > pszValue && *(pTemp-i) == L' ' ) {
  3497. i++;
  3498. }
  3499. if ( pTemp-i > pszValue &&
  3500. ( *(pTemp-i) == L'(') ) {
  3501. //
  3502. // find the next non space char
  3503. // must be ;
  3504. //
  3505. i=2;
  3506. while ( *(pTemp+i) == L' ' ) {
  3507. i++;
  3508. }
  3509. if ( *(pTemp+i) == L';' ) {
  3510. //
  3511. // find one, replace it with AU
  3512. //
  3513. *pTemp = szReplace[0];
  3514. *(pTemp+1) = szReplace[1];
  3515. }
  3516. pTemp += 2;
  3517. } else {
  3518. //
  3519. // this is not a one to convert
  3520. //
  3521. pTemp += 2;
  3522. }
  3523. }
  3524. }
  3525. return TRUE;
  3526. }
  3527. BOOL
  3528. SceIsSystemDatabase(
  3529. IN LPCTSTR DatabaseName
  3530. )
  3531. /*
  3532. Routine Description:
  3533. Determine if the given database is the default system database
  3534. Argument:
  3535. DatabaseName - the database name (full path)
  3536. Return Value:
  3537. TRUE - the given database is the system database
  3538. FALSE - the database is not the system database or error occurred
  3539. GetLastError() to get the error.
  3540. */
  3541. {
  3542. if ( DatabaseName == NULL ) {
  3543. SetLastError(ERROR_INVALID_PARAMETER);
  3544. return FALSE;
  3545. }
  3546. DWORD rc;
  3547. PWSTR DefProfile=NULL;
  3548. DWORD RegType;
  3549. /*
  3550. // do not save system database in registry
  3551. // always "hardcoded" to %windir%\security\database
  3552. // query the system database name
  3553. //
  3554. rc = ScepRegQueryValue(
  3555. HKEY_LOCAL_MACHINE,
  3556. SCE_ROOT_PATH,
  3557. L"DefaultProfile",
  3558. (PVOID *)&DefProfile,
  3559. &RegType
  3560. );
  3561. if ( rc != NO_ERROR ) {
  3562. */
  3563. //
  3564. // use the default
  3565. //
  3566. PWSTR SysRoot=NULL;
  3567. RegType = 0;
  3568. rc = ScepGetNTDirectory( &SysRoot, &RegType, SCE_FLAG_WINDOWS_DIR );
  3569. if ( rc == NO_ERROR ) {
  3570. if ( SysRoot != NULL ) {
  3571. //
  3572. // default location is %SystemRoot%\Security\Database\secedit.sdb
  3573. //
  3574. TCHAR TempName[256];
  3575. wcscpy(TempName, L"\\Security\\Database\\secedit.sdb");
  3576. RegType += wcslen(TempName)+1;
  3577. DefProfile = (PWSTR)ScepAlloc( 0, RegType*sizeof(WCHAR));
  3578. if ( DefProfile != NULL ) {
  3579. swprintf(DefProfile, L"%s%s", SysRoot, TempName );
  3580. *(DefProfile+RegType-1) = L'\0';
  3581. } else
  3582. rc = ERROR_NOT_ENOUGH_MEMORY;
  3583. ScepFree(SysRoot);
  3584. } else
  3585. rc = ERROR_INVALID_DATA;
  3586. }
  3587. // }
  3588. BOOL bRet=FALSE;
  3589. if ( (rc == NO_ERROR) && DefProfile ) {
  3590. if ( _wcsicmp(DefProfile, DatabaseName) == 0 ) {
  3591. //
  3592. // this is the system database
  3593. //
  3594. bRet = TRUE;
  3595. }
  3596. }
  3597. ScepFree(DefProfile);
  3598. //
  3599. // set last error and return
  3600. //
  3601. if ( bRet ) {
  3602. SetLastError(ERROR_SUCCESS);
  3603. } else {
  3604. SetLastError(rc);
  3605. }
  3606. return(bRet);
  3607. }
  3608. DWORD
  3609. ScepWriteVariableUnicodeLog(
  3610. IN HANDLE hFile,
  3611. IN BOOL bAddCRLF,
  3612. IN LPTSTR szFormat,
  3613. ...
  3614. )
  3615. {
  3616. if ( INVALID_HANDLE_VALUE == hFile || NULL == hFile ||
  3617. NULL == szFormat ) {
  3618. return(ERROR_INVALID_PARAMETER);
  3619. }
  3620. va_list args;
  3621. LPTSTR lpDebugBuffer;
  3622. DWORD rc=ERROR_NOT_ENOUGH_MEMORY;
  3623. lpDebugBuffer = (LPTSTR) LocalAlloc (LPTR, 2048 * sizeof(TCHAR));
  3624. if (lpDebugBuffer) {
  3625. va_start( args, szFormat );
  3626. _vsnwprintf(lpDebugBuffer, 2048 - 1, szFormat, args);
  3627. va_end( args );
  3628. //
  3629. // always put a CR/LF at the end
  3630. //
  3631. DWORD dwBytesWritten;
  3632. if ( WriteFile (hFile, (LPCVOID) lpDebugBuffer,
  3633. wcslen (lpDebugBuffer) * sizeof(WCHAR),
  3634. &dwBytesWritten,
  3635. NULL) ) {
  3636. if ( bAddCRLF ) {
  3637. WriteFile (hFile, (LPCVOID) c_szCRLF,
  3638. 2 * sizeof(WCHAR),
  3639. &dwBytesWritten,
  3640. NULL);
  3641. }
  3642. rc = ERROR_SUCCESS;
  3643. } else {
  3644. rc = GetLastError();
  3645. }
  3646. LocalFree(lpDebugBuffer);
  3647. }
  3648. return(rc);
  3649. }
  3650. DWORD
  3651. ScepWriteSingleUnicodeLog(
  3652. IN HANDLE hFile,
  3653. IN BOOL bAddCRLF,
  3654. IN LPWSTR szMsg
  3655. )
  3656. {
  3657. if ( INVALID_HANDLE_VALUE == hFile ) {
  3658. return(ERROR_INVALID_PARAMETER);
  3659. }
  3660. DWORD dwBytesWritten;
  3661. if ( WriteFile (hFile, (LPCVOID) szMsg,
  3662. wcslen (szMsg) * sizeof(WCHAR),
  3663. &dwBytesWritten,
  3664. NULL) ) {
  3665. if ( bAddCRLF) {
  3666. // add \r\n to the end of the string
  3667. WriteFile (hFile, (LPCVOID) c_szCRLF,
  3668. 2 * sizeof(WCHAR),
  3669. &dwBytesWritten,
  3670. NULL);
  3671. }
  3672. return(ERROR_SUCCESS);
  3673. } else {
  3674. return(GetLastError());
  3675. }
  3676. }
  3677. //+--------------------------------------------------------------------------
  3678. //
  3679. // Function: ScepWcstrr
  3680. //
  3681. // Synopsis: Returns ptr to rightmost occurence of pSubstring in pString, NULL if none
  3682. //
  3683. // Arguments: pString to look in, pSubstring to look for
  3684. //
  3685. // Returns: Returns ptr to rightmost occurence of pSubstring in pString, NULL if none
  3686. //
  3687. //+--------------------------------------------------------------------------
  3688. WCHAR *
  3689. ScepWcstrr(
  3690. IN PWSTR pString,
  3691. IN const WCHAR *pSubstring
  3692. )
  3693. {
  3694. int i, j, k;
  3695. for (i = wcslen(pString) - wcslen(pSubstring) ; i >= 0; i-- ) {
  3696. for (j = i, k = 0; pSubstring[k] != L'\0' && towlower(pString[j]) == towlower(pSubstring[k]); j++, k++)
  3697. ;
  3698. if ( k > 0 && pSubstring[k] == L'\0')
  3699. return pString + i;
  3700. }
  3701. return NULL;
  3702. }
  3703. DWORD
  3704. ScepExpandEnvironmentVariable(
  3705. IN PWSTR oldFileName,
  3706. IN PCWSTR szEnv,
  3707. IN DWORD nFlag,
  3708. OUT PWSTR *newFileName)
  3709. /*
  3710. Description:
  3711. Expand built-in environment variables known by SCE, including %SystemRoot%,
  3712. %SystemDirectory%, %SystemDrive%, %DSDIT%, %DSLOG%, %SYSVOL%, %BOOTDRIVE%.
  3713. Parameters:
  3714. oldFileName - the file name to expand
  3715. szEnv - the environment variable to search for
  3716. nFlag - the corresponding system env variable flag
  3717. SCE_FLAG_WINDOWS_DIR
  3718. SCE_FLAG_SYSTEM_DIR
  3719. SCE_FLAG_BOOT_DRIVE
  3720. SCE_FLAG_DSDIT_DIR
  3721. SCE_FLAG_DSLOG_DIR
  3722. SCE_FLAG_SYSVOL_DIR
  3723. newFileName - the expanded file name if succeeded
  3724. Return Value:
  3725. ERROR_FILE_NOT_FOUND if the environment varialbe is not found in the input file name
  3726. ERROR_SUCCESS if the env variable is successfully expanded
  3727. Otherwise, error code is returned.
  3728. */
  3729. {
  3730. if ( oldFileName == NULL || szEnv == NULL || newFileName == NULL ) {
  3731. return ERROR_INVALID_PARAMETER;
  3732. }
  3733. PWSTR pTemp = wcsstr( _wcsupr(oldFileName), szEnv);
  3734. LPTSTR NtDir=NULL;
  3735. DWORD newFileSize, dSize=0;
  3736. DWORD rc = ERROR_FILE_NOT_FOUND;
  3737. if ( pTemp != NULL ) {
  3738. //
  3739. // found the environment variable
  3740. //
  3741. rc = ScepGetNTDirectory( &NtDir, &dSize, nFlag );
  3742. if ( NO_ERROR == rc && NtDir ) {
  3743. pTemp += wcslen(szEnv);
  3744. BOOL bSysDrive=FALSE;
  3745. switch ( nFlag ) {
  3746. case SCE_FLAG_WINDOWS_DIR:
  3747. if ( _wcsicmp(szEnv, L"%SYSTEMDRIVE%") == 0 ) {
  3748. dSize = 3;
  3749. bSysDrive = TRUE;
  3750. }
  3751. break;
  3752. case SCE_FLAG_BOOT_DRIVE:
  3753. if ( *pTemp == L'\\' ) pTemp++; // NtDir contains the back slash already
  3754. break;
  3755. }
  3756. newFileSize = dSize + wcslen(pTemp) + 1;
  3757. *newFileName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, newFileSize*sizeof(TCHAR));
  3758. if (*newFileName != NULL) {
  3759. if ( SCE_FLAG_WINDOWS_DIR == nFlag && bSysDrive ) {
  3760. // system drive letter
  3761. **newFileName = NtDir[0];
  3762. if ( pTemp[0] )
  3763. swprintf(*newFileName+1, L":%s", _wcsupr(pTemp));
  3764. else
  3765. swprintf(*newFileName+1, L":\\");
  3766. } else {
  3767. swprintf(*newFileName, L"%s%s", NtDir, _wcsupr(pTemp));
  3768. }
  3769. }
  3770. else
  3771. rc = ERROR_NOT_ENOUGH_MEMORY;
  3772. } else if ( NO_ERROR == rc && !NtDir ) {
  3773. rc = ERROR_NOT_ENOUGH_MEMORY;
  3774. }
  3775. if ( NtDir ) {
  3776. ScepFree(NtDir);
  3777. }
  3778. }
  3779. return(rc);
  3780. }
  3781. DWORD
  3782. ScepEnforcePolicyPropagation()
  3783. {
  3784. DWORD rc;
  3785. HKEY hKey1=NULL;
  3786. HKEY hKey=NULL;
  3787. DWORD RegType;
  3788. DWORD dwInterval=0;
  3789. DWORD DataSize=sizeof(DWORD);
  3790. if(( rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3791. GPT_SCEDLL_NEW_PATH,
  3792. 0,
  3793. KEY_READ | KEY_WRITE,
  3794. &hKey
  3795. )) == ERROR_SUCCESS ) {
  3796. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  3797. SCE_ROOT_PATH,
  3798. 0,
  3799. KEY_READ | KEY_WRITE,
  3800. &hKey1
  3801. );
  3802. }
  3803. if ( ERROR_SUCCESS == rc ) {
  3804. if ( ERROR_SUCCESS != RegQueryValueEx(hKey1,
  3805. TEXT("GPOSavedInterval"),
  3806. 0,
  3807. &RegType,
  3808. (BYTE *)&dwInterval,
  3809. &DataSize
  3810. ) ) {
  3811. //
  3812. // either the value doesn't exist or fail to read it.
  3813. // In either case, it's considered as no backup value
  3814. // Now query the current value and save it
  3815. //
  3816. DataSize = sizeof(DWORD);
  3817. if ( ERROR_SUCCESS != RegQueryValueEx(hKey,
  3818. TEXT("MaxNoGPOListChangesInterval"),
  3819. 0,
  3820. &RegType,
  3821. (BYTE *)&dwInterval,
  3822. &DataSize
  3823. ) ) {
  3824. dwInterval = 960;
  3825. }
  3826. rc = RegSetValueEx( hKey1,
  3827. TEXT("GPOSavedInterval"),
  3828. 0,
  3829. REG_DWORD,
  3830. (BYTE *)&dwInterval,
  3831. sizeof(DWORD)
  3832. );
  3833. } // else if the value already exists, don't need to save it again
  3834. if ( ERROR_SUCCESS == rc ) {
  3835. dwInterval = 1;
  3836. rc = RegSetValueEx( hKey,
  3837. TEXT("MaxNoGPOListChangesInterval"),
  3838. 0,
  3839. REG_DWORD,
  3840. (BYTE *)&dwInterval,
  3841. sizeof(DWORD)
  3842. );
  3843. }
  3844. }
  3845. //
  3846. // close the keys
  3847. //
  3848. if ( hKey1 )
  3849. RegCloseKey( hKey1 );
  3850. if ( hKey )
  3851. RegCloseKey( hKey );
  3852. return(rc);
  3853. }
  3854. DWORD
  3855. ScepGetTimeStampString(
  3856. IN OUT PWSTR pvBuffer
  3857. )
  3858. /*
  3859. Retrun long format of date/time string based on the locale.
  3860. */
  3861. {
  3862. if ( pvBuffer == NULL ) {
  3863. return(ERROR_INVALID_PARAMETER);
  3864. }
  3865. DWORD rc;
  3866. LARGE_INTEGER CurrentTime;
  3867. LARGE_INTEGER SysTime;
  3868. TIME_FIELDS TimeFields;
  3869. NTSTATUS NtStatus;
  3870. FILETIME ft;
  3871. SYSTEMTIME st;
  3872. NtStatus = NtQuerySystemTime(&SysTime);
  3873. rc = RtlNtStatusToDosError(NtStatus);
  3874. RtlSystemTimeToLocalTime (&SysTime,&CurrentTime);
  3875. if ( NT_SUCCESS(NtStatus) &&
  3876. (CurrentTime.LowPart != 0 || CurrentTime.HighPart != 0) ) {
  3877. rc = ERROR_SUCCESS;
  3878. ft.dwLowDateTime = CurrentTime.LowPart;
  3879. ft.dwHighDateTime = CurrentTime.HighPart;
  3880. if ( !FileTimeToSystemTime(&ft, &st) ) {
  3881. rc = GetLastError();
  3882. } else {
  3883. //
  3884. // format date/time into the right locale format
  3885. //
  3886. TCHAR szDate[32];
  3887. TCHAR szTime[32];
  3888. //
  3889. // GetDateFormat is the NLS routine that formats a time in a
  3890. // locale-sensitive fashion.
  3891. //
  3892. if (0 == GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE,
  3893. &st, NULL,szDate, 32)) {
  3894. rc = GetLastError();
  3895. } else {
  3896. //
  3897. // GetTimeFormat is the NLS routine that formats a time in a
  3898. // locale-sensitive fashion.
  3899. //
  3900. if (0 == GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &st, NULL, szTime, 32)) {
  3901. rc = GetLastError();
  3902. } else {
  3903. //
  3904. // Concatenate date and time
  3905. //
  3906. wcscpy(pvBuffer, szDate);
  3907. wcscat(pvBuffer, L" ");
  3908. wcscat(pvBuffer, szTime);
  3909. }
  3910. }
  3911. }
  3912. //
  3913. // if can't get the system time in right locale,
  3914. // print it in the current (default) format
  3915. //
  3916. if ( rc != NO_ERROR ) {
  3917. memset(&TimeFields, 0, sizeof(TIME_FIELDS));
  3918. RtlTimeToTimeFields (
  3919. &CurrentTime,
  3920. &TimeFields
  3921. );
  3922. if ( TimeFields.Month > 0 && TimeFields.Month <= 12 &&
  3923. TimeFields.Day > 0 && TimeFields.Day <= 31 &&
  3924. TimeFields.Year > 1600 ) {
  3925. swprintf(pvBuffer, L"%02d/%02d/%04d %02d:%02d:%02d\0",
  3926. TimeFields.Month, TimeFields.Day, TimeFields.Year,
  3927. TimeFields.Hour, TimeFields.Minute, TimeFields.Second);
  3928. } else {
  3929. swprintf(pvBuffer, L"%08x08x\0", CurrentTime.HighPart, CurrentTime.LowPart);
  3930. }
  3931. }
  3932. rc = ERROR_SUCCESS;
  3933. }
  3934. return(rc);
  3935. }
  3936. DWORD
  3937. ScepAppendCreateMultiSzRegValue(
  3938. IN HKEY hKeyRoot,
  3939. IN PWSTR pszSubKey,
  3940. IN PWSTR pszValueName,
  3941. IN PWSTR pszValueValue
  3942. )
  3943. /*++
  3944. Routine Description:
  3945. This routine will append(if existing)/create(if not existing) w.r.t. MULTI_SZ values
  3946. Arguments:
  3947. hKeyRoot - root such as HKEY_LOCAL_MACHINE
  3948. pszSubKey - subkey such as "Software\\Microsoft\\Windows NT\\CurrentVersion\\SeCEdit"
  3949. pszValueName - value name of the key to be changed
  3950. pszValueValue - value of the value name to be changed
  3951. Return:
  3952. error code (DWORD)
  3953. --*/
  3954. {
  3955. DWORD rc = ERROR_SUCCESS;
  3956. DWORD dwSize = 0;
  3957. HKEY hKey = NULL;
  3958. DWORD dwNewKey = NULL;
  3959. DWORD dwRegType = 0;
  3960. if (hKeyRoot == NULL || pszSubKey == NULL || pszValueName == NULL || pszValueValue == NULL) {
  3961. return ERROR_INVALID_PARAMETER;
  3962. }
  3963. if(( rc = RegOpenKeyEx(hKeyRoot,
  3964. pszSubKey,
  3965. 0,
  3966. KEY_SET_VALUE | KEY_QUERY_VALUE ,
  3967. &hKey
  3968. )) != ERROR_SUCCESS ) {
  3969. rc = RegCreateKeyEx(
  3970. hKeyRoot,
  3971. pszSubKey,
  3972. 0,
  3973. NULL,
  3974. REG_OPTION_NON_VOLATILE,
  3975. KEY_WRITE,
  3976. NULL,
  3977. &hKey,
  3978. &dwNewKey
  3979. );
  3980. }
  3981. if ( ERROR_SUCCESS == rc ) {
  3982. //
  3983. // need to read the MULTI_SZ, append to it and set then new MULTI_SZ value
  3984. //
  3985. rc = RegQueryValueEx(hKey,
  3986. pszValueName,
  3987. 0,
  3988. &dwRegType,
  3989. NULL,
  3990. &dwSize
  3991. );
  3992. if ( ERROR_SUCCESS == rc || ERROR_FILE_NOT_FOUND == rc ) {
  3993. //
  3994. // dwSize is always size in bytes
  3995. //
  3996. DWORD dwBytesToAdd = 0;
  3997. //
  3998. // if dwUnicodeSize == 0, then MULTI_SZ value was non-existent before
  3999. //
  4000. DWORD dwUnicodeSize = (dwSize >= 2 ? dwSize/2 - 1 : 0);
  4001. dwBytesToAdd = 2 * (wcslen(pszValueValue) + 2);
  4002. PWSTR pszValue = (PWSTR)ScepAlloc( LMEM_ZEROINIT, dwSize + dwBytesToAdd) ;
  4003. if ( pszValue != NULL ) {
  4004. rc = RegQueryValueEx(hKey,
  4005. pszValueName,
  4006. 0,
  4007. &dwRegType,
  4008. (BYTE *)pszValue,
  4009. &dwSize
  4010. );
  4011. //
  4012. // append pszValueValue to the end of the MULTI_SZ taking care of duplicates
  4013. // i.e. abc\0def\0ghi\0\0 to something like
  4014. // abc\0def\0ghi\0jkl\0\0
  4015. //
  4016. if ( ScepMultiSzWcsstr(pszValue, pszValueValue) == NULL ) {
  4017. memcpy(pszValue + dwUnicodeSize, pszValueValue, dwBytesToAdd);
  4018. memset(pszValue + dwUnicodeSize + (dwBytesToAdd/2 - 2), '\0', 4);
  4019. if ( ERROR_SUCCESS == rc || ERROR_FILE_NOT_FOUND == rc) {
  4020. rc = RegSetValueEx( hKey,
  4021. pszValueName,
  4022. 0,
  4023. REG_MULTI_SZ,
  4024. (BYTE *)pszValue,
  4025. (dwUnicodeSize == 0 ? dwSize + dwBytesToAdd : dwSize + dwBytesToAdd - 2)
  4026. );
  4027. }
  4028. }
  4029. ScepFree(pszValue);
  4030. }
  4031. else {
  4032. rc = ERROR_NOT_ENOUGH_MEMORY;
  4033. }
  4034. }
  4035. }
  4036. if( hKey )
  4037. RegCloseKey( hKey );
  4038. return rc;
  4039. }
  4040. PWSTR
  4041. ScepMultiSzWcsstr(
  4042. PWSTR pszStringToSearchIn,
  4043. PWSTR pszStringToSearchFor
  4044. )
  4045. /*++
  4046. Routine Description:
  4047. MULTI_SZ version of wcsstr
  4048. Arguments:
  4049. pszStringToSearchIn - \0\0 terminated string to search in (MULTI_SZ)
  4050. pszStringToSearchFor - \0 terminated string to search for (regular unicode string)
  4051. Return:
  4052. pointer to first occurence of pszStringToSearchFor in pszStringToSearchIn
  4053. --*/
  4054. {
  4055. PWSTR pszCurrString = NULL;
  4056. if (pszStringToSearchIn == NULL || pszStringToSearchFor == NULL) {
  4057. return NULL;
  4058. }
  4059. if (pszStringToSearchFor[0] == L'\0' ||
  4060. (pszStringToSearchIn[0] == L'\0' && pszStringToSearchIn[1] == L'\0') ) {
  4061. return NULL;
  4062. }
  4063. pszCurrString = pszStringToSearchIn;
  4064. __try {
  4065. while ( !(pszCurrString[0] == L'\0' && pszCurrString[1] == L'\0') ) {
  4066. if ( NULL != wcsstr(pszCurrString, pszStringToSearchFor) ) {
  4067. return pszCurrString;
  4068. }
  4069. //
  4070. // so, if C:\0E:\0\0, advance pszCurrString to the first \0 at the end ie. C:\0E:\0\0
  4071. // ^ ^
  4072. pszCurrString += wcslen(pszCurrString) ;
  4073. if (pszCurrString[0] == L'\0' && pszCurrString[1] == L'\0') {
  4074. return NULL;
  4075. }
  4076. //
  4077. // if it stopped at C:\0E:\0\0, advance pszCurrString C:\0E:\0\0
  4078. // ^ ^
  4079. pszCurrString += 1;
  4080. }
  4081. } __except(EXCEPTION_EXECUTE_HANDLER) {
  4082. }
  4083. return NULL;
  4084. }
  4085. DWORD
  4086. ScepEscapeString(
  4087. IN const PWSTR pszSource,
  4088. IN const DWORD dwSourceChars,
  4089. IN const WCHAR wcEscapee,
  4090. IN const WCHAR wcEscaper,
  4091. IN OUT PWSTR pszTarget
  4092. )
  4093. /* ++
  4094. Routine Description:
  4095. Escapes escapee with escaper i.e.
  4096. escapee -> escaper escapee escaper
  4097. e.g. a,\0b\0c\0\0 -> a","\0b\0c\0\0
  4098. Arguments:
  4099. pszSource - The source string
  4100. dwSourceChars - The number of chars in pszSource
  4101. wcEscapee - The escapee
  4102. wcEscaper - The escaper
  4103. pszTarget - The destination string
  4104. Return value:
  4105. Number of characters copied to the target
  4106. -- */
  4107. {
  4108. DWORD dwTargetChars = 0;
  4109. for (DWORD dwIndex=0; dwIndex < dwSourceChars; dwIndex++) {
  4110. if ( pszSource[dwIndex] == wcEscapee ){
  4111. pszTarget[0] = wcEscaper;
  4112. pszTarget[1] = wcEscapee;
  4113. pszTarget[2] = wcEscaper;
  4114. pszTarget += 3;
  4115. dwTargetChars +=3;
  4116. }
  4117. else {
  4118. pszTarget[0] = pszSource[dwIndex];
  4119. pszTarget++;
  4120. ++dwTargetChars ;
  4121. }
  4122. }
  4123. return dwTargetChars;
  4124. }