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.

2665 lines
68 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. sceutil.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 "sceutil.h"
  14. #include "infp.h"
  15. #include <sddl.h>
  16. #include "commonrc.h"
  17. #include "client\CGenericLogger.h"
  18. extern HINSTANCE MyModuleHandle;
  19. BOOL
  20. ScepLookupWellKnownName(
  21. IN PWSTR Name,
  22. IN OPTIONAL LSA_HANDLE LsaPolicy,
  23. OPTIONAL OUT PWSTR *ppwszSid)
  24. {
  25. NTSTATUS NtStatus = STATUS_SUCCESS;
  26. PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
  27. PLSA_TRANSLATED_SID2 Sids=NULL;
  28. BOOL fFound = FALSE;
  29. BOOL fCloseHandle = FALSE;
  30. PSID pBuiltinSid = NULL;
  31. if ( Name == NULL ||
  32. Name[0] == L'\0' ||
  33. Name[0] == L'*')
  34. {
  35. return FALSE;
  36. }
  37. if ( NULL == LsaPolicy )
  38. {
  39. NtStatus = ScepOpenLsaPolicy(
  40. POLICY_LOOKUP_NAMES,
  41. &LsaPolicy,
  42. TRUE
  43. );
  44. fCloseHandle = TRUE;
  45. }
  46. if( NT_SUCCESS(NtStatus))
  47. {
  48. NtStatus = ScepLsaLookupNames2(
  49. LsaPolicy,
  50. LSA_LOOKUP_ISOLATED_AS_LOCAL,
  51. Name,
  52. &RefDomains,
  53. &Sids);
  54. }
  55. //
  56. // if it's well known constants (such as everyone, Network Service) or
  57. // it's a builtin account (such as Administrators),
  58. // always store them in SID string format
  59. //
  60. if ( NT_SUCCESS(NtStatus) &&
  61. ERROR_SUCCESS != ScepGetBuiltinSid(0, &pBuiltinSid))
  62. {
  63. NtStatus = STATUS_NO_MEMORY;
  64. }
  65. if ( NT_SUCCESS(NtStatus) &&
  66. Sids &&
  67. ( Sids[0].Use == SidTypeWellKnownGroup ||
  68. Sids[0].Use == SidTypeAlias &&
  69. Sids[0].DomainIndex >=0 &&
  70. RtlEqualSid(
  71. RefDomains->Domains[Sids[0].DomainIndex].Sid,
  72. pBuiltinSid)) &&
  73. Sids[0].Sid != NULL)
  74. {
  75. fFound = TRUE;
  76. if(ppwszSid)
  77. {
  78. NtStatus = ScepConvertSidToPrefixStringSid(
  79. Sids[0].Sid, ppwszSid);
  80. }
  81. }
  82. if ( Sids )
  83. {
  84. LsaFreeMemory(Sids);
  85. }
  86. if ( RefDomains )
  87. {
  88. LsaFreeMemory(RefDomains);
  89. }
  90. if( fCloseHandle && NULL != LsaPolicy )
  91. {
  92. LsaClose(LsaPolicy);
  93. }
  94. if ( pBuiltinSid )
  95. {
  96. ScepFree(pBuiltinSid);
  97. }
  98. return ( NT_SUCCESS(NtStatus) ? fFound : FALSE );
  99. }
  100. INT
  101. ScepLookupPrivByName(
  102. IN PCWSTR Right
  103. )
  104. /* ++
  105. Routine Description:
  106. This routine looksup a user right in SCE_Rights table and returns the
  107. index component in SCE_Rights. The index component indicates the bit
  108. number for the user right.
  109. Arguments:
  110. Right - The user right to look up
  111. Return value:
  112. The index component in SCE_Rights table if a match is found,
  113. -1 for no match
  114. -- */
  115. {
  116. DWORD i;
  117. for (i=0; i<cPrivCnt; i++) {
  118. if ( _wcsicmp(Right, SCE_Privileges[i].Name) == 0 )
  119. return (i);
  120. }
  121. return(-1);
  122. }
  123. SCESTATUS
  124. WINAPI
  125. SceLookupPrivRightName(
  126. IN INT Priv,
  127. OUT PWSTR Name,
  128. OUT PINT NameLen
  129. )
  130. {
  131. INT Len;
  132. if ( Name != NULL && NameLen == NULL )
  133. return(SCESTATUS_INVALID_PARAMETER);
  134. if ( Priv >= 0 && Priv < cPrivCnt ) {
  135. Len = wcslen(SCE_Privileges[Priv].Name);
  136. if ( Name != NULL ) {
  137. if ( *NameLen >= Len )
  138. wcscpy(Name, SCE_Privileges[Priv].Name);
  139. else {
  140. *NameLen = Len;
  141. return(SCESTATUS_BUFFER_TOO_SMALL);
  142. }
  143. }
  144. if ( NameLen != NULL)
  145. *NameLen = Len;
  146. return(SCESTATUS_SUCCESS);
  147. } else
  148. return SCESTATUS_RECORD_NOT_FOUND;
  149. }
  150. SCESTATUS
  151. SceInfpOpenProfile(
  152. IN PCWSTR ProfileName,
  153. IN HINF *hInf
  154. )
  155. /*
  156. Routine Description:
  157. This routine opens a profile and returns a handle. This handle may be used
  158. when read information out of the profile using Setup APIs. The handle must
  159. be closed by calling SCECloseInfProfile.
  160. Arguments:
  161. ProfileName - The profile to open
  162. hInf - the address for inf handle
  163. Return value:
  164. SCESTATUS
  165. */
  166. {
  167. if ( ProfileName == NULL || hInf == NULL ) {
  168. return(SCESTATUS_INVALID_PARAMETER);
  169. }
  170. //
  171. // Check to see if the INF file is opened OK.
  172. // SetupOpenInfFile is defined in setupapi.h
  173. //
  174. *hInf = SetupOpenInfFile(ProfileName,
  175. NULL,
  176. INF_STYLE_WIN4,
  177. NULL
  178. );
  179. if (*hInf == INVALID_HANDLE_VALUE)
  180. return( ScepDosErrorToSceStatus( GetLastError() ) );
  181. else
  182. return( SCESTATUS_SUCCESS);
  183. }
  184. SCESTATUS
  185. SceInfpCloseProfile(
  186. IN HINF hInf
  187. )
  188. {
  189. if ( hInf != INVALID_HANDLE_VALUE )
  190. SetupCloseInfFile( hInf );
  191. return(SCESTATUS_SUCCESS);
  192. }
  193. SCESTATUS
  194. ScepConvertMultiSzToDelim(
  195. IN PWSTR pValue,
  196. IN DWORD Len,
  197. IN WCHAR DelimFrom,
  198. IN WCHAR Delim
  199. )
  200. /*
  201. Convert the multi-sz delimiter \0 to space
  202. */
  203. {
  204. DWORD i;
  205. for ( i=0; i<Len && pValue; i++) {
  206. // if ( *(pValue+i) == L'\0' && *(pValue+i+1) != L'\0') {
  207. if ( *(pValue+i) == DelimFrom && i+1 < Len &&
  208. *(pValue+i+1) != L'\0' ) {
  209. //
  210. // a NULL delimiter is encounted and it's not the end (double NULL)
  211. //
  212. *(pValue+i) = Delim;
  213. }
  214. }
  215. return(SCESTATUS_SUCCESS);
  216. }
  217. /*
  218. SCESTATUS
  219. SceInfpInfErrorToSceStatus(
  220. IN SCEINF_STATUS InfErr
  221. )
  222. /* ++
  223. Routine Description:
  224. This routine converts error codes from Inf routines into SCESTATUS code.
  225. Arguments:
  226. InfErr - The error code from Inf routines
  227. Return Value:
  228. SCESTATUS code
  229. -- *//*
  230. {
  231. SCESTATUS rc;
  232. switch ( InfErr ) {
  233. case SCEINF_SUCCESS:
  234. rc = SCESTATUS_SUCCESS;
  235. break;
  236. case SCEINF_PROFILE_NOT_FOUND:
  237. rc = SCESTATUS_PROFILE_NOT_FOUND;
  238. break;
  239. case SCEINF_NOT_ENOUGH_MEMORY:
  240. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  241. break;
  242. case SCEINF_INVALID_PARAMETER:
  243. rc = SCESTATUS_INVALID_PARAMETER;
  244. break;
  245. case SCEINF_CORRUPT_PROFILE:
  246. rc = SCESTATUS_BAD_FORMAT;
  247. break;
  248. case SCEINF_INVALID_DATA:
  249. rc = SCESTATUS_INVALID_DATA;
  250. break;
  251. case SCEINF_ACCESS_DENIED:
  252. rc = SCESTATUS_ACCESS_DENIED;
  253. break;
  254. default:
  255. rc = SCESTATUS_OTHER_ERROR;
  256. break;
  257. }
  258. return(rc);
  259. }
  260. */
  261. //
  262. // below are exported APIs in secedit.h
  263. //
  264. SCESTATUS
  265. WINAPI
  266. SceCreateDirectory(
  267. IN PCWSTR ProfileLocation,
  268. IN BOOL FileOrDir,
  269. PSECURITY_DESCRIPTOR pSecurityDescriptor
  270. )
  271. {
  272. return ( ScepCreateDirectory(ProfileLocation,
  273. FileOrDir,
  274. pSecurityDescriptor
  275. ));
  276. }
  277. SCESTATUS
  278. WINAPI
  279. SceCompareSecurityDescriptors(
  280. IN AREA_INFORMATION Area,
  281. IN PSECURITY_DESCRIPTOR pSD1,
  282. IN PSECURITY_DESCRIPTOR pSD2,
  283. IN SECURITY_INFORMATION SeInfo,
  284. OUT PBOOL IsDifferent
  285. )
  286. {
  287. SE_OBJECT_TYPE ObjectType;
  288. BYTE resultSD=0;
  289. SCESTATUS rc;
  290. BOOL bContainer = FALSE;
  291. switch ( Area) {
  292. case AREA_REGISTRY_SECURITY:
  293. ObjectType = SE_REGISTRY_KEY;
  294. bContainer = TRUE;
  295. break;
  296. case AREA_FILE_SECURITY:
  297. ObjectType = SE_FILE_OBJECT;
  298. break;
  299. case AREA_DS_OBJECTS:
  300. ObjectType = SE_DS_OBJECT;
  301. bContainer = TRUE;
  302. break;
  303. case AREA_SYSTEM_SERVICE:
  304. ObjectType = SE_SERVICE;
  305. break;
  306. default:
  307. ObjectType = SE_FILE_OBJECT;
  308. break;
  309. }
  310. rc = ScepCompareObjectSecurity(
  311. ObjectType,
  312. bContainer,
  313. pSD1,
  314. pSD2,
  315. SeInfo,
  316. &resultSD);
  317. if ( resultSD )
  318. *IsDifferent = TRUE;
  319. else
  320. *IsDifferent = FALSE;
  321. return(rc);
  322. }
  323. SCESTATUS
  324. WINAPI
  325. SceAddToNameStatusList(
  326. IN OUT PSCE_NAME_STATUS_LIST *pNameStatusList,
  327. IN PWSTR Name,
  328. IN ULONG Len,
  329. IN DWORD Status
  330. )
  331. {
  332. return(ScepAddToNameStatusList(
  333. pNameStatusList,
  334. Name,
  335. Len,
  336. Status) );
  337. }
  338. SCESTATUS
  339. WINAPI
  340. SceAddToNameList(
  341. IN OUT PSCE_NAME_LIST *pNameList,
  342. IN PWSTR Name,
  343. IN ULONG Len
  344. )
  345. {
  346. return( ScepDosErrorToSceStatus(
  347. ScepAddToNameList(
  348. pNameList,
  349. Name,
  350. Len
  351. ) ) );
  352. }
  353. SCESTATUS
  354. WINAPI
  355. SceAddToObjectList(
  356. IN OUT PSCE_OBJECT_LIST *pObjectList,
  357. IN PWSTR Name,
  358. IN ULONG Len,
  359. IN BOOL IsContainer, // TRUE if the object is a container type
  360. IN BYTE Status, // SCE_STATUS_IGNORE, SCE_STATUS_CHECK, SCE_STATUS_OVERWRITE
  361. IN BYTE byFlags // SCE_CHECK_DUP if duplicate Name entry should not be added, SCE_INCREASE_COUNT
  362. )
  363. {
  364. return(ScepDosErrorToSceStatus(
  365. ScepAddToObjectList(
  366. pObjectList,
  367. Name,
  368. Len,
  369. IsContainer,
  370. Status,
  371. 0,
  372. byFlags
  373. ) ) );
  374. }
  375. BOOL
  376. SceCompareNameList(
  377. IN PSCE_NAME_LIST pList1,
  378. IN PSCE_NAME_LIST pList2
  379. )
  380. /*
  381. Routine Description:
  382. This routine compares two name lists for exact match. Sequence is not
  383. important in comparsion.
  384. */
  385. {
  386. PSCE_NAME_LIST pName1, pName2;
  387. DWORD Count1=0, Count2=0;
  388. if ( (pList2 == NULL && pList1 != NULL) ||
  389. (pList2 != NULL && pList1 == NULL) ) {
  390. // return(TRUE);
  391. // should be not equal
  392. return(FALSE);
  393. }
  394. for ( pName2=pList2; pName2 != NULL; pName2 = pName2->Next ) {
  395. if ( pName2->Name == NULL ) {
  396. continue;
  397. }
  398. Count2++;
  399. }
  400. for ( pName1=pList1; pName1 != NULL; pName1 = pName1->Next ) {
  401. if ( pName1->Name == NULL ) {
  402. continue;
  403. }
  404. Count1++;
  405. for ( pName2=pList2; pName2 != NULL; pName2 = pName2->Next ) {
  406. if ( pName2->Name == NULL ) {
  407. continue;
  408. }
  409. if ( _wcsicmp(pName1->Name, pName2->Name) == 0 ) {
  410. //
  411. // find a match
  412. //
  413. break; // the second for loop
  414. }
  415. }
  416. if ( pName2 == NULL ) {
  417. //
  418. // does not find a match
  419. //
  420. return(FALSE);
  421. }
  422. }
  423. if ( Count1 != Count2 )
  424. return(FALSE);
  425. return(TRUE);
  426. }
  427. DWORD
  428. WINAPI
  429. SceEnumerateServices(
  430. OUT PSCE_SERVICES *pServiceList,
  431. IN BOOL bServiceNameOnly
  432. )
  433. /*
  434. Routine Description:
  435. Enumerate all services installed on the local system. The information
  436. returned include startup status and security descriptor on each service
  437. object.
  438. Arguments:
  439. pServiceList - the list of services returned. Must be freed by LocalFree
  440. return value:
  441. ERROR_SUCCESS
  442. Win32 error codes
  443. */
  444. {
  445. SC_HANDLE hScManager = NULL;
  446. DWORD BytesNeeded, ServicesCount=0;
  447. LPENUM_SERVICE_STATUS pEnumBuffer = NULL;
  448. //
  449. // check arguments
  450. //
  451. if ( NULL == pServiceList )
  452. return(ERROR_INVALID_PARAMETER);
  453. //
  454. // open service control manager
  455. //
  456. hScManager = OpenSCManager(
  457. NULL,
  458. NULL,
  459. MAXIMUM_ALLOWED //SC_MANAGER_ALL_ACCESS
  460. // SC_MANAGER_CONNECT |
  461. // SC_MANAGER_ENUMERATE_SERVICE |
  462. // SC_MANAGER_QUERY_LOCK_STATUS
  463. );
  464. if ( NULL == hScManager ) {
  465. return( GetLastError() );
  466. }
  467. DWORD rc=NO_ERROR;
  468. DWORD i;
  469. DWORD status;
  470. if ( !bServiceNameOnly ) {
  471. //
  472. // Adjust privilege for setting SACL
  473. //
  474. status = SceAdjustPrivilege( SE_SECURITY_PRIVILEGE, TRUE, NULL );
  475. //
  476. // if can't adjust privilege, ignore (will error out later if SACL is requested)
  477. //
  478. }
  479. if ( !EnumServicesStatus(
  480. hScManager,
  481. SERVICE_WIN32, // do not expose driver | SERVICE_DRIVER,
  482. SERVICE_STATE_ALL,
  483. NULL,
  484. 0,
  485. &BytesNeeded,
  486. &ServicesCount,
  487. NULL) ) {
  488. rc = GetLastError();
  489. if (rc == ERROR_MORE_DATA || rc == ERROR_INSUFFICIENT_BUFFER)
  490. rc = ERROR_SUCCESS;
  491. else
  492. goto ExitHandler;
  493. }
  494. pEnumBuffer = (LPENUM_SERVICE_STATUS)LocalAlloc(LMEM_FIXED,(UINT)BytesNeeded);
  495. if ( NULL == pEnumBuffer ) {
  496. rc = ERROR_NOT_ENOUGH_MEMORY;
  497. goto ExitHandler;
  498. }
  499. if ( !EnumServicesStatus(
  500. hScManager,
  501. SERVICE_WIN32, // do not expose driver | SERVICE_DRIVER,
  502. SERVICE_STATE_ALL,
  503. pEnumBuffer,
  504. BytesNeeded,
  505. &BytesNeeded,
  506. &ServicesCount,
  507. NULL) ) {
  508. rc = GetLastError();
  509. goto ExitHandler;
  510. }
  511. for ( i=0; i < ServicesCount; i++ ) {
  512. //
  513. // add the service to our list
  514. //
  515. if ( bServiceNameOnly ) {
  516. //
  517. // only ask for service name, do not need to query
  518. //
  519. status = ScepAddOneServiceToList(
  520. pEnumBuffer[i].lpServiceName,
  521. pEnumBuffer[i].lpDisplayName,
  522. 0,
  523. NULL,
  524. 0,
  525. TRUE,
  526. pServiceList
  527. );
  528. } else {
  529. //
  530. // query startup and security descriptor
  531. //
  532. status = ScepQueryAndAddService(
  533. hScManager,
  534. pEnumBuffer[i].lpServiceName,
  535. pEnumBuffer[i].lpDisplayName,
  536. pServiceList
  537. );
  538. }
  539. if ( status != ERROR_SUCCESS ) {
  540. rc = status;
  541. goto ExitHandler;
  542. }
  543. }
  544. ExitHandler:
  545. if (pEnumBuffer) {
  546. LocalFree(pEnumBuffer);
  547. }
  548. //
  549. // clear memory and close handle
  550. //
  551. CloseServiceHandle (hScManager);
  552. if ( rc != ERROR_SUCCESS ) {
  553. //
  554. // free memory in pServiceList
  555. //
  556. SceFreePSCE_SERVICES(*pServiceList);
  557. *pServiceList = NULL;
  558. }
  559. if ( !bServiceNameOnly ) {
  560. //
  561. // Adjust privilege for SACL
  562. //
  563. SceAdjustPrivilege( SE_SECURITY_PRIVILEGE, FALSE, NULL );
  564. }
  565. return(rc);
  566. }
  567. DWORD
  568. ScepQueryAndAddService(
  569. IN SC_HANDLE hScManager,
  570. IN LPWSTR lpServiceName,
  571. IN LPWSTR lpDisplayName,
  572. OUT PSCE_SERVICES *pServiceList
  573. )
  574. /*
  575. Routine Description:
  576. Queries the security descriptor of the service and add all information
  577. to PSCE_SERVICE list
  578. Arguments:
  579. hScManager - service control manager handle
  580. lpServiceName - The service name
  581. ServiceStatus - The service status
  582. pServiceList - The service list to output
  583. Return Value:
  584. ERROR_SUCCESS
  585. Win32 errors
  586. */
  587. {
  588. SC_HANDLE hService;
  589. DWORD rc=ERROR_SUCCESS;
  590. if ( hScManager == NULL || lpServiceName == NULL || pServiceList == NULL ) {
  591. return(ERROR_INVALID_PARAMETER);
  592. }
  593. //
  594. // Open the service
  595. // SERVICE_ALL_ACCESS |
  596. // READ_CONTROL |
  597. // ACCESS_SYSTEM_SECURITY
  598. //
  599. hService = OpenService(
  600. hScManager,
  601. lpServiceName,
  602. MAXIMUM_ALLOWED |
  603. ACCESS_SYSTEM_SECURITY
  604. );
  605. if ( hService != NULL ) {
  606. //
  607. // Query the startup type
  608. //
  609. DWORD BytesNeeded=0;
  610. DWORD BufSize;
  611. //
  612. // Query configuration (Startup type)
  613. // get size first
  614. //
  615. if ( !QueryServiceConfig(
  616. hService,
  617. NULL,
  618. 0,
  619. &BytesNeeded
  620. ) ) {
  621. rc = GetLastError();
  622. if ( rc == ERROR_INSUFFICIENT_BUFFER ) {
  623. //
  624. // should always gets here
  625. //
  626. LPQUERY_SERVICE_CONFIG pConfig=NULL;
  627. pConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(0, BytesNeeded+1);
  628. if ( pConfig != NULL ) {
  629. rc = ERROR_SUCCESS;
  630. BufSize=BytesNeeded;
  631. //
  632. // the real query for Startup type (pConfig->dwStartType)
  633. //
  634. if ( QueryServiceConfig(
  635. hService,
  636. pConfig,
  637. BufSize,
  638. &BytesNeeded
  639. ) ) {
  640. //
  641. // Query the security descriptor length
  642. // the following function does not take NULL for the
  643. // address of security descriptor so use a temp buffer first
  644. // to get the real length
  645. //
  646. BYTE BufTmp[128];
  647. SECURITY_INFORMATION SeInfo;
  648. //
  649. // only query DACL and SACL information
  650. //
  651. /*
  652. SeInfo = DACL_SECURITY_INFORMATION |
  653. SACL_SECURITY_INFORMATION |
  654. GROUP_SECURITY_INFORMATION |
  655. OWNER_SECURITY_INFORMATION;
  656. */
  657. SeInfo = DACL_SECURITY_INFORMATION |
  658. SACL_SECURITY_INFORMATION;
  659. if ( !QueryServiceObjectSecurity(
  660. hService,
  661. SeInfo,
  662. (PSECURITY_DESCRIPTOR)BufTmp,
  663. 128,
  664. &BytesNeeded
  665. ) ) {
  666. rc = GetLastError();
  667. if ( rc == ERROR_INSUFFICIENT_BUFFER ||
  668. rc == ERROR_MORE_DATA ) {
  669. //
  670. // if buffer is not enough, it is ok
  671. // because BytesNeeded is the real length
  672. //
  673. rc = ERROR_SUCCESS;
  674. }
  675. } else
  676. rc = ERROR_SUCCESS;
  677. if ( rc == ERROR_SUCCESS ) {
  678. //
  679. // allocate buffer for security descriptor
  680. //
  681. PSECURITY_DESCRIPTOR pSecurityDescriptor=NULL;
  682. pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, BytesNeeded+2);
  683. if ( NULL != pSecurityDescriptor ) {
  684. //
  685. // query the security descriptor
  686. //
  687. BufSize = BytesNeeded;
  688. if ( QueryServiceObjectSecurity(
  689. hService,
  690. SeInfo,
  691. pSecurityDescriptor,
  692. BufSize,
  693. &BytesNeeded
  694. ) ) {
  695. //
  696. // create a service node and add it to the list
  697. //
  698. rc = ScepAddOneServiceToList(
  699. lpServiceName,
  700. lpDisplayName,
  701. pConfig->dwStartType,
  702. pSecurityDescriptor,
  703. SeInfo,
  704. TRUE,
  705. pServiceList
  706. );
  707. } else {
  708. //
  709. // error query the security descriptor
  710. //
  711. rc = GetLastError();
  712. }
  713. if ( rc != ERROR_SUCCESS ) {
  714. LocalFree(pSecurityDescriptor);
  715. }
  716. } else {
  717. //
  718. // cannot allocate memory for security descriptor
  719. //
  720. rc = ERROR_NOT_ENOUGH_MEMORY;
  721. }
  722. }
  723. } else {
  724. //
  725. // cannot query config
  726. //
  727. rc = GetLastError();
  728. }
  729. LocalFree(pConfig);
  730. } else
  731. rc = ERROR_NOT_ENOUGH_MEMORY;
  732. }
  733. } else {
  734. //
  735. // should not fall in here, if it does, just return success
  736. //
  737. }
  738. CloseServiceHandle(hService);
  739. } else {
  740. //
  741. // cannot open service
  742. //
  743. rc = GetLastError();
  744. }
  745. return(rc);
  746. }
  747. INT
  748. ScepLookupPrivByValue(
  749. IN DWORD Priv
  750. )
  751. /* ++
  752. Routine Description:
  753. This routine looksup a privilege in SCE_Privileges table and returns the
  754. index for the priv.
  755. Arguments:
  756. Priv - The privilege to look up
  757. Return value:
  758. The index in SCE_Privileges table if a match is found, or -1 for no match
  759. -- */
  760. {
  761. DWORD i;
  762. if ( Priv == 0 )
  763. return (-1);
  764. for ( i=0; i<cPrivCnt; i++) {
  765. if ( SCE_Privileges[i].Value == Priv )
  766. return i;
  767. }
  768. return (-1);
  769. }
  770. SCESTATUS
  771. ScepGetProductType(
  772. OUT PSCE_SERVER_TYPE srvProduct
  773. )
  774. {
  775. NT_PRODUCT_TYPE theType;
  776. if ( RtlGetNtProductType(&theType) ) {
  777. #if _WIN32_WINNT>=0x0500
  778. //
  779. // NT5+
  780. //
  781. switch (theType) {
  782. case NtProductLanManNt:
  783. *srvProduct = SCESVR_DC_WITH_DS;
  784. break;
  785. case NtProductServer:
  786. *srvProduct = SCESVR_NT5_SERVER;
  787. break;
  788. case NtProductWinNt:
  789. *srvProduct = SCESVR_NT5_WKS;
  790. break;
  791. default:
  792. *srvProduct = SCESVR_UNKNOWN;
  793. }
  794. #else
  795. //
  796. // NT4
  797. //
  798. switch (theType) {
  799. case NtProductLanManNt:
  800. *srvProduct = SCESVR_DC;
  801. break;
  802. case NtProductServer:
  803. *srvProduct = SCESVR_NT4_SERVER;
  804. break;
  805. case NtProductWinNt:
  806. *srvProduct = SCESVR_NT4_WKS;
  807. break;
  808. default:
  809. *srvProduct = SCESVR_UNKNOWN;
  810. }
  811. #endif
  812. } else {
  813. *srvProduct = SCESVR_UNKNOWN;
  814. }
  815. return(SCESTATUS_SUCCESS);
  816. }
  817. DWORD
  818. ScepAddTwoNamesToNameList(
  819. OUT PSCE_NAME_LIST *pNameList,
  820. IN BOOL bAddSeparator,
  821. IN PWSTR Name1,
  822. IN ULONG Length1,
  823. IN PWSTR Name2,
  824. IN ULONG Length2
  825. )
  826. /* ++
  827. Routine Description:
  828. This routine adds two names (wchar) to the name list in the format of
  829. Name1\Name2, or Name1Name2, depends if bSeparator is TRUE. This routine
  830. is used for Domain\Account tracking list
  831. Arguments:
  832. pNameList - The name list to add to.
  833. Name1 - The name 1 to add
  834. Length1 - the length of name1 (number of wchars)
  835. Name2 - the name 2 to add
  836. Length2 - the length of name2 (number of wchars)
  837. Return value:
  838. Win32 error code
  839. -- */
  840. {
  841. PSCE_NAME_LIST pList=NULL;
  842. ULONG Length;
  843. if ( pNameList == NULL )
  844. return(ERROR_INVALID_PARAMETER);
  845. if ( Name1 == NULL && Name2 == NULL )
  846. return(NO_ERROR);
  847. Length = Length1 + Length2;
  848. if ( Length <= 0 )
  849. return(NO_ERROR);
  850. pList = (PSCE_NAME_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_LIST));
  851. if ( pList == NULL )
  852. return(ERROR_NOT_ENOUGH_MEMORY);
  853. if ( bAddSeparator ) {
  854. Length++;
  855. }
  856. pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Length+1)*sizeof(TCHAR));
  857. if ( pList->Name == NULL ) {
  858. ScepFree(pList);
  859. return(ERROR_NOT_ENOUGH_MEMORY);
  860. }
  861. if ( Name1 != NULL && Length1 > 0 )
  862. wcsncpy(pList->Name, Name1, Length1);
  863. if ( bAddSeparator ) {
  864. wcsncat(pList->Name, L"\\", 1);
  865. }
  866. if ( Name2 != NULL && Length2 > 0 )
  867. wcsncat(pList->Name, Name2, Length2);
  868. pList->Next = *pNameList;
  869. *pNameList = pList;
  870. return(NO_ERROR);
  871. }
  872. NTSTATUS
  873. ScepDomainIdToSid(
  874. IN PSID DomainId,
  875. IN ULONG RelativeId,
  876. OUT PSID *Sid
  877. )
  878. /*++
  879. Routine Description:
  880. Given a domain Id and a relative ID create a SID
  881. Arguments:
  882. DomainId - The template SID to use.
  883. RelativeId - The relative Id to append to the DomainId.
  884. Sid - Returns a pointer to an allocated buffer containing the resultant
  885. Sid. Free this buffer using NetpMemoryFree.
  886. Return Value:
  887. NTSTATUS
  888. --*/
  889. {
  890. UCHAR DomainIdSubAuthorityCount; // Number of sub authorities in domain ID
  891. ULONG SidLength; // Length of newly allocated SID
  892. //
  893. // Allocate a Sid which has one more sub-authority than the domain ID.
  894. //
  895. DomainIdSubAuthorityCount = *(RtlSubAuthorityCountSid( DomainId ));
  896. SidLength = RtlLengthRequiredSid(DomainIdSubAuthorityCount+1);
  897. if ((*Sid = (PSID) ScepAlloc( (UINT)0, SidLength )) == NULL ) {
  898. return STATUS_NO_MEMORY;
  899. }
  900. //
  901. // Initialize the new SID to have the same inital value as the
  902. // domain ID.
  903. //
  904. if ( !NT_SUCCESS( RtlCopySid( SidLength, *Sid, DomainId ) ) ) {
  905. ScepFree( *Sid );
  906. *Sid = NULL;
  907. return STATUS_INTERNAL_ERROR;
  908. }
  909. //
  910. // Adjust the sub-authority count and
  911. // add the relative Id unique to the newly allocated SID
  912. //
  913. (*(RtlSubAuthorityCountSid( *Sid ))) ++;
  914. *RtlSubAuthoritySid( *Sid, DomainIdSubAuthorityCount ) = RelativeId;
  915. return ERROR_SUCCESS;
  916. }
  917. DWORD
  918. ScepConvertSidToPrefixStringSid(
  919. IN PSID pSid,
  920. OUT PWSTR *StringSid
  921. )
  922. /*
  923. The pair routine to convert stringsid to a Sid is ConvertStringSidToSid
  924. defined in sddl.h
  925. */
  926. {
  927. if ( pSid == NULL || StringSid == NULL ) {
  928. return(ERROR_INVALID_PARAMETER);
  929. }
  930. UNICODE_STRING UnicodeStringSid;
  931. DWORD rc = RtlNtStatusToDosError(
  932. RtlConvertSidToUnicodeString(&UnicodeStringSid,
  933. pSid,
  934. TRUE ));
  935. if ( ERROR_SUCCESS == rc ) {
  936. *StringSid = (PWSTR)ScepAlloc(LPTR, UnicodeStringSid.Length+2*sizeof(WCHAR));
  937. if ( *StringSid ) {
  938. (*StringSid)[0] = L'*';
  939. wcsncpy( (*StringSid)+1, UnicodeStringSid.Buffer, UnicodeStringSid.Length/2);
  940. } else {
  941. rc = ERROR_NOT_ENOUGH_MEMORY;
  942. }
  943. RtlFreeUnicodeString( &UnicodeStringSid );
  944. }
  945. return(rc);
  946. }
  947. NTSTATUS ScepIsMigratedAccount(
  948. IN LSA_HANDLE LsaHandle,
  949. IN PLSA_UNICODE_STRING pName,
  950. IN PLSA_UNICODE_STRING pDomain,
  951. IN PSID pSid,
  952. OUT bool *pbMigratedAccount
  953. )
  954. {
  955. NTSTATUS NtStatus = STATUS_SUCCESS;
  956. DWORD rc;
  957. LSA_UNICODE_STRING lusName;
  958. PSCE_NAME_LIST pNameList = NULL;
  959. PLSA_REFERENCED_DOMAIN_LIST pRefDomains = NULL;
  960. PLSA_TRANSLATED_SID2 pSids = NULL;
  961. rc = ScepAddTwoNamesToNameList(
  962. &pNameList,
  963. TRUE,
  964. pDomain->Buffer,
  965. pDomain->Length/2,
  966. pName->Buffer,
  967. pName->Length/2);
  968. if (ERROR_SUCCESS != rc) {
  969. NtStatus = STATUS_NO_MEMORY;
  970. }
  971. if (NT_SUCCESS(NtStatus)) {
  972. RtlInitUnicodeString(&lusName, pNameList->Name);
  973. NtStatus = LsaLookupNames2(
  974. LsaHandle,
  975. LSA_LOOKUP_ISOLATED_AS_LOCAL,
  976. 1,
  977. &lusName,
  978. &pRefDomains,
  979. &pSids);
  980. if (NT_SUCCESS(NtStatus)) {
  981. *pbMigratedAccount = !EqualSid(pSid, pSids[0].Sid);
  982. }
  983. }
  984. if (pRefDomains) {
  985. LsaFreeMemory(pRefDomains);
  986. }
  987. if (pSids) {
  988. LsaFreeMemory(pSids);
  989. }
  990. if (pNameList) {
  991. ScepFreeNameList(pNameList);
  992. }
  993. return NtStatus;
  994. }
  995. NTSTATUS
  996. ScepConvertSidToName(
  997. IN LSA_HANDLE LsaPolicy,
  998. IN PSID AccountSid,
  999. IN BOOL bFromDomain,
  1000. OUT PWSTR *AccountName,
  1001. OUT DWORD *Length OPTIONAL
  1002. )
  1003. {
  1004. if ( LsaPolicy == NULL || AccountSid == NULL ||
  1005. AccountName == NULL ) {
  1006. return(STATUS_INVALID_PARAMETER);
  1007. }
  1008. PSID pTmpSid=AccountSid;
  1009. PLSA_TRANSLATED_NAME Names=NULL;
  1010. PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains=NULL;
  1011. NTSTATUS NtStatus = LsaLookupSids(
  1012. LsaPolicy,
  1013. 1,
  1014. (PSID *)&pTmpSid,
  1015. &ReferencedDomains,
  1016. &Names
  1017. );
  1018. DWORD Len=0;
  1019. if ( NT_SUCCESS(NtStatus) ) {
  1020. if ( ( Names[0].Use != SidTypeInvalid &&
  1021. Names[0].Use != SidTypeUnknown ) ) {
  1022. //
  1023. // build the account name without domain name
  1024. //
  1025. if ( bFromDomain && Names[0].Use != SidTypeWellKnownGroup &&
  1026. ReferencedDomains->Entries > 0 &&
  1027. ReferencedDomains->Domains != NULL &&
  1028. Names[0].DomainIndex != -1 &&
  1029. (ULONG)(Names[0].DomainIndex) < ReferencedDomains->Entries &&
  1030. ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length > 0 &&
  1031. ScepIsSidFromAccountDomain( ReferencedDomains->Domains[Names[0].DomainIndex].Sid ) ) {
  1032. // For migrated accounts, sid will map to the new account and we'll lose
  1033. // permissions for the original account. Detect this case by doing a reverse
  1034. // lookup and comparing the SIDs
  1035. // If sid -> name -> sid returns a different sid, then it's a sid history
  1036. // name lookup and the account is from a different domain. Converting to current
  1037. // name will cause it to lose the original sid from the policy. We'll hold on
  1038. // to the original SID.
  1039. bool bMigratedAccount = false;
  1040. NtStatus = ScepIsMigratedAccount(
  1041. LsaPolicy,
  1042. &Names[0].Name,
  1043. &ReferencedDomains->Domains[Names[0].DomainIndex].Name,
  1044. pTmpSid,
  1045. &bMigratedAccount);
  1046. if(NT_SUCCESS(NtStatus) && bMigratedAccount) {
  1047. // return SID string
  1048. NtStatus = ScepConvertSidToPrefixStringSid(pTmpSid, AccountName);
  1049. Len = wcslen(*AccountName);
  1050. } else {
  1051. NtStatus = STATUS_SUCCESS; // ignore failure to detect migrated account
  1052. //
  1053. // build domain name\account name
  1054. //
  1055. Len = Names[0].Name.Length + ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length + 2;
  1056. *AccountName = (PWSTR)LocalAlloc(LPTR, Len+sizeof(TCHAR));
  1057. if ( *AccountName ) {
  1058. wcsncpy(*AccountName, ReferencedDomains->Domains[Names[0].DomainIndex].Name.Buffer,
  1059. ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length/2);
  1060. (*AccountName)[ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length/2] = L'\\';
  1061. wcsncpy((*AccountName)+ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length/2+1,
  1062. Names[0].Name.Buffer, Names[0].Name.Length/2);
  1063. } else {
  1064. NtStatus = STATUS_NO_MEMORY;
  1065. }
  1066. Len /= 2;
  1067. }
  1068. } else {
  1069. Len = Names[0].Name.Length/2;
  1070. *AccountName = (PWSTR)LocalAlloc(LPTR, Names[0].Name.Length+2);
  1071. if ( *AccountName ) {
  1072. wcsncpy(*AccountName, Names[0].Name.Buffer, Len);
  1073. } else {
  1074. NtStatus = STATUS_NO_MEMORY;
  1075. }
  1076. }
  1077. } else {
  1078. NtStatus = STATUS_NONE_MAPPED;
  1079. }
  1080. }
  1081. if ( ReferencedDomains ) {
  1082. LsaFreeMemory(ReferencedDomains);
  1083. ReferencedDomains = NULL;
  1084. }
  1085. if ( Names ) {
  1086. LsaFreeMemory(Names);
  1087. Names = NULL;
  1088. }
  1089. if ( NT_SUCCESS(NtStatus) && Length ) {
  1090. *Length = Len;
  1091. }
  1092. return(NtStatus);
  1093. }
  1094. NTSTATUS
  1095. ScepConvertNameToSid(
  1096. IN LSA_HANDLE LsaPolicy,
  1097. IN PWSTR AccountName,
  1098. OUT PSID *AccountSid
  1099. )
  1100. {
  1101. if ( LsaPolicy == NULL || AccountName == NULL ||
  1102. AccountSid == NULL ) {
  1103. return(STATUS_INVALID_PARAMETER);
  1104. }
  1105. PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
  1106. PLSA_TRANSLATED_SID2 Sids=NULL;
  1107. NTSTATUS NtStatus = ScepLsaLookupNames2(
  1108. LsaPolicy,
  1109. LSA_LOOKUP_ISOLATED_AS_LOCAL,
  1110. AccountName,
  1111. &RefDomains,
  1112. &Sids
  1113. );
  1114. if ( NT_SUCCESS(NtStatus) && Sids ) {
  1115. //
  1116. // build the account sid
  1117. //
  1118. if ( Sids[0].Use != SidTypeInvalid &&
  1119. Sids[0].Use != SidTypeUnknown &&
  1120. Sids[0].Sid != NULL ) {
  1121. //
  1122. // this name is mapped, the SID is in Sids[0].Sid
  1123. //
  1124. DWORD SidLength = RtlLengthSid(Sids[0].Sid);
  1125. if ( (*AccountSid = (PSID) ScepAlloc( (UINT)0, SidLength)) == NULL ) {
  1126. NtStatus = STATUS_NO_MEMORY;
  1127. } else {
  1128. //
  1129. // copy the SID
  1130. //
  1131. NtStatus = RtlCopySid( SidLength, *AccountSid, Sids[0].Sid );
  1132. if ( !NT_SUCCESS(NtStatus) ) {
  1133. ScepFree( *AccountSid );
  1134. *AccountSid = NULL;
  1135. }
  1136. }
  1137. } else {
  1138. NtStatus = STATUS_NONE_MAPPED;
  1139. }
  1140. }
  1141. if ( Sids ) {
  1142. LsaFreeMemory(Sids);
  1143. }
  1144. if ( RefDomains ) {
  1145. LsaFreeMemory(RefDomains);
  1146. }
  1147. return(NtStatus);
  1148. }
  1149. NTSTATUS
  1150. ScepLsaLookupNames2(
  1151. IN LSA_HANDLE PolicyHandle,
  1152. IN ULONG Flags,
  1153. IN PWSTR pszAccountName,
  1154. OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  1155. OUT PLSA_TRANSLATED_SID2 *Sids
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. Similar to LsaLookupNames2 except that on local lookup
  1160. failures, it resolves free text accounts to the domain
  1161. this machine is joined to
  1162. Arguments:
  1163. PolicyHandle - handle to LSA
  1164. Flags - usually LSA_LOOKUP_ISOLATED_AS_LOCAL
  1165. pszAccountName - name of account to lookup
  1166. ReferencedDomains - returns the reference domain id
  1167. (to be freed by caller)
  1168. Sids - returns the SID looked up
  1169. (to be freed by caller)
  1170. Return Value:
  1171. NTSTATUS
  1172. --*/
  1173. {
  1174. PWSTR pszScopedName = NULL;
  1175. UNICODE_STRING UnicodeName;
  1176. PPOLICY_ACCOUNT_DOMAIN_INFO pDomainInfo = NULL;
  1177. RtlInitUnicodeString(&UnicodeName, pszAccountName);
  1178. NTSTATUS NtStatus = LsaLookupNames2(
  1179. PolicyHandle,
  1180. Flags,
  1181. 1,
  1182. &UnicodeName,
  1183. ReferencedDomains,
  1184. Sids
  1185. );
  1186. if ((NtStatus == STATUS_SOME_NOT_MAPPED ||
  1187. NtStatus == STATUS_NONE_MAPPED) &&
  1188. NULL == wcschr(pszAccountName, L'\\') ) {
  1189. if ( NULL != *Sids) {
  1190. LsaFreeMemory(*Sids);
  1191. *Sids = NULL;
  1192. }
  1193. if ( NULL != *ReferencedDomains) {
  1194. LsaFreeMemory(*ReferencedDomains);
  1195. *ReferencedDomains = NULL;
  1196. }
  1197. NtStatus = LsaQueryInformationPolicy(PolicyHandle,
  1198. PolicyDnsDomainInformation,
  1199. ( PVOID * )&pDomainInfo );
  1200. if (!NT_SUCCESS(NtStatus) ||
  1201. pDomainInfo == NULL ||
  1202. pDomainInfo->DomainName.Buffer == NULL ||
  1203. pDomainInfo->DomainName.Length <= 0) {
  1204. NtStatus = STATUS_SOME_NOT_MAPPED;
  1205. goto ExitHandler;
  1206. }
  1207. pszScopedName = (PWSTR) LocalAlloc(LMEM_ZEROINIT,
  1208. (pDomainInfo->DomainName.Length/2 + wcslen(pszAccountName) + 2) * sizeof(WCHAR));
  1209. if (pszScopedName == NULL) {
  1210. NtStatus = STATUS_NO_MEMORY;
  1211. goto ExitHandler;
  1212. }
  1213. wcsncpy(pszScopedName, pDomainInfo->DomainName.Buffer, pDomainInfo->DomainName.Length/2);
  1214. wcscat(pszScopedName, L"\\");
  1215. wcscat(pszScopedName, pszAccountName);
  1216. RtlInitUnicodeString(&UnicodeName, pszScopedName);
  1217. NtStatus = LsaLookupNames2(
  1218. PolicyHandle,
  1219. Flags,
  1220. 1,
  1221. &UnicodeName,
  1222. ReferencedDomains,
  1223. Sids
  1224. );
  1225. }
  1226. ExitHandler:
  1227. if (pszScopedName) {
  1228. LocalFree(pszScopedName);
  1229. }
  1230. if (pDomainInfo) {
  1231. LsaFreeMemory( pDomainInfo );
  1232. }
  1233. if(!NT_SUCCESS(NtStatus))
  1234. {
  1235. if ( NULL != *Sids) {
  1236. LsaFreeMemory(*Sids);
  1237. *Sids = NULL;
  1238. }
  1239. if ( NULL != *ReferencedDomains) {
  1240. LsaFreeMemory(*ReferencedDomains);
  1241. *ReferencedDomains = NULL;
  1242. }
  1243. }
  1244. return NtStatus;
  1245. }
  1246. SCESTATUS
  1247. ScepConvertNameToSidString(
  1248. IN LSA_HANDLE LsaHandle,
  1249. IN PWSTR Name,
  1250. IN BOOL bAccountDomainOnly,
  1251. OUT PWSTR *SidString,
  1252. OUT DWORD *SidStrLen
  1253. )
  1254. {
  1255. if ( LsaHandle == NULL || Name == NULL ) {
  1256. return(SCESTATUS_INVALID_PARAMETER);
  1257. }
  1258. if ( Name[0] == L'\0' ) {
  1259. return(SCESTATUS_INVALID_PARAMETER);
  1260. }
  1261. if ( SidString == NULL || SidStrLen == NULL ) {
  1262. return(SCESTATUS_INVALID_PARAMETER);
  1263. }
  1264. //
  1265. // convert the sid string to a real sid
  1266. //
  1267. PSID pSid=NULL;
  1268. NTSTATUS NtStatus;
  1269. DWORD rc;
  1270. PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
  1271. PLSA_TRANSLATED_SID2 Sids=NULL;
  1272. NtStatus = ScepLsaLookupNames2(
  1273. LsaHandle,
  1274. LSA_LOOKUP_ISOLATED_AS_LOCAL,
  1275. Name,
  1276. &RefDomains,
  1277. &Sids
  1278. );
  1279. rc = RtlNtStatusToDosError(NtStatus);
  1280. if ( ERROR_SUCCESS == rc && Sids ) {
  1281. //
  1282. // name is found, make domain\account format
  1283. //
  1284. if ( Sids[0].Use != SidTypeInvalid &&
  1285. Sids[0].Use != SidTypeUnknown &&
  1286. Sids[0].Sid != NULL ) {
  1287. //
  1288. // this name is mapped
  1289. //
  1290. if ( !bAccountDomainOnly ||
  1291. ScepIsSidFromAccountDomain( Sids[0].Sid ) ) {
  1292. //
  1293. // convert to a sid string, note: a prefix "*" should be added
  1294. //
  1295. UNICODE_STRING UnicodeStringSid;
  1296. rc = RtlNtStatusToDosError(
  1297. RtlConvertSidToUnicodeString(&UnicodeStringSid,
  1298. Sids[0].Sid,
  1299. TRUE ));
  1300. if ( ERROR_SUCCESS == rc ) {
  1301. *SidStrLen = UnicodeStringSid.Length/2 + 1;
  1302. *SidString = (PWSTR)ScepAlloc(LPTR, UnicodeStringSid.Length + 2*sizeof(WCHAR));
  1303. if ( *SidString ) {
  1304. (*SidString)[0] = L'*';
  1305. wcsncpy((*SidString)+1, UnicodeStringSid.Buffer, (*SidStrLen)-1);
  1306. } else {
  1307. *SidStrLen = 0;
  1308. rc = ERROR_NOT_ENOUGH_MEMORY;
  1309. }
  1310. RtlFreeUnicodeString( &UnicodeStringSid );
  1311. }
  1312. } else {
  1313. //
  1314. // add only the account name
  1315. //
  1316. rc = ERROR_NONE_MAPPED;
  1317. }
  1318. } else {
  1319. rc = ERROR_NONE_MAPPED;
  1320. }
  1321. }
  1322. if ( Sids ) {
  1323. LsaFreeMemory(Sids);
  1324. }
  1325. if ( RefDomains ) {
  1326. LsaFreeMemory(RefDomains);
  1327. }
  1328. return(ScepDosErrorToSceStatus(rc));
  1329. }
  1330. SCESTATUS
  1331. ScepLookupSidStringAndAddToNameList(
  1332. IN LSA_HANDLE LsaHandle,
  1333. IN OUT PSCE_NAME_LIST *pNameList,
  1334. IN PWSTR LookupString,
  1335. IN ULONG Len
  1336. )
  1337. {
  1338. if ( LsaHandle == NULL || LookupString == NULL ) {
  1339. return(SCESTATUS_INVALID_PARAMETER);
  1340. }
  1341. if ( LookupString[0] == L'\0' ) {
  1342. return(SCESTATUS_INVALID_PARAMETER);
  1343. }
  1344. if ( Len <= 3 ||
  1345. (LookupString[1] != L'S' && LookupString[1] != L's') ||
  1346. LookupString[2] != L'-' ) {
  1347. return(SCESTATUS_INVALID_PARAMETER);
  1348. }
  1349. //
  1350. // convert the sid string to a real sid
  1351. //
  1352. PSID pSid=NULL;
  1353. NTSTATUS NtStatus;
  1354. DWORD rc;
  1355. PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
  1356. PLSA_TRANSLATED_NAME Names=NULL;
  1357. if ( ConvertStringSidToSid(LookupString+1, &pSid) ) {
  1358. NtStatus = LsaLookupSids(
  1359. LsaHandle,
  1360. 1,
  1361. &pSid,
  1362. &RefDomains,
  1363. &Names
  1364. );
  1365. rc = RtlNtStatusToDosError(NtStatus);
  1366. } else {
  1367. rc = GetLastError();
  1368. }
  1369. if ( ERROR_SUCCESS == rc && Names && RefDomains ) {
  1370. //
  1371. // name is found, make domain\account format
  1372. //
  1373. if ( ( Names[0].Use != SidTypeInvalid &&
  1374. Names[0].Use != SidTypeUnknown ) ) {
  1375. //
  1376. // this name is mapped
  1377. //
  1378. if ( RefDomains->Entries > 0 && Names[0].Use != SidTypeWellKnownGroup &&
  1379. RefDomains->Domains != NULL &&
  1380. Names[0].DomainIndex != -1 &&
  1381. (ULONG)(Names[0].DomainIndex) < RefDomains->Entries &&
  1382. RefDomains->Domains[Names[0].DomainIndex].Name.Length > 0 &&
  1383. ScepIsSidFromAccountDomain( RefDomains->Domains[Names[0].DomainIndex].Sid ) ) {
  1384. // For migrated accounts, sid will map to the new account and we'll lose
  1385. // permissions for the original account. Detect this case by doing a reverse
  1386. // lookup and comparing the SIDs
  1387. // If sid -> name -> sid returns a different sid, then it's a sid history
  1388. // name lookup and the account is from a different domain. Converting to current
  1389. // name will cause it to lose the original sid from the policy. We'll hold on
  1390. // to the original SID.
  1391. bool bMigratedAccount = false;
  1392. NtStatus = ScepIsMigratedAccount(
  1393. LsaHandle,
  1394. &Names[0].Name,
  1395. &RefDomains->Domains[Names[0].DomainIndex].Name,
  1396. pSid,
  1397. &bMigratedAccount);
  1398. if(NT_SUCCESS(NtStatus) && bMigratedAccount) {
  1399. // add SID string to list
  1400. rc = ScepAddToNameList(
  1401. pNameList,
  1402. LookupString,
  1403. Len);
  1404. } else {
  1405. NtStatus = STATUS_SUCCESS; // ignore failure to detect migrated account
  1406. //
  1407. // add both domain name and account name
  1408. //
  1409. rc = ScepAddTwoNamesToNameList(
  1410. pNameList,
  1411. TRUE,
  1412. RefDomains->Domains[Names[0].DomainIndex].Name.Buffer,
  1413. RefDomains->Domains[Names[0].DomainIndex].Name.Length/2,
  1414. Names[0].Name.Buffer,
  1415. Names[0].Name.Length/2);
  1416. }
  1417. } else {
  1418. //
  1419. // add only the account name
  1420. //
  1421. rc = ScepAddToNameList(
  1422. pNameList,
  1423. Names[0].Name.Buffer,
  1424. Names[0].Name.Length/2);
  1425. }
  1426. } else {
  1427. rc = ERROR_NONE_MAPPED;
  1428. }
  1429. }
  1430. if ( ERROR_SUCCESS != rc ) {
  1431. //
  1432. // either invalid sid string, or not found a name map, or
  1433. // failed to add to the name list, just simply add the sid string to the name list
  1434. //
  1435. rc = ScepAddToNameList(
  1436. pNameList,
  1437. LookupString,
  1438. Len);
  1439. }
  1440. if ( Names ) {
  1441. LsaFreeMemory(Names);
  1442. }
  1443. if ( RefDomains ) {
  1444. LsaFreeMemory(RefDomains);
  1445. }
  1446. if ( pSid ) {
  1447. LocalFree(pSid);
  1448. }
  1449. return(ScepDosErrorToSceStatus(rc));
  1450. }
  1451. SCESTATUS
  1452. ScepLookupNameAndAddToSidStringList(
  1453. IN LSA_HANDLE LsaHandle,
  1454. IN OUT PSCE_NAME_LIST *pNameList,
  1455. IN PWSTR LookupString,
  1456. IN ULONG Len
  1457. )
  1458. {
  1459. if ( LsaHandle == NULL || LookupString == NULL || Len == 0 ) {
  1460. return(SCESTATUS_INVALID_PARAMETER);
  1461. }
  1462. if ( LookupString[0] == L'\0' ) {
  1463. return(SCESTATUS_INVALID_PARAMETER);
  1464. }
  1465. //
  1466. // convert the sid string to a real sid
  1467. //
  1468. PSID pSid=NULL;
  1469. NTSTATUS NtStatus;
  1470. DWORD rc;
  1471. PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
  1472. PLSA_TRANSLATED_SID2 Sids=NULL;
  1473. UNICODE_STRING UnicodeName;
  1474. NtStatus = ScepLsaLookupNames2(
  1475. LsaHandle,
  1476. LSA_LOOKUP_ISOLATED_AS_LOCAL,
  1477. LookupString,
  1478. &RefDomains,
  1479. &Sids
  1480. );
  1481. rc = RtlNtStatusToDosError(NtStatus);
  1482. if ( ERROR_SUCCESS == rc && Sids ) {
  1483. //
  1484. // name is found, make domain\account format
  1485. //
  1486. if ( Sids[0].Use != SidTypeInvalid &&
  1487. Sids[0].Use != SidTypeUnknown &&
  1488. Sids[0].Sid ) {
  1489. //
  1490. // this name is mapped
  1491. // convert to a sid string, note: a prefix "*" should be added
  1492. //
  1493. UNICODE_STRING UnicodeStringSid;
  1494. rc = RtlNtStatusToDosError(
  1495. RtlConvertSidToUnicodeString(&UnicodeStringSid,
  1496. Sids[0].Sid,
  1497. TRUE ));
  1498. if ( ERROR_SUCCESS == rc ) {
  1499. rc = ScepAddTwoNamesToNameList(
  1500. pNameList,
  1501. FALSE,
  1502. TEXT("*"),
  1503. 1,
  1504. UnicodeStringSid.Buffer,
  1505. UnicodeStringSid.Length/2);
  1506. RtlFreeUnicodeString( &UnicodeStringSid );
  1507. }
  1508. } else {
  1509. rc = ERROR_NONE_MAPPED;
  1510. }
  1511. }
  1512. if ( ERROR_SUCCESS != rc ) {
  1513. //
  1514. // either invalid sid string, or not found a name map, or
  1515. // failed to add to the name list, just simply add the sid string to the name list
  1516. //
  1517. rc = ScepAddToNameList(
  1518. pNameList,
  1519. LookupString,
  1520. Len);
  1521. }
  1522. if ( Sids ) {
  1523. LsaFreeMemory(Sids);
  1524. }
  1525. if ( RefDomains ) {
  1526. LsaFreeMemory(RefDomains);
  1527. }
  1528. return(ScepDosErrorToSceStatus(rc));
  1529. }
  1530. NTSTATUS
  1531. ScepOpenLsaPolicy(
  1532. IN ACCESS_MASK access,
  1533. OUT PLSA_HANDLE pPolicyHandle,
  1534. IN BOOL bDoNotNotify
  1535. )
  1536. /* ++
  1537. Routine Description:
  1538. This routine opens the LSA policy with the desired access.
  1539. Arguments:
  1540. access - the desired access to the policy
  1541. pPolicyHandle - returned address of the Policy Handle
  1542. Return value:
  1543. NTSTATUS
  1544. -- */
  1545. {
  1546. NTSTATUS NtStatus;
  1547. LSA_OBJECT_ATTRIBUTES attributes;
  1548. SECURITY_QUALITY_OF_SERVICE service;
  1549. memset( &attributes, 0, sizeof(attributes) );
  1550. attributes.Length = sizeof(attributes);
  1551. attributes.SecurityQualityOfService = &service;
  1552. service.Length = sizeof(service);
  1553. service.ImpersonationLevel= SecurityImpersonation;
  1554. service.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1555. service.EffectiveOnly = TRUE;
  1556. //
  1557. // open the lsa policy first
  1558. //
  1559. NtStatus = LsaOpenPolicy(
  1560. NULL,
  1561. &attributes,
  1562. access,
  1563. pPolicyHandle
  1564. );
  1565. /*
  1566. if ( NT_SUCCESS(NtStatus) &&
  1567. bDoNotNotify &&
  1568. *pPolicyHandle ) {
  1569. NtStatus = LsaSetPolicyReplicationHandle(pPolicyHandle);
  1570. if ( !NT_SUCCESS(NtStatus) ) {
  1571. LsaClose( *pPolicyHandle );
  1572. *pPolicyHandle = NULL;
  1573. }
  1574. }
  1575. */
  1576. return(NtStatus);
  1577. }
  1578. BOOL
  1579. ScepIsSidFromAccountDomain(
  1580. IN PSID pSid
  1581. )
  1582. {
  1583. if ( pSid == NULL ) {
  1584. return(FALSE);
  1585. }
  1586. if ( !RtlValidSid(pSid) ) {
  1587. return(FALSE);
  1588. }
  1589. PSID_IDENTIFIER_AUTHORITY pia = RtlIdentifierAuthoritySid ( pSid );
  1590. if ( pia ) {
  1591. if ( pia->Value[5] != 5 ||
  1592. pia->Value[0] != 0 ||
  1593. pia->Value[1] != 0 ||
  1594. pia->Value[2] != 0 ||
  1595. pia->Value[3] != 0 ||
  1596. pia->Value[4] != 0 ) {
  1597. //
  1598. // this is not a account from account domain
  1599. //
  1600. return(FALSE);
  1601. }
  1602. if ( RtlSubAuthorityCountSid( pSid ) == 0 ||
  1603. *RtlSubAuthoritySid ( pSid, 0 ) != SECURITY_NT_NON_UNIQUE ) {
  1604. return(FALSE);
  1605. }
  1606. return(TRUE);
  1607. }
  1608. return(FALSE);
  1609. }
  1610. //+--------------------------------------------------------------------------
  1611. //
  1612. // Function: SetupINFAsUCS2
  1613. //
  1614. // Synopsis: Dumps some UCS-2 to the specified INF file if it
  1615. // doesn't already exist; this makes the .inf/.ini manipulation code
  1616. // use UCS-2.
  1617. //
  1618. // Arguments: The file to create and dump to
  1619. //
  1620. // Returns: 0 == failure, non-zero == success; use GetLastError()
  1621. // to retrieve the error code (same as WriteFile).
  1622. //
  1623. //+--------------------------------------------------------------------------
  1624. BOOL
  1625. SetupINFAsUCS2(LPCTSTR szName)
  1626. {
  1627. HANDLE file;
  1628. BOOL status;
  1629. file = CreateFile(szName,
  1630. GENERIC_READ | GENERIC_WRITE,
  1631. 0,
  1632. NULL,
  1633. CREATE_NEW,
  1634. FILE_ATTRIBUTE_NORMAL,
  1635. NULL);
  1636. if (file == INVALID_HANDLE_VALUE) {
  1637. if (GetLastError() != ERROR_ALREADY_EXISTS)
  1638. // Well, this isn't good -- we lose.
  1639. status = FALSE;
  1640. else
  1641. // Otherwise, the file already existed, which is just fine.
  1642. // We'll just let the .inf/.ini manipulation code keep using
  1643. // the same charset&encoding...
  1644. status = TRUE;
  1645. } else {
  1646. // We created the file -- it didn't exist.
  1647. // So we need to spew a little UCS-2 into it.
  1648. static WCHAR str[] = L"0[Unicode]\r\nUnicode=yes\r\n";
  1649. DWORD n_written;
  1650. BYTE *pbStr = (BYTE *)str;
  1651. pbStr[0] = 0xFF;
  1652. pbStr[1] = 0xFE;
  1653. status = WriteFile(file,
  1654. (LPCVOID)str,
  1655. sizeof(str) - sizeof(UNICODE_NULL),
  1656. &n_written,
  1657. NULL);
  1658. CloseHandle(file);
  1659. }
  1660. return status;
  1661. }
  1662. //+--------------------------------------------------------------------------
  1663. //
  1664. // Function: ScepStripPrefix
  1665. //
  1666. // Arguments: pwszPath to look in
  1667. //
  1668. // Returns: Returns ptr to stripped path (same if no stripping)
  1669. //
  1670. //+--------------------------------------------------------------------------
  1671. WCHAR *
  1672. ScepStripPrefix(
  1673. IN LPTSTR pwszPath
  1674. )
  1675. {
  1676. WCHAR wszMachPrefix[] = TEXT("LDAP://CN=Machine,");
  1677. INT iMachPrefixLen = lstrlen( wszMachPrefix );
  1678. WCHAR wszUserPrefix[] = TEXT("LDAP://CN=User,");
  1679. INT iUserPrefixLen = lstrlen( wszUserPrefix );
  1680. WCHAR *pwszPathSuffix;
  1681. //
  1682. // Strip out prefix to get the canonical path to Gpo
  1683. //
  1684. if ( CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1685. pwszPath, iUserPrefixLen, wszUserPrefix, iUserPrefixLen ) == CSTR_EQUAL ) {
  1686. pwszPathSuffix = pwszPath + iUserPrefixLen;
  1687. } else if ( CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1688. pwszPath, iMachPrefixLen, wszMachPrefix, iMachPrefixLen ) == CSTR_EQUAL ) {
  1689. pwszPathSuffix = pwszPath + iMachPrefixLen;
  1690. } else
  1691. pwszPathSuffix = pwszPath;
  1692. return pwszPathSuffix;
  1693. }
  1694. //+--------------------------------------------------------------------------
  1695. //
  1696. // Function: ScepGenerateGuid
  1697. //
  1698. // Arguments: out: the guid string
  1699. //
  1700. // Returns: Returns guid string (has to be freed outside
  1701. //
  1702. //+--------------------------------------------------------------------------
  1703. /*
  1704. DWORD
  1705. ScepGenerateGuid(
  1706. OUT PWSTR *ppwszGuid
  1707. )
  1708. {
  1709. GUID guid;
  1710. DWORD rc = ERROR_SUCCESS;
  1711. if (ppwszGuid == NULL)
  1712. return ERROR_INVALID_PARAMETER;
  1713. *ppwszGuid = (PWSTR) ScepAlloc(LMEM_ZEROINIT, (MAX_GUID_STRING_LEN + 1) * sizeof(WCHAR));
  1714. if (*ppwszGuid) {
  1715. if (ERROR_SUCCESS == (rc = ScepWbemErrorToDosError(CoCreateGuid( &guid )))) {
  1716. if (!SCEP_NULL_GUID(guid))
  1717. SCEP_GUID_TO_STRING(guid, *ppwszGuid);
  1718. else {
  1719. rc = ERROR_INVALID_PARAMETER;
  1720. }
  1721. }
  1722. } else
  1723. rc = ERROR_NOT_ENOUGH_MEMORY;
  1724. return rc;
  1725. }
  1726. */
  1727. SCESTATUS
  1728. SceInfpGetPrivileges(
  1729. IN HINF hInf,
  1730. IN BOOL bLookupAccount,
  1731. OUT PSCE_PRIVILEGE_ASSIGNMENT *pPrivileges,
  1732. OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
  1733. )
  1734. /* ++
  1735. Description:
  1736. Get user right assignments from a INF template. If bLookupAccount is set
  1737. to TRUE, the accounts in user right assignments will be translated to
  1738. account names (from SID format); else the information is returned in
  1739. the same way as defined in the template.
  1740. Arguments:
  1741. Return Value:
  1742. -- */
  1743. {
  1744. INFCONTEXT InfLine;
  1745. SCESTATUS rc=SCESTATUS_SUCCESS;
  1746. PSCE_PRIVILEGE_ASSIGNMENT pCurRight=NULL;
  1747. WCHAR Keyname[SCE_KEY_MAX_LENGTH];
  1748. PWSTR StrValue=NULL;
  1749. DWORD DataSize;
  1750. DWORD PrivValue;
  1751. DWORD i, cFields;
  1752. LSA_HANDLE LsaHandle=NULL;
  1753. //
  1754. // [Privilege Rights] section
  1755. //
  1756. if(SetupFindFirstLine(hInf,szPrivilegeRights,NULL,&InfLine)) {
  1757. //
  1758. // open lsa policy handle for sid/name lookup
  1759. //
  1760. rc = RtlNtStatusToDosError(
  1761. ScepOpenLsaPolicy(
  1762. POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
  1763. &LsaHandle,
  1764. TRUE
  1765. ));
  1766. if ( ERROR_SUCCESS != rc ) {
  1767. ScepBuildErrorLogInfo(
  1768. rc,
  1769. Errlog,
  1770. SCEERR_ADD,
  1771. TEXT("LSA")
  1772. );
  1773. return(ScepDosErrorToSceStatus(rc));
  1774. }
  1775. do {
  1776. memset(Keyname, '\0', SCE_KEY_MAX_LENGTH*sizeof(WCHAR));
  1777. rc = SCESTATUS_SUCCESS;
  1778. if ( SetupGetStringField(&InfLine, 0, Keyname,
  1779. SCE_KEY_MAX_LENGTH, NULL) ) {
  1780. //
  1781. // find a key name (which is a privilege name here ).
  1782. // lookup privilege's value
  1783. //
  1784. if ( ( PrivValue = ScepLookupPrivByName(Keyname) ) == -1 ) {
  1785. ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
  1786. Errlog,
  1787. SCEERR_INVALID_PRIVILEGE,
  1788. Keyname
  1789. );
  1790. // goto NextLine;
  1791. }
  1792. //
  1793. // a sm_privilege_assignment structure. allocate buffer
  1794. //
  1795. pCurRight = (PSCE_PRIVILEGE_ASSIGNMENT)ScepAlloc( LMEM_ZEROINIT,
  1796. sizeof(SCE_PRIVILEGE_ASSIGNMENT) );
  1797. if ( pCurRight == NULL ) {
  1798. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1799. goto Done;
  1800. }
  1801. pCurRight->Name = (PWSTR)ScepAlloc( (UINT)0, (wcslen(Keyname)+1)*sizeof(WCHAR));
  1802. if ( pCurRight->Name == NULL ) {
  1803. ScepFree(pCurRight);
  1804. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1805. goto Done;
  1806. }
  1807. wcscpy(pCurRight->Name, Keyname);
  1808. pCurRight->Value = PrivValue;
  1809. cFields = SetupGetFieldCount( &InfLine );
  1810. for ( i=0; i<cFields && rc==SCESTATUS_SUCCESS; i++) {
  1811. //
  1812. // read each user/group name
  1813. //
  1814. if ( SetupGetStringField( &InfLine, i+1, NULL, 0, &DataSize ) ) {
  1815. if (DataSize > 1) {
  1816. StrValue = (PWSTR)ScepAlloc( 0, (DataSize+1)*sizeof(WCHAR) );
  1817. if ( StrValue == NULL )
  1818. rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
  1819. else {
  1820. StrValue[DataSize] = L'\0';
  1821. if ( SetupGetStringField( &InfLine, i+1, StrValue,
  1822. DataSize, NULL) ) {
  1823. if ( bLookupAccount && StrValue[0] == L'*' && DataSize > 0 ) {
  1824. //
  1825. // this is a SID format, should look it up
  1826. //
  1827. rc = ScepLookupSidStringAndAddToNameList(
  1828. LsaHandle,
  1829. &(pCurRight->AssignedTo),
  1830. StrValue, // +1,
  1831. DataSize // -1
  1832. );
  1833. } else {
  1834. rc = ScepAddToNameList(&(pCurRight->AssignedTo),
  1835. StrValue,
  1836. DataSize );
  1837. }
  1838. } else
  1839. rc = SCESTATUS_INVALID_DATA;
  1840. }
  1841. ScepFree( StrValue );
  1842. StrValue = NULL;
  1843. }
  1844. } else {
  1845. ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
  1846. Errlog,
  1847. SCEERR_QUERY_INFO,
  1848. Keyname );
  1849. rc = SCESTATUS_INVALID_DATA;
  1850. }
  1851. }
  1852. if ( rc == SCESTATUS_SUCCESS ) {
  1853. //
  1854. // add this node to the list
  1855. //
  1856. pCurRight->Next = *pPrivileges;
  1857. *pPrivileges = pCurRight;
  1858. pCurRight = NULL;
  1859. } else
  1860. ScepFreePrivilege(pCurRight);
  1861. } else
  1862. rc = SCESTATUS_BAD_FORMAT;
  1863. //NextLine:
  1864. if (rc != SCESTATUS_SUCCESS ) {
  1865. ScepBuildErrorLogInfo( ScepSceStatusToDosError(rc),
  1866. Errlog,
  1867. SCEERR_QUERY_INFO,
  1868. szPrivilegeRights
  1869. );
  1870. goto Done;
  1871. }
  1872. } while(SetupFindNextLine(&InfLine,&InfLine));
  1873. }
  1874. Done:
  1875. if ( StrValue != NULL )
  1876. ScepFree(StrValue);
  1877. if ( LsaHandle ) {
  1878. LsaClose(LsaHandle);
  1879. }
  1880. return(rc);
  1881. }
  1882. NTSTATUS
  1883. ScepIsSystemContext(
  1884. IN HANDLE hUserToken,
  1885. OUT BOOL *pbSystem
  1886. )
  1887. {
  1888. NTSTATUS NtStatus;
  1889. DWORD nRequired;
  1890. //
  1891. // variables to determine calling context
  1892. //
  1893. PTOKEN_USER pUser=NULL;
  1894. SID_IDENTIFIER_AUTHORITY ia=SECURITY_NT_AUTHORITY;
  1895. PSID SystemSid=NULL;
  1896. BOOL b;
  1897. //
  1898. // get current user SID in the token
  1899. //
  1900. NtStatus = NtQueryInformationToken (hUserToken,
  1901. TokenUser,
  1902. NULL,
  1903. 0,
  1904. &nRequired
  1905. );
  1906. if ( STATUS_BUFFER_TOO_SMALL == NtStatus ) {
  1907. pUser = (PTOKEN_USER)LocalAlloc(0,nRequired+1);
  1908. if ( pUser ) {
  1909. NtStatus = NtQueryInformationToken (hUserToken,
  1910. TokenUser,
  1911. (PVOID)pUser,
  1912. nRequired,
  1913. &nRequired
  1914. );
  1915. } else {
  1916. NtStatus = STATUS_NO_MEMORY;
  1917. }
  1918. }
  1919. b = FALSE;
  1920. if ( NT_SUCCESS(NtStatus) && pUser && pUser->User.Sid ) {
  1921. //
  1922. // build system sid and compare with the current user SID
  1923. //
  1924. NtStatus = RtlAllocateAndInitializeSid (&ia,1,SECURITY_LOCAL_SYSTEM_RID,
  1925. 0, 0, 0, 0, 0, 0, 0, &SystemSid);
  1926. if ( NT_SUCCESS(NtStatus) && SystemSid ) {
  1927. //
  1928. // check to see if it is system sid
  1929. //
  1930. if ( RtlEqualSid(pUser->User.Sid, SystemSid) ) {
  1931. b=TRUE;
  1932. }
  1933. }
  1934. }
  1935. //
  1936. // free memory allocated
  1937. //
  1938. if ( SystemSid ) {
  1939. FreeSid(SystemSid);
  1940. }
  1941. if ( pUser ) {
  1942. LocalFree(pUser);
  1943. }
  1944. *pbSystem = b;
  1945. return NtStatus;
  1946. }
  1947. BOOL
  1948. IsNT5()
  1949. {
  1950. WCHAR szInfName[MAX_PATH+30];
  1951. szInfName[0] = L'\0';
  1952. DWORD cNumCharsReturned = GetSystemWindowsDirectory(szInfName, MAX_PATH);
  1953. if (cNumCharsReturned)
  1954. {
  1955. wcscat(szInfName, L"\\system32\\$winnt$.inf");
  1956. }
  1957. else {
  1958. return TRUE;
  1959. }
  1960. UINT nRet = GetPrivateProfileInt( L"Networking",
  1961. L"BuildNumber",
  1962. 0,
  1963. szInfName
  1964. );
  1965. if (nRet == 0) {
  1966. return TRUE;
  1967. }
  1968. else if (nRet > 1381) {
  1969. return TRUE;
  1970. }
  1971. return FALSE;
  1972. }
  1973. DWORD
  1974. ScepVerifyTemplateName(
  1975. IN PWSTR InfTemplateName,
  1976. OUT PSCE_ERROR_LOG_INFO *pErrlog OPTIONAL
  1977. )
  1978. /*
  1979. Routine Description:
  1980. This routine verifies the template name for read protection and
  1981. invalid path
  1982. Arguments:
  1983. InfTemplateName - the full path name of the inf template
  1984. pErrlog - the error log buffer
  1985. Return Value:
  1986. WIN32 error code
  1987. */
  1988. {
  1989. if ( !InfTemplateName ) {
  1990. return(ERROR_INVALID_PARAMETER);
  1991. }
  1992. PWSTR DefProfile;
  1993. DWORD rc;
  1994. //
  1995. // verify the InfTemplateName to generate
  1996. // if read only, or access denied, return ERROR_ACCESS_DENIED
  1997. // if invalid path, return ERROR_PATH_NOT_FOUND
  1998. //
  1999. DefProfile = InfTemplateName + wcslen(InfTemplateName)-1;
  2000. while ( DefProfile > InfTemplateName+1 ) {
  2001. if ( *DefProfile != L'\\') {
  2002. DefProfile--;
  2003. } else {
  2004. break;
  2005. }
  2006. }
  2007. rc = NO_ERROR;
  2008. if ( DefProfile > InfTemplateName+2 ) { // at least allow a drive letter, a colon, and a \
  2009. //
  2010. // find the directory path
  2011. //
  2012. DWORD Len=(DWORD)(DefProfile-InfTemplateName);
  2013. PWSTR TmpBuf=(PWSTR)LocalAlloc(0, (Len+1)*sizeof(WCHAR));
  2014. if ( TmpBuf ) {
  2015. wcsncpy(TmpBuf, InfTemplateName, Len);
  2016. TmpBuf[Len] = L'\0';
  2017. if ( 0xFFFFFFFF == GetFileAttributes(TmpBuf) )
  2018. rc = ERROR_PATH_NOT_FOUND;
  2019. LocalFree(TmpBuf);
  2020. } else {
  2021. rc = ERROR_NOT_ENOUGH_MEMORY;
  2022. }
  2023. } else if ( DefProfile == InfTemplateName+2 &&
  2024. InfTemplateName[1] == L':' ) {
  2025. //
  2026. // this is a template path off the root
  2027. //
  2028. } else {
  2029. //
  2030. // invalid directory path
  2031. //
  2032. rc = ERROR_PATH_NOT_FOUND;
  2033. }
  2034. if ( rc != NO_ERROR ) {
  2035. //
  2036. // error occurs
  2037. //
  2038. if ( ERROR_PATH_NOT_FOUND == rc ) {
  2039. ScepBuildErrorLogInfo(
  2040. rc,
  2041. pErrlog,
  2042. SCEERR_INVALID_PATH,
  2043. InfTemplateName
  2044. );
  2045. }
  2046. return(rc);
  2047. }
  2048. //
  2049. // make it unicode aware
  2050. // do not worry about failure
  2051. //
  2052. SetupINFAsUCS2(InfTemplateName);
  2053. //
  2054. // validate if the template is write protected
  2055. //
  2056. FILE *hTempFile;
  2057. hTempFile = _wfopen(InfTemplateName, L"a+");
  2058. if ( !hTempFile ) {
  2059. //
  2060. // can't overwrite/create the file, must be access denied
  2061. //
  2062. rc = ERROR_ACCESS_DENIED;
  2063. ScepBuildErrorLogInfo(
  2064. rc,
  2065. pErrlog,
  2066. SCEERR_ERROR_CREATE,
  2067. InfTemplateName
  2068. );
  2069. return(rc);
  2070. } else {
  2071. fclose( hTempFile );
  2072. }
  2073. return(rc);
  2074. }