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.

1942 lines
46 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. simauth.cpp
  5. Abstract:
  6. This module contains definition for the CSecurityCtx class.
  7. Revision History:
  8. --*/
  9. #if !defined(dllexp)
  10. #define dllexp __declspec( dllexport )
  11. #endif // !defined( dllexp )
  12. #ifdef __cplusplus
  13. extern "C" {
  14. #endif
  15. # include <nt.h>
  16. # include <ntrtl.h>
  17. # include <nturtl.h>
  18. # include <windows.h>
  19. #ifdef __cplusplus
  20. };
  21. #endif
  22. #include <dbgutil.h>
  23. #include <tcpdll.hxx>
  24. #include <inetinfo.h>
  25. #include <simauth2.h>
  26. #include <dbgtrace.h>
  27. //
  28. // SSL and SSPI related include files
  29. //
  30. extern "C" {
  31. #include <rpc.h>
  32. #define SECURITY_WIN32
  33. #include <sspi.h>
  34. #include <issperr.h>
  35. #include <ntlmsp.h>
  36. #include <ntdsapi.h>
  37. }
  38. //
  39. // try/finally macros
  40. //
  41. #define START_TRY __try {
  42. #define END_TRY }
  43. #define TRY_EXCEPT } __except(EXCEPTION_EXECUTE_HANDLER) {
  44. #define START_FINALLY } __finally {
  45. //
  46. // tracing
  47. //
  48. #define ENTER( _x_ ) TraceFunctEnter( _x_ );
  49. #define LEAVE TraceFunctLeave( );
  50. //
  51. // Points to protocol blocks
  52. //
  53. extern BOOL uuencode( BYTE * bufin,
  54. DWORD nbytes,
  55. BUFFER * pbuffEncoded,
  56. BOOL fBase64 );
  57. //
  58. // critsec protecting the following three items
  59. //
  60. CRITICAL_SECTION critProviderPackages;
  61. inline void LockPackages( void ) { EnterCriticalSection( &critProviderPackages ); }
  62. inline void UnlockPackages( void ) { LeaveCriticalSection( &critProviderPackages ); }
  63. //
  64. // "installed" packages the server should support
  65. //
  66. PAUTH_BLOCK ProviderPackages = NULL;
  67. //
  68. // count of "installed" packages the server should support
  69. //
  70. DWORD cProviderPackages = 0;
  71. //
  72. // memory for names of "installed" packages the server should support
  73. //
  74. LPSTR ProviderNames = NULL;
  75. //
  76. // Global gibraltar object and allow guest flag
  77. //
  78. BOOL CSecurityCtx::m_AllowGuest = TRUE;
  79. BOOL CSecurityCtx::m_StartAnonymous = TRUE;
  80. HANDLE CSecurityCtx::m_hTokenAnonymous = NULL;
  81. inline BOOL
  82. IsExperimental(
  83. LPSTR Protocol
  84. )
  85. /*++
  86. Routine Description:
  87. determines if the security package is marked as experimental ( ie X- )
  88. Arguments:
  89. LPSTR: name of the protocol or authentication package
  90. Return Value:
  91. BOOL: TRUE if starts with X-
  92. --*/
  93. {
  94. return (Protocol[0] == 'X' || Protocol[0] == 'x') && Protocol[1] == '-';
  95. }
  96. inline LPSTR
  97. PackageName(
  98. LPSTR Protocol
  99. )
  100. /*++
  101. Routine Description:
  102. returns the core security package name stripping X- if necessary
  103. Arguments:
  104. LPSTR: name of the protocol or authentication package
  105. Return Value:
  106. LPSTR: package name
  107. --*/
  108. {
  109. return IsExperimental( Protocol ) ? Protocol + 2 : Protocol ;
  110. }
  111. BOOL
  112. CSecurityCtx::Initialize(
  113. BOOL fAllowGuest,
  114. BOOL fStartAnonymous
  115. )
  116. /*++
  117. Routine Description:
  118. Activates the security package
  119. Arguments:
  120. PIIS_SERVER_INSTANCE is a ptr to a virtual server instance
  121. Return Value:
  122. TRUE, if successful. FALSE, otherwise.
  123. --*/
  124. {
  125. ENTER("CSecurityCtx::Initialize")
  126. m_AllowGuest = fAllowGuest;
  127. m_StartAnonymous = fStartAnonymous;
  128. if (m_StartAnonymous)
  129. {
  130. // This is only used by NNTP. And - NNTP only call it once in InitializeService
  131. // so we don't need any ref count on it.
  132. // Impersonate Anonymous token on this thread
  133. if (!ImpersonateAnonymousToken(GetCurrentThread()))
  134. {
  135. DWORD dw = GetLastError();
  136. ErrorTrace(0, "ImpersonateAnonymousToken() failed %x", dw);
  137. return FALSE;
  138. }
  139. // Get current thread token
  140. _ASSERT(m_hTokenAnonymous == NULL);
  141. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, TRUE, &m_hTokenAnonymous))
  142. {
  143. ErrorTrace(0, "OpenThreadToken() failed %x", GetLastError());
  144. ::RevertToSelf();
  145. return FALSE;
  146. }
  147. ::RevertToSelf();
  148. }
  149. InitializeCriticalSection( &critProviderPackages );
  150. LEAVE
  151. return(TRUE);
  152. } // Initialize
  153. VOID
  154. CSecurityCtx::Terminate(
  155. VOID
  156. )
  157. /*++
  158. Routine Description:
  159. Terminates the security package
  160. Arguments:
  161. None.
  162. Return Value:
  163. None.
  164. --*/
  165. {
  166. ENTER("CSecurityCtx::Terminate")
  167. //
  168. // Close cached credential handles
  169. //
  170. if (m_hTokenAnonymous)
  171. {
  172. CloseHandle(m_hTokenAnonymous);
  173. m_hTokenAnonymous = NULL;
  174. }
  175. if ( ProviderPackages != NULL )
  176. {
  177. LocalFree( (PVOID)ProviderPackages );
  178. ProviderPackages = NULL;
  179. }
  180. if ( ProviderNames != NULL )
  181. {
  182. LocalFree( (PVOID)ProviderNames );
  183. ProviderNames = NULL;
  184. }
  185. DeleteCriticalSection( &critProviderPackages );
  186. LEAVE
  187. return;
  188. } // Terminate
  189. CSecurityCtx::CSecurityCtx(
  190. PIIS_SERVER_INSTANCE pIisInstance,
  191. DWORD AuthFlags,
  192. DWORD InstanceAuthFlags,
  193. TCP_AUTHENT_INFO *pTcpAuthInfo
  194. ) :
  195. TCP_AUTHENT( AuthFlags ),
  196. m_IsAuthenticated( FALSE ),
  197. m_IsAnonymous( FALSE ),
  198. m_IsClearText( FALSE ),
  199. m_IsGuest( FALSE ),
  200. m_LoginName( NULL ),
  201. m_PackageName( NULL ),
  202. m_dwInstanceAuthFlags(InstanceAuthFlags),
  203. m_ProviderNames(NULL),
  204. m_ProviderPackages(NULL),
  205. m_cProviderPackages(0),
  206. m_fBase64((AuthFlags & TCPAUTH_BASE64) ? TRUE : FALSE)
  207. /*++
  208. Routine Description:
  209. Class constructor
  210. Arguments:
  211. None.
  212. Return Value:
  213. None
  214. --*/
  215. {
  216. TraceFunctEnterEx( (LPARAM)this, "CSecurityCtx::CSecurityCtx");
  217. m_szCleartextPackageName[0] = '\0';
  218. m_szMembershipBrokerName[0] = '\0';
  219. //
  220. // The instance will cache this info from the metabase
  221. // and pass it in on the constructor.
  222. //
  223. if ( pTcpAuthInfo )
  224. {
  225. m_TCPAuthentInfo.strAnonUserName.Copy(pTcpAuthInfo->strAnonUserName);
  226. m_TCPAuthentInfo.strAnonUserPassword.Copy(pTcpAuthInfo->strAnonUserPassword);
  227. m_TCPAuthentInfo.strDefaultLogonDomain.Copy(pTcpAuthInfo->strDefaultLogonDomain);
  228. m_TCPAuthentInfo.dwLogonMethod = pTcpAuthInfo->dwLogonMethod;
  229. m_TCPAuthentInfo.fDontUseAnonSubAuth = pTcpAuthInfo->fDontUseAnonSubAuth;
  230. }
  231. if ( m_StartAnonymous )
  232. {
  233. //
  234. // m_dwInstanceAuthFlags is set at class's ctor
  235. //
  236. //
  237. // if Anonymous logon is not allowed return immediately
  238. //
  239. if ( m_dwInstanceAuthFlags & INET_INFO_AUTH_ANONYMOUS )
  240. {
  241. m_IsAnonymous = TRUE;
  242. m_IsAuthenticated = TRUE;
  243. m_IsClearText = TRUE;
  244. }
  245. }
  246. } // CSecurityCtx
  247. CSecurityCtx::~CSecurityCtx(
  248. VOID
  249. )
  250. /*++
  251. Routine Description:
  252. Class destructor
  253. Arguments:
  254. None.
  255. Return Value:
  256. None
  257. --*/
  258. {
  259. //
  260. // no reason to do the remainder of Reset()
  261. //
  262. if ( m_LoginName != NULL )
  263. {
  264. LocalFree( (PVOID)m_LoginName);
  265. m_LoginName = NULL;
  266. }
  267. if ( m_PackageName != NULL )
  268. {
  269. LocalFree( (PVOID)m_PackageName);
  270. m_PackageName = NULL;
  271. }
  272. } // ~CSecurityCtx
  273. HANDLE
  274. CSecurityCtx::QueryImpersonationToken()
  275. /*++
  276. Routine Description:
  277. get impersonation token - overriding base class
  278. if it's nntp anonymous, use m_hTokenAnonymous instead of going into TCP_AUTHENT
  279. Arguments:
  280. None.
  281. Return Value:
  282. token handle
  283. --*/
  284. {
  285. if (m_IsAnonymous) return m_hTokenAnonymous;
  286. else return TCP_AUTHENT::QueryImpersonationToken();
  287. }
  288. VOID
  289. CSecurityCtx::Reset(
  290. VOID
  291. )
  292. /*++
  293. Routine Description:
  294. resets the instance to reauth user
  295. Arguments:
  296. None.
  297. Return Value:
  298. None
  299. --*/
  300. {
  301. if ( m_LoginName != NULL )
  302. {
  303. LocalFree( (PVOID)m_LoginName);
  304. m_LoginName = NULL;
  305. }
  306. if ( m_PackageName != NULL )
  307. {
  308. LocalFree( (PVOID)m_PackageName);
  309. m_PackageName = NULL;
  310. }
  311. m_IsAuthenticated = FALSE;
  312. m_IsAnonymous = FALSE;
  313. m_IsGuest = FALSE;
  314. TCP_AUTHENT::Reset();
  315. } // Reset
  316. VOID
  317. CSecurityCtx::SetCleartextPackageName(
  318. LPSTR szCleartextPackageName,
  319. LPSTR szMembershipBrokerName
  320. )
  321. /*++
  322. Routine Description:
  323. Sets the cleartext auth package name
  324. Arguments:
  325. szCleartextPackageName - Name of package
  326. Return Value:
  327. None
  328. --*/
  329. {
  330. TraceFunctEnter("SetCleartextPackageName");
  331. if (szCleartextPackageName)
  332. lstrcpy(m_szCleartextPackageName, szCleartextPackageName);
  333. else
  334. m_szCleartextPackageName[0] = '\0';
  335. if (szMembershipBrokerName)
  336. lstrcpy(m_szMembershipBrokerName, szMembershipBrokerName);
  337. else
  338. m_szMembershipBrokerName[0] = '\0';
  339. DebugTrace(0,"CleartextPackageName is %s MembershipBrokerName is %s", m_szCleartextPackageName, m_szMembershipBrokerName);
  340. }
  341. BOOL
  342. CSecurityCtx::SetInstanceAuthPackageNames(
  343. DWORD cProviderPackages,
  344. LPSTR ProviderNames,
  345. PAUTH_BLOCK ProviderPackages)
  346. /*++
  347. Routine Description:
  348. set the supported SSPI packages per instance basis
  349. --*/
  350. {
  351. TraceFunctEnter( "CSecurityCtx::SetInstanceAuthPackageNames" );
  352. if (cProviderPackages == 0 || ProviderNames == NULL || ProviderPackages == NULL)
  353. {
  354. ErrorTrace( 0, "Invalid Parameters");
  355. return FALSE;
  356. }
  357. m_cProviderPackages = cProviderPackages;
  358. m_ProviderNames = ProviderNames;
  359. m_ProviderPackages = ProviderPackages;
  360. return TRUE;
  361. }
  362. BOOL
  363. CSecurityCtx::GetInstanceAuthPackageNames(
  364. OUT LPBYTE ReplyString,
  365. IN OUT PDWORD ReplySize,
  366. IN PKG_REPLY_FMT PkgFmt
  367. )
  368. /*++
  369. Routine Description:
  370. get the supported SSPI packages per instance basis.
  371. different than set in that the packages are returned using various
  372. delimeters to make it easier for the client to format the buffer.
  373. Arguments:
  374. ReplyString - Reply to be sent to client.
  375. ReplySize - Size of the reply.
  376. PkgFmt - Format of the reply string.
  377. Return Value:
  378. BOOL: successful ??
  379. --*/
  380. {
  381. TraceFunctEnter( "CSecurityCtx::GetInstanceAuthPackageNames" );
  382. LPSTR pszNext = (LPSTR)ReplyString;
  383. DWORD cbReply = 0;
  384. DWORD cbDelim;
  385. LPSTR pbDelim;
  386. _ASSERT(PkgFmt == PkgFmtSpace || PkgFmt == PkgFmtCrLf);
  387. switch (PkgFmt)
  388. {
  389. case PkgFmtCrLf:
  390. {
  391. pbDelim = "\r\n";
  392. cbDelim = 2;
  393. break;
  394. }
  395. case PkgFmtSpace:
  396. default:
  397. {
  398. pbDelim = " ";
  399. cbDelim = 1;
  400. break;
  401. }
  402. }
  403. //
  404. // while in this loop ensure the contents dont change
  405. //
  406. for ( DWORD i=0; i < m_cProviderPackages; i++ )
  407. {
  408. LPSTR pszName = m_ProviderPackages[i].Name;
  409. DWORD cbName = lstrlen( pszName );
  410. //
  411. // +1 is for trailing space
  412. //
  413. if ( cbReply + cbName + cbDelim > *ReplySize )
  414. {
  415. break;
  416. }
  417. else
  418. {
  419. CopyMemory( pszNext, pszName, cbName );
  420. //
  421. // add the space separator
  422. //
  423. CopyMemory(pszNext + cbName, pbDelim, cbDelim);
  424. //
  425. // inc for loop pass
  426. //
  427. cbReply += cbName + cbDelim;
  428. pszNext += cbName + cbDelim;
  429. }
  430. }
  431. //
  432. // stamp the final trailing space with a NULL char
  433. //
  434. if ( cbReply > 0 && PkgFmt == PkgFmtSpace)
  435. {
  436. cbReply--;
  437. ReplyString[ cbReply ] = '\0';
  438. DebugTrace( 0, "Protocols: %s", ReplyString );
  439. }
  440. *ReplySize = cbReply;
  441. return TRUE;
  442. }
  443. BOOL
  444. CSecurityCtx::SetAuthPackageNames(
  445. LPSTR lpMultiSzProviders,
  446. DWORD cchMultiSzProviders
  447. )
  448. /*++
  449. Routine Description:
  450. set the supported SSPI packages
  451. Arguments:
  452. lpMultiSzProviders is the same format as returned by
  453. RegQueryValueEx for REG_MULTI_SZ values
  454. Return Value:
  455. BOOL: successful ??
  456. --*/
  457. {
  458. TraceFunctEnter( "CSecurityCtx::SetAuthPackageNames" );
  459. LPSTR psz, pszCopy = NULL;
  460. DWORD i, cProviders;
  461. PAUTH_BLOCK pBlock = NULL;
  462. if ( lpMultiSzProviders == NULL || cchMultiSzProviders == 0 )
  463. {
  464. ErrorTrace( 0, "Invalid Parameters: 0x%08X, %d",
  465. lpMultiSzProviders, cchMultiSzProviders );
  466. goto error;
  467. }
  468. pszCopy = (LPSTR)LocalAlloc( 0, cchMultiSzProviders );
  469. if ( pszCopy == NULL )
  470. {
  471. ErrorTrace( 0, "LocalAlloc failed: %d", GetLastError() );
  472. goto error;
  473. }
  474. CopyMemory( pszCopy, lpMultiSzProviders, cchMultiSzProviders );
  475. //
  476. // cchMultiSzProviders-1 is to avoid adding an additional provider
  477. // for the terminating NULL char
  478. //
  479. for ( i=0, cProviders=0, psz=pszCopy; i<cchMultiSzProviders-1; i++, psz++ )
  480. {
  481. if ( *psz == '\0' )
  482. {
  483. cProviders++;
  484. }
  485. }
  486. //
  487. // ensure we're at the end and hence at the second terminating NULL char
  488. //
  489. _ASSERT( *psz == '\0' );
  490. if ( cProviders < 1 )
  491. {
  492. ErrorTrace( 0, "No valid providers were found" );
  493. goto error;
  494. }
  495. pBlock = (PAUTH_BLOCK)LocalAlloc( 0, cProviders * sizeof(AUTH_BLOCK) );
  496. if ( pBlock == NULL )
  497. {
  498. ErrorTrace( 0, "AUTH_BLOCK LocalAlloc failed: %d", GetLastError() );
  499. goto error;
  500. }
  501. //
  502. // start at 1 since 0 indicates the Invalid protocol
  503. //
  504. for ( i=0, psz=pszCopy; i<cProviders; i++ )
  505. {
  506. //
  507. // this would be the place to check whether the package was valid
  508. //
  509. DebugTrace( 0, "Protocol: %s, Package: %s", psz, PackageName(psz) );
  510. pBlock[i].Name = psz;
  511. psz += lstrlen(psz) + 1;
  512. }
  513. //
  514. // set global to new value; autoupdate will require critsec and mem free
  515. //
  516. LockPackages();
  517. //
  518. // if we're replacing already set packages; free their memory
  519. //
  520. if ( ProviderPackages != NULL )
  521. {
  522. LocalFree( (PVOID)ProviderPackages );
  523. ProviderPackages = NULL;
  524. }
  525. if ( ProviderNames != NULL )
  526. {
  527. LocalFree( (PVOID)ProviderNames );
  528. ProviderNames = NULL;
  529. }
  530. ProviderPackages = pBlock;
  531. cProviderPackages = cProviders;
  532. ProviderNames = pszCopy;
  533. UnlockPackages();
  534. return TRUE;
  535. error:
  536. if ( pszCopy != NULL )
  537. {
  538. DebugTrace( 0, "Cleaning up pszCopy" );
  539. _VERIFY( LocalFree( (LPVOID)pszCopy ) == NULL );
  540. }
  541. if ( pBlock != NULL )
  542. {
  543. DebugTrace( 0, "Cleaning up pBlock" );
  544. _VERIFY( LocalFree( (LPVOID)pBlock ) == NULL );
  545. }
  546. return FALSE;
  547. } // SetAuthPackageNames
  548. BOOL
  549. CSecurityCtx::GetAuthPackageNames(
  550. OUT LPBYTE ReplyString,
  551. IN OUT PDWORD ReplySize,
  552. IN PKG_REPLY_FMT PkgFmt
  553. )
  554. /*++
  555. Routine Description:
  556. get the supported SSPI packages
  557. different than set in that the packages are returned using various
  558. delimeters to make it easier for the client to format the buffer.
  559. Arguments:
  560. ReplyString - Reply to be sent to client.
  561. ReplySize - Size of the reply.
  562. PkgFmt - Format of the reply string.
  563. Return Value:
  564. BOOL: successful ??
  565. --*/
  566. {
  567. TraceFunctEnter( "CSecurityCtx::GetAuthPackageNames" );
  568. LPSTR pszNext = (LPSTR)ReplyString;
  569. DWORD cbReply = 0;
  570. DWORD cbDelim;
  571. LPSTR pbDelim;
  572. _ASSERT(PkgFmt == PkgFmtSpace || PkgFmt == PkgFmtCrLf);
  573. switch (PkgFmt)
  574. {
  575. case PkgFmtCrLf:
  576. {
  577. pbDelim = "\r\n";
  578. cbDelim = 2;
  579. break;
  580. }
  581. case PkgFmtSpace:
  582. default:
  583. {
  584. pbDelim = " ";
  585. cbDelim = 1;
  586. break;
  587. }
  588. }
  589. //
  590. // while in this loop ensure the contents dont change
  591. //
  592. LockPackages();
  593. for ( DWORD i=0; i<cProviderPackages; i++ )
  594. {
  595. LPSTR pszName = ProviderPackages[i].Name;
  596. DWORD cbName = lstrlen( pszName );
  597. //
  598. // +1 is for trailing space
  599. //
  600. if ( cbReply + cbName + cbDelim > *ReplySize )
  601. {
  602. break;
  603. }
  604. else
  605. {
  606. CopyMemory( pszNext, pszName, cbName );
  607. //
  608. // add the space separator
  609. //
  610. CopyMemory(pszNext + cbName, pbDelim, cbDelim);
  611. //
  612. // inc for loop pass
  613. //
  614. cbReply += cbName + cbDelim;
  615. pszNext += cbName + cbDelim;
  616. }
  617. }
  618. //
  619. // free access to the list
  620. //
  621. UnlockPackages();
  622. //
  623. // stamp the final trailing space with a NULL char
  624. //
  625. if ( cbReply > 0 && PkgFmt == PkgFmtSpace)
  626. {
  627. cbReply--;
  628. ReplyString[ cbReply ] = '\0';
  629. DebugTrace( 0, "Protocols: %s", ReplyString );
  630. }
  631. *ReplySize = cbReply;
  632. return TRUE;
  633. } // GetAuthPackageNames
  634. BOOL
  635. CSecurityCtx::ProcessUser(
  636. IN PIIS_SERVER_INSTANCE pIisInstance,
  637. IN LPSTR pszUser,
  638. OUT REPLY_LIST* pReply
  639. )
  640. /*++
  641. Routine Description:
  642. Process AUTHINFO user command
  643. Arguments:
  644. pszUser - user name
  645. pReply - ptr to reply string id
  646. Return Value:
  647. successful
  648. --*/
  649. {
  650. TraceFunctEnterEx( (LPARAM)this, "CSecurityCtx::ProcessUser");
  651. DWORD nameLen;
  652. //
  653. // if we're already logged on reset the user credentials
  654. //
  655. if ( m_IsAuthenticated )
  656. {
  657. Reset();
  658. }
  659. //
  660. // Don't allow user to overwrite the existing name.
  661. //
  662. if ( m_LoginName != NULL )
  663. {
  664. *pReply = SecSyntaxErr;
  665. return FALSE;
  666. }
  667. if ( (m_dwInstanceAuthFlags & INET_INFO_AUTH_CLEARTEXT) == 0 )
  668. {
  669. *pReply = SecPermissionDenied;
  670. return FALSE;
  671. }
  672. if ( pszUser == NULL )
  673. {
  674. *pReply = SecSyntaxErr;
  675. return FALSE;
  676. }
  677. nameLen = lstrlen( pszUser ) + 1;
  678. //
  679. // if anonymous is not allowed; fail a zero length user name
  680. //
  681. if ( nameLen <= 1 &&
  682. (m_dwInstanceAuthFlags & INET_INFO_AUTH_ANONYMOUS) == 0 )
  683. {
  684. *pReply = SecPermissionDenied;
  685. return FALSE;
  686. }
  687. m_LoginName = (PCHAR)LocalAlloc( 0, nameLen );
  688. if ( m_LoginName == NULL )
  689. {
  690. *pReply = SecInternalErr;
  691. return FALSE;
  692. }
  693. CopyMemory( m_LoginName, pszUser, nameLen );
  694. //
  695. // Tell client to send the password
  696. //
  697. *pReply = SecNeedPwd;
  698. return TRUE;
  699. }
  700. BOOL
  701. CSecurityCtx::ShouldUseMbs( void )
  702. /*++
  703. Routine Description:
  704. Determines if MBS_BASIC is being used.
  705. Arguments:
  706. Return Value:
  707. TRUE if successful
  708. --*/
  709. {
  710. CHAR *pszCtPackage;
  711. //
  712. // Simple heuristics: if we have a cleartext package
  713. // name, we will use MBS if the current package name
  714. // is NULL,
  715. //
  716. pszCtPackage = PackageName(m_szCleartextPackageName);
  717. if (pszCtPackage[0] != '\0' && !m_PackageName)
  718. {
  719. return(TRUE);
  720. }
  721. return(FALSE);
  722. }
  723. #define __STRCPYX(s, cs, len) \
  724. lstrcpy((s), (cs)); (s) += (len)
  725. BOOL
  726. CSecurityCtx::MbsBasicLogon(
  727. IN LPSTR pszUser,
  728. IN LPSTR pszPass,
  729. OUT BOOL *pfAsGuest,
  730. OUT BOOL *pfAsAnonymous
  731. )
  732. /*++
  733. Routine Description:
  734. Perform a MBS Basic logon sequence
  735. Arguments:
  736. pszUser - Username, can be NULL
  737. pszPass - Password, may be NULL
  738. pfAsGuest - Returns TRUE is logged on as guest
  739. pfAsAnonymous - Returns TRUE is anonymous account used
  740. pReply - Pointer to reply string id
  741. psi - Server information block
  742. Return Value:
  743. successful
  744. --*/
  745. {
  746. TraceFunctEnterEx( (LPARAM)this, "CSecurityCtx::MbsBasicLogon");
  747. BYTE pbBlob[MAX_ACCT_DESC_LEN];
  748. DWORD dwBlobLength;
  749. BUFFER OutBuf;
  750. DWORD dwOutBufSize;
  751. BOOL fMoreData;
  752. BOOL fRet;
  753. CHAR *pTemp;
  754. SecBuffer InSecBuff[2];
  755. SecBufferDesc InSecBuffDesc;
  756. // PU2_BASIC_AUTHENTICATE_MSG pAuthMsg = (PU2_BASIC_AUTHENTICATE_MSG)pbBlob;
  757. _ASSERT(pfAsGuest);
  758. _ASSERT(pfAsAnonymous);
  759. if (!pszUser || !pszPass || !pfAsGuest || !pfAsAnonymous)
  760. {
  761. SetLastError(ERROR_INVALID_PARAMETER);
  762. ErrorTrace((LPARAM)this, "Input parameters NULL");
  763. return(FALSE);
  764. }
  765. *pfAsGuest = FALSE;
  766. *pfAsAnonymous = FALSE;
  767. if (lstrlen(pszUser) > UNLEN)
  768. {
  769. SetLastError(ERROR_INVALID_PARAMETER);
  770. ErrorTrace((LPARAM)this, "Username too long");
  771. return(FALSE);
  772. }
  773. if (lstrlen(pszPass) > PWLEN)
  774. {
  775. SetLastError(ERROR_INVALID_PARAMETER);
  776. ErrorTrace((LPARAM)this, "Password too long");
  777. return(FALSE);
  778. }
  779. //
  780. // With all the user name and password information, we will
  781. // build up a BLOB and then simply call Converse()
  782. //
  783. // The BLOB contains credential string of the format:
  784. // user:password\0
  785. //
  786. pTemp = (CHAR *)pbBlob;
  787. // __STRCPYX(pTemp, psi->QueryServiceName(), lstrlen(psi->QueryServiceName()));
  788. // __STRCPYX(pTemp, ":", 1);
  789. __STRCPYX(pTemp, pszUser, lstrlen(pszUser));
  790. __STRCPYX(pTemp, ":", 1);
  791. __STRCPYX(pTemp, pszPass, lstrlen(pszPass));
  792. //
  793. // Get the size of everything, not just the credentials
  794. //
  795. dwBlobLength = (DWORD)(pTemp - (CHAR *)pbBlob) + 1;
  796. //
  797. // U2 now requires 2 SecBuffer for MBS_BASIC
  798. //
  799. InSecBuffDesc.ulVersion = 0;
  800. InSecBuffDesc.cBuffers = 2;
  801. InSecBuffDesc.pBuffers = &InSecBuff[0];
  802. InSecBuff[0].cbBuffer = dwBlobLength;
  803. InSecBuff[0].BufferType = SECBUFFER_TOKEN;
  804. InSecBuff[0].pvBuffer = pbBlob;
  805. DebugTrace(0,"MbsBasicLogon: cleartext is %s membership is %s", m_szCleartextPackageName, m_szMembershipBrokerName);
  806. BYTE pbServer[sizeof(WCHAR)*MAX_PATH+sizeof(UNICODE_STRING)];
  807. UNICODE_STRING* pusU2Server = (UNICODE_STRING*)pbServer;
  808. WCHAR* pwszU2Server = (WCHAR*)((UNICODE_STRING*)pbServer+1);
  809. if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, m_szMembershipBrokerName, -1, pwszU2Server,
  810. MAX_PATH))
  811. {
  812. return FALSE;
  813. }
  814. pusU2Server->Length = (USHORT) (wcslen(pwszU2Server) * sizeof(WCHAR));
  815. pusU2Server->MaximumLength = (USHORT)(MAX_PATH * sizeof(WCHAR));
  816. pusU2Server->Buffer = (PWSTR)sizeof(UNICODE_STRING);
  817. InSecBuff[1].cbBuffer = sizeof(pbServer);
  818. InSecBuff[1].BufferType = SECBUFFER_PKG_PARAMS;
  819. InSecBuff[1].pvBuffer = (PVOID)pbServer;
  820. //
  821. // Just call Converse() to do all the work!
  822. // We blow away tha anon password immediately after we're done.
  823. //
  824. fRet = ConverseEx(&InSecBuffDesc,
  825. NULL, // SecBuffer is not encoded
  826. &OutBuf,
  827. &dwOutBufSize,
  828. &fMoreData,
  829. &m_TCPAuthentInfo,
  830. m_szCleartextPackageName,
  831. NULL, NULL, NULL);
  832. //
  833. // Check the return values
  834. //
  835. if (fRet)
  836. {
  837. StateTrace((LPARAM)this, "Authentication succeeded");
  838. //
  839. // This is a one-shot deal, so we do not expect any more data
  840. //
  841. if (fMoreData)
  842. {
  843. SetLastError(ERROR_MORE_DATA);
  844. ErrorTrace((LPARAM)this, "Internal error: More data not expected");
  845. return(FALSE);
  846. }
  847. //
  848. // We should also expect zero returned buffer length
  849. //
  850. // _ASSERT(dwOutBufSize == 0);
  851. }
  852. return(fRet);
  853. }
  854. BOOL
  855. CSecurityCtx::ProcessPass(
  856. IN PIIS_SERVER_INSTANCE pIisInstance,
  857. IN LPSTR pszPass,
  858. OUT REPLY_LIST* pReply
  859. )
  860. /*++
  861. Routine Description:
  862. Process AUTHINFO user command
  863. Arguments:
  864. pszPass - password
  865. pReply - ptr to reply string id
  866. Return Value:
  867. successful
  868. --*/
  869. {
  870. TraceFunctEnterEx( (LPARAM)this, "CSecurityCtx::ProcessPass");
  871. DWORD dwTick;
  872. BOOL fRet;
  873. TCP_AUTHENT_INFO tai; // use default ctor
  874. //
  875. // give username first
  876. //
  877. if ( m_LoginName == NULL )
  878. {
  879. *pReply = SecNoUsername;
  880. return FALSE;
  881. }
  882. if ( pszPass == NULL )
  883. {
  884. *pReply = SecSyntaxErr;
  885. return FALSE;
  886. }
  887. //
  888. // Get tick count for tracing
  889. //
  890. dwTick = GetTickCount();
  891. //
  892. // Added for U2 BASIC authentication: We check if the current
  893. // package is the U2 BASIC package. If not, we do the usual
  894. // ClearTextLogon() call. If so, we will call MBS
  895. //
  896. if (ShouldUseMbs())
  897. {
  898. //
  899. // This uses U2 BASIC
  900. //
  901. StateTrace((LPARAM)pIisInstance, "Doing Cleartext auth with package: <%s>",
  902. m_szCleartextPackageName);
  903. fRet = MbsBasicLogon(m_LoginName,
  904. pszPass,
  905. &m_IsGuest,
  906. &m_IsAnonymous);
  907. }
  908. else
  909. {
  910. //
  911. // K2_TODO: need to fill in TCP_AUTHENT_INFO !
  912. //
  913. tai.dwLogonMethod = LOGON32_LOGON_NETWORK;
  914. fRet = ClearTextLogon(
  915. m_LoginName,
  916. pszPass,
  917. &m_IsGuest,
  918. &m_IsAnonymous,
  919. pIisInstance,
  920. &tai
  921. );
  922. }
  923. //
  924. // Trace ticks for logon
  925. //
  926. dwTick = GetTickCount() - dwTick;
  927. DebugTrace( (LPARAM)this,
  928. "ClearTextLogon took %u ticks", dwTick );
  929. if ( fRet )
  930. {
  931. if ( m_IsGuest && m_AllowGuest == FALSE )
  932. {
  933. ErrorTrace( (LPARAM)this, "Guest acct disallowed %s",
  934. m_LoginName );
  935. }
  936. else if ( m_IsAnonymous &&
  937. ( m_dwInstanceAuthFlags & INET_INFO_AUTH_ANONYMOUS ) == 0 )
  938. {
  939. ErrorTrace( (LPARAM)this, "Anonymous logon disallowed %s",
  940. m_LoginName );
  941. }
  942. else
  943. {
  944. *pReply = m_IsAnonymous ? SecAuthOkAnon : SecAuthOk ;
  945. return m_IsAuthenticated = TRUE;
  946. }
  947. }
  948. else
  949. {
  950. ErrorTrace( (LPARAM)this,
  951. "ClearTextLogon failed for %s: %d",
  952. m_LoginName, GetLastError());
  953. //
  954. // reset the logon session to force the app to start over again
  955. //
  956. Reset();
  957. }
  958. *pReply = SecPermissionDenied;
  959. return FALSE;
  960. }
  961. BOOL
  962. CSecurityCtx::ProcessTransact(
  963. IN PIIS_SERVER_INSTANCE pIisInstance,
  964. IN LPSTR Blob,
  965. IN OUT LPBYTE ReplyString,
  966. IN OUT PDWORD ReplySize,
  967. OUT REPLY_LIST* pReply,
  968. IN DWORD BlobLength
  969. )
  970. /*++
  971. Routine Description:
  972. Process AUTHINFO user command
  973. Arguments:
  974. pszPass - password
  975. pReply - ptr to reply string id
  976. Return Value:
  977. successful
  978. --*/
  979. {
  980. TraceFunctEnterEx( (LPARAM)this, "CSecurityCtx::ProcessTransact");
  981. //
  982. // if we're already logged on reset the user credentials
  983. //
  984. if ( m_IsAuthenticated )
  985. {
  986. Reset();
  987. }
  988. //
  989. // If this is a new session, the first transact is the
  990. // protocol name
  991. //
  992. if ( m_PackageName == NULL )
  993. {
  994. PAUTH_BLOCK pBlock;
  995. LPSTR protocol;
  996. DWORD i;
  997. BOOL bFound = FALSE;
  998. if ( (m_dwInstanceAuthFlags & INET_INFO_AUTH_NT_AUTH) == 0 )
  999. {
  1000. *pReply = SecPermissionDenied;
  1001. return FALSE;
  1002. }
  1003. if ( (protocol = Blob) == NULL )
  1004. {
  1005. *pReply = SecSyntaxErr;
  1006. return FALSE;
  1007. }
  1008. //
  1009. // if its an X- protocol strip the X- header
  1010. //
  1011. protocol = PackageName( protocol );
  1012. //
  1013. // See if this is a supported protocol
  1014. // while in this loop ensure the contents dont change
  1015. //
  1016. LockPackages();
  1017. for ( i=0; i < m_cProviderPackages; i++ )
  1018. {
  1019. pBlock = &m_ProviderPackages[i];
  1020. //
  1021. // get the name of the Block's package and strip any X-
  1022. //
  1023. LPSTR pszPackageName = PackageName( pBlock->Name );
  1024. if ( lstrcmpi( pszPackageName, protocol ) == 0 )
  1025. {
  1026. //
  1027. // See if the package chosen was GSSAPI. If it was, then set
  1028. // m_PackageName to "Negotiate". This is required because the
  1029. // SASL GSSAPI mechanism maps to the NT Negotiate package
  1030. //
  1031. LPSTR pszPackageNameToUse = pszPackageName;
  1032. if (lstrcmpi( pszPackageName, "GSSAPI") == 0)
  1033. pszPackageNameToUse = "Negotiate";
  1034. DWORD cb = lstrlen( pszPackageNameToUse ) + 1;
  1035. DebugTrace( (LPARAM)this,
  1036. "Found: %s, Protocol %s, NT Package %s",
  1037. pszPackageName, pBlock->Name, pszPackageNameToUse );
  1038. //
  1039. // maintain a local copy of the package name in case
  1040. // the list changes during the negotiation
  1041. //
  1042. m_PackageName = (PCHAR)LocalAlloc( 0, cb );
  1043. if ( m_PackageName == NULL )
  1044. {
  1045. *pReply = SecInternalErr;
  1046. //
  1047. // free access to the list
  1048. //
  1049. UnlockPackages();
  1050. return FALSE;
  1051. }
  1052. CopyMemory( m_PackageName, pszPackageNameToUse, cb );
  1053. bFound = TRUE;
  1054. break;
  1055. }
  1056. }
  1057. //
  1058. // free access to the list
  1059. //
  1060. UnlockPackages();
  1061. if ( bFound == FALSE )
  1062. {
  1063. //
  1064. // not found
  1065. //
  1066. ErrorTrace( (LPARAM)this,
  1067. "could not find: %s", protocol );
  1068. //
  1069. // here's where we need to build the response string
  1070. // app needs to call us to enum the installed packages
  1071. // to the app can properly format the enumerated
  1072. // "installed" packages within a protocol specific err msg
  1073. //
  1074. *pReply = SecProtNS;
  1075. return FALSE;
  1076. }
  1077. else
  1078. {
  1079. //
  1080. // +OK response
  1081. //
  1082. *pReply = SecProtOk;
  1083. return TRUE;
  1084. }
  1085. }
  1086. else
  1087. {
  1088. DWORD nBuff;
  1089. BOOL moreData;
  1090. BOOL fRet;
  1091. DWORD dwTick;
  1092. BUFFER outBuff;
  1093. if ( Blob == NULL )
  1094. {
  1095. *pReply = SecSyntaxErr;
  1096. return FALSE;
  1097. }
  1098. //
  1099. // Get tick count for tracing
  1100. //
  1101. dwTick = GetTickCount();
  1102. // m_PackageName must already be set by now
  1103. _ASSERT(m_PackageName);
  1104. if (!lstrcmpi(m_PackageName, "DPA") && m_szMembershipBrokerName && m_szMembershipBrokerName[0]) {
  1105. SecBuffer InSecBuff[2];
  1106. SecBufferDesc InSecBuffDesc;
  1107. BUFFER DecodedBuf[2]; // scratch pad for decoding the sec buff
  1108. DebugTrace(NULL,"DPA broker server is %s", m_szMembershipBrokerName);
  1109. //
  1110. // for DPA authentication, we need to pass in 2 sec buffers
  1111. //
  1112. InSecBuffDesc.ulVersion = 0;
  1113. InSecBuffDesc.cBuffers = 2;
  1114. InSecBuffDesc.pBuffers = &InSecBuff[0];
  1115. //
  1116. // Fill in the first sec buffer
  1117. // This contains the security blob sent by client, and is already encoded
  1118. //
  1119. InSecBuff[0].cbBuffer = BlobLength ? BlobLength : lstrlen(Blob);
  1120. InSecBuff[0].BufferType = SECBUFFER_TOKEN;
  1121. InSecBuff[0].pvBuffer = Blob;
  1122. //
  1123. // Fill in the second sec buffer, which contains the U2 broker id
  1124. // Since ConverseEx will decode both sec buf, we need to encode
  1125. // the second buf before calling ConverseEx
  1126. //
  1127. BYTE pbServer[sizeof(WCHAR)*MAX_PATH+sizeof(UNICODE_STRING)];
  1128. UNICODE_STRING* pusU2Server = (UNICODE_STRING*)pbServer;
  1129. WCHAR* pwszU2Server = (WCHAR*)((UNICODE_STRING*)pbServer+1);
  1130. BUFFER EncBuf;
  1131. if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, m_szMembershipBrokerName, -1, pwszU2Server,
  1132. MAX_PATH))
  1133. {
  1134. ErrorTrace((LPARAM)this, "MultiByteToWideChar FAILED");
  1135. return FALSE;
  1136. }
  1137. pusU2Server->Length = (USHORT) (wcslen(pwszU2Server) * sizeof(WCHAR));
  1138. pusU2Server->MaximumLength = (USHORT)(MAX_PATH * sizeof(WCHAR));
  1139. pusU2Server->Buffer = (PWSTR)sizeof(UNICODE_STRING);
  1140. DWORD dwSize = MAX_PATH + sizeof(UNICODE_STRING);
  1141. if (!uuencode((PBYTE)pbServer, dwSize, &EncBuf, m_fBase64)) {
  1142. ErrorTrace((LPARAM)this, "uuencode FAILED");
  1143. return FALSE;
  1144. }
  1145. InSecBuff[1].cbBuffer = EncBuf.QuerySize();
  1146. InSecBuff[1].BufferType = SECBUFFER_PKG_PARAMS;
  1147. InSecBuff[1].pvBuffer = EncBuf.QueryPtr();
  1148. fRet = ConverseEx(&InSecBuffDesc,
  1149. DecodedBuf,
  1150. &outBuff,
  1151. &nBuff,
  1152. &moreData,
  1153. &m_TCPAuthentInfo,
  1154. m_PackageName,
  1155. NULL, NULL, NULL);
  1156. }
  1157. else {
  1158. //
  1159. // for non-DPA authentication (i.e. NTLM, etc)
  1160. //
  1161. fRet = Converse(Blob,
  1162. BlobLength ? BlobLength : lstrlen(Blob),
  1163. &outBuff,
  1164. &nBuff,
  1165. &moreData,
  1166. &m_TCPAuthentInfo,
  1167. m_PackageName);
  1168. }
  1169. //
  1170. // Trace ticks for conversing
  1171. //
  1172. dwTick = GetTickCount() - dwTick;
  1173. DebugTrace((LPARAM)this, "Converse(%s) took %u ticks", m_PackageName, dwTick );
  1174. if ( fRet )
  1175. {
  1176. DebugTrace( (LPARAM)this,
  1177. "Converse ret TRUE, nBuff: %d, moredata %d",
  1178. nBuff, moreData );
  1179. if ( moreData )
  1180. {
  1181. _ASSERT( nBuff != 0 );
  1182. CopyMemory( ReplyString, outBuff.QueryPtr(), nBuff );
  1183. *ReplySize = nBuff;
  1184. //
  1185. // reply equals SecNull to tell the app to send
  1186. // this buffer to remote client/server
  1187. //
  1188. *pReply = SecNull;
  1189. return TRUE;
  1190. } else {
  1191. STR strUser; // was BUFFER buff pre-K2
  1192. if ( m_IsGuest && m_AllowGuest == FALSE )
  1193. {
  1194. SetLastError( ERROR_LOGON_FAILURE );
  1195. *pReply = SecPermissionDenied;
  1196. return FALSE;
  1197. }
  1198. if ( TCP_AUTHENT::QueryUserName( &strUser ) )
  1199. {
  1200. m_LoginName = (PCHAR)LocalAlloc( 0, strUser.QuerySize() );
  1201. if ( m_LoginName != NULL )
  1202. {
  1203. CopyMemory( m_LoginName,
  1204. strUser.QueryPtr(),
  1205. strUser.QuerySize() );
  1206. DebugTrace( (LPARAM)this,
  1207. "Username: %s, size %d",
  1208. m_LoginName, strUser.QuerySize() );
  1209. *pReply = SecAuthOk;
  1210. }
  1211. else
  1212. {
  1213. ErrorTrace( (LPARAM)this,
  1214. "LocalAlloc failed. err: %d",
  1215. GetLastError() );
  1216. *pReply = SecInternalErr;
  1217. }
  1218. strUser.Resize(0);
  1219. }
  1220. else
  1221. {
  1222. ErrorTrace( (LPARAM)this,
  1223. "QueryUserName failed. err: %d",
  1224. GetLastError() );
  1225. *pReply = SecInternalErr;
  1226. //
  1227. // Firewall around NT bug where negotiation succeeds even though
  1228. // it should really have failed (when an empty buffer is passed
  1229. // to AcceptSecurityContext). In this case, the QueryUserName is
  1230. // the only valid check - gpulla.
  1231. //
  1232. return m_IsAuthenticated = FALSE;
  1233. }
  1234. return m_IsAuthenticated = TRUE;
  1235. }
  1236. }
  1237. else
  1238. {
  1239. SECURITY_STATUS ss = GetLastError();
  1240. ErrorTrace( (LPARAM)this,
  1241. "Converse failed. err: 0x%08X", ss );
  1242. *pReply = SecPermissionDenied;
  1243. }
  1244. }
  1245. return FALSE;
  1246. }
  1247. BOOL
  1248. CSecurityCtx::ProcessAuthInfo(
  1249. IN PIIS_SERVER_INSTANCE pIisInstance,
  1250. IN AUTH_COMMAND Command,
  1251. IN LPSTR Blob,
  1252. IN OUT LPBYTE ReplyString,
  1253. IN OUT PDWORD ReplySize,
  1254. OUT REPLY_LIST* pReply,
  1255. IN OPTIONAL DWORD BlobLength
  1256. )
  1257. /*++
  1258. Routine Description:
  1259. Process AUTHINFO commands
  1260. Arguments:
  1261. Command - Authinfo command received
  1262. Blob - Blob accompanying the command
  1263. ReplyString - Reply to be sent to client.
  1264. ReplySize - Size of the reply.
  1265. Return Value:
  1266. None.
  1267. --*/
  1268. {
  1269. //
  1270. // transition codes to support backward compatibility
  1271. // will be removed later when everybody has moved to new version of simauth2
  1272. //
  1273. if (!m_ProviderPackages) {
  1274. m_ProviderPackages = ProviderPackages;
  1275. m_ProviderNames = ProviderNames;
  1276. m_cProviderPackages = cProviderPackages;
  1277. }
  1278. TraceFunctEnterEx( (LPARAM)this, "CSecurityCtx::ProcessAuthInfo");
  1279. BOOL bSuccess = FALSE;
  1280. START_TRY
  1281. //
  1282. // We currently support USER, PASSWORD, and TRANSACT
  1283. //
  1284. switch( Command )
  1285. {
  1286. case AuthCommandUser:
  1287. bSuccess = ProcessUser( pIisInstance, Blob, pReply );
  1288. break;
  1289. case AuthCommandPassword:
  1290. bSuccess = ProcessPass( pIisInstance, Blob, pReply );
  1291. break;
  1292. case AuthCommandTransact:
  1293. bSuccess = ProcessTransact( pIisInstance,
  1294. Blob,
  1295. ReplyString,
  1296. ReplySize,
  1297. pReply,
  1298. BlobLength );
  1299. break;
  1300. default:
  1301. if ( m_IsAuthenticated )
  1302. {
  1303. Reset();
  1304. }
  1305. *pReply = SecSyntaxErr;
  1306. }
  1307. TRY_EXCEPT
  1308. END_TRY
  1309. _ASSERT( *pReply < NUM_SEC_REPLIES );
  1310. if ((DWORD)*pReply >= NUM_SEC_REPLIES)
  1311. *pReply = SecInternalErr;
  1312. return bSuccess;
  1313. } // ProcessAuthInfo
  1314. BOOL CSecurityCtx::ClientConverse(
  1315. IN VOID * pBuffIn,
  1316. IN DWORD cbBuffIn,
  1317. OUT BUFFER * pbuffOut,
  1318. OUT DWORD * pcbBuffOut,
  1319. OUT BOOL * pfNeedMoreData,
  1320. IN PTCP_AUTHENT_INFO pTAI,
  1321. IN CHAR * pszPackage,
  1322. IN CHAR * pszUser,
  1323. IN CHAR * pszPassword,
  1324. IN PIIS_SERVER_INSTANCE psi)
  1325. /*++
  1326. Routine Description:
  1327. Processes AUTH blobs for a client (ie, for an outbound connection). This is
  1328. a simple wrapper around TCP_AUTHENT::Converse; it will map Internet protocol
  1329. keywords to NT security package names.
  1330. Arguments:
  1331. Same as that for TCP_AUTHENT::Converse
  1332. Return Value:
  1333. Same as that for TCP_AUTHENT::Converse
  1334. --*/
  1335. {
  1336. LPSTR pszPackageToUse = pszPackage;
  1337. if (pszPackage != NULL &&
  1338. (lstrcmpi(pszPackage, "GSSAPI") == 0) ) {
  1339. pszPackageToUse = "Negotiate";
  1340. }
  1341. return( Converse(
  1342. pBuffIn, cbBuffIn,
  1343. pbuffOut, pcbBuffOut, pfNeedMoreData,
  1344. pTAI, pszPackageToUse,
  1345. pszUser, pszPassword,
  1346. psi) );
  1347. }
  1348. //
  1349. // Figure out if the local machine is a member of a domain, or in a
  1350. // workgroup. If we aren't in a domain then we don't want to call into
  1351. // ResetServicePrincipleNames.
  1352. //
  1353. // This function returns TRUE in error cases, because it is better to
  1354. // call into ResetServicePrininpleNames by mistake then it is to
  1355. // skip calling it.
  1356. //
  1357. // Implemented using this algorithm:
  1358. //
  1359. // There are many ways to find out if you are in a work group. You can
  1360. // call LsaOpenPolicy /
  1361. // LsaQueryInformationPolicy(PolicyDnsDomainInformation) / LsaClose, and
  1362. // check if the SID is non-null. That's authoritative.
  1363. //
  1364. // -Rich (Richard B. Ward (Exchange))
  1365. //
  1366. BOOL fInDomain() {
  1367. TraceFunctEnter("fInDomain");
  1368. LSA_HANDLE lsah;
  1369. LSA_OBJECT_ATTRIBUTES objAttr;
  1370. POLICY_DNS_DOMAIN_INFO *pDnsInfo;
  1371. NTSTATUS ec;
  1372. // cache the results of this here. one can't join a domain without
  1373. // rebooting, so this safe to do once
  1374. static BOOL fDidCheck = FALSE;
  1375. static BOOL fRet = TRUE;
  1376. if (!fDidCheck) {
  1377. ZeroMemory(&objAttr, sizeof(objAttr));
  1378. ec = LsaOpenPolicy(NULL,
  1379. &objAttr,
  1380. POLICY_VIEW_LOCAL_INFORMATION,
  1381. &lsah);
  1382. if (ec == ERROR_SUCCESS) {
  1383. ec = LsaQueryInformationPolicy(lsah,
  1384. PolicyDnsDomainInformation,
  1385. (void **) &pDnsInfo);
  1386. if (ec == ERROR_SUCCESS) {
  1387. DebugTrace(0, "pDnsInfo = %x", pDnsInfo);
  1388. // we are in a domain if there is a Sid
  1389. if (pDnsInfo && pDnsInfo->Sid) {
  1390. fRet = TRUE;
  1391. } else {
  1392. fRet = FALSE;
  1393. }
  1394. fDidCheck = TRUE;
  1395. LsaFreeMemory(pDnsInfo);
  1396. } else {
  1397. DebugTrace(0, "LsaQueryInformationPolicy failed with %x", ec);
  1398. }
  1399. LsaClose(lsah);
  1400. } else {
  1401. DebugTrace(0, "LsaOpenPolicy failed with %x", ec);
  1402. }
  1403. }
  1404. TraceFunctLeave();
  1405. return fRet;
  1406. }
  1407. BOOL
  1408. CSecurityCtx::ResetServicePrincipalNames(
  1409. IN LPCSTR szServiceClass)
  1410. /*++
  1411. Routine Description:
  1412. Unregisters all service principal names for the given service from the
  1413. local machine's computer account object.
  1414. Arguments:
  1415. szServiceClass: String identifying service class, eg. "SMTP"
  1416. Return Value:
  1417. None.
  1418. --*/
  1419. {
  1420. DWORD dwErr;
  1421. if (fInDomain()) {
  1422. dwErr = DsServerRegisterSpnA(
  1423. DS_SPN_DELETE_SPN_OP,
  1424. szServiceClass,
  1425. NULL);
  1426. } else {
  1427. dwErr = ERROR_SUCCESS;
  1428. }
  1429. if (dwErr != ERROR_SUCCESS) {
  1430. SetLastError(dwErr);
  1431. return( FALSE );
  1432. } else {
  1433. return( TRUE );
  1434. }
  1435. }
  1436. BOOL
  1437. CSecurityCtx::RegisterServicePrincipalNames(
  1438. IN LPCSTR szServiceClass,
  1439. IN LPCSTR szFQDN)
  1440. /*++
  1441. Routine Description:
  1442. Registers service specific SPNs for the provided FQDN. The list of SPNs is
  1443. generated by doing a gethostbyname on the FQDN, and using the returned IP
  1444. addresses as th SPNs.
  1445. Arguments:
  1446. szServiceClass: String identifying service class, eg. "SMTP"
  1447. szFQDN: The FQDN of the virtual server. It will be used to do a
  1448. gethostbyname and retrieve a list of IP addresses to use.
  1449. Return Value:
  1450. None.
  1451. --*/
  1452. {
  1453. DWORD dwErr, cIPAddresses;
  1454. if (fInDomain()) {
  1455. dwErr = DsServerRegisterSpnA(
  1456. DS_SPN_ADD_SPN_OP,
  1457. szServiceClass,
  1458. NULL);
  1459. } else {
  1460. dwErr = ERROR_SUCCESS;
  1461. }
  1462. if (dwErr != ERROR_SUCCESS) {
  1463. SetLastError(dwErr);
  1464. return( FALSE );
  1465. } else {
  1466. return( TRUE );
  1467. }
  1468. }
  1469. #define MAX_SPN 260
  1470. BOOL
  1471. CSecurityCtx::SetTargetPrincipalName(
  1472. IN LPCSTR szServiceClass,
  1473. IN LPCSTR szTargetIPOrFQDN)
  1474. /*++
  1475. Routine Description:
  1476. Unregisters all service principal names for the given service from the
  1477. local machine's computer account object.
  1478. Arguments:
  1479. szServiceClass: String identifying service class, eg. "SMTP"
  1480. Return Value:
  1481. None.
  1482. --*/
  1483. {
  1484. DWORD dwErr, cbTargetSPN;
  1485. CHAR szTargetSPN[MAX_SPN];
  1486. cbTargetSPN = sizeof(szTargetSPN);
  1487. dwErr = DsClientMakeSpnForTargetServerA(
  1488. szServiceClass,
  1489. szTargetIPOrFQDN,
  1490. &cbTargetSPN,
  1491. szTargetSPN);
  1492. if (dwErr == ERROR_SUCCESS) {
  1493. return( SetTargetName(szTargetSPN) );
  1494. } else {
  1495. SetLastError(dwErr);
  1496. return( FALSE );
  1497. }
  1498. }