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.

856 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: security.cxx
  7. //
  8. // Contents:
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "act.hxx"
  12. #include <alloca.h>
  13. #include <ntlsa.h>
  14. #define SECURITY_WIN32
  15. #define SECURITY_KERBEROS
  16. #include <security.h>
  17. #include <secint.h>
  18. // the constant generic mapping structure
  19. GENERIC_MAPPING sGenericMapping = {
  20. READ_CONTROL,
  21. READ_CONTROL,
  22. READ_CONTROL,
  23. READ_CONTROL};
  24. // Well-known low-privilege service account sids
  25. const SID sidLocalSystem = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID };
  26. const SID sidLocalService = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SERVICE_RID };
  27. const SID sidNetworkService = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_NETWORK_SERVICE_RID };
  28. //-------------------------------------------------------------------------
  29. //
  30. // CheckForAccess
  31. //
  32. // Checks whether the given token has COM_RIGHTS_EXECUTE access in the
  33. // given security descriptor.
  34. //
  35. //-------------------------------------------------------------------------
  36. BOOL
  37. CheckForAccess(
  38. IN CToken * pToken,
  39. IN SECURITY_DESCRIPTOR * pSD
  40. )
  41. {
  42. // if we have an empty SD, deny everyone
  43. if (!pSD)
  44. return FALSE;
  45. //
  46. // Some history here: we used to say, if pToken is NULL (implying an
  47. // unsecure activation), parse the security descriptor to see if
  48. // Everyone is granted access, and if so, allow the activation to
  49. // proceed. This was a DCOM-specific policy decision. In .NET Server
  50. // we changed instead to mapping an unsecure (unauthenticated) client
  51. // to the Anonymous identity. (Another DCOM-specific policy decision,
  52. // but it probably makes more sense than the original one). And so we
  53. // no longer parse the security descriptor, instead we just do a
  54. // straight-forward access check.
  55. //
  56. HANDLE hToken = pToken->GetToken();
  57. BOOL fAccess = FALSE;
  58. BOOL fSuccess = FALSE;
  59. DWORD dwGrantedAccess;
  60. PRIVILEGE_SET sPrivilegeSet;
  61. DWORD dwSetLen = sizeof( sPrivilegeSet );
  62. sPrivilegeSet.PrivilegeCount = 1;
  63. sPrivilegeSet.Control = 0;
  64. fSuccess = AccessCheck( (PSECURITY_DESCRIPTOR) pSD,
  65. hToken,
  66. COM_RIGHTS_EXECUTE,
  67. &sGenericMapping,
  68. &sPrivilegeSet,
  69. &dwSetLen,
  70. &dwGrantedAccess,
  71. &fAccess );
  72. if (fSuccess && fAccess)
  73. return TRUE;
  74. if (!fSuccess)
  75. {
  76. CairoleDebugOut((DEB_ERROR, "Bad Security Descriptor 0x%08x, Access Check returned 0x%x\n", pSD, GetLastError() ));
  77. }
  78. return FALSE;
  79. }
  80. HRESULT IsLowPrivilegeServiceAccount (LPCWSTR pwszDomain, LPCWSTR pwszName, BOOL* pfSvcAccount)
  81. {
  82. if (!pwszName || !pfSvcAccount)
  83. {
  84. return E_POINTER;
  85. }
  86. *pfSvcAccount = FALSE;
  87. HRESULT hr = S_OK;
  88. BYTE pbSid [sizeof (sidLocalService)] = {0};
  89. DWORD cbSid = sizeof (pbSid);
  90. WCHAR wszDomain [DNLEN + 1] = {0};
  91. DWORD cchDomain = sizeof (wszDomain) / sizeof (wszDomain[0]);
  92. SID_NAME_USE eUse;
  93. LPCWSTR pwszFullName = pwszName;
  94. LPWSTR pwszCopyFullName = NULL;
  95. // Build the full domain\account string if necessary
  96. if (pwszDomain)
  97. {
  98. SIZE_T cchFullNameLen = lstrlenW (pwszDomain) + 1 + lstrlenW (pwszName) + 1;
  99. SafeAllocaAllocate (pwszCopyFullName, cchFullNameLen * sizeof (WCHAR));
  100. if (!pwszCopyFullName)
  101. {
  102. return E_OUTOFMEMORY;
  103. }
  104. _snwprintf (pwszCopyFullName, cchFullNameLen, L"%s\\%s", pwszDomain, pwszName);
  105. pwszCopyFullName [cchFullNameLen - 1] = L'\0';
  106. pwszFullName = pwszCopyFullName;
  107. }
  108. // Lookup the sid for the account
  109. if (!LookupAccountName(NULL, pwszFullName, pbSid, &cbSid, wszDomain, &cchDomain, &eUse))
  110. {
  111. // Either our sid was too small, or a failure occurred.
  112. // If the former, returning *pfSvcAccount = FALSE is correct
  113. // If the latter, the subsequent call to LogonUser will catch it
  114. hr = S_FALSE;
  115. }
  116. else
  117. {
  118. // Compare to well known service sids
  119. if (eUse == SidTypeWellKnownGroup &&
  120. (EqualSid (pbSid, (PSID) &sidLocalService) || EqualSid (pbSid, (PSID) &sidNetworkService)))
  121. {
  122. *pfSvcAccount = TRUE;
  123. }
  124. }
  125. SafeAllocaFree (pwszCopyFullName);
  126. return hr;
  127. }
  128. HRESULT IsLocalSystemAccount(LPCWSTR pwszDomain, LPCWSTR pwszName, BOOL* pfLocalSystemAccount)
  129. {
  130. if (!pwszName || !pfLocalSystemAccount)
  131. {
  132. return E_POINTER;
  133. }
  134. *pfLocalSystemAccount = FALSE;
  135. HRESULT hr = S_OK;
  136. BYTE pbSid [sizeof (sidLocalSystem)] = {0};
  137. DWORD cbSid = sizeof (pbSid);
  138. WCHAR wszDomain [DNLEN + 1] = {0};
  139. DWORD cchDomain = sizeof (wszDomain) / sizeof (wszDomain[0]);
  140. SID_NAME_USE eUse;
  141. LPCWSTR pwszFullName = pwszName;
  142. LPWSTR pwszCopyFullName = NULL;
  143. // Build the full domain\account string if necessary
  144. if (pwszDomain)
  145. {
  146. SIZE_T cchFullNameLen = lstrlenW (pwszDomain) + 1 + lstrlenW (pwszName) + 1;
  147. SafeAllocaAllocate (pwszCopyFullName, cchFullNameLen * sizeof (WCHAR));
  148. if (!pwszCopyFullName)
  149. {
  150. return E_OUTOFMEMORY;
  151. }
  152. _snwprintf (pwszCopyFullName, cchFullNameLen, L"%s\\%s", pwszDomain, pwszName);
  153. pwszCopyFullName [cchFullNameLen - 1] = L'\0';
  154. pwszFullName = pwszCopyFullName;
  155. }
  156. // Lookup the sid for the account
  157. if (!LookupAccountName(NULL, pwszFullName, pbSid, &cbSid, wszDomain, &cchDomain, &eUse))
  158. {
  159. // Either our sid was too small, or a failure occurred.
  160. // If the former, returning *pfLocalSystemAccount = FALSE is correct
  161. // If the latter, the subsequent call to LogonUser will catch it
  162. hr = S_FALSE;
  163. }
  164. else
  165. {
  166. // Compare to well known service sids
  167. if (eUse == SidTypeWellKnownGroup &&
  168. (EqualSid (pbSid, (PSID) &sidLocalSystem)))
  169. {
  170. *pfLocalSystemAccount = TRUE;
  171. }
  172. }
  173. SafeAllocaFree (pwszCopyFullName);
  174. return hr;
  175. }
  176. HANDLE
  177. GetRunAsToken(
  178. DWORD clsctx,
  179. WCHAR *pwszAppID,
  180. WCHAR *pwszRunAsDomainName,
  181. WCHAR *pwszRunAsUserName,
  182. BOOL fForLaunch)
  183. {
  184. LSA_OBJECT_ATTRIBUTES sObjAttributes;
  185. HANDLE hPolicy = NULL;
  186. LSA_UNICODE_STRING sKey;
  187. WCHAR wszKey[CLSIDSTR_MAX+5];
  188. PLSA_UNICODE_STRING psPassword;
  189. HANDLE hToken;
  190. NTSTATUS Status;
  191. PKERB_INTERACTIVE_LOGON LogonInfo;
  192. ULONG LogonInfoSize = sizeof(KERB_INTERACTIVE_LOGON);
  193. STRING Name;
  194. ULONG PackageId;
  195. TOKEN_SOURCE SourceContext;
  196. PKERB_INTERACTIVE_PROFILE Profile = NULL;
  197. ULONG ProfileSize;
  198. LUID LogonId;
  199. QUOTA_LIMITS Quotas;
  200. NTSTATUS SubStatus;
  201. PUCHAR Where;
  202. UNICODE_STRING usRunAsUserName, usRunAsDomainName;
  203. PTOKEN_GROUPS TokenGroups = NULL;
  204. HRESULT hr = E_FAIL;
  205. if ( !pwszAppID )
  206. {
  207. // if we have a RunAs, we'd better have an appid....
  208. return 0;
  209. }
  210. ASSERT(gLSAHandle);
  211. ASSERT(gSidService);
  212. ASSERT(gpwszDefaultDomainName[0]);
  213. // formulate the access key
  214. lstrcpyW(wszKey, L"SCM:");
  215. lstrcatW(wszKey, pwszAppID );
  216. // UNICODE_STRING length fields are in bytes and include the NULL
  217. // terminator
  218. sKey.Length = (USHORT)((lstrlenW(wszKey) + 1) * sizeof(WCHAR));
  219. sKey.MaximumLength = (CLSIDSTR_MAX + 5) * sizeof(WCHAR);
  220. sKey.Buffer = wszKey;
  221. // Open the local security policy
  222. InitializeObjectAttributes(&sObjAttributes, NULL, 0L, NULL, NULL);
  223. if (!NT_SUCCESS(LsaOpenPolicy(NULL, &sObjAttributes,
  224. POLICY_GET_PRIVATE_INFORMATION, &hPolicy)))
  225. {
  226. return 0;
  227. }
  228. // Read the user's password
  229. if (!NT_SUCCESS(LsaRetrievePrivateData(hPolicy, &sKey, &psPassword)))
  230. {
  231. LsaClose(hPolicy);
  232. return 0;
  233. }
  234. // Close the policy handle, we're done with it now.
  235. LsaClose(hPolicy);
  236. // Possible for LsaRetrievePrivateData to return success but with a NULL
  237. // psPassword. If this happens we fail.
  238. if (!psPassword)
  239. {
  240. return 0;
  241. }
  242. //
  243. // Special case of NT AUTHORITY\System - cannot use LsaLogonUser to obtain such a
  244. // token, so we use our own process token. Note that we currently only support
  245. // this on the server registration code-path, and not the server-launch code path.
  246. //
  247. if (!fForLaunch)
  248. {
  249. BOOL fLocalSystemAccount = FALSE;
  250. hr = IsLocalSystemAccount(pwszRunAsDomainName, pwszRunAsUserName, &fLocalSystemAccount);
  251. if (SUCCEEDED(hr)) // keep going here in case of errors, LsaLogonUser will just fail below.
  252. {
  253. // If SYSTEM and user has supplied a blank password (for compatibility
  254. // reasons), use our own token
  255. if (fLocalSystemAccount && !lstrcmpiW(psPassword->Buffer, L""))
  256. {
  257. BOOL fResult = FALSE;
  258. HANDLE hProcess = NULL;
  259. HANDLE hProcessToken = NULL;
  260. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
  261. if (hProcess)
  262. {
  263. fResult = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hProcessToken);
  264. ASSERT(!fResult || hProcessToken);
  265. CloseHandle(hProcess);
  266. }
  267. return hProcessToken;
  268. }
  269. }
  270. }
  271. BOOLEAN b = RtlCreateUnicodeString(&usRunAsUserName, pwszRunAsUserName);
  272. if (FALSE == b)
  273. {
  274. SecureZeroMemory(psPassword->Buffer, psPassword->Length);
  275. LsaFreeMemory( psPassword );
  276. return 0;
  277. }
  278. if ( (pwszRunAsDomainName[0] == L'.') && (pwszRunAsDomainName[1] == L'\0'))
  279. b = RtlCreateUnicodeString(&usRunAsDomainName, gpwszDefaultDomainName);
  280. else
  281. b = RtlCreateUnicodeString(&usRunAsDomainName, pwszRunAsDomainName);
  282. if (FALSE == b)
  283. {
  284. RtlFreeUnicodeString(&usRunAsUserName);
  285. SecureZeroMemory(psPassword->Buffer, psPassword->Length);
  286. LsaFreeMemory( psPassword );
  287. return 0;
  288. }
  289. LogonInfoSize += usRunAsUserName.MaximumLength + usRunAsDomainName.MaximumLength + psPassword->MaximumLength ;
  290. LogonInfo = (PKERB_INTERACTIVE_LOGON) LocalAlloc(LMEM_ZEROINIT, LogonInfoSize);
  291. if (!LogonInfo)
  292. {
  293. RtlFreeUnicodeString(&usRunAsUserName);
  294. RtlFreeUnicodeString(&usRunAsDomainName);
  295. SecureZeroMemory(psPassword->Buffer, psPassword->Length);
  296. LsaFreeMemory( psPassword );
  297. return NULL;
  298. }
  299. LogonInfo->MessageType = KerbInteractiveLogon;
  300. Where = (PUCHAR) (LogonInfo + 1);
  301. LogonInfo->UserName.Buffer = (LPWSTR) Where;
  302. LogonInfo->UserName.MaximumLength = usRunAsUserName.MaximumLength ;
  303. LogonInfo->UserName.Length = usRunAsUserName.Length ;
  304. RtlCopyMemory( LogonInfo->UserName.Buffer,
  305. usRunAsUserName.Buffer,
  306. usRunAsUserName.MaximumLength );
  307. Where += LogonInfo->UserName.Length + sizeof(WCHAR);
  308. LogonInfo->LogonDomainName.Buffer = (LPWSTR) Where ;
  309. LogonInfo->LogonDomainName.MaximumLength = usRunAsDomainName.MaximumLength;
  310. LogonInfo->LogonDomainName.Length = usRunAsDomainName.Length ;
  311. RtlCopyMemory( LogonInfo->LogonDomainName.Buffer,
  312. usRunAsDomainName.Buffer,
  313. usRunAsDomainName.MaximumLength );
  314. Where += LogonInfo->LogonDomainName.Length + sizeof(WCHAR);
  315. LogonInfo->Password.Buffer = (LPWSTR) Where;
  316. LogonInfo->Password.MaximumLength = psPassword->MaximumLength;
  317. LogonInfo->Password.Length = psPassword->Length - sizeof(WCHAR); // The LSA API retrives length=maxlength
  318. RtlCopyMemory( LogonInfo->Password.Buffer,
  319. psPassword->Buffer,
  320. LogonInfo->Password.MaximumLength );
  321. // Clear the password
  322. SecureZeroMemory(psPassword->Buffer, psPassword->Length);
  323. LsaFreeMemory( psPassword );
  324. RtlFreeUnicodeString(&usRunAsUserName);
  325. RtlFreeUnicodeString(&usRunAsDomainName);
  326. Where += LogonInfo->Password.Length + sizeof(WCHAR);
  327. strncpy(
  328. SourceContext.SourceName,
  329. "DCOMSCM",sizeof(SourceContext.SourceName)
  330. );
  331. Status = NtAllocateLocallyUniqueId(
  332. &SourceContext.SourceIdentifier
  333. );
  334. if (!NT_SUCCESS(Status))
  335. {
  336. SecureZeroMemory(LogonInfo, LogonInfoSize);
  337. LocalFree(LogonInfo);
  338. return NULL ;
  339. }
  340. RtlInitString( &Name, NEGOSSP_NAME_A);
  341. Status = LsaLookupAuthenticationPackage(
  342. gLSAHandle,
  343. &Name,
  344. &PackageId
  345. );
  346. if (!NT_SUCCESS(Status))
  347. {
  348. SecureZeroMemory(LogonInfo, LogonInfoSize);
  349. LocalFree(LogonInfo);
  350. return NULL ;
  351. }
  352. //
  353. // Now call LsaLogonUser
  354. //
  355. RtlInitString(
  356. &Name,
  357. "DCOMSCM"
  358. );
  359. BOOL fSvcAccount = FALSE;
  360. if (FAILED (IsLowPrivilegeServiceAccount (pwszRunAsDomainName, pwszRunAsUserName, &fSvcAccount)))
  361. {
  362. SecureZeroMemory(LogonInfo, LogonInfoSize);
  363. LocalFree(LogonInfo);
  364. return NULL;
  365. }
  366. // Service accounts should have blank passwords
  367. ASSERT (!fSvcAccount || (psPassword->Buffer && !psPassword->Buffer[0]));
  368. #define TOKEN_GROUP_COUNT 1
  369. // if local/network service, no need to add the serivce SID
  370. if (!fSvcAccount)
  371. {
  372. TokenGroups = (PTOKEN_GROUPS)LocalAlloc(LMEM_ZEROINIT, sizeof(TOKEN_GROUPS) +
  373. (TOKEN_GROUP_COUNT - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES));
  374. if (TokenGroups == NULL) {
  375. SecureZeroMemory(LogonInfo, LogonInfoSize);
  376. LocalFree(LogonInfo);
  377. return NULL ;
  378. }
  379. // Add the service SID to the token so the resulting
  380. // process can impersonate
  381. TokenGroups->GroupCount = TOKEN_GROUP_COUNT;
  382. TokenGroups->Groups[0].Sid = gSidService;
  383. TokenGroups->Groups[0].Attributes =
  384. SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
  385. SE_GROUP_ENABLED_BY_DEFAULT;
  386. }
  387. Status = LsaLogonUser(
  388. gLSAHandle,
  389. &Name,
  390. fSvcAccount ? Service : Batch,
  391. PackageId,
  392. LogonInfo,
  393. LogonInfoSize,
  394. TokenGroups, //NULL for service accounts
  395. &SourceContext,
  396. (PVOID *) &Profile,
  397. &ProfileSize,
  398. &LogonId,
  399. &hToken,
  400. &Quotas,
  401. &SubStatus
  402. );
  403. SecureZeroMemory(LogonInfo, LogonInfoSize);
  404. LocalFree(LogonInfo);
  405. LocalFree(TokenGroups);
  406. // Log the specifed user on
  407. if (!NT_SUCCESS(Status))
  408. {
  409. // a-sergiv (Sergei O. Ivanov), 6-17-99
  410. // Fix for com+ 9383/nt 272085
  411. // Apply event filters
  412. DWORD dwActLogLvl = GetActivationFailureLoggingLevel();
  413. if(dwActLogLvl == 2)
  414. return 0;
  415. if(dwActLogLvl != 1 && clsctx & CLSCTX_NO_FAILURE_LOG)
  416. return 0;
  417. // for this message,
  418. // %1 is the error number string
  419. // %2 is the domain name
  420. // %3 is the user name
  421. // %4 is the CLSID
  422. HANDLE LogHandle;
  423. LPWSTR Strings[4]; // array of message strings.
  424. WCHAR wszErrnum[20];
  425. WCHAR wszClsid[GUIDSTR_MAX];
  426. // Save the error number
  427. wsprintf(wszErrnum, L"%lu",GetLastError() );
  428. Strings[0] = wszErrnum;
  429. // Put in the RunAs identity
  430. Strings[1] = pwszRunAsDomainName;
  431. Strings[2] = pwszRunAsUserName;
  432. // Get the clsid
  433. Strings[3] = pwszAppID;
  434. // Get the log handle, then report then event.
  435. LogHandle = RegisterEventSource( NULL,
  436. SCM_EVENT_SOURCE );
  437. if ( LogHandle )
  438. {
  439. ReportEvent( LogHandle,
  440. EVENTLOG_ERROR_TYPE,
  441. 0, // event category
  442. EVENT_RPCSS_RUNAS_CANT_LOGIN,
  443. NULL, // SID
  444. 4, // 4 strings passed
  445. 0, // 0 bytes of binary
  446. (LPCTSTR *)Strings, // array of strings
  447. NULL ); // no raw data
  448. // clean up the event log handle
  449. DeregisterEventSource(LogHandle);
  450. }
  451. return 0;
  452. }
  453. else
  454. {
  455. if (Profile)
  456. {
  457. LsaFreeReturnBuffer(Profile);
  458. }
  459. }
  460. return hToken;
  461. }
  462. BOOL
  463. DuplicateTokenAsPrimary(
  464. HANDLE hUserToken,
  465. PSID psidUserSid,
  466. HANDLE *hPrimaryToken
  467. )
  468. {
  469. OBJECT_ATTRIBUTES ObjectAttributes;
  470. PSECURITY_DESCRIPTOR psdNewProcessTokenSD;
  471. NTSTATUS NtStatus;
  472. *hPrimaryToken = NULL;
  473. if (hUserToken == NULL)
  474. {
  475. return(FALSE);
  476. }
  477. //
  478. // Create the security descriptor that we want to put in the Token.
  479. //
  480. CAccessInfo AccessInfo(psidUserSid);
  481. psdNewProcessTokenSD = AccessInfo.IdentifyAccess(
  482. FALSE,
  483. TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS |
  484. TOKEN_ADJUST_DEFAULT | TOKEN_QUERY |
  485. TOKEN_DUPLICATE | TOKEN_IMPERSONATE | READ_CONTROL,
  486. TOKEN_QUERY
  487. );
  488. if (psdNewProcessTokenSD == NULL)
  489. {
  490. CairoleDebugOut((DEB_ERROR, "Failed to create SD for process token\n"));
  491. return(FALSE);
  492. }
  493. InitializeObjectAttributes(
  494. &ObjectAttributes,
  495. NULL,
  496. 0,
  497. NULL,
  498. psdNewProcessTokenSD
  499. );
  500. NtStatus = NtDuplicateToken(
  501. hUserToken, // Duplicate this token
  502. TOKEN_ALL_ACCESS, // Give me this access to the resulting token
  503. &ObjectAttributes,
  504. FALSE, // EffectiveOnly
  505. TokenPrimary, // TokenType
  506. hPrimaryToken // Duplicate token handle stored here
  507. );
  508. if (!NT_SUCCESS(NtStatus))
  509. {
  510. CairoleDebugOut((DEB_ERROR, "CreateAndSetProcessToken failed to duplicate primary token for new user process, status = 0x%lx\n", NtStatus));
  511. return(FALSE);
  512. }
  513. return TRUE;
  514. }
  515. BOOL
  516. DuplicateTokenForSessionUse(
  517. HANDLE hUserToken,
  518. HANDLE *hDuplicate
  519. )
  520. {
  521. OBJECT_ATTRIBUTES ObjectAttributes;
  522. PSECURITY_DESCRIPTOR psdNewProcessTokenSD;
  523. NTSTATUS NtStatus;
  524. if (hUserToken == NULL) {
  525. return(TRUE);
  526. }
  527. *hDuplicate = NULL;
  528. InitializeObjectAttributes(
  529. &ObjectAttributes,
  530. NULL,
  531. 0,
  532. NULL,
  533. NULL
  534. );
  535. NtStatus = NtDuplicateToken(
  536. hUserToken, // Duplicate this token
  537. TOKEN_ALL_ACCESS, //Give me this access to the resulting token
  538. &ObjectAttributes,
  539. FALSE, // EffectiveOnly
  540. TokenPrimary, // TokenType
  541. hDuplicate // Duplicate token handle stored here
  542. );
  543. if (!NT_SUCCESS(NtStatus)) {
  544. CairoleDebugOut((DEB_ERROR, "CreateAndSetProcessToken failed to duplicate primary token for new user process, status = 0x%lx\n", NtStatus));
  545. return(FALSE);
  546. }
  547. return TRUE;
  548. }
  549. /***************************************************************************\
  550. * GetUserSid
  551. *
  552. * Allocs space for the user sid, fills it in and returns a pointer.
  553. * The sid should be freed by calling DeleteUserSid.
  554. *
  555. * Note the sid returned is the user's real sid, not the per-logon sid.
  556. *
  557. * Returns pointer to sid or NULL on failure.
  558. *
  559. * History:
  560. * 26-Aug-92 Davidc Created.
  561. * 31-Mar-94 AndyH Copied from Winlogon, changed arg from pGlobals
  562. \***************************************************************************/
  563. PSID
  564. GetUserSid(
  565. HANDLE hUserToken
  566. )
  567. {
  568. BYTE achBuffer[100];
  569. PTOKEN_USER pUser = (PTOKEN_USER) &achBuffer;
  570. PSID pSid;
  571. DWORD dwBytesRequired;
  572. NTSTATUS NtStatus;
  573. BOOL fAllocatedBuffer = FALSE;
  574. NtStatus = NtQueryInformationToken(
  575. hUserToken, // Handle
  576. TokenUser, // TokenInformationClass
  577. pUser, // TokenInformation
  578. sizeof(achBuffer), // TokenInformationLength
  579. &dwBytesRequired // ReturnLength
  580. );
  581. if (!NT_SUCCESS(NtStatus))
  582. {
  583. if (NtStatus != STATUS_BUFFER_TOO_SMALL)
  584. {
  585. ASSERT(NtStatus == STATUS_BUFFER_TOO_SMALL);
  586. return NULL;
  587. }
  588. //
  589. // Allocate space for the user info
  590. //
  591. pUser = (PTOKEN_USER) PrivMemAlloc(dwBytesRequired);
  592. if (pUser == NULL)
  593. {
  594. CairoleDebugOut((DEB_ERROR, "Failed to allocate %d bytes\n", dwBytesRequired));
  595. ASSERT(pUser != NULL);
  596. return NULL;
  597. }
  598. fAllocatedBuffer = TRUE;
  599. //
  600. // Read in the UserInfo
  601. //
  602. NtStatus = NtQueryInformationToken(
  603. hUserToken, // Handle
  604. TokenUser, // TokenInformationClass
  605. pUser, // TokenInformation
  606. dwBytesRequired, // TokenInformationLength
  607. &dwBytesRequired // ReturnLength
  608. );
  609. if (!NT_SUCCESS(NtStatus))
  610. {
  611. CairoleDebugOut((DEB_ERROR, "Failed to query user info from user token, status = 0x%lx\n", NtStatus));
  612. ASSERT(NtStatus == STATUS_SUCCESS);
  613. PrivMemFree((HANDLE)pUser);
  614. return NULL;
  615. }
  616. }
  617. // Alloc buffer for copy of SID
  618. dwBytesRequired = RtlLengthSid(pUser->User.Sid);
  619. pSid = (PSID) PrivMemAlloc(dwBytesRequired);
  620. if (pSid == NULL)
  621. {
  622. CairoleDebugOut((DEB_ERROR, "Failed to allocate %d bytes\n", dwBytesRequired));
  623. if (fAllocatedBuffer == TRUE)
  624. {
  625. PrivMemFree((HANDLE)pUser);
  626. }
  627. return NULL;
  628. }
  629. // Copy SID
  630. NtStatus = RtlCopySid(dwBytesRequired, pSid, pUser->User.Sid);
  631. if (fAllocatedBuffer == TRUE)
  632. {
  633. PrivMemFree((HANDLE)pUser);
  634. }
  635. if (!NT_SUCCESS(NtStatus))
  636. {
  637. CairoleDebugOut((DEB_ERROR, "RtlCopySid failed, status = 0x%lx\n", NtStatus));
  638. ASSERT(NtStatus != STATUS_SUCCESS);
  639. PrivMemFree(pSid);
  640. pSid = NULL;
  641. }
  642. return pSid;
  643. }
  644. HANDLE GetUserTokenForSession(
  645. ULONG ulSessionId
  646. )
  647. {
  648. BOOL fRet = FALSE;
  649. HANDLE hToken = NULL;
  650. //
  651. // We used to have a lot of complicated code for doing this
  652. // logic. The WTSQueryUserToken api replaces all of that
  653. // quite nicely. Only downside is that wtsapi32.dll has a
  654. // moderately large dependency list. Since under normal
  655. // conditions we won't need to use this api until after someone
  656. // logs on, we delay-load link to wtsapi32 to avoid the load
  657. // hit during boot.
  658. //
  659. fRet = WTSQueryUserToken(ulSessionId, &hToken);
  660. if (!fRet)
  661. {
  662. return NULL;
  663. }
  664. ASSERT(hToken);
  665. return hToken;
  666. }
  667. // Global default launch permissions
  668. CSecDescriptor* gpDefaultLaunchPermissions;
  669. CSecDescriptor*
  670. GetDefaultLaunchPermissions()
  671. {
  672. CSecDescriptor* pSD = NULL;
  673. gpClientLock->LockShared();
  674. pSD = gpDefaultLaunchPermissions;
  675. if (pSD)
  676. pSD->IncRefCount();
  677. gpClientLock->UnlockShared();
  678. return pSD;
  679. }
  680. void
  681. SetDefaultLaunchPermissions(CSecDescriptor* pNewLaunchPerms)
  682. {
  683. CSecDescriptor* pOldSD = NULL;
  684. gpClientLock->LockExclusive();
  685. pOldSD = gpDefaultLaunchPermissions;
  686. gpDefaultLaunchPermissions = pNewLaunchPerms;
  687. if (gpDefaultLaunchPermissions)
  688. gpDefaultLaunchPermissions->IncRefCount();
  689. gpClientLock->UnlockExclusive();
  690. if (pOldSD)
  691. pOldSD->DecRefCount();
  692. return;
  693. }
  694. CSecDescriptor::CSecDescriptor(SECURITY_DESCRIPTOR* pSD) : _lRefs(1)
  695. {
  696. ASSERT(pSD);
  697. _pSD = pSD; // we own it now
  698. }
  699. CSecDescriptor::~CSecDescriptor()
  700. {
  701. ASSERT(_lRefs == 0);
  702. ASSERT(_pSD);
  703. PrivMemFree(_pSD);
  704. }
  705. void CSecDescriptor::IncRefCount()
  706. {
  707. ASSERT(_lRefs > 0);
  708. LONG lRefs = InterlockedIncrement(&_lRefs);
  709. }
  710. void CSecDescriptor::DecRefCount()
  711. {
  712. ASSERT(_lRefs > 0);
  713. LONG lRefs = InterlockedDecrement(&_lRefs);
  714. if (lRefs == 0)
  715. {
  716. delete this;
  717. }
  718. }
  719. SECURITY_DESCRIPTOR* CSecDescriptor::GetSD()
  720. {
  721. ASSERT(_pSD);
  722. ASSERT(_lRefs > 0);
  723. return _pSD;
  724. }