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.

3335 lines
85 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. security.c
  7. This module manages security for the Internet Services.
  8. FILE HISTORY:
  9. KeithMo 07-Mar-1993 Created.
  10. MuraliK 05-Jan-1995 Enable statistics query on RPC to go free.
  11. */
  12. #include "tcpdllp.hxx"
  13. #pragma hdrstop
  14. #include <string.h>
  15. #include <mbstring.h>
  16. #include <limits.h>
  17. #include "infosec.hxx"
  18. #include <inetsvcs.h>
  19. #include "TokenAcl.hxx"
  20. //
  21. // Token Cache lock. Controls access to the token cache list
  22. //
  23. #define LockTokenCache() EnterCriticalSection( &csTokenCacheLock )
  24. #define UnlockTokenCache() LeaveCriticalSection( &csTokenCacheLock )
  25. //
  26. // The check period for how long a token can be in the cache. Tokens can
  27. // be in the cache for up to two times this value (in seconds)
  28. //
  29. #define DEFAULT_CACHED_TOKEN_TTL (15 * 60)
  30. //
  31. // Globals
  32. //
  33. CRITICAL_SECTION csTokenCacheLock;
  34. HANDLE g_hProcessImpersonationToken = NULL;
  35. HANDLE g_hProcessPrimaryToken = NULL;
  36. BOOL g_fUseSingleToken = FALSE;
  37. BOOL g_fAlwaysCheckForDuplicateLogon = FALSE;
  38. BOOL g_fUseAdvapi32Logon = FALSE;
  39. BOOL g_fCertCheckForRevocation = FALSE;
  40. TS_TOKEN g_pctProcessToken;
  41. BOOL g_fCertCheckCA = TRUE;
  42. HINSTANCE g_hWinTrust = NULL;
  43. PFN_WinVerifyTrust g_pfnWinVerifyTrust = NULL;
  44. BOOL g_fLastPriorityUPNLogon = FALSE;
  45. //
  46. // Well-known SIDs.
  47. //
  48. PSID psidWorld;
  49. PSID psidLocalSystem;
  50. PSID psidAdmins;
  51. PSID psidServerOps;
  52. PSID psidPowerUsers;
  53. PSID g_psidGuestUser;
  54. PSID g_psidProcessUser;
  55. # define GUEST_USER_SID_BUFFER_LEN (200)
  56. BYTE g_GuestUserSidBuffer[GUEST_USER_SID_BUFFER_LEN];
  57. //
  58. // The API security object. Client access to the TCP Server APIs
  59. // are validated against this object.
  60. //
  61. PSECURITY_DESCRIPTOR sdApiObject;
  62. LUID g_ChangeNotifyPrivilegeTcbValue;
  63. PTOKEN_PRIVILEGES g_pTokPrev = NULL;
  64. //
  65. // This table maps generic rights (like GENERIC_READ) to
  66. // specific rights (like TCP_QUERY_SECURITY).
  67. //
  68. GENERIC_MAPPING TCPApiObjectMapping = {
  69. TCP_GENERIC_READ, // generic read
  70. TCP_GENERIC_WRITE, // generic write
  71. TCP_GENERIC_EXECUTE, // generic execute
  72. TCP_ALL_ACCESS // generic all
  73. };
  74. //
  75. // List of cached tokens, the token list lock and the cookie to the token
  76. // scavenger schedule item. The token cache TTL gets converted to msecs
  77. // during startup
  78. //
  79. BOOL IsTokenCacheInitialized = FALSE;
  80. LIST_ENTRY TokenCacheList;
  81. DWORD dwScheduleCookie = 0;
  82. DWORD cmsecTokenCacheTTL = DEFAULT_CACHED_TOKEN_TTL;
  83. CHAR g_achComputerName[DNLEN+1];
  84. LIST_ENTRY CredentialCacheList;
  85. CRITICAL_SECTION csCredentialCacheLock;
  86. //
  87. // Private prototypes.
  88. //
  89. DWORD
  90. CreateWellKnownSids(
  91. HINSTANCE hDll
  92. );
  93. VOID
  94. FreeWellKnownSids(
  95. VOID
  96. );
  97. DWORD
  98. CreateApiSecurityObject(
  99. VOID
  100. );
  101. VOID
  102. DeleteApiSecurityObject(
  103. VOID
  104. );
  105. TS_TOKEN
  106. ValidateUser(
  107. PCHAR pszDomainName,
  108. PCHAR pszUserName,
  109. PCHAR pszPassword,
  110. BOOL fAnonymous,
  111. BOOL * pfAsGuest,
  112. DWORD dwLogonMethod,
  113. TCHAR * pszWorkstation,
  114. LARGE_INTEGER * pExpiry,
  115. BOOL * pfExpiry,
  116. BOOL fUseSubAuthIfAnonymous
  117. );
  118. VOID EnableTcbPrivilege(
  119. VOID
  120. );
  121. BOOL
  122. BuildAcctDesc(
  123. IN const CHAR * pszUser,
  124. IN const CHAR * pszDomain,
  125. IN const CHAR * pszPwd,
  126. IN BOOL fUseSubAuth,
  127. OUT CHAR * pchAcctDesc, // must be MAX_ACCT_DESC_LEN
  128. OUT LPDWORD pdwAcctDescLen
  129. );
  130. BOOL
  131. AddTokenToCache(
  132. IN const CHAR * pszUser,
  133. IN const CHAR * pszDomain,
  134. IN const CHAR * pszPwd,
  135. IN BOOL fUseSubAuth,
  136. IN HANDLE hToken,
  137. IN DWORD dwLogonMethod,
  138. OUT CACHED_TOKEN * * ppct,
  139. BOOL fCheckAlreadyExist,
  140. LPBOOL pfAlreadyExist
  141. );
  142. BOOL
  143. FindCachedToken(
  144. IN const CHAR * pszUser,
  145. IN const CHAR * pszDomain,
  146. IN const CHAR * pszPwd,
  147. IN BOOL fResetTTL,
  148. IN BOOL fUseSubAuth,
  149. IN DWORD dwLogonMethod,
  150. OUT CACHED_TOKEN * * ppct
  151. );
  152. VOID
  153. WINAPI
  154. TokenCacheScavenger(
  155. IN VOID * pContext
  156. );
  157. //
  158. // Public functions.
  159. //
  160. /*******************************************************************
  161. NAME: InitializeSecurity
  162. SYNOPSIS: Initializes security authentication & impersonation
  163. routines.
  164. RETURNS: DWORD - NO_ERROR if successful, otherwise a Win32
  165. error code.
  166. NOTES: This routine may only be called by a single thread
  167. of execution; it is not necessarily multi-thread safe.
  168. HISTORY:
  169. KeithMo 07-Mar-1993 Created.
  170. ********************************************************************/
  171. DWORD
  172. InitializeSecurity(
  173. IN HINSTANCE hDll
  174. )
  175. {
  176. NTSTATUS ntStatus;
  177. DWORD err;
  178. DWORD nName;
  179. HANDLE hAccToken;
  180. HKEY hKey;
  181. DWORD dwType;
  182. DWORD dwValue;
  183. DWORD nBytes;
  184. //
  185. // Read the registry key to see whether tsunami caching is enabled
  186. //
  187. err = RegOpenKeyEx(
  188. HKEY_LOCAL_MACHINE,
  189. INETA_PARAMETERS_KEY,
  190. 0,
  191. KEY_READ,
  192. &hKey
  193. );
  194. if ( err == ERROR_SUCCESS ) {
  195. nBytes = sizeof(dwValue);
  196. err = RegQueryValueEx(
  197. hKey,
  198. INETA_W3ONLY_NO_AUTH,
  199. NULL,
  200. &dwType,
  201. (LPBYTE)&dwValue,
  202. &nBytes
  203. );
  204. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  205. g_fW3OnlyNoAuth = (BOOL)!!dwValue;
  206. if ( g_fW3OnlyNoAuth ) {
  207. DbgPrint("W3OnlyNoAuth set to TRUE in Registry.\n");
  208. } else {
  209. DbgPrint("W3OnlyNoAuth set to FALSE in Registry.\n");
  210. }
  211. }
  212. nBytes = sizeof(dwValue);
  213. err = RegQueryValueEx(
  214. hKey,
  215. INETA_ALWAYS_CHECK_FOR_DUPLICATE_LOGON,
  216. NULL,
  217. &dwType,
  218. (LPBYTE)&dwValue,
  219. &nBytes
  220. );
  221. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  222. g_fAlwaysCheckForDuplicateLogon = (BOOL)dwValue;
  223. }
  224. nBytes = sizeof(dwValue);
  225. err = RegQueryValueEx(
  226. hKey,
  227. INETA_USE_ADVAPI32_LOGON,
  228. NULL,
  229. &dwType,
  230. (LPBYTE)&dwValue,
  231. &nBytes
  232. );
  233. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  234. g_fUseAdvapi32Logon = (BOOL)dwValue;
  235. }
  236. nBytes = sizeof(dwValue);
  237. err = RegQueryValueEx(
  238. hKey,
  239. INETA_CHECK_CERT_REVOCATION,
  240. NULL,
  241. &dwType,
  242. (LPBYTE)&dwValue,
  243. &nBytes
  244. );
  245. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  246. g_fCertCheckForRevocation = (BOOL)dwValue;
  247. }
  248. nBytes = sizeof(dwValue);
  249. err = RegQueryValueEx(
  250. hKey,
  251. "CertCheckCA",
  252. NULL,
  253. &dwType,
  254. (LPBYTE)&dwValue,
  255. &nBytes
  256. );
  257. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  258. g_fCertCheckCA = (BOOL)dwValue;
  259. }
  260. nBytes = sizeof(dwValue);
  261. err = RegQueryValueEx(
  262. hKey,
  263. "LastPriorityUPNLogon",
  264. NULL,
  265. &dwType,
  266. (LPBYTE)&dwValue,
  267. &nBytes
  268. );
  269. if ( (err == ERROR_SUCCESS) && (dwType == REG_DWORD) ) {
  270. g_fLastPriorityUPNLogon = !!dwValue;
  271. }
  272. RegCloseKey( hKey );
  273. }
  274. IF_DEBUG( DLL_SECURITY )
  275. {
  276. DBGPRINTF(( DBG_CONTEXT, "Initializing security\n" ));
  277. }
  278. IsTokenCacheInitialized = TRUE;
  279. InitializeListHead( &TokenCacheList );
  280. INITIALIZE_CRITICAL_SECTION( &csTokenCacheLock );
  281. InitializeListHead( &CredentialCacheList );
  282. INITIALIZE_CRITICAL_SECTION( &csCredentialCacheLock );
  283. if ( g_fW3OnlyNoAuth ) {
  284. DBGPRINTF((DBG_CONTEXT,
  285. "InitializeSecurity: NT Security disabled for W3OnlyNoAuth\n"));
  286. g_fUseSingleToken = TRUE;
  287. if ( !(g_pctProcessToken = new CACHED_TOKEN) )
  288. {
  289. return ERROR_NOT_ENOUGH_MEMORY;
  290. }
  291. g_pctProcessToken->_cRef = INT_MAX/2;
  292. InitializeListHead( &g_pctProcessToken->_ListEntry );
  293. if ( !OpenProcessToken (
  294. GetCurrentProcess(),
  295. TOKEN_DUPLICATE|TOKEN_IMPERSONATE|TOKEN_QUERY,
  296. &hAccToken
  297. ) )
  298. {
  299. DBGPRINTF((DBG_CONTEXT, "fail OpenProcessToken\n"));
  300. return GetLastError();
  301. }
  302. if ( !pfnDuplicateTokenEx( hAccToken,
  303. 0,
  304. NULL,
  305. SecurityImpersonation,
  306. TokenPrimary,
  307. &g_hProcessPrimaryToken ))
  308. {
  309. DBGPRINTF((DBG_CONTEXT, "fail pfnDuplicateTokenEx primary\n"));
  310. CloseHandle( hAccToken );
  311. return GetLastError();
  312. }
  313. if ( !pfnDuplicateTokenEx( hAccToken,
  314. 0,
  315. NULL,
  316. SecurityImpersonation,
  317. TokenImpersonation,
  318. &g_hProcessImpersonationToken ))
  319. {
  320. DBGPRINTF((DBG_CONTEXT, "fail pfnDuplicateTokenEx impersonate\n"));
  321. CloseHandle( hAccToken );
  322. CloseHandle( g_hProcessPrimaryToken );
  323. return GetLastError();
  324. }
  325. err = CreateWellKnownSids( hDll );
  326. if ( err != NO_ERROR ) {
  327. DBGPRINTF((DBG_CONTEXT,"CreateWellKnownSids failed with %d\n",err));
  328. goto exit;
  329. }
  330. //
  331. // Create the API security object.
  332. //
  333. err = CreateApiSecurityObject();
  334. if ( err != NO_ERROR ) {
  335. DBGPRINTF((DBG_CONTEXT,"CreateApiSecurityObjects failed with %d\n",err));
  336. goto exit;
  337. }
  338. g_pctProcessToken->_hToken = g_hProcessPrimaryToken;
  339. g_pctProcessToken->m_hImpersonationToken = g_hProcessImpersonationToken;
  340. return(NO_ERROR);
  341. }
  342. //
  343. // Create well-known SIDs.
  344. //
  345. err = CreateWellKnownSids( hDll );
  346. if ( err != NO_ERROR ) {
  347. DBGPRINTF((DBG_CONTEXT,"CreateWellKnownSids failed with %d\n",err));
  348. goto exit;
  349. }
  350. //
  351. // Create the API security object.
  352. //
  353. err = CreateApiSecurityObject();
  354. if ( err != NO_ERROR ) {
  355. DBGPRINTF((DBG_CONTEXT,"CreateApiSecurityObjects failed with %d\n",err));
  356. goto exit;
  357. }
  358. {
  359. HKEY hkey;
  360. //
  361. // Get the default token TTL, must be at least one second
  362. //
  363. if ( !RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  364. INETA_PARAMETERS_KEY,
  365. 0,
  366. KEY_READ,
  367. &hkey )) {
  368. cmsecTokenCacheTTL = ReadRegistryDword( hkey,
  369. "UserTokenTTL",
  370. DEFAULT_CACHED_TOKEN_TTL);
  371. RegCloseKey( hkey );
  372. }
  373. cmsecTokenCacheTTL = max( 1, cmsecTokenCacheTTL );
  374. cmsecTokenCacheTTL *= 1000;
  375. IF_DEBUG( DLL_SECURITY )
  376. {
  377. DBGPRINTF(( DBG_CONTEXT,
  378. "Scheduling token cached scavenger to %d seconds\n",
  379. cmsecTokenCacheTTL/1000 ));
  380. }
  381. //
  382. // Schedule a work item for the token scavenger
  383. //
  384. dwScheduleCookie = ScheduleWorkItem( TokenCacheScavenger,
  385. NULL,
  386. cmsecTokenCacheTTL,
  387. TRUE ); // Periodic
  388. }
  389. pfnLogon32Initialize( NULL, DLL_PROCESS_ATTACH, NULL );
  390. if ( g_pTokPrev = (PTOKEN_PRIVILEGES)LocalAlloc( LMEM_FIXED,
  391. sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)) )
  392. {
  393. if ( !LookupPrivilegeValue(
  394. NULL,
  395. "SeChangeNotifyPrivilege",
  396. &g_ChangeNotifyPrivilegeTcbValue
  397. ) )
  398. {
  399. g_pTokPrev->PrivilegeCount = 0;
  400. }
  401. else
  402. {
  403. g_pTokPrev->PrivilegeCount = 1;
  404. g_pTokPrev->Privileges[0].Luid = g_ChangeNotifyPrivilegeTcbValue;
  405. g_pTokPrev->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  406. }
  407. }
  408. nName = sizeof(g_achComputerName);
  409. if ( !GetComputerName( g_achComputerName, &nName ) )
  410. {
  411. g_achComputerName[0] = '\0';
  412. }
  413. g_hWinTrust = LoadLibrary( "wintrust.dll" );
  414. if ( g_hWinTrust != NULL )
  415. {
  416. g_pfnWinVerifyTrust = (PFN_WinVerifyTrust)GetProcAddress( g_hWinTrust, "WinVerifyTrust" );
  417. }
  418. //
  419. // Success!
  420. //
  421. IF_DEBUG( DLL_SECURITY )
  422. {
  423. DBGPRINTF(( DBG_CONTEXT, "Security initialized\n" ));
  424. }
  425. exit:
  426. return err;
  427. } // InitializeSecurity
  428. /*******************************************************************
  429. NAME: TerminateSecurity
  430. SYNOPSIS: Terminate security authentication & impersonation
  431. routines.
  432. NOTES: This routine may only be called by a single thread
  433. of execution; it is not necessarily multi-thread safe.
  434. HISTORY:
  435. KeithMo 07-Mar-1993 Created.
  436. ********************************************************************/
  437. VOID
  438. TerminateSecurity(
  439. VOID
  440. )
  441. {
  442. CACHED_TOKEN * pct;
  443. CACHED_CREDENTIAL * pcred;
  444. DBGPRINTF((DBG_CONTEXT,"TerminateSecurity called\n"));
  445. IF_DEBUG( DLL_SECURITY )
  446. {
  447. DBGPRINTF(( DBG_CONTEXT,
  448. "Terminating security\n" ));
  449. }
  450. //
  451. // Delete any tokens still in the cache
  452. //
  453. if ( IsTokenCacheInitialized )
  454. {
  455. LockTokenCache();
  456. while ( !IsListEmpty( &TokenCacheList ))
  457. {
  458. pct = CONTAINING_RECORD( TokenCacheList.Flink,
  459. CACHED_TOKEN,
  460. _ListEntry );
  461. RemoveEntryList( &pct->_ListEntry );
  462. pct->_ListEntry.Flink = NULL;
  463. //
  464. // If the ref count isn't zero then somebody didn't delete all of
  465. // their tokens
  466. //
  467. DBG_ASSERT( pct->_cRef == 1 );
  468. CACHED_TOKEN::Dereference( pct );
  469. }
  470. UnlockTokenCache();
  471. DeleteCriticalSection( &csTokenCacheLock );
  472. }
  473. //
  474. // Delete any credential in the cache
  475. //
  476. EnterCriticalSection( &csCredentialCacheLock );
  477. while ( !IsListEmpty( &CredentialCacheList ))
  478. {
  479. pcred = CONTAINING_RECORD( CredentialCacheList.Flink,
  480. CACHED_CREDENTIAL,
  481. _ListEntry );
  482. RemoveEntryList( &pcred->_ListEntry );
  483. pcred->_ListEntry.Flink = NULL;
  484. delete pcred;
  485. }
  486. LeaveCriticalSection( &csCredentialCacheLock );
  487. DeleteCriticalSection( &csCredentialCacheLock );
  488. if ( g_fUseSingleToken ) {
  489. CloseHandle( g_hProcessImpersonationToken );
  490. CloseHandle( g_hProcessPrimaryToken );
  491. delete g_pctProcessToken;
  492. return;
  493. }
  494. FreeWellKnownSids();
  495. DeleteApiSecurityObject();
  496. //
  497. // Remove the scheduled scavenger
  498. //
  499. if ( dwScheduleCookie )
  500. {
  501. RemoveWorkItem( dwScheduleCookie );
  502. }
  503. if ( g_pTokPrev )
  504. {
  505. LocalFree( g_pTokPrev );
  506. g_pTokPrev = NULL;
  507. }
  508. if ( g_hWinTrust != NULL )
  509. {
  510. g_pfnWinVerifyTrust = NULL;
  511. FreeLibrary( g_hWinTrust );
  512. g_hWinTrust = NULL;
  513. }
  514. pfnLogon32Initialize( NULL, DLL_PROCESS_DETACH, NULL );
  515. IF_DEBUG( DLL_SECURITY )
  516. {
  517. DBGPRINTF(( DBG_CONTEXT,
  518. "Security terminated\n" ));
  519. }
  520. } // TerminateSecurity
  521. /*******************************************************************
  522. NAME: TsLogonUser
  523. SYNOPSIS: Validates a user's credentials, then sets the
  524. impersonation for the current thread. In effect,
  525. the current thread "becomes" the user.
  526. ENTRY: pUserData - The user initiating the request (NULL for
  527. the default account).
  528. pszPassword - The user's password. May be NULL.
  529. pfAsGuest - Will receive TRUE if the user was validated
  530. with guest privileges.
  531. pfAsAnonymous - Will receive TRUE if the user received the
  532. services anonymous token
  533. pszWorkstation - workstation name for remote user
  534. can be NULL if default ( local computer) to be used
  535. pExpiry - updated with pwd expiration date/time
  536. pfExpiryAvailable - updated with TRUE if pwd expiration
  537. date/time available
  538. RETURNS: HANDLE - Token handle to use for impersonation or NULL
  539. if the user couldn't be validated. Call GetLastError
  540. for more information.
  541. HISTORY:
  542. KeithMo 18-Mar-1993 Created.
  543. Johnl 14-Oct-1994 Mutilated for TCPSvcs
  544. ********************************************************************/
  545. TS_TOKEN
  546. TsLogonUser(
  547. IN CHAR * pszUser,
  548. IN CHAR * pszPassword,
  549. OUT BOOL * pfAsGuest,
  550. OUT BOOL * pfAsAnonymous,
  551. IN PIIS_SERVER_INSTANCE psi,
  552. PTCP_AUTHENT_INFO pTAI,
  553. IN CHAR * pszWorkstation,
  554. OUT LARGE_INTEGER * pExpiry,
  555. OUT BOOL * pfExpiryAvailable
  556. )
  557. {
  558. DBG_ASSERT( pfAsGuest != NULL );
  559. DBG_ASSERT( pfAsAnonymous != NULL );
  560. STACK_STATSTR (strAnonPwd, PWLEN+1);
  561. STACK_STATSTR (strDomainAndUser, IIS_DNLEN+UNLEN+2);
  562. STACK_STATSTR (strAnonUser, UNLEN+1);
  563. CHAR * pszUserOnly;
  564. CHAR * pszDomain;
  565. TS_TOKEN hToken;
  566. BOOL fUseDefaultDomain = TRUE;
  567. TCP_AUTHENT_INFO InstanceAuthentInfo;
  568. if ( g_fUseSingleToken ) {
  569. *pfAsGuest = TRUE;
  570. *pfAsAnonymous = TRUE;
  571. *pfExpiryAvailable = FALSE;
  572. CACHED_TOKEN::Reference( g_pctProcessToken );
  573. return g_pctProcessToken;
  574. }
  575. // If the client didn't pass in metabase info, grab what we need from
  576. // the instance.
  577. //
  578. if (pTAI == NULL)
  579. {
  580. InstanceAuthentInfo.strAnonUserName.Copy( "iusr_xxx" ); //(CHAR *)psi->QueryAnonUserName();
  581. InstanceAuthentInfo.strAnonUserPassword.Copy( "" );
  582. InstanceAuthentInfo.strDefaultLogonDomain.Copy( "" ); //(CHAR *)psi->QueryDefaultLogonDomain();
  583. InstanceAuthentInfo.dwLogonMethod = MD_LOGON_INTERACTIVE; //psi->QueryLogonMethod();
  584. InstanceAuthentInfo.fDontUseAnonSubAuth = TRUE;
  585. pTAI = &InstanceAuthentInfo;
  586. }
  587. //
  588. // Make a quick copy of the anonymous user for this server for later
  589. // usage
  590. //
  591. if ( !pTAI->strAnonUserName.Clone( &strAnonUser) ||
  592. !pTAI->strAnonUserPassword.Clone( &strAnonPwd) )
  593. {
  594. goto InvalidParamError;
  595. }
  596. // if the password is stored hashed, unhash it for usage
  597. if (pTAI->fPwdIsHashed)
  598. {
  599. strAnonPwd.Unhash();
  600. }
  601. //
  602. // Empty user defaults to the anonymous user
  603. //
  604. if ( !pszUser || *pszUser == '\0' )
  605. {
  606. pszUser = strAnonUser.QueryStr();
  607. pszPassword = strAnonPwd.QueryStr();
  608. fUseDefaultDomain = FALSE;
  609. *pfAsAnonymous = TRUE;
  610. }
  611. else
  612. {
  613. *pfAsAnonymous = FALSE;
  614. }
  615. //
  616. // Validate parameters & state.
  617. //
  618. if ( strlen(pszUser) >= (IIS_DNLEN+UNLEN+2) )
  619. {
  620. goto InvalidParamError;
  621. }
  622. if( pszPassword == NULL )
  623. {
  624. pszPassword = "";
  625. }
  626. else if ( strlen(pszPassword) > PWLEN )
  627. {
  628. goto InvalidParamError;
  629. }
  630. //
  631. // Did the user specify a domain in the domain\user format?
  632. //
  633. PSTR pszDefDom = NULL;
  634. if (strchr( pszUser, '/' ) || _mbschr( (PUCHAR)pszUser, '\\' ))
  635. {
  636. //
  637. // Save a copy of the domain\user so we can squirrel around
  638. // with it a bit.
  639. //
  640. if ( !strDomainAndUser.Copy( pszUser))
  641. {
  642. goto InvalidParamError;
  643. }
  644. //
  645. // Crack the name into domain/user components.
  646. //
  647. if ( !CrackUserAndDomain( strDomainAndUser.QueryStr(),
  648. &pszUserOnly,
  649. &pszDomain ))
  650. {
  651. goto InvalidParamError;
  652. }
  653. fUseDefaultDomain = FALSE;
  654. }
  655. else
  656. {
  657. //
  658. // it's either a user only, or UPN format
  659. //
  660. pszUserOnly = pszUser;
  661. pszDomain = NULL;
  662. //
  663. // we may need to use the default domain, so let's see if it's valid
  664. //
  665. pszDefDom = pTAI->strDefaultLogonDomain.QueryStr();
  666. if ( !pszDefDom ||
  667. !*pszDefDom ||
  668. strchr( pszDefDom, '/' ) ||
  669. _mbschr( (PUCHAR)pszDefDom, '\\' ))
  670. {
  671. fUseDefaultDomain = FALSE;
  672. }
  673. }
  674. //
  675. // So, here is what we do:
  676. // - if the user specified a domain in the domain\user format, we'll only try that.
  677. // - if we had any reason not to use the default domain, we will not try to.
  678. // - if the username has a '@' in it and no '\', we'll try a UPN logon and also the default domain
  679. //
  680. PSTR pszD1, pszD2;
  681. BOOL fAttemptSecondLogon;
  682. if (pszDomain)
  683. {
  684. //
  685. // user specified domain\user
  686. //
  687. pszD1 = pszDomain;
  688. pszD2 = NULL;
  689. fAttemptSecondLogon = FALSE;
  690. }
  691. else if (!fUseDefaultDomain)
  692. {
  693. //
  694. // we are not trying the default domain, so it's either a local user or UPN format
  695. //
  696. pszD1 = "";
  697. pszD2 = NULL;
  698. fAttemptSecondLogon = FALSE;
  699. }
  700. else if (!strchr( pszUserOnly, '@' ))
  701. {
  702. //
  703. // it's not a UPN format, so use the default domain
  704. //
  705. pszD1 = pszDefDom;
  706. pszD2 = NULL;
  707. fAttemptSecondLogon = FALSE;
  708. }
  709. else
  710. {
  711. //
  712. // here is the tricky part:
  713. // - no domain\user was specified,
  714. // - we could use a default domain name
  715. // - there is a '@' in the username, so it might be a UPN format
  716. // we resolve this ambiguity by attempting logon twice, the order depends on the
  717. // registry key LastPriorityUPNLogon
  718. //
  719. if (g_fLastPriorityUPNLogon)
  720. {
  721. //
  722. // try the default domain first
  723. //
  724. pszD1 = pszDefDom;
  725. pszD2 = "";
  726. }
  727. else
  728. {
  729. //
  730. // try UPN logon first
  731. //
  732. pszD1 = "";
  733. pszD2 = pszDefDom;
  734. }
  735. fAttemptSecondLogon = TRUE;
  736. }
  737. //
  738. // Validate the domain/user/password combo and create
  739. // an impersonation token.
  740. //
  741. hToken = ValidateUser( pszD1,
  742. pszUserOnly,
  743. pszPassword,
  744. *pfAsAnonymous,
  745. pfAsGuest,
  746. pTAI->dwLogonMethod,
  747. pszWorkstation,
  748. pExpiry,
  749. pfExpiryAvailable,
  750. !pTAI->fDontUseAnonSubAuth
  751. );
  752. if (hToken == NULL &&
  753. fAttemptSecondLogon &&
  754. GetLastError() == ERROR_LOGON_FAILURE)
  755. {
  756. //
  757. // the logon failed, but we get to try again with a different format
  758. //
  759. hToken = ValidateUser( pszD2,
  760. pszUserOnly,
  761. pszPassword,
  762. *pfAsAnonymous,
  763. pfAsGuest,
  764. pTAI->dwLogonMethod,
  765. pszWorkstation,
  766. pExpiry,
  767. pfExpiryAvailable,
  768. !pTAI->fDontUseAnonSubAuth
  769. );
  770. }
  771. strAnonPwd.Clear();
  772. if( hToken == NULL )
  773. {
  774. STR strError;
  775. const CHAR * psz[2];
  776. DWORD dwErr = GetLastError();
  777. psi->LoadStr( strError, dwErr, FALSE );
  778. psz[0] = pszUser;
  779. psz[1] = strError.QueryStr();
  780. psi->m_Service->LogEvent(
  781. INET_SVCS_FAILED_LOGON,
  782. 2,
  783. psz,
  784. dwErr );
  785. //
  786. // Validation failure.
  787. //
  788. if ( dwErr == ERROR_LOGON_TYPE_NOT_GRANTED ||
  789. dwErr == ERROR_ACCOUNT_DISABLED )
  790. {
  791. SetLastError( ERROR_ACCESS_DENIED );
  792. }
  793. else
  794. {
  795. //
  796. // Reset LastError(), as LogEvent() may have overwritten it
  797. // e.g log is full
  798. //
  799. SetLastError( dwErr );
  800. }
  801. return NULL;
  802. }
  803. //
  804. // Success!
  805. //
  806. return hToken;
  807. InvalidParamError:
  808. return NULL;
  809. } // TsLogonUser
  810. /*******************************************************************
  811. NAME: ValidateUser
  812. SYNOPSIS: Validate a given domain/user/password tuple.
  813. ENTRY: pszDomainName - The user's domain (NULL = current).
  814. pszUserName - The user's name.
  815. pszPassword - The user's (plaintext) password.
  816. fAnonymous - TRUE if this is the anonymous user
  817. pfAsGuest - Will receive TRUE if the user was validated
  818. with guest privileges.
  819. dwLogonMethod - interactive or batch
  820. pszWorkstation - workstation name for remote user
  821. can be NULL if default ( local computer) to be used
  822. pExpiry - updated with pwd expiration date/time
  823. pfExpiryAvailable - updated with TRUE if pwd expiration
  824. date/time available
  825. fUseSubAuthIfAnonymous - TRUE if logon anonymous user
  826. using IIS sub-auth
  827. RETURNS: HANDLE - An impersonation token, NULL if user cannot
  828. be validated. Call GetLastError for more information.
  829. HISTORY:
  830. KeithMo 07-Mar-1993 Created.
  831. ********************************************************************/
  832. TS_TOKEN ValidateUser(
  833. PCHAR pszDomainName,
  834. PCHAR pszUserName,
  835. PCHAR pszPassword,
  836. BOOL fAnonymous,
  837. BOOL * pfAsGuest,
  838. DWORD dwLogonMethod,
  839. CHAR * pszWorkstation,
  840. LARGE_INTEGER * pExpiry,
  841. BOOL * pfExpiryAvailable,
  842. BOOL fUseSubAuthIfAnonymous
  843. )
  844. {
  845. CACHED_TOKEN * pct = NULL;
  846. HANDLE hToken;
  847. HANDLE hImpersonationToken = NULL;
  848. BOOL fExpiry = FALSE;
  849. DWORD dwSubAuth = 0;
  850. CHAR achCookie[32];
  851. BOOL fExist;
  852. if ( pfExpiryAvailable )
  853. {
  854. *pfExpiryAvailable = FALSE;
  855. }
  856. if ( fAnonymous && fUseSubAuthIfAnonymous )
  857. {
  858. if ( !pfnNetUserCookieA( pszUserName,
  859. IIS_SUBAUTH_SEED,
  860. achCookie,
  861. sizeof(achCookie ) ) )
  862. {
  863. return FALSE;
  864. }
  865. dwSubAuth = IIS_SUBAUTH_ID;
  866. pszPassword = achCookie;
  867. dwLogonMethod = LOGON32_LOGON_IIS_NETWORK;
  868. }
  869. //
  870. // Is it in the cache? References the token if we find it
  871. //
  872. if ( FindCachedToken( pszUserName,
  873. pszDomainName,
  874. pszPassword,
  875. fAnonymous, // Reset the TTL if anonymous
  876. fAnonymous && fUseSubAuthIfAnonymous,
  877. dwLogonMethod,
  878. &pct ))
  879. {
  880. *pfAsGuest = pct->IsGuest();
  881. if ( NULL != pExpiry) {
  882. memcpy( pExpiry, pct->QueryExpiry(), sizeof(LARGE_INTEGER) );
  883. }
  884. if ( pfExpiryAvailable )
  885. {
  886. *pfExpiryAvailable = TRUE;
  887. }
  888. return pct;
  889. }
  890. if ( (dwLogonMethod == LOGON32_LOGON_NETWORK ||
  891. dwLogonMethod == LOGON32_LOGON_BATCH ||
  892. dwLogonMethod == LOGON32_LOGON_INTERACTIVE ||
  893. dwLogonMethod == LOGON32_LOGON_IIS_NETWORK ||
  894. dwLogonMethod == LOGON32_LOGON_NETWORK_CLEARTEXT ) &&
  895. ( !g_fUseAdvapi32Logon || dwSubAuth == IIS_SUBAUTH_ID ) )
  896. {
  897. if ( !pfnLogonNetUserA( pszUserName,
  898. pszDomainName,
  899. pszPassword,
  900. pszWorkstation,
  901. dwSubAuth,
  902. dwLogonMethod,
  903. LOGON32_PROVIDER_DEFAULT,
  904. &hToken,
  905. pExpiry ))
  906. {
  907. if ( fAnonymous &&
  908. ( GetLastError() == ERROR_LOGON_TYPE_NOT_GRANTED ) &&
  909. ( dwLogonMethod == LOGON32_LOGON_INTERACTIVE ) )
  910. {
  911. // try again
  912. dwLogonMethod = LOGON32_LOGON_BATCH;
  913. if ( !pfnLogonNetUserA( pszUserName,
  914. pszDomainName,
  915. pszPassword,
  916. pszWorkstation,
  917. dwSubAuth,
  918. dwLogonMethod,
  919. LOGON32_PROVIDER_DEFAULT,
  920. &hToken,
  921. pExpiry ))
  922. {
  923. return NULL;
  924. }
  925. }
  926. else
  927. {
  928. return NULL;
  929. }
  930. }
  931. fExpiry = TRUE;
  932. if ( pfExpiryAvailable )
  933. {
  934. *pfExpiryAvailable = TRUE;
  935. }
  936. }
  937. else
  938. {
  939. if ( !LogonUserA( pszUserName,
  940. pszDomainName,
  941. pszPassword,
  942. dwLogonMethod,
  943. LOGON32_PROVIDER_WINNT50,
  944. &hToken ))
  945. {
  946. return NULL;
  947. }
  948. }
  949. if ( dwLogonMethod == LOGON32_LOGON_NETWORK ||
  950. dwLogonMethod == LOGON32_LOGON_IIS_NETWORK ||
  951. dwLogonMethod == LOGON32_LOGON_NETWORK_CLEARTEXT )
  952. {
  953. hImpersonationToken = hToken;
  954. if ( !pfnDuplicateTokenEx( hImpersonationToken,
  955. TOKEN_ALL_ACCESS,
  956. NULL,
  957. SecurityDelegation,
  958. TokenPrimary,
  959. &hToken ))
  960. {
  961. if ( !pfnDuplicateTokenEx( hImpersonationToken,
  962. TOKEN_ALL_ACCESS,
  963. NULL,
  964. SecurityImpersonation,
  965. TokenPrimary,
  966. &hToken ))
  967. {
  968. CloseHandle( hImpersonationToken );
  969. return NULL;
  970. }
  971. }
  972. }
  973. *pfAsGuest = IsGuestUser(hToken);
  974. //
  975. // Add this new token to the cache, hToken gets replaced by the
  976. // cached token object
  977. //
  978. if ( !AddTokenToCache( pszUserName,
  979. pszDomainName,
  980. pszPassword,
  981. fAnonymous && fUseSubAuthIfAnonymous,
  982. hToken,
  983. dwLogonMethod,
  984. &pct,
  985. g_fAlwaysCheckForDuplicateLogon | fAnonymous,
  986. &fExist ))
  987. {
  988. if ( hImpersonationToken != NULL )
  989. {
  990. CloseHandle( hImpersonationToken );
  991. }
  992. CloseHandle( hToken );
  993. return NULL;
  994. }
  995. pct->SetGuest(*pfAsGuest);
  996. if ( fExpiry )
  997. {
  998. pct->SetExpiry( pExpiry );
  999. }
  1000. //
  1001. // DuplicateToken() apparently returns an impersonated token
  1002. // so it is not necessary to call pfnDuplicateTokenEx
  1003. //
  1004. if ( !fExist )
  1005. {
  1006. if ( hImpersonationToken == NULL
  1007. && !pfnDuplicateTokenEx( hToken, // hSourceToken
  1008. TOKEN_ALL_ACCESS,
  1009. NULL,
  1010. SecurityDelegation, // Obtain impersonation
  1011. TokenImpersonation,
  1012. &hImpersonationToken) // hDestinationToken
  1013. ) {
  1014. if ( !pfnDuplicateTokenEx( hToken, // hSourceToken
  1015. TOKEN_ALL_ACCESS,
  1016. NULL,
  1017. SecurityImpersonation, // Obtain impersonation
  1018. TokenImpersonation,
  1019. &hImpersonationToken) // hDestinationToken
  1020. ) {
  1021. hImpersonationToken = NULL;
  1022. }
  1023. }
  1024. // Bug 86489:
  1025. // Grant all access to the token for "Everyone" so that ISAPIs that run out of proc
  1026. // can do an OpenThreadToken call
  1027. if (FAILED( GrantAllAccessToToken( hImpersonationToken ) ) )
  1028. {
  1029. CloseHandle( hImpersonationToken );
  1030. DBG_ASSERT( FALSE );
  1031. return NULL;
  1032. }
  1033. pct->SetImpersonationToken( hImpersonationToken);
  1034. }
  1035. else if ( hImpersonationToken )
  1036. {
  1037. CloseHandle( hImpersonationToken );
  1038. }
  1039. return pct;
  1040. } // ValidateUser
  1041. # define MAX_TOKEN_USER_INFO (300)
  1042. BOOL
  1043. IsGuestUser(IN HANDLE hToken)
  1044. /*++
  1045. Given a user token, this function determines if the token belongs
  1046. to a guest user. It returns true if the token is a guest user token.
  1047. Arguments:
  1048. hToken - handle for the Security token for a user.
  1049. Returns:
  1050. BOOL.
  1051. History:
  1052. MuraliK 22-Jan-1996 Created.
  1053. --*/
  1054. {
  1055. BOOL fGuest = FALSE;
  1056. BYTE rgbInfo[MAX_TOKEN_USER_INFO];
  1057. DWORD cbTotalRequired;
  1058. //
  1059. // Get the user information associated with the token.
  1060. // Using this we can then query to find out if it belongs to a guest user.
  1061. //
  1062. if (GetTokenInformation( hToken,
  1063. TokenUser,
  1064. (LPVOID ) rgbInfo,
  1065. MAX_TOKEN_USER_INFO,
  1066. &cbTotalRequired)
  1067. ) {
  1068. TOKEN_USER * pTokenUser = (TOKEN_USER *) rgbInfo;
  1069. PSID pSid = pTokenUser->User.Sid;
  1070. fGuest = EqualSid( pSid, g_psidGuestUser);
  1071. } else {
  1072. IF_DEBUG( DLL_SECURITY) {
  1073. DBGPRINTF(( DBG_CONTEXT,
  1074. "GetTokenInformation(%08x) failed. Error = %d."
  1075. " sizeof(TOKEN_USER) = %d, cb = %d\n",
  1076. hToken,
  1077. GetLastError(),
  1078. sizeof(TOKEN_USER), cbTotalRequired
  1079. ));
  1080. }
  1081. }
  1082. return ( fGuest);
  1083. } // IsGuestUser()
  1084. /*******************************************************************
  1085. NAME: TsImpersonateUser
  1086. SYNOPSIS: Causes the current thread to impersonate the user
  1087. represented by the given impersonation token.
  1088. ENTRY: hToken - A handle to an impersonation token created
  1089. with ValidateUser. This is actually a pointer to
  1090. a cached token object.
  1091. RETURNS: BOOL - TRUE if successful, FALSE otherwise.
  1092. HISTORY:
  1093. KeithMo 07-Mar-1993 Created.
  1094. MuraliK 21-Feb-1996 Optimized Token caching
  1095. ********************************************************************/
  1096. BOOL TsImpersonateUser( TS_TOKEN hToken )
  1097. {
  1098. HANDLE hTok;
  1099. IF_DEBUG( DLL_SECURITY )
  1100. {
  1101. DBGPRINTF(( DBG_CONTEXT,
  1102. "impersonating user token %08lX : Imperonation(%08lx)\n",
  1103. CTO_TO_TOKEN(hToken),
  1104. ((CACHED_TOKEN *) hToken)->QueryImpersonationToken()
  1105. ));
  1106. }
  1107. hTok = ((CACHED_TOKEN *) hToken)->QueryImpersonationToken();
  1108. if ( hTok == NULL) {
  1109. // if there is no impersonation token use the normal token itself.
  1110. hTok = CTO_TO_TOKEN(hToken);
  1111. }
  1112. #if DBG
  1113. if( !ImpersonateLoggedOnUser( hTok ) )
  1114. {
  1115. DBGPRINTF(( DBG_CONTEXT,
  1116. "cannot impersonate user token %08lX, error %08lX\n",
  1117. CTO_TO_TOKEN(hToken),
  1118. GetLastError() ));
  1119. return FALSE;
  1120. }
  1121. return TRUE;
  1122. # else
  1123. return ( ImpersonateLoggedOnUser(hTok));
  1124. # endif // DBG
  1125. } // TsImpersonateUser
  1126. /*******************************************************************
  1127. NAME: TsDeleteUserToken
  1128. SYNOPSIS: Deletes a token created with ValidateUser.
  1129. ENTRY: hToken - An impersonation token created with
  1130. ValidateUser.
  1131. RETURNS: BOOL - TRUE if successful, FALSE otherwise.
  1132. HISTORY:
  1133. KeithMo 07-Mar-1993 Created.
  1134. ********************************************************************/
  1135. BOOL TsDeleteUserToken(
  1136. TS_TOKEN hToken
  1137. )
  1138. {
  1139. NTSTATUS ntStatus = STATUS_SUCCESS;
  1140. CACHED_TOKEN::Dereference( (CACHED_TOKEN *) hToken );
  1141. return TRUE;
  1142. } // DeleteUserToken
  1143. HANDLE
  1144. TsTokenToHandle(
  1145. TS_TOKEN hToken
  1146. )
  1147. /*++
  1148. Description:
  1149. Converts the token object into a real impersonation handle
  1150. Arguments:
  1151. hToken - pointer to cached token object
  1152. Returns:
  1153. Handle of real impersonation token
  1154. --*/
  1155. {
  1156. DBG_ASSERT( hToken != NULL );
  1157. return CTO_TO_TOKEN( hToken );
  1158. }
  1159. HANDLE
  1160. TsTokenToImpHandle(
  1161. TS_TOKEN hToken
  1162. )
  1163. /*++
  1164. Description:
  1165. Converts the token object into an impersonation handle
  1166. Arguments:
  1167. hToken - pointer to cached token object
  1168. Returns:
  1169. Handle of impersonation token
  1170. --*/
  1171. {
  1172. DBG_ASSERT( hToken != NULL );
  1173. return CTO_TO_IMPTOKEN( hToken );
  1174. }
  1175. BOOL
  1176. BuildAnonymousAcctDesc(
  1177. PTCP_AUTHENT_INFO pTAI
  1178. )
  1179. /*++
  1180. Routine Description:
  1181. Builds the anonymous account description based on the authentication
  1182. info structure.
  1183. Arguments:
  1184. pTAI - Pointer to authentication info to build
  1185. Returns:
  1186. TRUE if Success, FALSE otherwise
  1187. --*/
  1188. {
  1189. STACK_STATSTR (strDomainAndUser, IIS_DNLEN+UNLEN+2);
  1190. STACK_STATSTR (strPassword, PWLEN+1);
  1191. PCHAR pszUserOnly;
  1192. PCHAR pszDomain;
  1193. CHAR achAcctDesc[MAX_ACCT_DESC_LEN];
  1194. DWORD cbDescLen;
  1195. BOOL RetVal;
  1196. if ( g_fUseSingleToken ) {
  1197. pTAI->cbAnonAcctDesc = 0;
  1198. return TRUE;
  1199. }
  1200. if ( !pTAI->strAnonUserName.Clone( &strDomainAndUser) ||
  1201. !pTAI->strAnonUserPassword.Clone( &strPassword) )
  1202. {
  1203. RetVal = FALSE;
  1204. goto BuildAnonymousAcctDesc_exit;
  1205. }
  1206. // if the password is stored hashed, unhash it for usage
  1207. if (pTAI->fPwdIsHashed) {
  1208. strPassword.Unhash();
  1209. }
  1210. if ( !CrackUserAndDomain( strDomainAndUser.QueryStr(),
  1211. &pszUserOnly,
  1212. &pszDomain ))
  1213. {
  1214. DBGPRINTF((DBG_CONTEXT,
  1215. "BuildAnonymousAcctDesc: Call to CrackUserAndDomain failed\n"));
  1216. RetVal = FALSE;
  1217. goto BuildAnonymousAcctDesc_exit;
  1218. }
  1219. if ( !BuildAcctDesc( pszUserOnly,
  1220. pszDomain,
  1221. strPassword.QueryStr(),
  1222. !pTAI->fDontUseAnonSubAuth,
  1223. achAcctDesc,
  1224. &pTAI->cbAnonAcctDesc ) ||
  1225. !pTAI->bAnonAcctDesc.Resize( pTAI->cbAnonAcctDesc ))
  1226. {
  1227. RetVal = FALSE;
  1228. goto BuildAnonymousAcctDesc_exit;
  1229. }
  1230. memcpy( pTAI->bAnonAcctDesc.QueryPtr(),
  1231. achAcctDesc,
  1232. pTAI->cbAnonAcctDesc );
  1233. RetVal = TRUE;
  1234. BuildAnonymousAcctDesc_exit:
  1235. strPassword.Clear();
  1236. return RetVal;
  1237. }
  1238. BOOL
  1239. BuildAcctDesc(
  1240. IN const CHAR * pszUser,
  1241. IN const CHAR * pszDomain,
  1242. IN const CHAR * pszPwd,
  1243. IN BOOL fUseSubAuth,
  1244. OUT CHAR * pchAcctDesc,
  1245. OUT LPDWORD pdwAcctDescLen
  1246. )
  1247. /*++
  1248. Description:
  1249. Builds a cache descriptor for account cache
  1250. Arguments:
  1251. pszUser - User name attempting to logon
  1252. pszDomain - Domain the user belongs to
  1253. pszPwd - password (case sensitive)
  1254. fUseSubAuth - TRUE if sub-authenticator used
  1255. pchAcctDesc - updated with descriptor
  1256. pdwAcctDescLen - updated with descriptor length
  1257. Returns:
  1258. TRUE on success, otherwise FALSE
  1259. --*/
  1260. {
  1261. if ( fUseSubAuth )
  1262. {
  1263. pszPwd = "";
  1264. }
  1265. size_t lU = strlen( pszUser ) + 1;
  1266. size_t lD = strlen( pszDomain ) + 1;
  1267. size_t lP = strlen( pszPwd ) + 1;
  1268. if ( lU > (UNLEN+1) ||
  1269. lD > (IIS_DNLEN+1) ||
  1270. lP > (PWLEN+1) )
  1271. {
  1272. SetLastError( ERROR_INVALID_PARAMETER );
  1273. return FALSE;
  1274. }
  1275. *pdwAcctDescLen = (DWORD)(1 + lU + lD + lP);
  1276. LPBYTE pD = (BYTE *) pchAcctDesc;
  1277. *pD++ = (BYTE)fUseSubAuth;
  1278. memcpy( pD, pszUser, lU );
  1279. CharLower( (LPSTR)pD );
  1280. memcpy( pD + lU, pszDomain, lD );
  1281. _strlwr( (LPSTR)(pD+lU) );
  1282. memcpy( pD + lU + lD, pszPwd, lP );
  1283. DBG_ASSERT( (lU + lD + lP) < MAX_ACCT_DESC_LEN );
  1284. return TRUE;
  1285. }
  1286. BOOL
  1287. FindCachedToken(
  1288. IN const CHAR * pszUser,
  1289. IN const CHAR * pszDomain,
  1290. IN const CHAR * pszPwd,
  1291. IN BOOL fResetTTL,
  1292. IN BOOL fUseSubAuth,
  1293. IN DWORD dwLogonMethod,
  1294. OUT CACHED_TOKEN * * ppct
  1295. )
  1296. /*++
  1297. Description:
  1298. Checks to see if the specified user token handle is cached
  1299. Arguments:
  1300. pszUser - User name attempting to logon
  1301. pszDomain - Domain the user belongs to
  1302. pszPwd - password (case sensitive)
  1303. fResetTTL - Resets the TTL for this token
  1304. fUseSubAuth - TRUE if sub-authenticator used
  1305. dwLogonMethod - Logon method (Batch, Interactive, Network)
  1306. ppct - Receives token object
  1307. Returns:
  1308. TRUE on success and FALSE if the entry couldn't be found
  1309. --*/
  1310. {
  1311. LIST_ENTRY * pEntry;
  1312. CACHED_TOKEN * pct;
  1313. CHAR achAcctDesc[MAX_ACCT_DESC_LEN];
  1314. DWORD dwAcctDescLen;
  1315. LPBYTE pAcctDesc;
  1316. DBG_ASSERT( pszUser != NULL );
  1317. if ( !BuildAcctDesc( pszUser, pszDomain, pszPwd, fUseSubAuth, achAcctDesc, &dwAcctDescLen) )
  1318. {
  1319. return FALSE;
  1320. }
  1321. DBG_ASSERT( dwAcctDescLen < sizeof(achAcctDesc ));
  1322. pAcctDesc = (LPBYTE)achAcctDesc;
  1323. LockTokenCache();
  1324. for ( pEntry = TokenCacheList.Flink;
  1325. pEntry != &TokenCacheList;
  1326. pEntry = pEntry->Flink )
  1327. {
  1328. pct = CONTAINING_RECORD( pEntry, CACHED_TOKEN, _ListEntry );
  1329. if ( pct->m_dwAcctDescLen == dwAcctDescLen &&
  1330. pct->m_dwLogonMethod == dwLogonMethod &&
  1331. !memcmp( pct->_achAcctDesc, pAcctDesc, dwAcctDescLen ) )
  1332. {
  1333. CACHED_TOKEN::Reference( pct );
  1334. *ppct = pct;
  1335. //
  1336. // Reset the TTL if this is the anonymous user so items in the
  1337. // cache don't get invalidated (token handle used as a
  1338. // discriminator)
  1339. if ( fResetTTL )
  1340. {
  1341. pct->_TTL = 2;
  1342. }
  1343. UnlockTokenCache();
  1344. return TRUE;
  1345. }
  1346. if( !_stricmp( pct->m_achUserName, pszUser ) &&
  1347. !_stricmp( pct->m_achDomainName, pszDomain ) &&
  1348. pct->m_dwLogonMethod == dwLogonMethod )
  1349. {
  1350. UnlockTokenCache();
  1351. RemoveTokenFromCache( pct );
  1352. return FALSE;
  1353. }
  1354. }
  1355. UnlockTokenCache();
  1356. return FALSE;
  1357. } // FindCachedToken
  1358. TS_TOKEN
  1359. FastFindAnonymousToken(
  1360. IN PTCP_AUTHENT_INFO pTAI
  1361. )
  1362. /*++
  1363. Description:
  1364. Checks to see if the specified anonymous user token handle is cached.
  1365. Don't call this function when using the sub-authenticator!
  1366. Arguments:
  1367. pTAI - pointer to the anonymous authentication info
  1368. Returns:
  1369. Pointer to the cached object.
  1370. --*/
  1371. {
  1372. LIST_ENTRY * pEntry;
  1373. CACHED_TOKEN * pct;
  1374. LockTokenCache();
  1375. for ( pEntry = TokenCacheList.Flink;
  1376. pEntry != &TokenCacheList;
  1377. pEntry = pEntry->Flink ) {
  1378. pct = CONTAINING_RECORD( pEntry, CACHED_TOKEN, _ListEntry );
  1379. DBG_ASSERT(pct->m_dwAcctDescLen > 0);
  1380. if ( (pct->m_dwAcctDescLen == pTAI->cbAnonAcctDesc ) &&
  1381. RtlEqualMemory(
  1382. pct->_achAcctDesc,
  1383. pTAI->bAnonAcctDesc.QueryPtr(),
  1384. pct->m_dwAcctDescLen ) ) {
  1385. CACHED_TOKEN::Reference( pct );
  1386. //
  1387. // Reset the TTL if this is the anonymous user so items in the
  1388. // cache don't get invalidated (token handle used as a
  1389. // discriminator)
  1390. pct->_TTL = 2;
  1391. UnlockTokenCache();
  1392. return pct;
  1393. }
  1394. }
  1395. UnlockTokenCache();
  1396. return NULL;
  1397. } // FastFindAnonymousToken
  1398. BOOL
  1399. AddTokenToCache(
  1400. IN const CHAR * pszUser,
  1401. IN const CHAR * pszDomain,
  1402. IN const CHAR * pszPwd,
  1403. IN BOOL fUseSubAuth,
  1404. IN HANDLE hToken,
  1405. IN DWORD dwLogonMethod,
  1406. OUT CACHED_TOKEN * * ppct,
  1407. BOOL fCheckAlreadyExist,
  1408. LPBOOL pfExist
  1409. )
  1410. /*++
  1411. Description:
  1412. Adds the specified token to the cache and converts the token handle
  1413. to a cached token object
  1414. Arguments:
  1415. pszUser - User name attempting to logon
  1416. pszDomain - Domain the user belongs to
  1417. pszPwd - Cast sensitive password
  1418. fUseSubAuth - TRUE if subauth to be used
  1419. phToken - Contains the token handle that was just logged on
  1420. dwLogonMethod - Logon Method
  1421. ppct - Receives cached token object
  1422. fCheckAlreadyExist - check if entry with same name already exist
  1423. pfExist - updated with TRUE if acct already exists
  1424. Returns:
  1425. TRUE on success and FALSE if the entry couldn't be found
  1426. --*/
  1427. {
  1428. LIST_ENTRY * pEntry;
  1429. CACHED_TOKEN * pctF;
  1430. CACHED_TOKEN * pct;
  1431. DWORD dwAcctDescLen;
  1432. BOOL fFound = FALSE;
  1433. CHAR achAcctDesc[MAX_ACCT_DESC_LEN];
  1434. DBG_ASSERT( pszUser != NULL );
  1435. if( ( strlen( pszUser ) >= UNLEN ) ||
  1436. ( strlen( pszDomain ) >= IIS_DNLEN ) )
  1437. {
  1438. SetLastError( ERROR_INVALID_PARAMETER );
  1439. return FALSE;
  1440. }
  1441. if ( !BuildAcctDesc( pszUser, pszDomain, pszPwd, fUseSubAuth, achAcctDesc, &dwAcctDescLen) )
  1442. {
  1443. return FALSE;
  1444. }
  1445. pct = new CACHED_TOKEN;
  1446. if ( !pct )
  1447. {
  1448. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1449. return FALSE;
  1450. }
  1451. pct->_hToken = hToken;
  1452. pct->m_hImpersonationToken = NULL; // initialize to invalid value
  1453. CopyMemory( pct->_achAcctDesc, achAcctDesc, dwAcctDescLen );
  1454. pct->m_dwAcctDescLen = dwAcctDescLen;
  1455. pct->m_dwLogonMethod = dwLogonMethod;
  1456. strcpy( pct->m_achUserName, pszUser );
  1457. strcpy( pct->m_achDomainName, pszDomain );
  1458. //
  1459. // Add the token to the list, we check for duplicates at callers's request
  1460. //
  1461. LockTokenCache();
  1462. if ( fCheckAlreadyExist )
  1463. {
  1464. for ( pEntry = TokenCacheList.Flink;
  1465. pEntry != &TokenCacheList;
  1466. pEntry = pEntry->Flink )
  1467. {
  1468. pctF = CONTAINING_RECORD( pEntry, CACHED_TOKEN, _ListEntry );
  1469. if ( pctF->m_dwAcctDescLen == dwAcctDescLen &&
  1470. !memcmp( pctF->_achAcctDesc, pct->_achAcctDesc, dwAcctDescLen ) &&
  1471. pctF->m_dwLogonMethod == dwLogonMethod )
  1472. {
  1473. fFound = TRUE;
  1474. break;
  1475. }
  1476. }
  1477. }
  1478. *pfExist = fFound;
  1479. if ( !fFound )
  1480. {
  1481. InsertHeadList( &TokenCacheList, &pct->_ListEntry );
  1482. }
  1483. else
  1484. {
  1485. // delete cache item ( was not yet on list )
  1486. CACHED_TOKEN::Dereference( pct );
  1487. pct = pctF;
  1488. }
  1489. CACHED_TOKEN::Reference( pct );
  1490. UnlockTokenCache();
  1491. *ppct = pct;
  1492. return TRUE;
  1493. } // AddTokenToCache
  1494. VOID
  1495. RemoveTokenFromCache( IN CACHED_TOKEN * pct)
  1496. {
  1497. DBG_ASSERT( pct != NULL);
  1498. LockTokenCache();
  1499. //
  1500. // Remove from the list
  1501. //
  1502. if ( pct->_ListEntry.Flink )
  1503. {
  1504. RemoveEntryList( &pct->_ListEntry );
  1505. pct->_ListEntry.Flink = NULL;
  1506. //
  1507. // Free any handles this user may still have open
  1508. //
  1509. TsCacheFlushUser( pct->_hToken, FALSE );
  1510. CACHED_TOKEN::Dereference( pct );
  1511. }
  1512. UnlockTokenCache();
  1513. return;
  1514. } // RemoveTokenFromCache()
  1515. VOID
  1516. WINAPI
  1517. TokenCacheScavenger(
  1518. IN VOID * /* pContext */
  1519. )
  1520. /*++
  1521. Description:
  1522. Decrements TTLs and removes tokens that have timed out
  1523. Arguments:
  1524. pContext - Not used
  1525. --*/
  1526. {
  1527. LIST_ENTRY * pEntry;
  1528. LIST_ENTRY * pEntryNext;
  1529. CACHED_TOKEN * pct;
  1530. LockTokenCache();
  1531. for ( pEntry = TokenCacheList.Flink;
  1532. pEntry != &TokenCacheList; )
  1533. {
  1534. pEntryNext = pEntry->Flink;
  1535. pct = CONTAINING_RECORD( pEntry, CACHED_TOKEN, _ListEntry );
  1536. if ( !(--pct->_TTL) )
  1537. {
  1538. IF_DEBUG( DLL_SECURITY )
  1539. {
  1540. DBGPRINTF(( DBG_CONTEXT,
  1541. "[TokenCacheScavenger] Timing out token for %s\n",
  1542. pct->_achAcctDesc ));
  1543. }
  1544. //
  1545. // This item has timed out, remove from the list
  1546. //
  1547. RemoveEntryList( &pct->_ListEntry );
  1548. pct->_ListEntry.Flink = NULL;
  1549. //
  1550. // Free any handles this user may still have open
  1551. //
  1552. TsCacheFlushUser( pct->_hToken, FALSE );
  1553. CACHED_TOKEN::Dereference( pct );
  1554. }
  1555. pEntry = pEntryNext;
  1556. }
  1557. UnlockTokenCache();
  1558. } // TokenCacheScavenger
  1559. BOOL
  1560. TsGetSecretW(
  1561. WCHAR * pszSecretName,
  1562. BUFFER * pbufSecret
  1563. )
  1564. /*++
  1565. Description:
  1566. Retrieves the specified unicode secret
  1567. Arguments:
  1568. pszSecretName - LSA Secret to retrieve
  1569. pbufSecret - Receives found secret
  1570. Returns:
  1571. TRUE on success and FALSE if any failure.
  1572. --*/
  1573. {
  1574. BOOL fResult;
  1575. NTSTATUS ntStatus;
  1576. PUNICODE_STRING punicodePassword = NULL;
  1577. UNICODE_STRING unicodeSecret;
  1578. LSA_HANDLE hPolicy;
  1579. OBJECT_ATTRIBUTES ObjectAttributes;
  1580. if ( pfnLsaOpenPolicy == NULL ) {
  1581. DBGPRINTF((DBG_CONTEXT,"LsaOpenPolicy does not exist on win95\n"));
  1582. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1583. return(FALSE);
  1584. }
  1585. //
  1586. // Open a policy to the remote LSA
  1587. //
  1588. InitializeObjectAttributes( &ObjectAttributes,
  1589. NULL,
  1590. 0L,
  1591. NULL,
  1592. NULL );
  1593. ntStatus = pfnLsaOpenPolicy( NULL,
  1594. &ObjectAttributes,
  1595. POLICY_ALL_ACCESS,
  1596. &hPolicy );
  1597. if ( !NT_SUCCESS( ntStatus ) )
  1598. {
  1599. SetLastError( pfnLsaNtStatusToWinError( ntStatus ) );
  1600. return FALSE;
  1601. }
  1602. InitUnicodeString( &unicodeSecret, pszSecretName );
  1603. //
  1604. // Query the secret value.
  1605. //
  1606. ntStatus = pfnLsaRetrievePrivateData( hPolicy,
  1607. &unicodeSecret,
  1608. &punicodePassword );
  1609. if( NT_SUCCESS(ntStatus) )
  1610. {
  1611. DWORD cbNeeded;
  1612. cbNeeded = punicodePassword->Length + sizeof(WCHAR);
  1613. if ( !pbufSecret->Resize( cbNeeded ) )
  1614. {
  1615. ntStatus = STATUS_NO_MEMORY;
  1616. goto Failure;
  1617. }
  1618. CopyMemory(
  1619. pbufSecret->QueryPtr(),
  1620. punicodePassword->Buffer,
  1621. punicodePassword->Length
  1622. );
  1623. *((WCHAR *) pbufSecret->QueryPtr() +
  1624. punicodePassword->Length / sizeof(WCHAR)) = L'\0';
  1625. ZeroMemory( punicodePassword->Buffer,
  1626. punicodePassword->MaximumLength );
  1627. }
  1628. Failure:
  1629. fResult = NT_SUCCESS(ntStatus);
  1630. //
  1631. // Cleanup & exit.
  1632. //
  1633. if( punicodePassword != NULL )
  1634. {
  1635. pfnLsaFreeMemory( (PVOID)punicodePassword );
  1636. }
  1637. pfnLsaClose( hPolicy );
  1638. if ( !fResult )
  1639. {
  1640. SetLastError( pfnLsaNtStatusToWinError( ntStatus ));
  1641. }
  1642. return fResult;
  1643. } // TsGetSecretW
  1644. DWORD
  1645. TsSetSecretW(
  1646. IN LPWSTR SecretName,
  1647. IN LPWSTR pSecret,
  1648. IN DWORD cbSecret
  1649. )
  1650. /*++
  1651. Description
  1652. Sets the specified LSA secret
  1653. Arguments:
  1654. SecretName - Name of the LSA secret
  1655. pSecret - Pointer to secret memory
  1656. cbSecret - Size of pSecret memory block
  1657. Note:
  1658. --*/
  1659. {
  1660. LSA_HANDLE hPolicy;
  1661. UNICODE_STRING unicodePassword;
  1662. UNICODE_STRING unicodeServer;
  1663. NTSTATUS ntStatus;
  1664. OBJECT_ATTRIBUTES ObjectAttributes;
  1665. UNICODE_STRING unicodeSecret;
  1666. InitUnicodeString( &unicodeServer,
  1667. L"" );
  1668. //
  1669. // Initialize the unicode string by hand so we can handle '\0' in the
  1670. // string
  1671. //
  1672. unicodePassword.Buffer = pSecret;
  1673. unicodePassword.Length = (USHORT) cbSecret;
  1674. unicodePassword.MaximumLength = (USHORT) cbSecret;
  1675. //
  1676. // Open a policy to the remote LSA
  1677. //
  1678. InitializeObjectAttributes( &ObjectAttributes,
  1679. NULL,
  1680. 0L,
  1681. NULL,
  1682. NULL );
  1683. ntStatus = pfnLsaOpenPolicy( &unicodeServer,
  1684. &ObjectAttributes,
  1685. POLICY_ALL_ACCESS,
  1686. &hPolicy );
  1687. if ( !NT_SUCCESS( ntStatus ) )
  1688. return pfnLsaNtStatusToWinError( ntStatus );
  1689. //
  1690. // Create or open the LSA secret
  1691. //
  1692. InitUnicodeString( &unicodeSecret,
  1693. SecretName );
  1694. ntStatus = pfnLsaStorePrivateData( hPolicy,
  1695. &unicodeSecret,
  1696. &unicodePassword );
  1697. pfnLsaClose( hPolicy );
  1698. if ( !NT_SUCCESS( ntStatus ))
  1699. {
  1700. return pfnLsaNtStatusToWinError( ntStatus );
  1701. }
  1702. return NO_ERROR;
  1703. } // TsSetSecretW()
  1704. /*******************************************************************
  1705. NAME: ApiAccessCheck
  1706. SYNOPSIS: Impersonate the RPC client, then check for valid
  1707. access against our server security object.
  1708. ENTRY: maskDesiredAccess - Specifies the desired access mask.
  1709. This mask must not contain generic accesses.
  1710. RETURNS: DWORD - NO_ERROR if access granted, ERROR_ACCESS_DENIED
  1711. if access denied, other Win32 errors if something
  1712. tragic happened.
  1713. HISTORY:
  1714. KeithMo 26-Mar-1993 Created.
  1715. ********************************************************************/
  1716. DWORD TsApiAccessCheck( ACCESS_MASK maskDesiredAccess )
  1717. {
  1718. DWORD err;
  1719. BOOL fRet;
  1720. if ( maskDesiredAccess == TCP_QUERY_STATISTICS) {
  1721. //
  1722. // Statistics query should be allowed without authentication.
  1723. // Any body can bring up perfmon and request statistics.
  1724. //
  1725. return ( NO_ERROR);
  1726. }
  1727. //
  1728. // Impersonate the RPC client.
  1729. //
  1730. err = (DWORD)RpcImpersonateClient( NULL );
  1731. if( err != NO_ERROR )
  1732. {
  1733. IF_DEBUG( DLL_SECURITY )
  1734. {
  1735. DBGPRINTF(( DBG_CONTEXT,
  1736. "cannot impersonate rpc client, error %lu\n",
  1737. err ));
  1738. }
  1739. } else {
  1740. BOOL fAccessStatus;
  1741. BOOL fGenerateOnClose;
  1742. ACCESS_MASK maskAccessGranted = 0;
  1743. //
  1744. // Validate access.
  1745. //
  1746. if ( g_fUseSingleToken )
  1747. {
  1748. HANDLE hAccToken;
  1749. BYTE Set[256];
  1750. DWORD dwSet = sizeof(Set);
  1751. if ( OpenThreadToken( GetCurrentThread(), TOKEN_READ, TRUE, &hAccToken ) )
  1752. {
  1753. fRet = AccessCheck( sdApiObject,
  1754. hAccToken,
  1755. maskDesiredAccess,
  1756. &TCPApiObjectMapping,
  1757. (PPRIVILEGE_SET)&Set,
  1758. &dwSet,
  1759. &maskAccessGranted,
  1760. &fAccessStatus );
  1761. CloseHandle( hAccToken );
  1762. }
  1763. else
  1764. {
  1765. fRet = FALSE;
  1766. }
  1767. }
  1768. else
  1769. {
  1770. fRet = AccessCheckAndAuditAlarmW( SUBSYSTEM_NAME,
  1771. NULL,
  1772. OBJECTTYPE_NAME,
  1773. OBJECT_NAME,
  1774. sdApiObject,
  1775. maskDesiredAccess,
  1776. &TCPApiObjectMapping,
  1777. FALSE,
  1778. &maskAccessGranted,
  1779. &fAccessStatus,
  1780. &fGenerateOnClose );
  1781. }
  1782. if ( !fRet ) {
  1783. err = GetLastError();
  1784. }
  1785. //
  1786. // Revert to our former self.
  1787. //
  1788. DBG_REQUIRE( !RpcRevertToSelf() );
  1789. //
  1790. // Check the results.
  1791. //
  1792. if( err != NO_ERROR ) {
  1793. IF_DEBUG( DLL_SECURITY ) {
  1794. DBGPRINTF(( DBG_CONTEXT,
  1795. "cannot check access, error %lu\n",
  1796. err ));
  1797. }
  1798. } else if( !fAccessStatus ) {
  1799. err = ERROR_ACCESS_DENIED;
  1800. IF_DEBUG( DLL_SECURITY ) {
  1801. DBGPRINTF(( DBG_CONTEXT,
  1802. "bad access status, error %lu\n",
  1803. err ));
  1804. }
  1805. }
  1806. }
  1807. return (err);
  1808. } // ApiAccessCheck
  1809. /*******************************************************************
  1810. NAME: CreateWellKnownSids
  1811. SYNOPSIS: Create some well-known SIDs used to create a security
  1812. descriptor for the API security object.
  1813. RETURNS: NTSTATUS - An NT Status code.
  1814. HISTORY:
  1815. KeithMo 26-Mar-1993 Created.
  1816. ********************************************************************/
  1817. DWORD CreateWellKnownSids( HINSTANCE hDll )
  1818. {
  1819. DWORD error = NO_ERROR;
  1820. SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
  1821. SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY;
  1822. BOOL fRet;
  1823. fRet = AllocateAndInitializeSid( &siaWorld,
  1824. 1,
  1825. SECURITY_WORLD_RID,
  1826. 0,0,0,0,0,0,0,
  1827. &psidWorld );
  1828. if( fRet )
  1829. {
  1830. fRet = AllocateAndInitializeSid( &siaNt,
  1831. 1,
  1832. SECURITY_LOCAL_SYSTEM_RID,
  1833. 0,0,0,0,0,0,0,
  1834. &psidLocalSystem );
  1835. }
  1836. if( fRet )
  1837. {
  1838. fRet = AllocateAndInitializeSid( &siaNt,
  1839. 2,
  1840. SECURITY_BUILTIN_DOMAIN_RID,
  1841. DOMAIN_ALIAS_RID_ADMINS,
  1842. 0,0,0,0,0,0,
  1843. &psidAdmins );
  1844. }
  1845. if( fRet )
  1846. {
  1847. fRet = AllocateAndInitializeSid( &siaNt,
  1848. 2,
  1849. SECURITY_BUILTIN_DOMAIN_RID,
  1850. DOMAIN_ALIAS_RID_SYSTEM_OPS,
  1851. 0,0,0,0,0,0,
  1852. &psidServerOps );
  1853. }
  1854. if( fRet )
  1855. {
  1856. fRet = AllocateAndInitializeSid( &siaNt,
  1857. 2,
  1858. SECURITY_BUILTIN_DOMAIN_RID,
  1859. DOMAIN_ALIAS_RID_POWER_USERS,
  1860. 0,0,0,0,0,0,
  1861. &psidPowerUsers );
  1862. }
  1863. if( fRet )
  1864. {
  1865. USER_MODALS_INFO_2 * pUsrModals2 = NULL;
  1866. HINSTANCE hInstance = NULL;
  1867. NET_USER_MODALS_GET_FN pfnNetUserModalsGet = NULL;
  1868. NET_API_BUFFER_FREE_FN pfnNetApiBufferFree = NULL;
  1869. //
  1870. // Construct well-known-sid for Guest User on the local computer
  1871. //
  1872. // 1) Obtain the sid for the local machine's domain
  1873. // 2) copy domain sid to guest user sid
  1874. // 3) append DOMAIN_USER_RID_GUEST to the domain sid in GuestUser sid.
  1875. //
  1876. g_psidGuestUser = (PSID ) g_GuestUserSidBuffer;
  1877. hInstance = LoadLibrary("netapi32.dll");
  1878. if ( hInstance != NULL ) {
  1879. pfnNetUserModalsGet = (NET_USER_MODALS_GET_FN)
  1880. GetProcAddress(hInstance,"NetUserModalsGet");
  1881. pfnNetApiBufferFree = (NET_API_BUFFER_FREE_FN)
  1882. GetProcAddress(hInstance,"NetApiBufferFree");
  1883. }
  1884. if ( (pfnNetUserModalsGet != NULL) &&
  1885. (pfnNetApiBufferFree != NULL) ) {
  1886. fRet = ( (pfnNetUserModalsGet(NULL, // local computer
  1887. 2, // get level 2 information
  1888. (LPBYTE *) &pUsrModals2
  1889. ) == 0)
  1890. &&
  1891. CopySid(GUEST_USER_SID_BUFFER_LEN - 4,// Buffer len
  1892. g_psidGuestUser, // psidDestination
  1893. pUsrModals2->usrmod2_domain_id // obtain domain sid.
  1894. )
  1895. );
  1896. } else {
  1897. DBGPRINTF((DBG_CONTEXT,"Unable to get netapi32 entrypoints\n"));
  1898. fRet = FALSE;
  1899. }
  1900. //
  1901. // if successful append the DOMAIN_USER_RID_GUEST.
  1902. //
  1903. if ( fRet) {
  1904. DWORD lenSid = GetLengthSid( g_psidGuestUser);
  1905. CHAR nSubAuth;
  1906. //
  1907. // There is no Win32 way to set a SID value.
  1908. // We will munge around on our own.
  1909. // Pretty dangerous thing to do :-(
  1910. //
  1911. // increment the number of sub authorities
  1912. nSubAuth = *((UCHAR *) ((UCHAR *) g_psidGuestUser + 1));
  1913. nSubAuth++;
  1914. *((UCHAR *) ((UCHAR *) g_psidGuestUser + 1)) = nSubAuth;
  1915. // Store the new sub authority (Domain User Rid for Guest).
  1916. *((ULONG *) ((BYTE *) g_psidGuestUser + lenSid)) =
  1917. DOMAIN_USER_RID_GUEST;
  1918. } else {
  1919. g_psidGuestUser = NULL;
  1920. }
  1921. if ( pUsrModals2 != NULL) {
  1922. NET_API_STATUS ns = pfnNetApiBufferFree( (LPVOID )pUsrModals2);
  1923. pUsrModals2 = NULL;
  1924. }
  1925. if ( hInstance != NULL ) {
  1926. FreeLibrary(hInstance);
  1927. }
  1928. }
  1929. if ( fRet && g_fUseSingleToken )
  1930. {
  1931. BYTE abInfo[256];
  1932. DWORD dwInfo;
  1933. if ( GetTokenInformation( g_hProcessPrimaryToken,
  1934. TokenUser,
  1935. abInfo,
  1936. sizeof(abInfo),
  1937. &dwInfo ) )
  1938. {
  1939. if ( !(g_psidProcessUser = (PSID)LocalAlloc( LMEM_FIXED,
  1940. GetLengthSid(((TOKEN_USER*)abInfo)->User.Sid))) )
  1941. {
  1942. fRet = FALSE;
  1943. }
  1944. else
  1945. {
  1946. memcpy ( g_psidProcessUser,
  1947. ((TOKEN_USER*)abInfo)->User.Sid,
  1948. GetLengthSid(((TOKEN_USER*)abInfo)->User.Sid) );
  1949. }
  1950. }
  1951. else
  1952. {
  1953. fRet = FALSE;
  1954. }
  1955. }
  1956. if ( !fRet ) {
  1957. error = GetLastError( );
  1958. IF_DEBUG( DLL_SECURITY ) {
  1959. DBGPRINTF(( DBG_CONTEXT,
  1960. "cannot create well-known sids\n" ));
  1961. }
  1962. }
  1963. return error;
  1964. } // CreateWellKnownSids
  1965. /*******************************************************************
  1966. NAME: FreeWellKnownSids
  1967. SYNOPSIS: Frees the SIDs created with CreateWellKnownSids.
  1968. HISTORY:
  1969. KeithMo 26-Mar-1993 Created.
  1970. ********************************************************************/
  1971. VOID FreeWellKnownSids( VOID )
  1972. {
  1973. if( psidWorld != NULL )
  1974. {
  1975. FreeSid( psidWorld );
  1976. psidWorld = NULL;
  1977. }
  1978. if( psidLocalSystem != NULL )
  1979. {
  1980. FreeSid( psidLocalSystem );
  1981. psidLocalSystem = NULL;
  1982. }
  1983. if( psidAdmins != NULL )
  1984. {
  1985. FreeSid( psidAdmins );
  1986. psidAdmins = NULL;
  1987. }
  1988. if( psidServerOps != NULL )
  1989. {
  1990. FreeSid( psidServerOps );
  1991. psidServerOps = NULL;
  1992. }
  1993. if( psidPowerUsers != NULL )
  1994. {
  1995. FreeSid( psidPowerUsers );
  1996. psidPowerUsers = NULL;
  1997. }
  1998. if( g_psidProcessUser != NULL )
  1999. {
  2000. LocalFree( g_psidProcessUser );
  2001. g_psidProcessUser = NULL;
  2002. }
  2003. } // FreeWellKnownSids
  2004. /*******************************************************************
  2005. NAME: CreateApiSecurityObject
  2006. SYNOPSIS: Create an abstract security object used for validating
  2007. user access to the TCP Server APIs.
  2008. RETURNS: NTSTATUS - An NT Status code.
  2009. HISTORY:
  2010. KeithMo 26-Mar-1993 Created.
  2011. ********************************************************************/
  2012. DWORD CreateApiSecurityObject( VOID )
  2013. {
  2014. DWORD err;
  2015. ACE_DATA aces[] =
  2016. {
  2017. {
  2018. ACCESS_ALLOWED_ACE_TYPE,
  2019. 0,
  2020. 0,
  2021. TCP_ALL_ACCESS,
  2022. &psidLocalSystem
  2023. },
  2024. {
  2025. ACCESS_ALLOWED_ACE_TYPE,
  2026. 0,
  2027. 0,
  2028. TCP_ALL_ACCESS,
  2029. &psidAdmins
  2030. },
  2031. {
  2032. ACCESS_ALLOWED_ACE_TYPE,
  2033. 0,
  2034. 0,
  2035. TCP_ALL_ACCESS,
  2036. &psidServerOps
  2037. },
  2038. {
  2039. ACCESS_ALLOWED_ACE_TYPE,
  2040. 0,
  2041. 0,
  2042. TCP_ALL_ACCESS,
  2043. &psidPowerUsers
  2044. },
  2045. {
  2046. ACCESS_ALLOWED_ACE_TYPE,
  2047. 0,
  2048. 0,
  2049. TCP_GENERIC_EXECUTE,
  2050. &psidWorld
  2051. },
  2052. {
  2053. ACCESS_ALLOWED_ACE_TYPE,
  2054. 0,
  2055. 0,
  2056. TCP_GENERIC_EXECUTE,
  2057. &g_psidProcessUser
  2058. },
  2059. };
  2060. #define NUM_ACES (sizeof(aces) / sizeof(RTL_ACE_DATA))
  2061. err = INetCreateSecurityObject( aces,
  2062. (ULONG)(g_fUseSingleToken ? NUM_ACES : NUM_ACES-1),
  2063. NULL,
  2064. NULL,
  2065. &TCPApiObjectMapping,
  2066. &sdApiObject );
  2067. IF_DEBUG( DLL_SECURITY )
  2068. {
  2069. if( err )
  2070. {
  2071. DBGPRINTF(( DBG_CONTEXT,
  2072. "cannot create api security object, error %d\n",
  2073. err ));
  2074. }
  2075. }
  2076. return err;
  2077. } // CreateApiSecurityObject
  2078. /*******************************************************************
  2079. NAME: DeleteApiSecurityObject
  2080. SYNOPSIS: Frees the security descriptor created with
  2081. CreateApiSecurityObject.
  2082. HISTORY:
  2083. KeithMo 26-Mar-1993 Created.
  2084. ********************************************************************/
  2085. VOID DeleteApiSecurityObject( VOID )
  2086. {
  2087. INetDeleteSecurityObject( &sdApiObject );
  2088. } // DeleteApiSecurityObject
  2089. //
  2090. // Short routine to enable the TcbPrivilege for testing services running
  2091. // as an executable (rather then a service). Note that the account
  2092. // running the .exe must be added in User Manager's User Right's dialog
  2093. // under "Act as part of the OS"
  2094. //
  2095. VOID EnableTcbPrivilege(
  2096. VOID
  2097. )
  2098. {
  2099. HANDLE ProcessHandle = NULL;
  2100. HANDLE TokenHandle = NULL;
  2101. BOOL Result;
  2102. LUID TcbValue;
  2103. LUID AuditValue;
  2104. TOKEN_PRIVILEGES * TokenPrivileges;
  2105. CHAR buf[ 5 * sizeof(TOKEN_PRIVILEGES) ];
  2106. ProcessHandle = OpenProcess(
  2107. PROCESS_QUERY_INFORMATION,
  2108. FALSE,
  2109. GetCurrentProcessId()
  2110. );
  2111. if ( ProcessHandle == NULL ) {
  2112. //
  2113. // This should not happen
  2114. //
  2115. goto Cleanup;
  2116. }
  2117. Result = OpenProcessToken (
  2118. ProcessHandle,
  2119. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  2120. &TokenHandle
  2121. );
  2122. if ( !Result ) {
  2123. //
  2124. // This should not happen
  2125. //
  2126. goto Cleanup;
  2127. }
  2128. //
  2129. // Find out the value of TakeOwnershipPrivilege
  2130. //
  2131. Result = LookupPrivilegeValue(
  2132. NULL,
  2133. "SeTcbPrivilege",
  2134. &TcbValue
  2135. );
  2136. if ( !Result ) {
  2137. goto Cleanup;
  2138. }
  2139. //
  2140. // Need this for RPC impersonation (calls NtAccessCheckAndAuditAlarm)
  2141. //
  2142. Result = LookupPrivilegeValue(
  2143. NULL,
  2144. "SeAuditPrivilege",
  2145. &AuditValue
  2146. );
  2147. if ( !Result ) {
  2148. goto Cleanup;
  2149. }
  2150. //
  2151. // Set up the privilege set we will need
  2152. //
  2153. TokenPrivileges = (TOKEN_PRIVILEGES *) buf;
  2154. TokenPrivileges->PrivilegeCount = 2;
  2155. TokenPrivileges->Privileges[0].Luid = TcbValue;
  2156. TokenPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  2157. TokenPrivileges->Privileges[1].Luid = AuditValue;
  2158. TokenPrivileges->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
  2159. (VOID) AdjustTokenPrivileges (
  2160. TokenHandle,
  2161. FALSE,
  2162. TokenPrivileges,
  2163. sizeof(buf),
  2164. NULL,
  2165. NULL
  2166. );
  2167. Cleanup:
  2168. if ( TokenHandle )
  2169. {
  2170. CloseHandle( TokenHandle );
  2171. }
  2172. if ( ProcessHandle )
  2173. {
  2174. CloseHandle( ProcessHandle );
  2175. }
  2176. }
  2177. BOOL CrackUserAndDomain(
  2178. CHAR * pszDomainAndUser,
  2179. CHAR * * ppszUser,
  2180. CHAR * * ppszDomain
  2181. )
  2182. /*++
  2183. Routine Description:
  2184. Given a user name potentially in the form domain\user, zero terminates
  2185. the domain name and returns pointers to the domain name and the user name
  2186. Arguments:
  2187. pszDomainAndUser - Pointer to user name or domain and user name
  2188. ppszUser - Receives pointer to user portion of name
  2189. ppszDomain - Receives pointer to domain portion of name
  2190. Return Value:
  2191. TRUE if successful, FALSE otherwise (call GetLastError)
  2192. --*/
  2193. {
  2194. static CHAR szDefaultDomain[MAX_COMPUTERNAME_LENGTH+1];
  2195. // BUGBUG: how come this does not screw up multi domain per multi site???
  2196. //
  2197. // Crack the name into domain/user components.
  2198. //
  2199. *ppszDomain = pszDomainAndUser;
  2200. *ppszUser = (PCHAR)_mbspbrk( (PUCHAR)pszDomainAndUser, (PUCHAR)"/\\" );
  2201. if( *ppszUser == NULL )
  2202. {
  2203. //
  2204. // No domain name specified, just the username so we assume the
  2205. // user is on the local machine
  2206. //
  2207. if ( !*szDefaultDomain )
  2208. {
  2209. if ( !pfnGetDefaultDomainName( szDefaultDomain,
  2210. sizeof(szDefaultDomain)))
  2211. {
  2212. return FALSE;
  2213. }
  2214. }
  2215. *ppszDomain = szDefaultDomain;
  2216. *ppszUser = pszDomainAndUser;
  2217. }
  2218. else
  2219. {
  2220. //
  2221. // Both domain & user specified, skip delimiter.
  2222. //
  2223. **ppszUser = '\0';
  2224. (*ppszUser)++;
  2225. if( ( **ppszUser == '\0' ) ||
  2226. ( **ppszUser == '\\' ) ||
  2227. ( **ppszUser == '/' ) ||
  2228. ( *pszDomainAndUser == '\0' ) )
  2229. {
  2230. //
  2231. // Name is of one of the following (invalid) forms:
  2232. //
  2233. // "domain\"
  2234. // "domain\\..."
  2235. // "domain/..."
  2236. // "\username"
  2237. // "/username"
  2238. //
  2239. SetLastError( ERROR_INVALID_PARAMETER );
  2240. return FALSE;
  2241. }
  2242. }
  2243. return TRUE;
  2244. }
  2245. LONG
  2246. WINAPI
  2247. NullReferenceMapper(
  2248. IN HMAPPER *pMap
  2249. )
  2250. /*++
  2251. Routine Description:
  2252. Increment reference count to mapper
  2253. Arguments:
  2254. pMap - ptr to mapper struct
  2255. Returns:
  2256. Ref count
  2257. --*/
  2258. {
  2259. DBG_ASSERT( ((IisMapper*)pMap)->dwSignature == IIS_MAPPER_SIGNATURE );
  2260. return pfnInterlockedExchangeAdd( &((IisMapper*)pMap)->lRefCount, 1 ) + 1;
  2261. }
  2262. LONG
  2263. WINAPI
  2264. NullDeReferenceMapper(
  2265. IN HMAPPER *pMap
  2266. )
  2267. /*++
  2268. Routine Description:
  2269. Decrement reference count to mapper
  2270. Arguments:
  2271. pMap - ptr to mapper struct
  2272. Returns:
  2273. Ref count
  2274. --*/
  2275. {
  2276. LONG l;
  2277. DBG_ASSERT( ((IisMapper*)pMap)->dwSignature == IIS_MAPPER_SIGNATURE );
  2278. if ( !(l = pfnInterlockedExchangeAdd( &((IisMapper*)pMap)->lRefCount, -1 ) - 1 ) )
  2279. {
  2280. LocalFree( pMap );
  2281. }
  2282. return l;
  2283. }
  2284. DWORD WINAPI NullGetIssuerList(
  2285. HMAPPER *phMapper, // in
  2286. VOID * Reserved, // in
  2287. BYTE * pIssuerList, // out
  2288. DWORD * pcbIssuerList // out
  2289. )
  2290. /*++
  2291. Routine Description:
  2292. Called to retrieve the list of preferred cert issuers
  2293. Arguments:
  2294. ppIssuer -- updated with ptr buffer of issuers
  2295. pdwIssuer -- updated with issuers buffer size
  2296. Returns:
  2297. TRUE if success, FALSE if error
  2298. --*/
  2299. {
  2300. return SEC_E_UNSUPPORTED_FUNCTION;
  2301. }
  2302. DWORD WINAPI NullGetChallenge(
  2303. HMAPPER *pMap, // in
  2304. BYTE * pAuthenticatorId, // in
  2305. DWORD cbAuthenticatorId, // in
  2306. BYTE * pChallenge, // out
  2307. DWORD * pcbChallenge // out
  2308. )
  2309. /*++
  2310. Routine Description:
  2311. Get challenge for auth sequence
  2312. Arguments:
  2313. Not used
  2314. Returns:
  2315. FALSE ( not supported )
  2316. --*/
  2317. {
  2318. DBG_ASSERT( ((IisMapper*)pMap)->dwSignature == IIS_MAPPER_SIGNATURE );
  2319. return SEC_E_UNSUPPORTED_FUNCTION;
  2320. }
  2321. DWORD WINAPI NullMapCredential(
  2322. HMAPPER * phMapper,
  2323. DWORD dwCredentialType,
  2324. const VOID* pCredential, // in
  2325. const VOID* pAuthority, // in
  2326. HLOCATOR * phToken
  2327. )
  2328. /*++
  2329. Routine Description:
  2330. Called to map a certificate to a NT account
  2331. Arguments:
  2332. phMapper - ptr to mapper descriptor
  2333. dwCredentialType -- type of credential
  2334. pCredential - ptr to PCERT_CONTEXT for client cert
  2335. pAuthority - ptr to PCERT_CONTEXT for Certifying authority
  2336. phToken -- updated with impersonation access token
  2337. Returns:
  2338. FALSE ( mapping always fail )
  2339. --*/
  2340. {
  2341. DBG_ASSERT( ((IisMapper*)phMapper)->dwSignature == IIS_MAPPER_SIGNATURE );
  2342. return SEC_E_UNSUPPORTED_FUNCTION;
  2343. }
  2344. DWORD WINAPI NullCloseLocator(
  2345. HMAPPER *pMap,
  2346. HLOCATOR hLocator //in
  2347. )
  2348. /*++
  2349. Routine Description:
  2350. Called to close a HLOCATOR returned by MapCredential
  2351. Arguments:
  2352. tokenhandle -- HLOCATOR
  2353. Returns:
  2354. TRUE if success, FALSE if error
  2355. --*/
  2356. {
  2357. DBG_ASSERT( ((IisMapper*)pMap)->dwSignature == IIS_MAPPER_SIGNATURE );
  2358. if (hLocator == 1) {
  2359. return SEC_E_OK;
  2360. }
  2361. else {
  2362. if (CloseHandle( (HANDLE)hLocator )) {\
  2363. return SEC_E_OK;
  2364. }
  2365. else {
  2366. }
  2367. }
  2368. return hLocator == 1 ? TRUE : CloseHandle( (HANDLE)hLocator );
  2369. }
  2370. DWORD WINAPI NullGetAccessToken(
  2371. HMAPPER *pMap,
  2372. HLOCATOR tokenhandle,
  2373. HANDLE * phToken
  2374. )
  2375. /*++
  2376. Routine Description:
  2377. Called to retrieve an access token from a mapping
  2378. Arguments:
  2379. tokenhandle -- HLOCATOR returned by MapCredential
  2380. phToken -- updated with potentially new token
  2381. Returns:
  2382. TRUE if success, FALSE if error
  2383. --*/
  2384. {
  2385. DBG_ASSERT( ((IisMapper*)pMap)->dwSignature == IIS_MAPPER_SIGNATURE );
  2386. if ( tokenhandle == 1 )
  2387. {
  2388. *phToken = (HANDLE)tokenhandle;
  2389. }
  2390. else if ( !pfnDuplicateTokenEx( (HANDLE)tokenhandle,
  2391. TOKEN_ALL_ACCESS,
  2392. NULL,
  2393. SecurityImpersonation,
  2394. TokenImpersonation,
  2395. phToken ))
  2396. {
  2397. return SEC_E_UNSUPPORTED_FUNCTION;
  2398. }
  2399. return SEC_E_OK;
  2400. }
  2401. DWORD WINAPI NullQueryMappedCredentialAttributes(
  2402. HMAPPER *phMapper, // in
  2403. HLOCATOR hLocator, // in
  2404. ULONG ulAttribute, // in
  2405. PVOID pBuffer, //out
  2406. DWORD *pcbBuffer // in out
  2407. )
  2408. {
  2409. return ( SEC_E_NOT_SUPPORTED );
  2410. }
  2411. QuerySingleAccessToken(
  2412. VOID
  2413. )
  2414. /*++
  2415. Routine Description:
  2416. Query status of single access token mode
  2417. Arguments:
  2418. None
  2419. Returns:
  2420. TRUE if single access token mode used, otherwise FALSE
  2421. --*/
  2422. {
  2423. return g_fUseSingleToken;
  2424. }
  2425. BOOL
  2426. CACHED_CREDENTIAL::GetCredential(
  2427. LPSTR pszPackage,
  2428. PIIS_SERVER_INSTANCE psi,
  2429. PTCP_AUTHENT_INFO pTAI,
  2430. CredHandle* prcred,
  2431. ULONG* pcbMaxToken
  2432. )
  2433. /*++
  2434. Routine Description:
  2435. Get SSPI credential handle from cache
  2436. Arguments:
  2437. pszPackage - SSPI package name, e.g NTLM
  2438. psi - pointer to server instance
  2439. pTAI - pointer to authent info, only DomainName used
  2440. prcred - updated with CredHandle from cache
  2441. pcbMaxToken - updated with max token size used by this package
  2442. Returns:
  2443. TRUE if success, otherwise FALSE
  2444. --*/
  2445. {
  2446. LIST_ENTRY * pEntry;
  2447. CACHED_CREDENTIAL * pcred;
  2448. SEC_WINNT_AUTH_IDENTITY AuthIdentity;
  2449. SEC_WINNT_AUTH_IDENTITY * pAuthIdentity;
  2450. SecPkgInfo * pspkg;
  2451. TimeStamp Lifetime;
  2452. STACK_STR ( strDefaultLogonDomain, IIS_DNLEN+1 );
  2453. SECURITY_STATUS ss;
  2454. DBG_ASSERT( pszPackage != NULL );
  2455. DBG_ASSERT( pTAI != NULL );
  2456. EnterCriticalSection( &csCredentialCacheLock );
  2457. for ( pEntry = CredentialCacheList.Flink;
  2458. pEntry != &CredentialCacheList;
  2459. pEntry = pEntry->Flink )
  2460. {
  2461. pcred = CONTAINING_RECORD( pEntry, CACHED_CREDENTIAL, _ListEntry );
  2462. if ( !strcmp( pszPackage, pcred->_PackageName.QueryStr() ) &&
  2463. !strcmp( pTAI->strDefaultLogonDomain.QueryStr(), pcred->_DefaultDomain.QueryStr() ) )
  2464. {
  2465. goto Exit;
  2466. }
  2467. }
  2468. if ( (pcred = new CACHED_CREDENTIAL) == NULL )
  2469. {
  2470. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2471. goto Exit;
  2472. }
  2473. if ( !pcred->_PackageName.Copy( pszPackage ) ||
  2474. !pcred->_DefaultDomain.Copy( pTAI->strDefaultLogonDomain ) )
  2475. {
  2476. delete pcred;
  2477. pcred = NULL;
  2478. goto Exit;
  2479. }
  2480. //
  2481. // provide default logon domain
  2482. //
  2483. if ( psi == NULL )
  2484. {
  2485. pAuthIdentity = NULL;
  2486. }
  2487. else
  2488. {
  2489. pAuthIdentity = &AuthIdentity;
  2490. memset( &AuthIdentity,
  2491. 0,
  2492. sizeof( AuthIdentity ));
  2493. if ( pTAI->strDefaultLogonDomain.QueryCCH() <= IIS_DNLEN )
  2494. {
  2495. strDefaultLogonDomain.Copy( pTAI->strDefaultLogonDomain );
  2496. AuthIdentity.Domain = (LPBYTE)strDefaultLogonDomain.QueryStr();
  2497. }
  2498. if ( AuthIdentity.Domain != NULL )
  2499. {
  2500. if ( AuthIdentity.DomainLength =
  2501. strlen( (LPCTSTR)AuthIdentity.Domain ) )
  2502. {
  2503. // remove trailing '\\' if present
  2504. if ( AuthIdentity.Domain[AuthIdentity.DomainLength-1]
  2505. == '\\' )
  2506. {
  2507. --AuthIdentity.DomainLength;
  2508. }
  2509. }
  2510. }
  2511. if ( AuthIdentity.DomainLength == 0 )
  2512. {
  2513. pAuthIdentity = NULL;
  2514. }
  2515. else
  2516. {
  2517. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  2518. }
  2519. }
  2520. ss = pfnAcquireCredentialsHandle( NULL, // New principal
  2521. pszPackage, // Package name
  2522. SECPKG_CRED_INBOUND,
  2523. NULL, // Logon ID
  2524. pAuthIdentity, // Auth Data
  2525. NULL, // Get key func
  2526. NULL, // Get key arg
  2527. &pcred->_hcred,
  2528. &Lifetime );
  2529. //
  2530. // Need to determine the max token size for this package
  2531. //
  2532. if ( ss == STATUS_SUCCESS )
  2533. {
  2534. pcred->_fHaveCredHandle = TRUE;
  2535. ss = pfnQuerySecurityPackageInfo( (char *) pszPackage,
  2536. &pspkg );
  2537. }
  2538. if ( ss == STATUS_SUCCESS )
  2539. {
  2540. pcred->_cbMaxToken = pspkg->cbMaxToken;
  2541. DBG_ASSERT( pspkg->fCapabilities & SECPKG_FLAG_CONNECTION );
  2542. pfnFreeContextBuffer( pspkg );
  2543. }
  2544. if ( ss != STATUS_SUCCESS )
  2545. {
  2546. DBGPRINTF(( DBG_CONTEXT,
  2547. "[GetCredential] AcquireCredentialsHandle or QuerySecurityPackageInfo failed, error %d\n",
  2548. ss ));
  2549. SetLastError( ss );
  2550. delete pcred;
  2551. pcred = NULL;
  2552. }
  2553. else
  2554. {
  2555. InsertHeadList( &CredentialCacheList, &pcred->_ListEntry );
  2556. }
  2557. Exit:
  2558. if ( pcred )
  2559. {
  2560. *pcbMaxToken = pcred->_cbMaxToken;
  2561. *prcred = pcred->_hcred;
  2562. }
  2563. LeaveCriticalSection( &csCredentialCacheLock );
  2564. return pcred ? TRUE : FALSE;
  2565. }
  2566. CACHED_CREDENTIAL::~CACHED_CREDENTIAL(
  2567. )
  2568. /*++
  2569. Routine Description:
  2570. SSPI Credential cache entry destructor
  2571. Arguments:
  2572. None
  2573. Returns:
  2574. Nothing
  2575. --*/
  2576. {
  2577. if ( _fHaveCredHandle )
  2578. {
  2579. pfnFreeCredentialsHandle( &_hcred );
  2580. }
  2581. }