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

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