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.

1067 lines
30 KiB

  1. /*************************************************************************
  2. *
  3. * inipath.c
  4. *
  5. * Routines to manage per user mapping of Ini file paths
  6. *
  7. * copyright notice: Copyright 1998, Microsoft Corporation
  8. *
  9. *
  10. *
  11. *************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //*** Instance data
  15. ULONG ulWinDirFlags = 0; // State of user's Windows directory
  16. #define WINDIR_FLAGS_VALID 0x01 // The flags are initialized
  17. #define WINDIR_USER_WINDIR_OK 0x02 // User's Windows dir exists
  18. #define WINDOWS_DIR L"WINDOWS"
  19. UNICODE_STRING WindowsDir = { sizeof(WINDOWS_DIR) - sizeof(UNICODE_NULL) , sizeof(WINDOWS_DIR) + sizeof(UNICODE_NULL), WINDOWS_DIR };
  20. WCHAR gpwszDefaultUserName[MAX_PATH+1];
  21. /******************************************************************************
  22. *
  23. * TermsrvPerUserWinDirMapping
  24. *
  25. *
  26. /******************************************************************************/
  27. BOOLEAN TermsrvPerUserWinDirMapping() {
  28. #ifdef PERUSERBYREQUEST
  29. PRTL_USER_PROCESS_PARAMETERS pUserParam;
  30. PWCHAR pwch, pwchext;
  31. WCHAR pwcAppName[MAX_PATH+1];
  32. ULONG ulCompat=0, ulAppType=0;
  33. // Get the path of the executable name
  34. pUserParam = NtCurrentPeb()->ProcessParameters;
  35. // Get the executable name, if there's no \ just use the name as it is
  36. pwch = wcsrchr(pUserParam->ImagePathName.Buffer, L'\\');
  37. if (pwch) {
  38. pwch++;
  39. } else {
  40. pwch = pUserParam->ImagePathName.Buffer;
  41. }
  42. wcscpy(pwcAppName, pwch);
  43. pwch = pwcAppName;
  44. if (_wcsicmp(pwch, L"ntvdm.exe")) {
  45. // If not a 16 bit app
  46. // Check if we should return the per user windows dir for this app
  47. GetCtxAppCompatFlags(&ulCompat, &ulAppType);
  48. if (!(ulCompat & TERMSRV_COMPAT_PERUSERWINDIR) ||
  49. !(ulCompat & ulAppType)) {
  50. //
  51. // Let the standard GetWindowsDirectory call return the actual path
  52. //
  53. return FALSE;
  54. }
  55. }
  56. return TRUE;
  57. #else
  58. ULONG ulCompat=0, ulAppType = 0;
  59. // Check if we should return the system windows dir for this app
  60. GetCtxAppCompatFlags(&ulCompat, &ulAppType);
  61. if ((ulCompat & CITRIX_COMPAT_SYSWINDIR) &&
  62. (ulCompat & ulAppType)) {
  63. return FALSE;
  64. } else {
  65. return TRUE;
  66. }
  67. #endif
  68. }
  69. /******************************************************************************
  70. *
  71. * TermsrvBuildIniFileName
  72. *
  73. * Build the INI file name based on the INIPATH or HOMEPATH (if no INIPATH)
  74. *
  75. * ENTRY:
  76. * pFQName (output)
  77. * Buffer to place fully qualified INI file name
  78. * pBaseFileName (input)
  79. * pointer to buffer containing base INI file name
  80. *
  81. * EXIT:
  82. * NTSTATUS
  83. *
  84. *****************************************************************************/
  85. NTSTATUS
  86. TermsrvBuildIniFileName(
  87. OUT PUNICODE_STRING pFQName,
  88. IN PUNICODE_STRING pBaseFileName
  89. )
  90. {
  91. NTSTATUS Status;
  92. USHORT indexLastWChar;
  93. ULONG ulCompat, ulAppType=0;
  94. //Added By SalimC
  95. /*
  96. * If in install mode, use the base windows directory
  97. * like a stock NT.
  98. */
  99. if( IsSystemLUID() || TermsrvAppInstallMode() ) {
  100. return( STATUS_UNSUCCESSFUL );
  101. }
  102. //END SalimC
  103. if (!TermsrvPerUserWinDirMapping()) {
  104. return( STATUS_UNSUCCESSFUL );
  105. }
  106. #if 0
  107. GetCtxAppCompatFlags(&ulCompat, &ulAppType);
  108. if (((ulCompat & TERMSRV_COMPAT_SYSWINDIR) && (ulCompat & ulAppType))) {
  109. return STATUS_UNSUCCESSFUL;
  110. }
  111. #endif
  112. Status = GetPerUserWindowsDirectory( pFQName );
  113. if ( NT_SUCCESS( Status ) ) {
  114. /*
  115. * Add a '\' if one's not already there
  116. */
  117. if ( indexLastWChar = pFQName->Length / sizeof( WCHAR ) ) {
  118. if ( pFQName->Buffer[--indexLastWChar] != L'\\' ) {
  119. Status = RtlAppendUnicodeToString( pFQName, L"\\" );
  120. }
  121. }
  122. /*
  123. * Append the base file name to the fully qualified directory name
  124. */
  125. if ( NT_SUCCESS( Status ) ) {
  126. Status = RtlAppendUnicodeStringToString( pFQName, pBaseFileName );
  127. }
  128. }
  129. return( Status );
  130. }
  131. /******************************************************************************
  132. *
  133. * GetPerUserWindowsDirectory
  134. *
  135. * Get the user's INI file directory
  136. *
  137. * ENTRY:
  138. * pFQName (output)
  139. * Buffer to place fully qualified INI file name
  140. *
  141. * EXIT:
  142. * NTSTATUS
  143. *
  144. *****************************************************************************/
  145. NTSTATUS
  146. GetPerUserWindowsDirectory(
  147. OUT PUNICODE_STRING pFQName
  148. )
  149. {
  150. NTSTATUS Status;
  151. int indexLastWChar;
  152. USHORT Length;
  153. #if 0 //Bug fix #340691: Inherit the security
  154. PSECURITY_ATTRIBUTES psa = NULL;
  155. #endif //Bug fix #340691: Inherit the security
  156. UNICODE_STRING UserProfilePath;
  157. WCHAR* pwszFQProfileName;
  158. #if DBG
  159. char pszFile[MAX_PATH+1];
  160. #endif
  161. UNICODE_STRING BaseHomePathVariableName, BaseHomeDriveVariableName;
  162. /*
  163. * If in install mode, use the base windows directory
  164. * like a stock NT.
  165. */
  166. if( IsSystemLUID() || TermsrvAppInstallMode() ) {
  167. //Status = GetEnvPath( pFQName, NULL, &BaseWindowsDirectory );
  168. return( STATUS_UNSUCCESSFUL );
  169. }
  170. /*
  171. * Check for HOMEDRIVE and HOMEPATH
  172. */
  173. RtlInitUnicodeString(&BaseHomeDriveVariableName,L"HOMEDRIVE");
  174. RtlInitUnicodeString(&BaseHomePathVariableName,L"HOMEPATH");
  175. if (!NT_SUCCESS(Status = GetEnvPath( pFQName, &BaseHomeDriveVariableName,
  176. &BaseHomePathVariableName ))){
  177. if (Status == STATUS_BUFFER_TOO_SMALL) {
  178. // Need 2 bytes for the "\" character to cat FQN and WindowsDir
  179. Length = pFQName->Length + sizeof(WCHAR) + WindowsDir.Length;
  180. #if DBG
  181. DbgPrint("pFQName->Length = %u WindowsDir.Length = %u Length = %u\n",
  182. pFQName->Length, WindowsDir.Length, Length);
  183. #endif
  184. pFQName->Length = Length;
  185. #if DBG
  186. DbgPrint("\nGetEnvPath return STATUS_BUFFER_TOO_SMALL\n");
  187. #endif
  188. } else {
  189. #if DBG
  190. DbgPrint("GetEnvPath failed with Status %lx\n",Status);
  191. #endif
  192. }
  193. return Status;
  194. }
  195. /*
  196. * If the user profile is Default User then use the
  197. * base windows directory.
  198. */
  199. if (pwszFQProfileName = wcsrchr( pFQName->Buffer, L'\\' )) {
  200. if (_wcsnicmp(pwszFQProfileName+1, gpwszDefaultUserName, MAX_PATH+1) == 0) {
  201. return STATUS_UNSUCCESSFUL;
  202. }
  203. }
  204. /*
  205. * Check buffer length
  206. */
  207. Length = pFQName->Length + sizeof(WCHAR) + WindowsDir.Length;
  208. // take into account the NULL terminator character
  209. if (pFQName->MaximumLength < Length + 1) {
  210. // Need 2 bytes for the NULL terminator
  211. Length += sizeof(WCHAR);
  212. pFQName->Length = Length;
  213. Status = STATUS_BUFFER_TOO_SMALL;
  214. goto done;
  215. }
  216. /*
  217. * Add a trailing backslash if one's not already there
  218. */
  219. if ( indexLastWChar = pFQName->Length / sizeof( WCHAR ) ) {
  220. if ( pFQName->Buffer[--indexLastWChar] != L'\\' ) {
  221. if (NT_SUCCESS(RtlAppendUnicodeToString( pFQName, L"\\" ))) {
  222. /*
  223. * Append "WINDOWS" to home dir
  224. */
  225. Status = RtlAppendUnicodeStringToString( pFQName, &WindowsDir );
  226. }
  227. } else {
  228. Status = RtlAppendUnicodeStringToString( pFQName, &WindowsDir );
  229. }
  230. }
  231. if (NT_SUCCESS(Status)) {
  232. // Check if we've already tried to create the user's windows path
  233. if (ulWinDirFlags & WINDIR_FLAGS_VALID) {
  234. if (ulWinDirFlags & WINDIR_USER_WINDIR_OK) {
  235. goto done;
  236. } else {
  237. Status = STATUS_OBJECT_PATH_INVALID;
  238. }
  239. }
  240. }
  241. if ( NT_SUCCESS(Status) ) {
  242. WCHAR Buffer[MAX_PATH+1];
  243. SECURITY_ATTRIBUTES sa;
  244. BOOL fDirCreated = FALSE;
  245. // Mark this process's windows directory flags as valid
  246. ulWinDirFlags |= WINDIR_FLAGS_VALID;
  247. #if 0 //Bug fix #340691: Inherit the security
  248. /*
  249. * Since creating a security descriptor calls LookupAccountName,
  250. * which is very time consuming, we only do that if we have to
  251. * create the directory (which should rarely happen anyway).
  252. */
  253. if ( CreateDirectoryW( (LPCWSTR)pFQName->Buffer, NULL ) &&
  254. RemoveDirectoryW( (LPCWSTR)pFQName->Buffer ) &&
  255. CtxCreateSecurityDescriptor( &sa ) ) {
  256. psa = &sa;
  257. }
  258. /*
  259. * Create windows directory if it doesn't exist
  260. */
  261. if ( !CreateDirectoryW( (LPCWSTR)pFQName->Buffer, psa ) ) {
  262. #endif //Bug fix #340691: Inherit the security
  263. if ( !CreateDirectoryW( (LPCWSTR)pFQName->Buffer, NULL ) ) {
  264. if ( (Status = GetLastError()) == ERROR_ALREADY_EXISTS ) {
  265. Status = STATUS_SUCCESS;
  266. }
  267. #if DBG
  268. else {
  269. wcstombs( pszFile, pFQName->Buffer, sizeof(pszFile) );
  270. DbgPrint( "KERNEL32: Error (%d) creating dir '%s'\n",
  271. Status, pszFile );
  272. }
  273. #endif
  274. } else {
  275. fDirCreated = TRUE;
  276. }
  277. if (NT_SUCCESS(Status)) {
  278. /*
  279. * Create system directory if it doesn't exist
  280. * (ignore return code)
  281. */
  282. wcscpy( Buffer, pFQName->Buffer );
  283. wcscat( Buffer, L"\\system" );
  284. /*
  285. * If the user's WINDOWS directory already existed but the
  286. * WINDOWS\SYSTEM directory didn't, we need to create the
  287. * security descriptor (this scenario is even rarer).
  288. */
  289. #if 0 //Bug fix #340691: Inherit the security
  290. if ( !psa && !fDirCreated &&
  291. CreateDirectoryW( (LPCWSTR)Buffer, NULL ) &&
  292. RemoveDirectoryW( (LPCWSTR)Buffer ) &&
  293. CtxCreateSecurityDescriptor( &sa ) ) {
  294. psa = &sa;
  295. }
  296. if ( !CreateDirectoryW( (LPCWSTR)Buffer, psa ) ) {
  297. #endif
  298. if ( !CreateDirectoryW( (LPCWSTR)Buffer, NULL ) ) {
  299. #if DBG
  300. if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
  301. wcstombs( pszFile, Buffer, sizeof(pszFile) );
  302. DbgPrint( "KERNEL32: Error (%d) creating dir '%s'\n",
  303. GetLastError(), pszFile );
  304. }
  305. #endif
  306. }
  307. ulWinDirFlags |= WINDIR_USER_WINDIR_OK;
  308. }
  309. }
  310. done:
  311. #if 0 //Bug fix #340691: Inherit the security
  312. if ( psa ) {
  313. CtxFreeSecurityDescriptor( psa );
  314. }
  315. #endif //Bug fix #340691: Inherit the security
  316. #if DDBG
  317. wcstombs( pszFile, pFQName->Buffer, sizeof(pszFile) );
  318. DbgPrint( "KERNEL32: ctxwindir='%s'\n", Status ? "Error" : pszFile );
  319. #endif
  320. return( Status );
  321. }
  322. /******************************************************************************
  323. *
  324. * GetEnvPath
  325. *
  326. * Retrieve a fully qualified path derived from a drive and dir env variable
  327. *
  328. * ENTRY:
  329. * pFQPath (output)
  330. * Buffer to place fully qualified path name
  331. * pDriveVariableName (input)
  332. * pointer to buffer containing env variable name for drive
  333. * if NULL, pPathVariableName is a FQPath and no env vars are used
  334. * pPathVariableName (input)
  335. * pointer to buffer containing env variable name for dir
  336. *
  337. * EXIT:
  338. * NTSTATUS
  339. *
  340. * If NTSTATUS is STATUS_BUFFER_TOO_SMALL, pFQPath->Length will be set
  341. * to the buffer size needed.
  342. *
  343. *****************************************************************************/
  344. NTSTATUS
  345. GetEnvPath(
  346. OUT PUNICODE_STRING pFQPath,
  347. IN PUNICODE_STRING pDriveVariableName,
  348. IN PUNICODE_STRING pPathVariableName
  349. )
  350. {
  351. NTSTATUS Status = STATUS_SUCCESS;
  352. UNICODE_STRING Path;
  353. USHORT Length;
  354. if ( pDriveVariableName ) {
  355. /*
  356. * First let's figure out how big the buffer needs to be
  357. * We need to do this in case the buffer is too small and we
  358. * need to return the required size
  359. */
  360. RtlInitUnicodeString( &Path, NULL );
  361. /*
  362. * See if an env variable is defined for the drive
  363. */
  364. Status = RtlQueryEnvironmentVariable_U( NULL, pDriveVariableName,
  365. &Path);
  366. switch ( Status ) {
  367. case STATUS_BUFFER_TOO_SMALL:
  368. Length = Path.Length; // Count how big this the drive spec is
  369. break;
  370. case STATUS_SUCCESS:
  371. Status = STATUS_OBJECT_NAME_NOT_FOUND; // Something's wrong!
  372. default:
  373. goto done;
  374. break;
  375. }
  376. /*
  377. * See if an env variable is defined for the directory
  378. */
  379. Path.Length = 0;
  380. Status = RtlQueryEnvironmentVariable_U( NULL, pPathVariableName,
  381. &Path);
  382. switch ( Status ) {
  383. case STATUS_BUFFER_TOO_SMALL:
  384. Length += Path.Length; // Count how big this the dir spec is
  385. break;
  386. case STATUS_SUCCESS:
  387. Status = STATUS_OBJECT_NAME_NOT_FOUND; // Something's wrong!
  388. default:
  389. goto done;
  390. break;
  391. }
  392. /*
  393. * If the buffer is too small, return the max size needed
  394. */
  395. if ( Length + sizeof(WCHAR) > pFQPath->MaximumLength ) {
  396. Status = STATUS_BUFFER_TOO_SMALL;
  397. pFQPath->Length = Length + sizeof(WCHAR); // return size
  398. goto done;
  399. }
  400. /*
  401. * Get the env variable for the drive - should work if we got this far
  402. */
  403. if ( Status = RtlQueryEnvironmentVariable_U( NULL, pDriveVariableName,
  404. pFQPath) ) {
  405. goto done;
  406. }
  407. /*
  408. * Setup a receive buffer that points to the proper spot in pFQPath
  409. */
  410. Length = pFQPath->Length; // Save the drive length
  411. Path.Length = 0;
  412. Path.MaximumLength = pFQPath->MaximumLength - Length;
  413. (ULONG_PTR)Path.Buffer = (ULONG_PTR)pFQPath->Buffer + (ULONG)Length;
  414. /*
  415. * Get the env variable for the directory - should work if we got this far
  416. * Then append it to the end of the drive spec
  417. */
  418. if ( Status = RtlQueryEnvironmentVariable_U( NULL, pPathVariableName,
  419. &Path) ) {
  420. goto done;
  421. }
  422. /*
  423. * Fix up the structure and we're done
  424. */
  425. pFQPath->Length = Path.Length + Length;
  426. } else {
  427. /*
  428. * pPathVariableName is really the FQ directory name
  429. */
  430. if ( (pPathVariableName->Length + sizeof(WCHAR)) > pFQPath->MaximumLength ) {
  431. Status = STATUS_BUFFER_TOO_SMALL;
  432. pFQPath->Length = pPathVariableName->Length + sizeof(WCHAR); // return size
  433. } else {
  434. RtlCopyUnicodeString( pFQPath, pPathVariableName );
  435. }
  436. }
  437. done:
  438. return( Status );
  439. }
  440. /******************************************************************************
  441. *
  442. * TermsrvConvertSysRootToUserDir
  443. *
  444. * People who use INI files should never have to fully qualify them, but some
  445. * people do anyway. What's more, some people do it wrong. For example,
  446. * Microsoft PowerPoint 4.0 will call GetSystemDir (not GetWindowsDir) and
  447. * will strip off "\system" to build a fully qualified path.
  448. *
  449. * ENTRY:
  450. * pFQPath (input/output)
  451. * Buffer containing fully qualified path name
  452. *
  453. * EXIT:
  454. * NTSTATUS
  455. *
  456. * If NTSTATUS is not STATUS_SUCCESS, the directory was not converted
  457. *
  458. *****************************************************************************/
  459. NTSTATUS
  460. TermsrvConvertSysRootToUserDir(
  461. OUT PUNICODE_STRING pFQPath,
  462. IN PUNICODE_STRING BaseWindowsDirectory
  463. )
  464. {
  465. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  466. PWSTR p;
  467. INT_PTR c;
  468. WCHAR buffer[MAX_PATH+1];
  469. UNICODE_STRING BaseFileName;
  470. #if DDBG
  471. char pszFile[MAX_PATH+1];
  472. #endif
  473. ULONG ulCompat, ulAppType=0;
  474. /*
  475. * If in install mode, use the base windows directory
  476. * like a stock NT.
  477. */
  478. if( IsSystemLUID() || TermsrvAppInstallMode() ) {
  479. goto done;
  480. }
  481. #if 0
  482. GetCtxAppCompatFlags(&ulCompat, &ulAppType);
  483. if (((ulCompat & TERMSRV_COMPAT_SYSWINDIR) && (ulCompat & ulAppType))) {
  484. goto done;
  485. }
  486. #endif
  487. if (!TermsrvPerUserWinDirMapping()) {
  488. goto done;
  489. }
  490. /*
  491. * Check for NULL pointers
  492. */
  493. if ( !pFQPath || !pFQPath->Buffer ) {
  494. #if DBG
  495. DbgPrint( "KERNEL32: Bogus ini path\n" );
  496. #endif
  497. goto done;
  498. }
  499. /*
  500. * Validate and isolate the path
  501. */
  502. if ( !(p = wcsrchr( pFQPath->Buffer, L'\\' ) ) ) {
  503. #if DBG
  504. DbgPrint( "KERNEL32: No backslash in ini path\n" );
  505. #endif
  506. goto done;
  507. }
  508. c = (INT_PTR)((ULONG_PTR)p - (ULONG_PTR)pFQPath->Buffer);
  509. #if DDBG
  510. wcstombs( pszFile, BaseWindowsDirectory->Buffer, sizeof(pszFile) );
  511. DbgPrint( "KERNEL32: c(%d) c2(%d) BaseWinDir: '%s'\n",
  512. c, (int)BaseWindowsDirectory->Length, pszFile );
  513. wcstombs( pszFile, p, sizeof(pszFile) );
  514. DbgPrint( "KERNEL32: BaseFileName: '%s'\n", pszFile );
  515. #endif
  516. if ( c != (INT_PTR)BaseWindowsDirectory->Length ) {
  517. #if DDBG
  518. DbgPrint( "KERNEL32: Path length diff from BaseWinDir length\n" );
  519. #endif
  520. goto done;
  521. }
  522. /*
  523. * See if the path is the same as the base windows directory
  524. */
  525. c /= sizeof(WCHAR);
  526. if ( _wcsnicmp( BaseWindowsDirectory->Buffer, pFQPath->Buffer, (size_t)c ) ) {
  527. #if DDBG
  528. DbgPrint( "KERNEL32: Path diff from BaseWinDir\n" );
  529. #endif
  530. goto done;
  531. }
  532. /*
  533. * Use the user's directory instead
  534. */
  535. wcscpy( buffer, ++p );
  536. RtlInitUnicodeString( &BaseFileName, buffer );
  537. Status = TermsrvBuildIniFileName( pFQPath, &BaseFileName );
  538. done:
  539. #if DDBG
  540. wcstombs( pszFile, pFQPath->Buffer, sizeof(pszFile) );
  541. DbgPrint( "KERNEL32: Exit(%x) ConvertSystemRootToUserDir: '%s'\n",
  542. Status, pszFile );
  543. #endif
  544. return( Status );
  545. }
  546. /******************************************************************************
  547. *
  548. * CtxCreateSecurityDescriptor
  549. *
  550. * This routine will create a security descriptor based on the specified
  551. * generic flags. If this function succeeds, the caller needs to call
  552. * CtxFreeSecurityDescriptor() when it is done using the descriptor.
  553. *
  554. * ENTRY:
  555. * psa (output)
  556. * Pointer to uninitialized security attributes structure
  557. *
  558. * EXIT:
  559. * TRUE if successful, FALSE if error occurred
  560. *
  561. * (GetLastError() can be called to retrieve error code)
  562. *
  563. *****************************************************************************/
  564. #if 0 //Bug fix #340691: Inherit the security
  565. BOOL CtxCreateSecurityDescriptor( PSECURITY_ATTRIBUTES psa )
  566. {
  567. BOOL fSuccess = FALSE;
  568. NTSTATUS Status;
  569. PSID psidAdmin, psidUser;
  570. UINT cb = sizeof( SECURITY_DESCRIPTOR ) + 2 * sizeof(PSID);
  571. UINT cbAcl = sizeof(ACL);
  572. PACL pAcl;
  573. PSID *ppsidAdmin, *ppsidUser;
  574. SID_IDENTIFIER_AUTHORITY gSystemSidAuthority = SECURITY_NT_AUTHORITY;
  575. HANDLE hUserToken;
  576. PTOKEN_USER pTokenUser = NULL;
  577. DWORD cbNeeded;
  578. /*
  579. * Initialize pointers to dynamic memory blocks
  580. */
  581. psa->lpSecurityDescriptor = NULL;
  582. psidAdmin = NULL;
  583. psidUser = NULL;
  584. /*
  585. * Get the SID of the bult-in Administrators group
  586. */
  587. Status = RtlAllocateAndInitializeSid(
  588. &gSystemSidAuthority,
  589. 2,
  590. SECURITY_BUILTIN_DOMAIN_RID,
  591. DOMAIN_ALIAS_RID_ADMINS,
  592. 0,0,0,0,0,0,
  593. &psidAdmin);
  594. if (!NT_SUCCESS(Status)) {
  595. #if DBG
  596. DbgPrint("KERNEL32: Couldn't allocate Administrators SID (0x%x)\n", Status );
  597. #endif
  598. goto done;
  599. }
  600. /*
  601. * Get the SID for the current user from their process token
  602. */
  603. Status = NtOpenThreadToken(
  604. NtCurrentThread(),
  605. TOKEN_QUERY,
  606. TRUE,
  607. &hUserToken);
  608. if (Status == STATUS_NO_TOKEN) {
  609. Status = NtOpenProcessToken(
  610. NtCurrentProcess(),
  611. TOKEN_QUERY,
  612. &hUserToken);
  613. }
  614. if (!NT_SUCCESS(Status)) {
  615. #if DBG
  616. DbgPrint("KERNEL32: Couldn't access process' token (0x%x)\n", Status );
  617. #endif
  618. RtlFreeHeap( RtlProcessHeap(), 0, psidAdmin );
  619. goto done;
  620. }
  621. Status = NtQueryInformationToken(
  622. hUserToken,
  623. TokenUser,
  624. NULL,
  625. 0,
  626. &cbNeeded );
  627. if (Status == STATUS_BUFFER_TOO_SMALL) {
  628. pTokenUser = (PTOKEN_USER)RtlAllocateHeap( RtlProcessHeap(), 0, cbNeeded );
  629. if (pTokenUser != NULL) {
  630. Status = NtQueryInformationToken(
  631. hUserToken,
  632. TokenUser,
  633. (LPVOID)pTokenUser,
  634. cbNeeded,
  635. &cbNeeded );
  636. if (NT_SUCCESS(Status)) {
  637. /*
  638. * Make a copy of the user's SID
  639. */
  640. psidUser = RtlAllocateHeap( RtlProcessHeap(), 0, RtlLengthSid(pTokenUser->User.Sid) );
  641. if (psidUser != NULL) {
  642. Status = RtlCopySid( RtlLengthSid(pTokenUser->User.Sid), psidUser, pTokenUser->User.Sid );
  643. } else {
  644. Status = STATUS_NO_MEMORY;
  645. }
  646. }
  647. } else {
  648. Status = STATUS_NO_MEMORY;
  649. }
  650. }
  651. if (pTokenUser != NULL) {
  652. RtlFreeHeap( RtlProcessHeap(), 0, pTokenUser );
  653. }
  654. NtClose(hUserToken);
  655. if (!NT_SUCCESS(Status)) {
  656. #if DBG
  657. DbgPrint("KERNEL32: Couldn't query user's token (0x%x)\n", Status );
  658. #endif
  659. RtlFreeHeap( RtlProcessHeap(), 0, psidAdmin );
  660. if (psidUser != NULL) {
  661. RtlFreeHeap( RtlProcessHeap(), 0, psidUser );
  662. }
  663. goto done;
  664. }
  665. /*
  666. * Figure out how much memory we need to allocate for the SD
  667. */
  668. cbAcl += sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid( psidUser ) - sizeof(DWORD);
  669. cbAcl += sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid( psidAdmin ) - sizeof(DWORD);
  670. /*
  671. * Allocate all the memory we need for the security descriptor
  672. */
  673. if ( !(psa->lpSecurityDescriptor =
  674. (PSECURITY_DESCRIPTOR)LocalAlloc( LPTR, cb + cbAcl ) ) ) {
  675. #if DBG
  676. DbgPrint("KERNEL32: No memory to create security descriptor (%d)\n",
  677. cb + cbAcl);
  678. #endif
  679. goto done;
  680. }
  681. /*
  682. * Divvy up our memory block to include SIDs and ACLs
  683. */
  684. ppsidAdmin = (PSID*)((ULONG_PTR)psa->lpSecurityDescriptor + sizeof(SECURITY_DESCRIPTOR));
  685. ppsidUser = (PSID*)((ULONG_PTR)ppsidAdmin + sizeof(PSID));
  686. pAcl = (PACL)((ULONG_PTR)ppsidUser + sizeof(PSID));
  687. /*
  688. * Save the SIDs - the SIDs must not be freed until we're done
  689. * using the security descriptor
  690. */
  691. *ppsidAdmin = psidAdmin;
  692. *ppsidUser = psidUser;
  693. /*
  694. * Initialize the rest of the security attributes structure
  695. */
  696. psa->nLength = sizeof( SECURITY_ATTRIBUTES );
  697. psa->bInheritHandle = FALSE;
  698. /*
  699. * Initialize the security descriptor
  700. */
  701. if ( Status = RtlCreateSecurityDescriptor(
  702. psa->lpSecurityDescriptor,
  703. SECURITY_DESCRIPTOR_REVISION ) ) {
  704. #if DBG
  705. DbgPrint( "KERNEL32: Error (%08X) initializing security descriptor\n",
  706. Status );
  707. #endif
  708. goto done;
  709. }
  710. /*
  711. * Set the owner
  712. */
  713. if ( Status = RtlSetOwnerSecurityDescriptor( psa->lpSecurityDescriptor,
  714. NULL, FALSE ) ) {
  715. #if DBG
  716. DbgPrint( "KERNEL32: Error (%08X) setting security descriptor owner\n",
  717. Status );
  718. #endif
  719. goto done;
  720. }
  721. /*
  722. * Set the group
  723. */
  724. if ( Status = RtlSetGroupSecurityDescriptor( psa->lpSecurityDescriptor,
  725. psidAdmin, FALSE ) ) {
  726. #if DBG
  727. DbgPrint( "KERNEL32: Error (%08X) setting security descriptor owner\n",
  728. Status );
  729. #endif
  730. goto done;
  731. }
  732. /*
  733. * Initialize the ACL
  734. */
  735. if ( Status = RtlCreateAcl( pAcl, cbAcl, ACL_REVISION ) ) {
  736. #if DBG
  737. DbgPrint( "KERNEL32: Error (%08X) initializing ACL\n",
  738. Status );
  739. #endif
  740. goto done;
  741. }
  742. /*
  743. * Add user ACE
  744. */
  745. if ( Status = CtxAddAccessAllowedAce( pAcl, ACL_REVISION, GENERIC_ALL, psidUser, 0 ) ) {
  746. #if DBG
  747. DbgPrint( "KERNEL32: Error (%08X) adding user ACE\n", Status );
  748. #endif
  749. goto done;
  750. }
  751. /*
  752. * Add Administrators ACE
  753. */
  754. if ( Status = CtxAddAccessAllowedAce( pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin, 1 ) ) {
  755. #if DBG
  756. DbgPrint( "KERNEL32: Error (%08X) adding admin ACE\n", Status );
  757. #endif
  758. goto done;
  759. }
  760. /*
  761. * Set the discretionary ACL
  762. */
  763. if ( Status = RtlSetDaclSecurityDescriptor( psa->lpSecurityDescriptor,
  764. TRUE, pAcl, FALSE ) ) {
  765. #if DBG
  766. DbgPrint( "KERNEL32: Error (%08X) setting security descriptor owner\n",
  767. Status );
  768. #endif
  769. goto done;
  770. }
  771. fSuccess = TRUE;
  772. done:
  773. if ( !fSuccess && psa->lpSecurityDescriptor ) {
  774. CtxFreeSecurityDescriptor( psa );
  775. }
  776. return( fSuccess );
  777. }
  778. /******************************************************************************
  779. *
  780. * CtxFreeSecurityDescriptor
  781. *
  782. * This routine will free resources allocated in a corresponding
  783. * CtxCreateSecurityDescriptor() call.
  784. *
  785. * ENTRY:
  786. * psa (input)
  787. * Pointer to security attributes
  788. *
  789. * EXIT:
  790. * TRUE if successful, FALSE if error occurred
  791. *
  792. * (GetLastError() can be called to retrieve error code)
  793. *
  794. *****************************************************************************/
  795. BOOL CtxFreeSecurityDescriptor( PSECURITY_ATTRIBUTES psa )
  796. {
  797. BOOL fSuccess = TRUE;
  798. PSID *ppsidAdmin, *ppsidUser;
  799. if ( psa->lpSecurityDescriptor ) {
  800. ppsidAdmin = (PSID*)((ULONG_PTR)psa->lpSecurityDescriptor + sizeof(SECURITY_DESCRIPTOR));
  801. ppsidUser = (PSID*)((ULONG_PTR)ppsidAdmin + sizeof(PSID));
  802. if ( *ppsidUser ) {
  803. CtxFreeSID( *ppsidUser );
  804. }
  805. if ( *ppsidAdmin ) {
  806. CtxFreeSID( *ppsidAdmin );
  807. }
  808. fSuccess = !LocalFree( psa->lpSecurityDescriptor );
  809. #if DDBG
  810. DbgPrint( "KERNEL32: fSuccess(%d) freeing security descriptor (%08X)\n",
  811. fSuccess, psa->lpSecurityDescriptor );
  812. #endif
  813. }
  814. return( fSuccess );
  815. }
  816. NTSTATUS
  817. CtxAddAccessAllowedAce (
  818. IN OUT PACL Acl,
  819. IN ULONG AceRevision,
  820. IN ACCESS_MASK AccessMask,
  821. IN PSID Sid,
  822. IN DWORD index
  823. )
  824. {
  825. NTSTATUS Status;
  826. ACE_HEADER *pHeader;
  827. /*
  828. * First add the ACL
  829. */
  830. if ( !(Status = RtlAddAccessAllowedAce( Acl, AceRevision,
  831. AccessMask, Sid ) ) ) {
  832. /*
  833. * Get the ACE
  834. */
  835. if ( Status = RtlGetAce( Acl, index, &pHeader ) ) {
  836. #if DBG
  837. DbgPrint( "KERNEL32: Error (%X) from RtlGetAce\n", Status );
  838. #endif
  839. goto done;
  840. }
  841. /*
  842. * Now set the inheritence bits
  843. */
  844. pHeader->AceFlags |= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
  845. }
  846. done:
  847. return( Status );
  848. }
  849. #endif //Bug fix #340691: Inherit the security
  850. // from \nt\private\windows\gina\userenv\globals.h
  851. #define PROFILE_LIST_PATH L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
  852. #define DEFAULT_USER_PROFILE L"DefaultUserProfile"
  853. #define DEFAULT_USER L"Default User"
  854. BOOL GetDefaultUserProfileName(
  855. LPWSTR lpProfileDir,
  856. LPDWORD lpcchSize
  857. )
  858. {
  859. WCHAR* pwszProfileName;
  860. BYTE pKeyValueInfo[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+(MAX_PATH+1)*sizeof(WCHAR)];
  861. ULONG ulSize;
  862. DWORD dwLength;
  863. BOOL bRetVal = FALSE;
  864. HKEY hKey;
  865. NTSTATUS Status;
  866. OBJECT_ATTRIBUTES ObjectAttributes;
  867. UNICODE_STRING UnicodeString;
  868. //
  869. // Query for the Default User profile name
  870. //
  871. RtlInitUnicodeString(&UnicodeString, PROFILE_LIST_PATH);
  872. InitializeObjectAttributes(&ObjectAttributes,
  873. &UnicodeString,
  874. OBJ_CASE_INSENSITIVE,
  875. NULL,
  876. NULL);
  877. Status = NtOpenKey( &hKey,
  878. KEY_READ,
  879. &ObjectAttributes );
  880. //lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, PROFILE_LIST_PATH,
  881. // 0, KEY_READ, &hKey);
  882. if (!NT_SUCCESS(Status)) {
  883. #if DBG
  884. DbgPrint("TSAppCmp:GetDefaultUserProfileName: Failed to open profile list key with 0x%x.",Status);
  885. #endif
  886. SetLastError(RtlNtStatusToDosError(Status));
  887. return FALSE;
  888. }
  889. //lResult = RegQueryValueExW(hKey, DEFAULT_USER_PROFILE, NULL, &dwType,
  890. // (LPBYTE) wszProfileName, &dwSize);
  891. RtlInitUnicodeString(&UnicodeString, DEFAULT_USER_PROFILE);
  892. Status = NtQueryValueKey( hKey,
  893. &UnicodeString,
  894. KeyValuePartialInformation,
  895. pKeyValueInfo,
  896. sizeof(pKeyValueInfo),
  897. &ulSize);
  898. pwszProfileName = (WCHAR*)(((PKEY_VALUE_PARTIAL_INFORMATION)pKeyValueInfo)->Data);
  899. if (!NT_SUCCESS(Status)) {
  900. lstrcpy (pwszProfileName, DEFAULT_USER);
  901. }
  902. NtClose(hKey);
  903. //
  904. // Save the result if possible
  905. dwLength = lstrlen(pwszProfileName) + 1;
  906. if (lpProfileDir) {
  907. if (*lpcchSize >= dwLength) {
  908. lstrcpy (lpProfileDir, pwszProfileName);
  909. bRetVal = TRUE;
  910. } else {
  911. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  912. }
  913. } else {
  914. SetLastError(ERROR_INVALID_PARAMETER);
  915. }
  916. *lpcchSize = dwLength;
  917. return bRetVal;
  918. }
  919.