Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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