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.

3716 lines
99 KiB

  1. /*--
  2. Copyright (c) 1994-1997 Microsoft Corporation
  3. Module Name:
  4. secpkg.c
  5. Abstract:
  6. Security package used for Netlogon's secure channel between two netlogon
  7. processes.
  8. Author:
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. 05-Mar-1994 (MikeSw)
  15. Created as user mode example SSPI
  16. 02-Nov-1997 (CliffV)
  17. Converted to be the Netlogon security package.
  18. --*/
  19. //
  20. // Common include files.
  21. //
  22. #include "logonsrv.h" // Include files common to entire service
  23. #pragma hdrstop
  24. //
  25. // Include files specific to this .c file
  26. //
  27. #include <spseal.h>
  28. //
  29. // Authentication Data for the Netlogon Authentication Package.
  30. //
  31. // This is the auth data to pass to RpcBindingSetAuthInfo for the
  32. // Netlogon authentication package.
  33. //
  34. typedef struct _NL_AUTH_DATA {
  35. //
  36. // Signature to identify that this is really AUTH Data
  37. //
  38. ULONG Signature;
  39. #define NL_AUTH_DATA_SIGNATURE 0x29120227
  40. //
  41. // Size of this structure (in bytes)
  42. //
  43. ULONG Size;
  44. //
  45. // Information describing the session between the client and server.
  46. //
  47. SESSION_INFO SessionInfo;
  48. //
  49. // Domain name of the domain we're connecting to.
  50. //
  51. ULONG OemNetbiosDomainNameOffset;
  52. ULONG OemNetbiosDomainNameLength;
  53. ULONG Utf8DnsDomainNameOffset;
  54. //
  55. // Computer name of this machine
  56. //
  57. ULONG OemComputerNameOffset;
  58. ULONG OemComputerNameLength;
  59. ULONG Utf8ComputerNameOffset;
  60. ULONG Utf8ComputerNameLength;
  61. ULONG Utf8DnsHostNameOffset;
  62. } NL_AUTH_DATA, *PNL_AUTH_DATA;
  63. //
  64. // A single credential
  65. // Only the outbound side has a credential allocated. The inbound side simply
  66. // returns a constant handle to the caller.
  67. #define NL_AUTH_SERVER_CRED 0xfefefefe
  68. typedef struct _NL_AUTH_CREDENTIAL {
  69. //
  70. // Handle identifying the credential
  71. //
  72. CredHandle CredentialHandle;
  73. //
  74. // Global list of all credentials
  75. //
  76. struct _NL_AUTH_CREDENTIAL *Next;
  77. //
  78. // Reference count
  79. //
  80. ULONG ReferenceCount;
  81. //
  82. // For a client side (outbound) credential,
  83. // this is a pointer to the information from the client session structure
  84. // representing the secure channel to the server.
  85. //
  86. PNL_AUTH_DATA ClientAuthData;
  87. } NL_AUTH_CREDENTIAL, *PNL_AUTH_CREDENTIAL;
  88. //
  89. // A single context.
  90. //
  91. typedef struct _NL_AUTH_CONTEXT {
  92. //
  93. // Handle identifying the context
  94. //
  95. CtxtHandle ContextHandle;
  96. //
  97. // Global list of all contexts
  98. //
  99. struct _NL_AUTH_CONTEXT * Next;
  100. LARGE_INTEGER Nonce;
  101. ULONG ContextFlags;
  102. //
  103. // Information describing the session between the client and server.
  104. //
  105. SESSION_INFO SessionInfo;
  106. enum {
  107. Idle,
  108. FirstInit,
  109. FirstAccept,
  110. SecondInit
  111. } State;
  112. //
  113. // Flags
  114. //
  115. BOOLEAN Inbound;
  116. } NL_AUTH_CONTEXT, *PNL_AUTH_CONTEXT;
  117. #define BUFFERTYPE(_x_) ((_x_).BufferType & ~SECBUFFER_ATTRMASK)
  118. //
  119. // On the wire message transmitted from client to server during the bind.
  120. //
  121. typedef enum {
  122. Negotiate,
  123. NegotiateResponse
  124. } NL_AUTH_MESSAGE_TYPE;
  125. typedef struct _NL_AUTH_MESSAGE {
  126. NL_AUTH_MESSAGE_TYPE MessageType;
  127. ULONG Flags;
  128. #define NL_AUTH_NETBIOS_DOMAIN_NAME 0x0001 // Netbios Domain name exists in buffer
  129. #define NL_AUTH_NETBIOS_COMPUTER_NAME 0x0002 // Netbios Computer name exists in buffer
  130. #define NL_AUTH_DNS_DOMAIN_NAME 0x0004 // DNS Domain name exists in buffer
  131. #define NL_AUTH_DNS_HOST_NAME 0x0008 // DNS Host name exists in buffer
  132. #define NL_AUTH_UTF8_NETBIOS_COMPUTER_NAME 0x0010 // UTF-8 Netbios Computer name exists in buffer
  133. UCHAR Buffer[1];
  134. } NL_AUTH_MESSAGE, *PNL_AUTH_MESSAGE;
  135. //
  136. // Signature for signed and sealed messages
  137. //
  138. #define NL_AUTH_ETYPE KERB_ETYPE_RC4_PLAIN_OLD // Encryption algorithm to use
  139. #define NL_AUTH_CHECKSUM KERB_CHECKSUM_MD5_HMAC // Checksum algorithm to use
  140. typedef struct _NL_AUTH_SIGNATURE {
  141. BYTE SignatureAlgorithm[2]; // see below table for values
  142. union {
  143. BYTE SignFiller[4]; // filler, must be ff ff ff ff
  144. struct {
  145. BYTE SealAlgorithm[2];
  146. BYTE SealFiller[2];
  147. };
  148. };
  149. BYTE Flags[2];
  150. #define NL_AUTH_SIGNED_BYTES 8 // Number of bytes in signature before SequenceNumber
  151. #define NL_AUTH_SEQUENCE_SIZE 8
  152. BYTE SequenceNumber[NL_AUTH_SEQUENCE_SIZE];
  153. BYTE Checksum[8];
  154. // Confounder must be the last field in the structure since it isn't sent on
  155. // the wire if we're only signing the message.
  156. #define NL_AUTH_CONFOUNDER_SIZE 8
  157. BYTE Confounder[NL_AUTH_CONFOUNDER_SIZE];
  158. } NL_AUTH_SIGNATURE, *PNL_AUTH_SIGNATURE;
  159. #define PACKAGE_NAME NL_PACKAGE_NAME
  160. #define PACKAGE_COMMENT L"Package for securing Netlogon's Secure Channel"
  161. #define PACAKGE_CAPABILITIES (SECPKG_FLAG_TOKEN_ONLY | \
  162. SECPKG_FLAG_MULTI_REQUIRED | \
  163. SECPKG_FLAG_CONNECTION | \
  164. SECPKG_FLAG_INTEGRITY | \
  165. SECPKG_FLAG_PRIVACY)
  166. #define PACKAGE_VERSION 1
  167. #define PACKAGE_RPCID RPC_C_AUTHN_NETLOGON
  168. #define PACKAGE_MAXTOKEN (sizeof(NL_AUTH_MESSAGE) + DNLEN + 1 + CNLEN + 1 + 2*(NL_MAX_DNS_LENGTH+1) )
  169. #define PACKAGE_SIGNATURE_SIZE sizeof(NL_AUTH_SIGNATURE)
  170. SecurityFunctionTableW SecTableW = {SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
  171. EnumerateSecurityPackagesW,
  172. NULL,
  173. AcquireCredentialsHandleW,
  174. FreeCredentialsHandle,
  175. NULL, // LogonUser
  176. InitializeSecurityContextW,
  177. AcceptSecurityContext,
  178. NULL,
  179. DeleteSecurityContext,
  180. NULL,
  181. QueryContextAttributesW,
  182. ImpersonateSecurityContext,
  183. RevertSecurityContext,
  184. MakeSignature,
  185. VerifySignature,
  186. FreeContextBuffer,
  187. QuerySecurityPackageInfoW,
  188. SealMessage,
  189. UnsealMessage,
  190. };
  191. PNL_AUTH_CONTEXT ContextList;
  192. PNL_AUTH_CREDENTIAL CredentialList;
  193. //
  194. // Id's to identify a context or credential.
  195. // Access serialized by NlGlobalSecPkgCritSect
  196. //
  197. LARGE_INTEGER NextId = {0,0};
  198. TimeStamp Forever = {0x7fffffff,0xfffffff};
  199. TimeStamp Never = {0,0};
  200. PVOID
  201. NlBuildAuthData(
  202. PCLIENT_SESSION ClientSession
  203. )
  204. /*++
  205. Routine Description:
  206. Allocate an authentication data structure suitable for passing to
  207. RpcBindingSetAuthInfo
  208. On Entry,
  209. The caller must be a writer of the trust list entry.
  210. The trust list entry must be authenticated.
  211. Arguments:
  212. ClientSession - Authenticated session describing the secure channel to a
  213. DC.
  214. Return Value:
  215. Pointer to the AUTH_DATA. (Buffer should be freed by calling I_NetLogonFree.)
  216. NULL: memory could not be allocated
  217. --*/
  218. {
  219. ULONG Size;
  220. PNL_AUTH_DATA ClientAuthData;
  221. LPBYTE Where;
  222. ULONG DnsDomainNameSize;
  223. ULONG DnsHostNameSize;
  224. NlAssert( ClientSession->CsReferenceCount > 0 );
  225. NlAssert( ClientSession->CsFlags & CS_WRITER );
  226. NlAssert( ClientSession->CsState == CS_AUTHENTICATED );
  227. //
  228. // Determine the size of the entry
  229. //
  230. DnsDomainNameSize =
  231. (ClientSession->CsUtf8DnsDomainName != NULL ?
  232. (strlen( ClientSession->CsUtf8DnsDomainName ) + 1) :
  233. 0);
  234. #ifdef notdef
  235. DnsHostNameSize =
  236. (ClientSession->CsDomainInfo->DomUtf8DnsHostName != NULL ?
  237. (strlen( ClientSession->CsDomainInfo->DomUtf8DnsHostName ) + 1) :
  238. 0);
  239. #else // notdef
  240. DnsHostNameSize = 0;
  241. #endif // notdef
  242. Size = sizeof(NL_AUTH_DATA) +
  243. ClientSession->CsOemNetbiosDomainNameLength + 1 +
  244. ClientSession->CsDomainInfo->DomOemComputerNameLength + 1 +
  245. ClientSession->CsDomainInfo->DomUtf8ComputerNameLength + 1 +
  246. DnsDomainNameSize +
  247. DnsHostNameSize;
  248. //
  249. // Allocate the entry
  250. //
  251. ClientAuthData = NetpMemoryAllocate( Size );
  252. if ( ClientAuthData == NULL ) {
  253. return NULL;
  254. }
  255. Where = (LPBYTE) (ClientAuthData + 1);
  256. RtlZeroMemory( ClientAuthData, sizeof(NL_AUTH_DATA) );
  257. //
  258. // Fill in the fixed length fields.
  259. //
  260. ClientAuthData->Signature = NL_AUTH_DATA_SIGNATURE;
  261. ClientAuthData->Size = Size;
  262. ClientAuthData->SessionInfo.SessionKey = ClientSession->CsSessionKey;
  263. ClientAuthData->SessionInfo.NegotiatedFlags = ClientSession->CsNegotiatedFlags;
  264. //
  265. // Copy the Netbios domain name of the domain hosted by the DC into the buffer
  266. //
  267. if ( ClientSession->CsOemNetbiosDomainNameLength != 0 ) {
  268. ClientAuthData->OemNetbiosDomainNameOffset = (ULONG) (Where-(LPBYTE)ClientAuthData);
  269. ClientAuthData->OemNetbiosDomainNameLength =
  270. ClientSession->CsOemNetbiosDomainNameLength;
  271. RtlCopyMemory( Where,
  272. ClientSession->CsOemNetbiosDomainName,
  273. ClientSession->CsOemNetbiosDomainNameLength + 1 );
  274. Where += ClientAuthData->OemNetbiosDomainNameLength + 1;
  275. }
  276. //
  277. // Copy the OEM Netbios computer name of this machine into the buffer.
  278. //
  279. // ???: Only copy the Netbios computername or DNS host name. Copy the
  280. // one that was passed to the server on the NetServerReqChallenge.
  281. //
  282. if ( ClientSession->CsDomainInfo->DomOemComputerNameLength != 0 ) {
  283. ClientAuthData->OemComputerNameOffset = (ULONG) (Where-(LPBYTE)ClientAuthData);
  284. ClientAuthData->OemComputerNameLength =
  285. ClientSession->CsDomainInfo->DomOemComputerNameLength;
  286. RtlCopyMemory( Where,
  287. ClientSession->CsDomainInfo->DomOemComputerName,
  288. ClientSession->CsDomainInfo->DomOemComputerNameLength + 1);
  289. Where += ClientAuthData->OemComputerNameLength + 1;
  290. }
  291. //
  292. // Copy the UTF-8 Netbios computer name of this machine into the buffer.
  293. //
  294. if ( ClientSession->CsDomainInfo->DomUtf8ComputerNameLength != 0 ) {
  295. ClientAuthData->Utf8ComputerNameOffset = (ULONG) (Where-(LPBYTE)ClientAuthData);
  296. ClientAuthData->Utf8ComputerNameLength =
  297. ClientSession->CsDomainInfo->DomUtf8ComputerNameLength;
  298. RtlCopyMemory( Where,
  299. ClientSession->CsDomainInfo->DomUtf8ComputerName,
  300. ClientSession->CsDomainInfo->DomUtf8ComputerNameLength +1 );
  301. Where += ClientAuthData->Utf8ComputerNameLength + 1;
  302. }
  303. //
  304. // Copy the DNS domain name of the domain hosted by the DC into the buffer.
  305. //
  306. if ( ClientSession->CsUtf8DnsDomainName != NULL ) {
  307. ClientAuthData->Utf8DnsDomainNameOffset = (ULONG) (Where-(LPBYTE)ClientAuthData);
  308. RtlCopyMemory( Where, ClientSession->CsUtf8DnsDomainName, DnsDomainNameSize );
  309. Where += DnsDomainNameSize;
  310. }
  311. //
  312. // Copy the DNS host name name of this machine into the buffer.
  313. //
  314. // ???: Only copy the Netbios computername or DNS host name. Copy the
  315. // one that was passed to the server on the NetServerReqChallenge.
  316. //
  317. #ifdef notdef
  318. if ( ClientSession->CsDomainInfo->DomUtf8DnsHostName != NULL ) {
  319. ClientAuthData->Utf8DnsHostNameOffset = (ULONG) (Where-(LPBYTE)ClientAuthData);
  320. RtlCopyMemory( Where, ClientSession->CsDomainInfo->DomUtf8DnsHostName, DnsHostNameSize );
  321. Where += DnsHostNameSize;
  322. }
  323. #endif // notdef
  324. return ClientAuthData;
  325. }
  326. BOOL
  327. NlEqualClientSessionKey(
  328. PCLIENT_SESSION ClientSession,
  329. PVOID ClientContext
  330. )
  331. /*++
  332. Routine Description:
  333. Checks whether the session key on the client session is equal
  334. to the session key on the client context.
  335. On Entry,
  336. The caller must be a writer of the trust list entry.
  337. Arguments:
  338. ClientSession - Authenticated session describing the secure channel to a DC
  339. ClientContext - Client context returned from a previous call to NlBuildAuthData
  340. Return Value:
  341. TRUE if the two session keys are equal.
  342. FALSE, otherwise.
  343. --*/
  344. {
  345. PNL_AUTH_DATA ClientAuthData = ClientContext;
  346. if ( ClientAuthData == NULL ) {
  347. return FALSE;
  348. }
  349. if ( RtlEqualMemory( &ClientSession->CsSessionKey,
  350. &ClientAuthData->SessionInfo.SessionKey,
  351. sizeof(ClientSession->CsSessionKey) ) ) {
  352. return TRUE;
  353. } else{
  354. return FALSE;
  355. }
  356. }
  357. BOOL
  358. NlStartNetlogonCall(
  359. VOID
  360. )
  361. /*++
  362. Routine Description:
  363. Start a procedure call from outside the Netlogon service into the
  364. Netlogon Service.
  365. Arguments:
  366. None.
  367. Return Value:
  368. TRUE - Call is OK. (Caller must call NlEndNetlogonCall())
  369. FALSE - Netlogon is not started.
  370. --*/
  371. {
  372. //
  373. // If caller is calling when the netlogon service isn't running,
  374. // tell it so.
  375. //
  376. EnterCriticalSection( &NlGlobalMsvCritSect );
  377. if ( !NlGlobalMsvEnabled ) {
  378. LeaveCriticalSection( &NlGlobalMsvCritSect );
  379. return FALSE;
  380. }
  381. NlGlobalMsvThreadCount ++;
  382. LeaveCriticalSection( &NlGlobalMsvCritSect );
  383. return TRUE;
  384. }
  385. VOID
  386. NlEndNetlogonCall(
  387. VOID
  388. )
  389. /*++
  390. Routine Description:
  391. End a procedure call from outside the Netlogon service into the
  392. Netlogon Service.
  393. Arguments:
  394. None.
  395. Return Value:
  396. None.
  397. --*/
  398. {
  399. //
  400. // Indicate that the calling thread has left netlogon.dll
  401. //
  402. EnterCriticalSection( &NlGlobalMsvCritSect );
  403. NlGlobalMsvThreadCount --;
  404. if ( NlGlobalMsvThreadCount == 0 && !NlGlobalMsvEnabled ) {
  405. if ( !SetEvent( NlGlobalMsvTerminateEvent ) ) {
  406. NlPrint((NL_CRITICAL, "Cannot set MSV termination event: %lu\n",
  407. GetLastError() ));
  408. }
  409. }
  410. LeaveCriticalSection( &NlGlobalMsvCritSect );
  411. }
  412. PNL_AUTH_CREDENTIAL
  413. LocateCredential(
  414. PCredHandle CredentialHandle
  415. )
  416. /*++
  417. Routine Description:
  418. Find a credential given its handle
  419. Arguments:
  420. CredentialHandle - Handle to the credential to locate
  421. Return Value:
  422. Pointer to the credential
  423. --*/
  424. {
  425. PNL_AUTH_CREDENTIAL TestCredential;
  426. RtlEnterCriticalSection(&NlGlobalSecPkgCritSect);
  427. for ( TestCredential = CredentialList;
  428. TestCredential != NULL;
  429. TestCredential = TestCredential->Next ) {
  430. if ( TestCredential->CredentialHandle.dwUpper == CredentialHandle->dwUpper &&
  431. TestCredential->CredentialHandle.dwLower == CredentialHandle->dwLower ) {
  432. break;
  433. }
  434. }
  435. RtlLeaveCriticalSection(&NlGlobalSecPkgCritSect);
  436. return(TestCredential);
  437. }
  438. BOOLEAN
  439. DeleteCredential(
  440. PCtxtHandle CredentialHandle
  441. )
  442. /*++
  443. Routine Description:
  444. Delete a credential given its handle
  445. Arguments:
  446. CredentialHandle - Handle to the credential to locate
  447. Return Value:
  448. TRUE: if credential existed.
  449. --*/
  450. {
  451. PNL_AUTH_CREDENTIAL TestCredential, LastCredential;
  452. //
  453. // Find the credential.
  454. //
  455. RtlEnterCriticalSection(&NlGlobalSecPkgCritSect);
  456. LastCredential = NULL;
  457. for ( TestCredential = CredentialList;
  458. TestCredential != NULL ;
  459. TestCredential = TestCredential->Next ) {
  460. if ( TestCredential->CredentialHandle.dwUpper == CredentialHandle->dwUpper &&
  461. TestCredential->CredentialHandle.dwLower == CredentialHandle->dwLower ) {
  462. break;
  463. }
  464. LastCredential = TestCredential;
  465. }
  466. //
  467. // If we found it,
  468. // Dereference it.
  469. //
  470. if ( TestCredential != NULL ) {
  471. TestCredential->ReferenceCount --;
  472. //
  473. // If this is the last dereference,
  474. // delink it and delete it.
  475. //
  476. if ( TestCredential->ReferenceCount == 0 ) {
  477. if (LastCredential != NULL) {
  478. LastCredential->Next = TestCredential->Next;
  479. } else {
  480. NlAssert(CredentialList == TestCredential);
  481. CredentialList = TestCredential->Next;
  482. }
  483. NlPrint(( NL_SESSION_MORE,
  484. "DeleteCredential: %lx.%lx: credential freed\n",
  485. CredentialHandle->dwUpper, CredentialHandle->dwLower ));
  486. LocalFree(TestCredential);
  487. } else {
  488. NlPrint(( NL_SESSION_MORE,
  489. "DeleteCredential: %lx.%lx: credential dereferenced: %ld\n",
  490. CredentialHandle->dwUpper, CredentialHandle->dwLower,
  491. TestCredential->ReferenceCount ));
  492. }
  493. } else {
  494. NlPrint(( NL_SESSION_MORE,
  495. "DeleteCredential: %lx.%lx: credential handle not found\n",
  496. CredentialHandle->dwUpper, CredentialHandle->dwLower ));
  497. }
  498. RtlLeaveCriticalSection(&NlGlobalSecPkgCritSect);
  499. return( TestCredential == NULL ? FALSE : TRUE );
  500. }
  501. PNL_AUTH_CREDENTIAL
  502. AllocateCredential(
  503. IN PNL_AUTH_DATA ClientAuthData
  504. )
  505. /*++
  506. Routine Description:
  507. Allocate and initialize a credential (Client or server side)
  508. Arguments:
  509. ClientAuthData - The client auth data to capture.
  510. Return Value:
  511. Allocated credential. Delete this credential by DeleteCredential( Credential->CredentialHandle );
  512. NULL if credential cannot be allocated.
  513. --*/
  514. {
  515. PNL_AUTH_CREDENTIAL Credential;
  516. //
  517. // Determine if we already have a credential
  518. //
  519. RtlEnterCriticalSection(&NlGlobalSecPkgCritSect);
  520. for ( Credential = CredentialList;
  521. Credential != NULL;
  522. Credential = Credential->Next ) {
  523. if ( ClientAuthData->Size == Credential->ClientAuthData->Size &&
  524. RtlEqualMemory( ClientAuthData,
  525. Credential->ClientAuthData,
  526. ClientAuthData->Size ) ) {
  527. //
  528. // Return the existing credential to the caller.
  529. //
  530. Credential->ReferenceCount ++;
  531. NlPrint(( NL_SESSION_MORE,
  532. "AllocateCredential: %lx.%lx: credential referenced: %ld\n",
  533. Credential->CredentialHandle.dwUpper,
  534. Credential->CredentialHandle.dwLower,
  535. Credential->ReferenceCount ));
  536. goto Cleanup;
  537. }
  538. }
  539. //
  540. // Allocate a credential block.
  541. //
  542. Credential = (PNL_AUTH_CREDENTIAL)
  543. LocalAlloc( LMEM_ZEROINIT,
  544. sizeof(NL_AUTH_CREDENTIAL) +
  545. ClientAuthData->Size );
  546. if (Credential == NULL) {
  547. goto Cleanup;
  548. }
  549. //
  550. // Initialize the credential.
  551. //
  552. NextId.QuadPart ++;
  553. Credential->CredentialHandle.dwUpper = NextId.HighPart;
  554. Credential->CredentialHandle.dwLower = NextId.LowPart;
  555. Credential->ReferenceCount = 1;
  556. Credential->Next = CredentialList;
  557. CredentialList = Credential;
  558. //
  559. // Capture a local copy of the credential
  560. // The caller might free the one passed in to us.
  561. //
  562. Credential->ClientAuthData = (PNL_AUTH_DATA)
  563. (((LPBYTE)Credential) + sizeof(NL_AUTH_CREDENTIAL));
  564. RtlCopyMemory( Credential->ClientAuthData,
  565. ClientAuthData,
  566. ClientAuthData->Size );
  567. NlPrint(( NL_SESSION_MORE,
  568. "AllocateCredential: %lx.%lx: credential allocated\n",
  569. Credential->CredentialHandle.dwUpper,
  570. Credential->CredentialHandle.dwLower ));
  571. Cleanup:
  572. RtlLeaveCriticalSection(&NlGlobalSecPkgCritSect);
  573. return Credential;
  574. }
  575. PNL_AUTH_CONTEXT
  576. LocateContext(
  577. PCtxtHandle ContextHandle
  578. )
  579. /*++
  580. Routine Description:
  581. Find a context given its handle
  582. Arguments:
  583. ContextHandle - Handle to the context to locate
  584. Return Value:
  585. Pointer to the context
  586. --*/
  587. {
  588. PNL_AUTH_CONTEXT TestContext;
  589. RtlEnterCriticalSection(&NlGlobalSecPkgCritSect);
  590. for ( TestContext = ContextList;
  591. TestContext != NULL;
  592. TestContext = TestContext->Next ) {
  593. if ( TestContext->ContextHandle.dwUpper == ContextHandle->dwUpper &&
  594. TestContext->ContextHandle.dwLower == ContextHandle->dwLower ) {
  595. break;
  596. }
  597. }
  598. RtlLeaveCriticalSection(&NlGlobalSecPkgCritSect);
  599. return(TestContext);
  600. }
  601. BOOLEAN
  602. DeleteContext(
  603. PCtxtHandle ContextHandle
  604. )
  605. /*++
  606. Routine Description:
  607. Delete a context given its handle
  608. Arguments:
  609. ContextHandle - Handle to the context to locate
  610. Return Value:
  611. TRUE: Context existed
  612. --*/
  613. {
  614. PNL_AUTH_CONTEXT TestContext, LastContext;
  615. //
  616. // Find the context.
  617. //
  618. RtlEnterCriticalSection(&NlGlobalSecPkgCritSect);
  619. LastContext = NULL;
  620. for ( TestContext = ContextList;
  621. TestContext != NULL ;
  622. TestContext = TestContext->Next ) {
  623. if ( TestContext->ContextHandle.dwUpper == ContextHandle->dwUpper &&
  624. TestContext->ContextHandle.dwLower == ContextHandle->dwLower ) {
  625. break;
  626. }
  627. LastContext = TestContext;
  628. }
  629. //
  630. // If we found it,
  631. // and it is no longer needed as a context or a credential,
  632. // delink it and delete it.
  633. //
  634. if ( TestContext != NULL ) {
  635. if (LastContext != NULL) {
  636. LastContext->Next = TestContext->Next;
  637. } else {
  638. NlAssert(ContextList == TestContext);
  639. ContextList = TestContext->Next;
  640. }
  641. NlPrint(( NL_SESSION_MORE,
  642. "DeleteContext: %lx.%lx: context freed\n",
  643. ContextHandle->dwUpper, ContextHandle->dwLower ));
  644. LocalFree(TestContext);
  645. } else {
  646. NlPrint(( NL_SESSION_MORE,
  647. "DeleteContext: %lx.%lx: context handle not found\n",
  648. ContextHandle->dwUpper, ContextHandle->dwLower ));
  649. }
  650. RtlLeaveCriticalSection(&NlGlobalSecPkgCritSect);
  651. return( TestContext == NULL ? FALSE : TRUE );
  652. }
  653. PNL_AUTH_CONTEXT
  654. AllocateContext(
  655. IN ULONG fContextReq
  656. )
  657. /*++
  658. Routine Description:
  659. Allocate and initialize a context (Client or server side)
  660. Arguments:
  661. fContextReq - Context request flags
  662. Return Value:
  663. Allocated context. Delete this context by DeleteContext( Context->ContextHandle, FALSE );
  664. NULL if context cannot be allocated.
  665. --*/
  666. {
  667. PNL_AUTH_CONTEXT Context;
  668. //
  669. // Allocate a context block.
  670. //
  671. Context = (PNL_AUTH_CONTEXT) LocalAlloc( LMEM_ZEROINIT, sizeof(NL_AUTH_CONTEXT) );
  672. if (Context == NULL) {
  673. return NULL;
  674. }
  675. //
  676. // Initialize the context.
  677. //
  678. Context->State = Idle;
  679. Context->ContextFlags = fContextReq;
  680. RtlEnterCriticalSection(&NlGlobalSecPkgCritSect);
  681. NextId.QuadPart ++;
  682. Context->ContextHandle.dwUpper = NextId.HighPart;
  683. Context->ContextHandle.dwLower = NextId.LowPart;
  684. Context->Next = ContextList;
  685. ContextList = Context;
  686. RtlLeaveCriticalSection(&NlGlobalSecPkgCritSect);
  687. return Context;
  688. }
  689. PSecBuffer
  690. LocateBuffer(PSecBufferDesc Buffer, ULONG MinimumSize)
  691. /*++
  692. Routine Description:
  693. Arguments:
  694. Standard.
  695. Return Value:
  696. --*/
  697. {
  698. ULONG Index;
  699. if (Buffer == NULL) {
  700. return(NULL);
  701. }
  702. for (Index = 0; Index < Buffer->cBuffers ; Index++) {
  703. if ( BUFFERTYPE(Buffer->pBuffers[Index]) == SECBUFFER_TOKEN) {
  704. //
  705. // Do size checking
  706. //
  707. if (Buffer->pBuffers[Index].cbBuffer < MinimumSize) {
  708. return(NULL);
  709. }
  710. return(&Buffer->pBuffers[Index]);
  711. }
  712. }
  713. return(NULL);
  714. }
  715. PSecBuffer
  716. LocateSecBuffer(PSecBufferDesc Buffer)
  717. /*++
  718. Routine Description:
  719. Locate a buffer suitable for authentication
  720. Arguments:
  721. Standard.
  722. Return Value:
  723. --*/
  724. {
  725. return(LocateBuffer(Buffer, sizeof(NL_AUTH_MESSAGE)));
  726. }
  727. PSecBuffer
  728. LocateSigBuffer(PSecBufferDesc Buffer)
  729. /*++
  730. Routine Description:
  731. Locate a buffer suitable for a signature
  732. Arguments:
  733. Standard.
  734. Return Value:
  735. --*/
  736. {
  737. return(LocateBuffer(Buffer, PACKAGE_SIGNATURE_SIZE - NL_AUTH_CONFOUNDER_SIZE ));
  738. }
  739. PSecurityFunctionTableW SEC_ENTRY
  740. InitSecurityInterfaceW(VOID)
  741. /*++
  742. Routine Description:
  743. Initialization routine called by RPC to get pointers to all other routines.
  744. Arguments:
  745. None.
  746. Return Value:
  747. Pointer to function table.
  748. --*/
  749. {
  750. NlPrint(( NL_SESSION_MORE,
  751. "InitSecurityInterfaceW: called\n" ));
  752. return(&SecTableW);
  753. }
  754. SECURITY_STATUS SEC_ENTRY
  755. AcquireCredentialsHandleW(
  756. LPWSTR pszPrincipal, // Name of principal
  757. LPWSTR pszPackageName, // Name of package
  758. unsigned long fCredentialUse, // Flags indicating use
  759. void SEC_FAR * pvLogonId, // Pointer to logon ID
  760. void SEC_FAR * pAuthData, // Package specific data
  761. SEC_GET_KEY_FN pGetKeyFn, // Pointer to GetKey() func
  762. void SEC_FAR * pvGetKeyArgument, // Value to pass to GetKey()
  763. PCredHandle phCredential, // (out) Cred Handle
  764. PTimeStamp ptsExpiry // (out) Lifetime (optional)
  765. )
  766. /*++
  767. Routine Description:
  768. Client and Server side routine to grab a credential handle.
  769. Arguments:
  770. Standard.
  771. Return Value:
  772. --*/
  773. {
  774. SECURITY_STATUS SecStatus;
  775. PNL_AUTH_CREDENTIAL Credential = NULL;
  776. NlPrint(( NL_SESSION_MORE,
  777. "AcquireCredentialsHandleW: called\n" ));
  778. //
  779. // If caller is calling when the netlogon service isn't running,
  780. // tell it so.
  781. //
  782. if ( !NlStartNetlogonCall() ) {
  783. return SEC_E_SECPKG_NOT_FOUND;
  784. }
  785. //
  786. // Validate the input parameters
  787. //
  788. if ((fCredentialUse & (SECPKG_CRED_BOTH)) == 0) {
  789. NlPrint(( NL_CRITICAL,
  790. "AcquireCredentialHandle: Bad Credential Use 0x%lx.\n", fCredentialUse ));
  791. SecStatus = SEC_E_UNKNOWN_CREDENTIALS;
  792. goto Cleanup;
  793. }
  794. if ((fCredentialUse & (SECPKG_CRED_BOTH)) == SECPKG_CRED_BOTH) {
  795. NlPrint(( NL_CRITICAL,
  796. "AcquireCredentialHandle: Bad Credential Use 0x%lx.\n", fCredentialUse ));
  797. SecStatus = SEC_E_UNKNOWN_CREDENTIALS;
  798. goto Cleanup;
  799. }
  800. //
  801. // Handle a client credential
  802. //
  803. if ((fCredentialUse & (SECPKG_CRED_BOTH)) == SECPKG_CRED_OUTBOUND) {
  804. //
  805. // Sanity check the client session
  806. //
  807. if ( pAuthData == NULL ) {
  808. NlPrint(( NL_CRITICAL,
  809. "AcquireCredentialHandle: NULL auth data\n" ));
  810. SecStatus = SEC_E_INVALID_TOKEN;
  811. goto Cleanup;
  812. }
  813. if ( ((PNL_AUTH_DATA)pAuthData)->Signature != NL_AUTH_DATA_SIGNATURE ) {
  814. NlPrint(( NL_CRITICAL,
  815. "AcquireCredentialHandle: Invalid Signature on auth data\n" ));
  816. SecStatus = SEC_E_INVALID_TOKEN;
  817. goto Cleanup;
  818. }
  819. //
  820. // Allocate a credential to remember the AuthData (ClientSession) in.
  821. //
  822. Credential = AllocateCredential( (PNL_AUTH_DATA)pAuthData );
  823. if (Credential == NULL) {
  824. NlPrint(( NL_CRITICAL,
  825. "AcquireCredentialHandle: Cannot allocate context\n" ));
  826. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  827. goto Cleanup;
  828. }
  829. //
  830. // Return to the caller.
  831. //
  832. *phCredential = Credential->CredentialHandle;
  833. *ptsExpiry = Forever;
  834. SecStatus = SEC_E_OK;
  835. //
  836. // Handle a server credential
  837. //
  838. // We don't need a credential on the server side.
  839. // Silently succeed.
  840. //
  841. } else {
  842. phCredential->dwUpper = NL_AUTH_SERVER_CRED; // Just return a constant
  843. phCredential->dwLower = 0;
  844. *ptsExpiry = Forever;
  845. SecStatus = SEC_E_OK;
  846. goto Cleanup;
  847. }
  848. Cleanup:
  849. NlPrint(( NL_SESSION_MORE,
  850. "AcquireCredentialsHandleW: %lx.%lx: returns 0x%lx\n",
  851. phCredential->dwUpper, phCredential->dwLower,
  852. SecStatus ));
  853. // Let netlogon service exit.
  854. NlEndNetlogonCall();
  855. return SecStatus;
  856. UNREFERENCED_PARAMETER( pvGetKeyArgument );
  857. UNREFERENCED_PARAMETER( pGetKeyFn );
  858. UNREFERENCED_PARAMETER( pAuthData );
  859. UNREFERENCED_PARAMETER( pvLogonId );
  860. UNREFERENCED_PARAMETER( pszPackageName );
  861. UNREFERENCED_PARAMETER( pszPrincipal );
  862. }
  863. SECURITY_STATUS SEC_ENTRY
  864. FreeCredentialsHandle(
  865. PCredHandle phCredential // Handle to free
  866. )
  867. /*++
  868. Routine Description:
  869. Arguments:
  870. Standard.
  871. Return Value:
  872. --*/
  873. {
  874. NlPrint(( NL_SESSION_MORE,
  875. "FreeCredentialsHandle: %lx.%lx: called\n",
  876. phCredential->dwUpper, phCredential->dwLower ));
  877. //
  878. // Don't require that Netlogon be running. Some credential handles are
  879. // deleted as Netlogon is shutting down.
  880. //
  881. //
  882. // Ignore server side credentials.
  883. //
  884. if ( phCredential->dwUpper == NL_AUTH_SERVER_CRED &&
  885. phCredential->dwLower == 0 ) {
  886. return(SEC_E_OK);
  887. }
  888. //
  889. // For the Client side,
  890. // Delete the credential.
  891. //
  892. if ( DeleteCredential( phCredential ) ) {
  893. return(SEC_E_OK);
  894. } else {
  895. return(SEC_E_UNKNOWN_CREDENTIALS);
  896. }
  897. }
  898. SECURITY_STATUS SEC_ENTRY
  899. InitializeSecurityContextW(
  900. PCredHandle phCredential, // Cred to base context
  901. PCtxtHandle phContext, // Existing context (OPT)
  902. LPWSTR pszTargetName, // Name of target
  903. unsigned long fContextReq, // Context Requirements
  904. unsigned long Reserved1, // Reserved, MBZ
  905. unsigned long TargetDataRep, // Data rep of target
  906. PSecBufferDesc pInput, // Input Buffers
  907. unsigned long Reserved2, // Reserved, MBZ
  908. PCtxtHandle phNewContext, // (out) New Context handle
  909. PSecBufferDesc pOutput, // (inout) Output Buffers
  910. unsigned long SEC_FAR * pfContextAttr, // (out) Context attrs
  911. PTimeStamp ptsExpiry // (out) Life span (OPT)
  912. )
  913. /*++
  914. Routine Description:
  915. Client side routine to define a security context.
  916. Arguments:
  917. Standard.
  918. Return Value:
  919. --*/
  920. {
  921. SECURITY_STATUS SecStatus;
  922. NET_API_STATUS NetStatus;
  923. PNL_AUTH_CONTEXT Context = NULL;
  924. PNL_AUTH_CREDENTIAL Credential = NULL;
  925. NL_AUTH_MESSAGE UNALIGNED *Message = NULL;
  926. PSecBuffer OutputBuffer;
  927. PSecBuffer InputBuffer;
  928. WORD CompressOffset[10];
  929. CHAR *CompressUtf8String[10];
  930. ULONG CompressCount = 0;
  931. ULONG Utf8StringSize;
  932. LPBYTE Where;
  933. NlPrint(( NL_SESSION_MORE,
  934. "InitializeSecurityContext: %ws: called\n", pszTargetName ));
  935. //
  936. // If caller is calling when the netlogon service isn't running,
  937. // tell it so.
  938. //
  939. if ( !NlStartNetlogonCall() ) {
  940. return SEC_E_SECPKG_NOT_FOUND;
  941. }
  942. if (fContextReq & ISC_REQ_ALLOCATE_MEMORY) {
  943. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  944. goto Cleanup;
  945. }
  946. OutputBuffer = LocateSecBuffer(pOutput);
  947. if (OutputBuffer == NULL) {
  948. SecStatus = SEC_E_INVALID_TOKEN;
  949. goto Cleanup;
  950. }
  951. //
  952. // Handle the first init call,
  953. //
  954. if (phContext == NULL) {
  955. PNL_AUTH_DATA ClientAuthData;
  956. //
  957. // Find the credential and ensure it is outbound
  958. //
  959. if ( phCredential == NULL ) {
  960. SecStatus = SEC_E_UNKNOWN_CREDENTIALS;
  961. goto Cleanup;
  962. }
  963. NlPrint(( NL_SESSION_MORE,
  964. "InitializeSecurityContext: %lx.%lx: %ws: called with cred handle\n",
  965. phCredential->dwUpper, phCredential->dwLower,
  966. pszTargetName ));
  967. //
  968. // Locate the credential and make sure this is a client side call.
  969. //
  970. Credential = LocateCredential( phCredential );
  971. if (Credential == NULL) {
  972. SecStatus = SEC_E_UNKNOWN_CREDENTIALS;
  973. goto Cleanup;
  974. }
  975. ClientAuthData = Credential->ClientAuthData;
  976. if ( ClientAuthData == NULL ) {
  977. SecStatus = SEC_E_INVALID_TOKEN;
  978. goto Cleanup;
  979. }
  980. NlAssert( ClientAuthData->Signature == NL_AUTH_DATA_SIGNATURE );
  981. //
  982. // Build an output token.
  983. //
  984. // This token simply tells the server side of the authentication
  985. // package our computer name.
  986. //
  987. Message = (PNL_AUTH_MESSAGE) OutputBuffer->pvBuffer;
  988. SmbPutUlong( &Message->MessageType, Negotiate );
  989. Message->Flags = 0;
  990. Where = &Message->Buffer[0];
  991. //
  992. // Copy the Netbios domain name of the domain hosted by the DC into the buffer
  993. //
  994. // OEM on the wire is bad. Luckily, if the DC is in a different locale,
  995. // that DC also has a DNS domain name and we'll use that to find the
  996. // hosted domain.
  997. //
  998. if ( ClientAuthData->OemNetbiosDomainNameLength != 0 ) {
  999. strcpy( Where,
  1000. ((LPBYTE)ClientAuthData) +
  1001. ClientAuthData->OemNetbiosDomainNameOffset );
  1002. Where += ClientAuthData->OemNetbiosDomainNameLength + 1;
  1003. Message->Flags |= NL_AUTH_NETBIOS_DOMAIN_NAME;
  1004. }
  1005. //
  1006. // Copy the computer name of this machine into the buffer.
  1007. //
  1008. // ???: Only copy the Netbios computername or DNS host name. Copy the
  1009. // one that was passed to the server on the NetServerReqChallenge.
  1010. //
  1011. // OEM on the wire is bad. So pass the UTF-8 version, too.
  1012. //
  1013. if ( ClientAuthData->OemComputerNameLength != 0 ) {
  1014. strcpy( Where,
  1015. ((LPBYTE)ClientAuthData) +
  1016. ClientAuthData->OemComputerNameOffset );
  1017. Where += ClientAuthData->OemComputerNameLength + 1;
  1018. Message->Flags |= NL_AUTH_NETBIOS_COMPUTER_NAME;
  1019. }
  1020. //
  1021. // Copy the DNS domain name of the domain hosted by the DC into the buffer.
  1022. //
  1023. Utf8StringSize = 2*(NL_MAX_DNS_LENGTH+1);
  1024. CompressCount = 0; // No strings compressed yet.
  1025. if ( ClientAuthData->Utf8DnsDomainNameOffset != 0 ) {
  1026. NetStatus = NlpUtf8ToCutf8(
  1027. (LPBYTE)Message,
  1028. ((LPBYTE)ClientAuthData) +
  1029. ClientAuthData->Utf8DnsDomainNameOffset,
  1030. FALSE,
  1031. &Where,
  1032. &Utf8StringSize,
  1033. &CompressCount,
  1034. CompressOffset,
  1035. CompressUtf8String );
  1036. if ( NetStatus != NO_ERROR ) {
  1037. NlPrint((NL_CRITICAL,
  1038. "Cannot pack DomainName into message %ld\n",
  1039. NetStatus ));
  1040. SecStatus = SEC_E_INVALID_TOKEN;
  1041. goto Cleanup;
  1042. }
  1043. Message->Flags |= NL_AUTH_DNS_DOMAIN_NAME;
  1044. }
  1045. //
  1046. // Copy the DNS host name name of this machine into the buffer.
  1047. //
  1048. // ???: Only copy the Netbios computername or DNS host name. Copy the
  1049. // one that was passed to the server on the NetServerReqChallenge.
  1050. //
  1051. if ( ClientAuthData->Utf8DnsHostNameOffset != 0 ) {
  1052. NetStatus = NlpUtf8ToCutf8(
  1053. (LPBYTE)Message,
  1054. ((LPBYTE)ClientAuthData) +
  1055. ClientAuthData->Utf8DnsHostNameOffset,
  1056. FALSE,
  1057. &Where,
  1058. &Utf8StringSize,
  1059. &CompressCount,
  1060. CompressOffset,
  1061. CompressUtf8String );
  1062. if ( NetStatus != NO_ERROR ) {
  1063. NlPrint((NL_CRITICAL,
  1064. "Cannot pack dns host name into message %ld\n",
  1065. NetStatus ));
  1066. SecStatus = SEC_E_INVALID_TOKEN;
  1067. goto Cleanup;
  1068. }
  1069. Message->Flags |= NL_AUTH_DNS_HOST_NAME;
  1070. }
  1071. //
  1072. // Copy the UTF-8 netbios computer name of this machine into the buffer.
  1073. //
  1074. // ???: Only copy the Netbios computername or DNS host name. Copy the
  1075. // one that was passed to the server on the NetServerReqChallenge.
  1076. //
  1077. // OEM on the wire is bad. So pass the UTF-8 version, too.
  1078. //
  1079. if ( ClientAuthData->Utf8ComputerNameLength != 0 ) {
  1080. NetStatus = NlpUtf8ToCutf8(
  1081. (LPBYTE)Message,
  1082. ((LPBYTE)ClientAuthData) +
  1083. ClientAuthData->Utf8ComputerNameOffset,
  1084. TRUE,
  1085. &Where,
  1086. &Utf8StringSize,
  1087. &CompressCount,
  1088. CompressOffset,
  1089. CompressUtf8String );
  1090. if ( NetStatus != NO_ERROR ) {
  1091. NlPrint((NL_CRITICAL,
  1092. "Cannot pack UTF-8 netbios computer name into message %ld\n",
  1093. NetStatus ));
  1094. SecStatus = SEC_E_INVALID_TOKEN;
  1095. goto Cleanup;
  1096. }
  1097. Message->Flags |= NL_AUTH_UTF8_NETBIOS_COMPUTER_NAME;
  1098. }
  1099. //
  1100. // Allocate a context.
  1101. //
  1102. Context = AllocateContext( fContextReq );
  1103. if ( Context == NULL) {
  1104. NlPrint(( NL_CRITICAL,
  1105. "InitializeSecurityContext: Cannot allocate context\n" ));
  1106. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1107. goto Cleanup;
  1108. }
  1109. //
  1110. // Mark the context to indicate what state we're in.
  1111. //
  1112. Context->State = FirstInit;
  1113. Context->Inbound = FALSE;
  1114. //
  1115. // Grab the session key
  1116. //
  1117. Context->SessionInfo = ClientAuthData->SessionInfo;
  1118. //
  1119. // Ask the caller to call us back
  1120. //
  1121. OutputBuffer->cbBuffer = (DWORD)(Where - (LPBYTE)Message);
  1122. *phNewContext = Context->ContextHandle;
  1123. *pfContextAttr = fContextReq;
  1124. *ptsExpiry = Forever;
  1125. SecStatus = SEC_I_CONTINUE_NEEDED;
  1126. //
  1127. // Handle the second call
  1128. //
  1129. } else {
  1130. NlPrint(( NL_SESSION_MORE,
  1131. "InitializeSecurityContext: %lx.%lx: %ws: called with context handle\n",
  1132. phContext->dwUpper, phContext->dwLower,
  1133. pszTargetName ));
  1134. //
  1135. // This is the second call. Lookup the old context.
  1136. //
  1137. // Locate the context and make sure this is a client side call.
  1138. //
  1139. Context = LocateContext( phContext );
  1140. if (Context == NULL) {
  1141. SecStatus = SEC_E_INVALID_HANDLE;
  1142. goto Cleanup;
  1143. }
  1144. //
  1145. // Ensure we're in the right state.
  1146. //
  1147. if ( Context->State != FirstInit ) {
  1148. SecStatus = SEC_E_INVALID_HANDLE;
  1149. goto Cleanup;
  1150. }
  1151. //
  1152. // Check that the input message is what we expected.
  1153. //
  1154. InputBuffer = LocateSecBuffer(pInput);
  1155. if (InputBuffer == NULL) {
  1156. SecStatus = SEC_E_INVALID_TOKEN;
  1157. goto Cleanup;
  1158. }
  1159. Message = (PNL_AUTH_MESSAGE) InputBuffer->pvBuffer;
  1160. if ( InputBuffer->cbBuffer < sizeof(NL_AUTH_MESSAGE) ) {
  1161. SecStatus = SEC_E_INVALID_TOKEN;
  1162. goto Cleanup;
  1163. }
  1164. if ( Message->MessageType != NegotiateResponse ) {
  1165. SecStatus = SEC_E_INVALID_TOKEN;
  1166. goto Cleanup;
  1167. }
  1168. Context->State = SecondInit;
  1169. Context->Nonce.QuadPart = 0;
  1170. //
  1171. // Return to the caller.
  1172. //
  1173. OutputBuffer->cbBuffer = 0;
  1174. *pfContextAttr = fContextReq;
  1175. *ptsExpiry = Forever;
  1176. SecStatus = SEC_E_OK;
  1177. }
  1178. Cleanup:
  1179. NlPrint(( NL_SESSION_MORE,
  1180. "InitializeSecurityContext: returns 0x%lx\n", SecStatus ));
  1181. // Let netlogon service exit.
  1182. NlEndNetlogonCall();
  1183. return SecStatus;
  1184. UNREFERENCED_PARAMETER( Reserved2 );
  1185. UNREFERENCED_PARAMETER( TargetDataRep );
  1186. UNREFERENCED_PARAMETER( Reserved1 );
  1187. UNREFERENCED_PARAMETER( pszTargetName );
  1188. UNREFERENCED_PARAMETER( pInput );
  1189. }
  1190. SECURITY_STATUS SEC_ENTRY
  1191. AcceptSecurityContext(
  1192. PCredHandle phCredential, // Cred to base context
  1193. PCtxtHandle phContext, // Existing context (OPT)
  1194. PSecBufferDesc pInput, // Input buffer
  1195. unsigned long fContextReq, // Context Requirements
  1196. unsigned long TargetDataRep, // Target Data Rep
  1197. PCtxtHandle phNewContext, // (out) New context handle
  1198. PSecBufferDesc pOutput, // (inout) Output buffers
  1199. unsigned long SEC_FAR * pfContextAttr, // (out) Context attributes
  1200. PTimeStamp ptsExpiry // (out) Life span (OPT)
  1201. )
  1202. /*++
  1203. Routine Description:
  1204. Servert side routine to define a security context.
  1205. Arguments:
  1206. Standard.
  1207. Return Value:
  1208. --*/
  1209. {
  1210. SECURITY_STATUS SecStatus;
  1211. PNL_AUTH_CONTEXT Context = NULL;
  1212. NL_AUTH_MESSAGE UNALIGNED *Message = NULL;
  1213. PSecBuffer OutputBuffer = NULL;
  1214. PSecBuffer InputBuffer;
  1215. LPBYTE Where;
  1216. LPSTR DnsDomainName = NULL;
  1217. LPSTR DnsHostName = NULL;
  1218. LPSTR Utf8ComputerName = NULL;
  1219. LPSTR OemDomainName = NULL;
  1220. LPWSTR UnicodeDomainName = NULL;
  1221. LPSTR OemComputerName = NULL;
  1222. LPWSTR UnicodeComputerName = NULL;
  1223. PDOMAIN_INFO DomainInfo = NULL;
  1224. PSERVER_SESSION ServerSession;
  1225. SESSION_INFO SessionInfo;
  1226. SecHandle CurrentHandle = {0};
  1227. NlPrint(( NL_SESSION_MORE,
  1228. "AcceptSecurityContext: called\n" ));
  1229. //
  1230. // If caller is calling when the netlogon service isn't running,
  1231. // tell it so.
  1232. //
  1233. if ( !NlStartNetlogonCall() ) {
  1234. return SEC_E_SECPKG_NOT_FOUND;
  1235. }
  1236. if (fContextReq & ISC_REQ_ALLOCATE_MEMORY) {
  1237. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1238. goto Cleanup;
  1239. }
  1240. InputBuffer = LocateSecBuffer(pInput);
  1241. if (InputBuffer == NULL) {
  1242. SecStatus = SEC_E_INVALID_TOKEN;
  1243. goto Cleanup;
  1244. }
  1245. //
  1246. // Make sure the output buffer exists.
  1247. //
  1248. OutputBuffer = LocateSecBuffer(pOutput);
  1249. if (OutputBuffer == NULL) {
  1250. SecStatus = SEC_E_INVALID_TOKEN;
  1251. goto Cleanup;
  1252. }
  1253. //
  1254. // Handle the first server side call.
  1255. //
  1256. if (phContext == NULL) {
  1257. //
  1258. // Validate the credential handle.
  1259. //
  1260. if ( phCredential == NULL ||
  1261. phCredential->dwUpper != NL_AUTH_SERVER_CRED ||
  1262. phCredential->dwLower != 0 ) {
  1263. SecStatus = SEC_E_UNKNOWN_CREDENTIALS;
  1264. goto Cleanup;
  1265. }
  1266. CurrentHandle = *phCredential;
  1267. //
  1268. // Check that the input message is what we expected.
  1269. //
  1270. Message = (PNL_AUTH_MESSAGE) InputBuffer->pvBuffer;
  1271. if ( InputBuffer->cbBuffer < sizeof(NL_AUTH_MESSAGE) ) {
  1272. SecStatus = SEC_E_INVALID_TOKEN;
  1273. goto Cleanup;
  1274. }
  1275. if ( Message->MessageType != Negotiate ) {
  1276. SecStatus = SEC_E_INVALID_TOKEN;
  1277. goto Cleanup;
  1278. }
  1279. Where = &Message->Buffer[0];
  1280. //
  1281. // Get Netbios hosted domain name from the buffer
  1282. //
  1283. if ( Message->Flags & NL_AUTH_NETBIOS_DOMAIN_NAME ) {
  1284. if ( !NetpLogonGetOemString(
  1285. Message,
  1286. InputBuffer->cbBuffer,
  1287. &Where,
  1288. DNLEN+1,
  1289. &OemDomainName ) ) {
  1290. NlPrint((NL_CRITICAL,
  1291. "AcceptSecurityContext: %lx.%lx: cannot get netbios domain name\n",
  1292. CurrentHandle.dwUpper, CurrentHandle.dwLower ));
  1293. SecStatus = SEC_E_INVALID_TOKEN;
  1294. goto Cleanup;
  1295. }
  1296. }
  1297. //
  1298. // Get the Netbios client computer name from the message.
  1299. //
  1300. if ( Message->Flags & NL_AUTH_NETBIOS_COMPUTER_NAME ) {
  1301. //
  1302. // Get the computer name of the
  1303. if ( !NetpLogonGetOemString(
  1304. Message,
  1305. InputBuffer->cbBuffer,
  1306. &Where,
  1307. CNLEN+1,
  1308. &OemComputerName ) ) {
  1309. NlPrint((NL_CRITICAL,
  1310. "AcceptSecurityContext: %lx.%lx: Cannot parse computer name\n",
  1311. CurrentHandle.dwUpper, CurrentHandle.dwLower ));
  1312. SecStatus = SEC_E_INVALID_TOKEN;
  1313. goto Cleanup;
  1314. }
  1315. }
  1316. //
  1317. // Get the domain name of the hosted domain from the message.
  1318. //
  1319. // Either get a utf-8 DNS domain name or an OEM netbios domain name
  1320. //
  1321. if ( Message->Flags & NL_AUTH_DNS_DOMAIN_NAME ) {
  1322. if ( !NetpLogonGetCutf8String(
  1323. Message,
  1324. InputBuffer->cbBuffer,
  1325. &Where,
  1326. &DnsDomainName ) ) {
  1327. NlPrint(( NL_CRITICAL,
  1328. "AcceptSecurityContext: %lx.%lx: DNS domain bad.\n",
  1329. CurrentHandle.dwUpper, CurrentHandle.dwLower ));
  1330. SecStatus = SEC_E_INVALID_TOKEN;
  1331. goto Cleanup;
  1332. }
  1333. }
  1334. //
  1335. // Get the DNS client computer name from the message.
  1336. //
  1337. //
  1338. if ( Message->Flags & NL_AUTH_DNS_HOST_NAME ) {
  1339. if ( !NetpLogonGetCutf8String(
  1340. Message,
  1341. InputBuffer->cbBuffer,
  1342. &Where,
  1343. &DnsHostName ) ) {
  1344. NlPrint(( NL_CRITICAL,
  1345. "AcceptSecurityContext: %lx.%lx: DNS hostname bad.\n",
  1346. CurrentHandle.dwUpper, CurrentHandle.dwLower
  1347. ));
  1348. SecStatus = SEC_E_INVALID_TOKEN;
  1349. goto Cleanup;
  1350. }
  1351. //
  1352. // Ensure Netbios name isn't also present
  1353. //
  1354. if ( Message->Flags & NL_AUTH_NETBIOS_COMPUTER_NAME ) {
  1355. NlPrint((NL_CRITICAL,
  1356. "AcceptSecurityContext: %lx.%lx: both DNS '%s' and Netbios '%s' client name specified\n",
  1357. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1358. DnsHostName,
  1359. OemComputerName ));
  1360. /* This isn't fatal */
  1361. }
  1362. }
  1363. //
  1364. // Get the UTF8 netbios computer name
  1365. //
  1366. if ( Message->Flags & NL_AUTH_UTF8_NETBIOS_COMPUTER_NAME ) {
  1367. if ( !NetpLogonGetCutf8String(
  1368. Message,
  1369. InputBuffer->cbBuffer,
  1370. &Where,
  1371. &Utf8ComputerName ) ) {
  1372. NlPrint(( NL_CRITICAL,
  1373. "AcceptSecurityContext: %lx.%lx: UTF8 computer name bad.\n",
  1374. CurrentHandle.dwUpper, CurrentHandle.dwLower
  1375. ));
  1376. SecStatus = SEC_E_INVALID_TOKEN;
  1377. goto Cleanup;
  1378. }
  1379. }
  1380. //
  1381. // Try to find the hosted domain using DNS
  1382. //
  1383. if ( DnsDomainName != NULL ) {
  1384. DomainInfo = NlFindDnsDomain( DnsDomainName,
  1385. NULL,
  1386. FALSE, // don't lookup NDNCs
  1387. TRUE, // check alias names
  1388. NULL ); // don't care if alias name matched
  1389. if ( DomainInfo == NULL ) {
  1390. NlPrint((NL_CRITICAL,
  1391. "AcceptSecurityContext: %lx.%lx: Cannot find domain %s\n",
  1392. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1393. DnsDomainName ));
  1394. SecStatus = SEC_E_INVALID_TOKEN;
  1395. goto Cleanup;
  1396. }
  1397. //
  1398. // Try to find hosted domain name using netbios.
  1399. //
  1400. } else {
  1401. //
  1402. // Make sure we were passed one.
  1403. //
  1404. if ( OemDomainName == NULL) {
  1405. NlPrint((NL_CRITICAL,
  1406. "AcceptSecurityContext: %lx.%lx: Neither DNS or netbios domain name specified (fatal)\n",
  1407. CurrentHandle.dwUpper, CurrentHandle.dwLower ));
  1408. SecStatus = SEC_E_INVALID_TOKEN;
  1409. goto Cleanup;
  1410. }
  1411. //
  1412. // Convert to unicode
  1413. // Note: this is bogus since the clients OEM code page may be different
  1414. // than ours.
  1415. //
  1416. UnicodeDomainName = NetpAllocWStrFromStr( OemDomainName );
  1417. if ( UnicodeDomainName == NULL ) {
  1418. NlPrint((NL_CRITICAL,
  1419. "AcceptSecurityContext: %lx.%lx: Cannot alloc domain name %s\n",
  1420. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1421. OemDomainName ));
  1422. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1423. goto Cleanup;
  1424. }
  1425. //
  1426. // Look the name up.
  1427. //
  1428. DomainInfo = NlFindNetbiosDomain( UnicodeDomainName, FALSE );
  1429. if ( DomainInfo == NULL ) {
  1430. NlPrint((NL_CRITICAL,
  1431. "AcceptSecurityContext: %lx.%lx: Cannot find domain %ws (fatal)\n",
  1432. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1433. UnicodeDomainName ));
  1434. SecStatus = SEC_E_INVALID_TOKEN;
  1435. goto Cleanup;
  1436. }
  1437. }
  1438. //
  1439. // Get the name of the client machine.
  1440. //
  1441. // If the client computer passed us its DnsHostName,
  1442. // use that.
  1443. //
  1444. if ( DnsHostName != NULL ) {
  1445. UnicodeComputerName = NetpAllocWStrFromUtf8Str( DnsHostName );
  1446. if ( UnicodeComputerName == NULL ) {
  1447. NlPrint((NL_CRITICAL,
  1448. "AcceptSecurityContext: %lx.%lx: Cannot alloc DNS computer name %s\n",
  1449. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1450. DnsHostName ));
  1451. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1452. goto Cleanup;
  1453. }
  1454. //
  1455. // If the client computer passed us its Netbios name in UTF-8,
  1456. // use that.
  1457. //
  1458. } else if ( Utf8ComputerName != NULL ) {
  1459. UnicodeComputerName = NetpAllocWStrFromUtf8Str( Utf8ComputerName );
  1460. if ( UnicodeComputerName == NULL ) {
  1461. NlPrint((NL_CRITICAL,
  1462. "AcceptSecurityContext: %lx.%lx: Cannot alloc utf8 computer name %s\n",
  1463. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1464. Utf8ComputerName ));
  1465. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1466. goto Cleanup;
  1467. }
  1468. //
  1469. // If the client computer passed us its Netbios name in OEM,
  1470. // use that.
  1471. // OEM is bad since the clients code page might be different than ours.
  1472. //
  1473. } else if ( OemComputerName != NULL ) {
  1474. UnicodeComputerName = NetpAllocWStrFromStr( OemComputerName );
  1475. if ( UnicodeComputerName == NULL ) {
  1476. NlPrint((NL_CRITICAL,
  1477. "AcceptSecurityContext: %lx.%lx: Cannot alloc oem computer name %s\n",
  1478. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1479. OemComputerName ));
  1480. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1481. goto Cleanup;
  1482. }
  1483. //
  1484. // At this point it is fatal if we don't know the client computer name
  1485. //
  1486. } else {
  1487. NlPrint((NL_CRITICAL,
  1488. "AcceptSecurityContext: %lx.%lx: Don't know client computer name.\n",
  1489. CurrentHandle.dwUpper, CurrentHandle.dwLower ));
  1490. SecStatus = SEC_E_INVALID_TOKEN;
  1491. goto Cleanup;
  1492. }
  1493. //
  1494. // Find the server session containing the session key
  1495. // and make a copy of it.
  1496. //
  1497. NlPrint((NL_SESSION_MORE,
  1498. "AcceptSecurityContext: %lx.%lx: from %ws\n",
  1499. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1500. UnicodeComputerName ));
  1501. LOCK_SERVER_SESSION_TABLE( DomainInfo );
  1502. ServerSession = NlFindNamedServerSession( DomainInfo, UnicodeComputerName );
  1503. if (ServerSession == NULL) {
  1504. UNLOCK_SERVER_SESSION_TABLE( DomainInfo );
  1505. NlPrint((NL_CRITICAL,
  1506. "AcceptSecurityContext: %lx.%lx: Can't NlFindNamedServerSession for %ws\n",
  1507. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1508. UnicodeComputerName ));
  1509. SecStatus = SEC_E_INVALID_TOKEN;
  1510. goto Cleanup;
  1511. }
  1512. SessionInfo.SessionKey = ServerSession->SsSessionKey;
  1513. SessionInfo.NegotiatedFlags = ServerSession->SsNegotiatedFlags;
  1514. //
  1515. // Indicate that this server session is being used
  1516. // to keep it alive.
  1517. //
  1518. ServerSession->SsCheck = 0;
  1519. UNLOCK_SERVER_SESSION_TABLE( DomainInfo );
  1520. //
  1521. // Build a new context.
  1522. //
  1523. Context = AllocateContext( fContextReq );
  1524. if (Context == NULL) {
  1525. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1526. goto Cleanup;
  1527. }
  1528. Context->State = FirstAccept;
  1529. Context->Inbound = TRUE;
  1530. Context->SessionInfo = SessionInfo;
  1531. //
  1532. // Build an output token.
  1533. //
  1534. Message = (PNL_AUTH_MESSAGE) OutputBuffer->pvBuffer;
  1535. Message->MessageType = NegotiateResponse;
  1536. Message->Flags = 0;
  1537. Message->Buffer[0] = '\0';
  1538. OutputBuffer->cbBuffer = sizeof(NL_AUTH_MESSAGE);
  1539. //
  1540. // Tell the caller he need not call us back.
  1541. //
  1542. *phNewContext = Context->ContextHandle;
  1543. CurrentHandle = *phNewContext;
  1544. *pfContextAttr = fContextReq;
  1545. *ptsExpiry = Forever;
  1546. SecStatus = SEC_E_OK;
  1547. //
  1548. // We asked the caller to not call us back.
  1549. //
  1550. } else {
  1551. NlAssert( FALSE );
  1552. NlPrint((NL_CRITICAL,
  1553. "AcceptSecurityContext: Second accept called.\n" ));
  1554. SecStatus = SEC_E_INVALID_TOKEN;
  1555. goto Cleanup;
  1556. }
  1557. Cleanup:
  1558. if ( DnsDomainName != NULL ) {
  1559. NetpMemoryFree( DnsDomainName );
  1560. }
  1561. if ( DnsHostName != NULL ) {
  1562. NetpMemoryFree( DnsHostName );
  1563. }
  1564. if ( Utf8ComputerName != NULL ) {
  1565. NetpMemoryFree( Utf8ComputerName );
  1566. }
  1567. if ( UnicodeComputerName != NULL ) {
  1568. NetApiBufferFree( UnicodeComputerName );
  1569. }
  1570. if ( UnicodeDomainName != NULL ) {
  1571. NetApiBufferFree( UnicodeDomainName );
  1572. }
  1573. if ( DomainInfo != NULL ) {
  1574. NlDereferenceDomain( DomainInfo );
  1575. }
  1576. NlPrint(( NL_SESSION_MORE,
  1577. "AcceptSecurityContext: %lx.%lx: returns 0x%lx\n",
  1578. CurrentHandle.dwUpper, CurrentHandle.dwLower,
  1579. SecStatus ));
  1580. // Let netlogon service exit.
  1581. NlEndNetlogonCall();
  1582. return SecStatus;
  1583. UNREFERENCED_PARAMETER( TargetDataRep );
  1584. UNREFERENCED_PARAMETER( pOutput );
  1585. }
  1586. SECURITY_STATUS SEC_ENTRY
  1587. DeleteSecurityContext(
  1588. PCtxtHandle phContext // Context to delete
  1589. )
  1590. /*++
  1591. Routine Description:
  1592. Routine to delete client or server side security context.
  1593. Arguments:
  1594. Standard.
  1595. Return Value:
  1596. --*/
  1597. {
  1598. NlPrint(( NL_SESSION_MORE,
  1599. "DeleteSecurityContext: %lx.%lx: called\n",
  1600. phContext->dwUpper, phContext->dwLower ));
  1601. //
  1602. // Don't require that Netlogon be running. Some security contexts are
  1603. // deleted as Netlogon is shutting down.
  1604. //
  1605. if ( DeleteContext( phContext )) {
  1606. return(SEC_E_OK);
  1607. } else {
  1608. return(SEC_E_INVALID_HANDLE);
  1609. }
  1610. }
  1611. SECURITY_STATUS SEC_ENTRY
  1612. EnumerateSecurityPackagesW(
  1613. unsigned long SEC_FAR * pcPackages, // Receives num. packages
  1614. PSecPkgInfoW SEC_FAR * ppPackageInfo // Receives array of info
  1615. )
  1616. /*++
  1617. Routine Description:
  1618. Routine to return a description of all the security packages implemented
  1619. by this DLL.
  1620. Arguments:
  1621. Standard.
  1622. Return Value:
  1623. --*/
  1624. {
  1625. SECURITY_STATUS SecStatus;
  1626. SecStatus = QuerySecurityPackageInfoW(
  1627. PACKAGE_NAME,
  1628. ppPackageInfo
  1629. );
  1630. if (SecStatus == SEC_E_OK) {
  1631. *pcPackages = 1;
  1632. }
  1633. return(SecStatus);
  1634. }
  1635. SECURITY_STATUS SEC_ENTRY
  1636. QuerySecurityPackageInfoW(
  1637. LPWSTR pszPackageName, // Name of package
  1638. PSecPkgInfoW SEC_FAR * ppPackageInfo // Receives package info
  1639. )
  1640. /*++
  1641. Routine Description:
  1642. Routine to return the description of the named security package.
  1643. Arguments:
  1644. Standard.
  1645. Return Value:
  1646. --*/
  1647. {
  1648. SECURITY_STATUS SecStatus;
  1649. PSecPkgInfoW PackageInfo;
  1650. ULONG PackageInfoSize;
  1651. PUCHAR Where;
  1652. if (_wcsicmp(pszPackageName, PACKAGE_NAME)) {
  1653. SecStatus = SEC_E_SECPKG_NOT_FOUND;
  1654. goto Cleanup;
  1655. }
  1656. PackageInfoSize = sizeof(SecPkgInfoW) +
  1657. (wcslen(PACKAGE_NAME) + 1 +
  1658. wcslen(PACKAGE_COMMENT) + 1) * sizeof(WCHAR);
  1659. PackageInfo = (PSecPkgInfoW) LocalAlloc(0,PackageInfoSize);
  1660. if (PackageInfo == NULL) {
  1661. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1662. goto Cleanup;
  1663. }
  1664. PackageInfo->fCapabilities = PACAKGE_CAPABILITIES;
  1665. PackageInfo->wVersion = PACKAGE_VERSION;
  1666. PackageInfo->wRPCID = PACKAGE_RPCID;
  1667. PackageInfo->cbMaxToken = PACKAGE_MAXTOKEN;
  1668. Where = (PUCHAR) (PackageInfo + 1);
  1669. PackageInfo->Name = (LPWSTR) Where;
  1670. Where += (wcslen(PACKAGE_NAME) + 1) * sizeof(WCHAR);
  1671. wcscpy(PackageInfo->Name, PACKAGE_NAME);
  1672. PackageInfo->Comment = (LPWSTR) Where;
  1673. Where += (wcslen(PACKAGE_COMMENT) + 1) * sizeof(WCHAR);
  1674. wcscpy(PackageInfo->Comment, PACKAGE_COMMENT);
  1675. NlAssert((Where - (PBYTE) PackageInfo) == (LONG) PackageInfoSize);
  1676. *ppPackageInfo = PackageInfo;
  1677. SecStatus = SEC_E_OK;
  1678. Cleanup:
  1679. NlPrint(( NL_SESSION_MORE,
  1680. "QuerySecurityPackageInfo: returns 0x%lx\n", SecStatus ));
  1681. return SecStatus;
  1682. }
  1683. SECURITY_STATUS SEC_ENTRY
  1684. FreeContextBuffer(
  1685. void SEC_FAR * pvContextBuffer
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. Routine to free a context buffer.
  1690. Arguments:
  1691. Standard.
  1692. Return Value:
  1693. --*/
  1694. {
  1695. LocalFree(pvContextBuffer);
  1696. return(SEC_E_OK);
  1697. }
  1698. SECURITY_STATUS SEC_ENTRY
  1699. ImpersonateSecurityContext(
  1700. PCtxtHandle phContext // Context to impersonate
  1701. )
  1702. /*++
  1703. Routine Description:
  1704. Server side routine to impersonate an authenticated user.
  1705. Arguments:
  1706. Standard.
  1707. Return Value:
  1708. --*/
  1709. {
  1710. NTSTATUS Status;
  1711. Status = RtlImpersonateSelf(SecurityImpersonation);
  1712. if (NT_SUCCESS(Status)) {
  1713. return(SEC_E_OK);
  1714. } else {
  1715. return(SEC_E_NO_IMPERSONATION);
  1716. }
  1717. UNREFERENCED_PARAMETER( phContext );
  1718. }
  1719. SECURITY_STATUS SEC_ENTRY
  1720. RevertSecurityContext(
  1721. PCtxtHandle phContext // Context from which to re
  1722. )
  1723. /*++
  1724. Routine Description:
  1725. Server side routine to undo a previous imperonation.
  1726. Arguments:
  1727. Standard.
  1728. Return Value:
  1729. --*/
  1730. {
  1731. RevertToSelf();
  1732. return(SEC_E_OK);
  1733. UNREFERENCED_PARAMETER( phContext );
  1734. }
  1735. SECURITY_STATUS SEC_ENTRY
  1736. QueryContextAttributesW(
  1737. PCtxtHandle phContext, // Context to query
  1738. unsigned long ulAttribute, // Attribute to query
  1739. void SEC_FAR * pBuffer // Buffer for attributes
  1740. )
  1741. /*++
  1742. Routine Description:
  1743. Routine to return information about a context.
  1744. Arguments:
  1745. Standard.
  1746. Return Value:
  1747. --*/
  1748. {
  1749. SECURITY_STATUS SecStatus;
  1750. PNL_AUTH_CONTEXT Context;
  1751. PSecPkgContext_Sizes ContextSizes;
  1752. PSecPkgContext_NamesW ContextNames;
  1753. PSecPkgContext_Lifespan ContextLifespan;
  1754. PSecPkgContext_DceInfo ContextDceInfo;
  1755. //
  1756. // If caller is calling when the netlogon service isn't running,
  1757. // tell it so.
  1758. //
  1759. if ( !NlStartNetlogonCall() ) {
  1760. return SEC_E_SECPKG_NOT_FOUND;
  1761. }
  1762. //
  1763. // Locate the context and make sure this is a client side call.
  1764. //
  1765. Context = LocateContext( phContext );
  1766. if (Context == NULL) {
  1767. SecStatus = SEC_E_INVALID_HANDLE;
  1768. goto Cleanup;
  1769. }
  1770. //
  1771. //
  1772. //
  1773. switch(ulAttribute) {
  1774. case SECPKG_ATTR_SIZES:
  1775. ContextSizes = (PSecPkgContext_Sizes) pBuffer;
  1776. ContextSizes->cbMaxSignature = PACKAGE_SIGNATURE_SIZE;
  1777. if ((Context->ContextFlags & ISC_REQ_CONFIDENTIALITY) != 0) {
  1778. ContextSizes->cbSecurityTrailer = PACKAGE_SIGNATURE_SIZE;
  1779. ContextSizes->cbBlockSize = 1;
  1780. } else {
  1781. ContextSizes->cbSecurityTrailer = 0;
  1782. ContextSizes->cbBlockSize = 0;
  1783. }
  1784. ContextSizes->cbMaxToken = PACKAGE_MAXTOKEN;
  1785. break;
  1786. #ifdef notdef // Only support the ones RPC uses
  1787. case SECPKG_ATTR_NAMES:
  1788. ContextNames = (PSecPkgContext_Names) pBuffer;
  1789. ContextNames->sUserName = (LPWSTR) LocalAlloc(0,sizeof(L"dummy user"));
  1790. if (ContextNames->sUserName == NULL) {
  1791. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1792. goto Cleanup;
  1793. }
  1794. wcscpy(ContextNames->sUserName, L"dummy user");
  1795. break;
  1796. case SECPKG_ATTR_LIFESPAN:
  1797. ContextLifespan = (PSecPkgContext_Lifespan) pBuffer;
  1798. ContextLifespan->tsStart = Never;
  1799. ContextLifespan->tsExpiry = Forever;
  1800. break;
  1801. case SECPKG_ATTR_DCE_INFO:
  1802. ContextDceInfo = (PSecPkgContext_DceInfo) pBuffer;
  1803. ContextDceInfo->AuthzSvc = 0;
  1804. ContextDceInfo->pPac = (PVOID) LocalAlloc(0,sizeof(L"dummy user"));
  1805. if (ContextDceInfo->pPac == NULL) {
  1806. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1807. goto Cleanup;
  1808. }
  1809. wcscpy((LPWSTR) ContextDceInfo->pPac, L"dummy user");
  1810. break;
  1811. #endif // notdef // Only support the ones RPC uses
  1812. default:
  1813. SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
  1814. goto Cleanup;
  1815. }
  1816. SecStatus = SEC_E_OK;
  1817. Cleanup:
  1818. NlPrint(( NL_SESSION_MORE,
  1819. "QueryContextAttributes: %lx.%lx: %ld returns 0x%lx\n",
  1820. phContext->dwUpper, phContext->dwLower,
  1821. ulAttribute,
  1822. SecStatus ));
  1823. // Let netlogon service exit.
  1824. NlEndNetlogonCall();
  1825. return SecStatus;
  1826. UNREFERENCED_PARAMETER( pBuffer );
  1827. }
  1828. SECURITY_STATUS
  1829. KerbMapNtStatusToSecStatus(
  1830. IN NTSTATUS Status
  1831. )
  1832. {
  1833. SECURITY_STATUS SecStatus;
  1834. //
  1835. // Check for security status and let them through
  1836. //
  1837. if (HRESULT_FACILITY(Status) == FACILITY_SECURITY )
  1838. {
  1839. return(Status);
  1840. }
  1841. switch(Status) {
  1842. case STATUS_SUCCESS:
  1843. SecStatus = SEC_E_OK;
  1844. break;
  1845. case STATUS_INSUFFICIENT_RESOURCES:
  1846. case STATUS_NO_MEMORY:
  1847. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1848. break;
  1849. case STATUS_NETLOGON_NOT_STARTED:
  1850. case STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
  1851. case STATUS_NO_LOGON_SERVERS:
  1852. case STATUS_NO_SUCH_DOMAIN:
  1853. SecStatus = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  1854. break;
  1855. case STATUS_NO_SUCH_LOGON_SESSION:
  1856. SecStatus = SEC_E_UNKNOWN_CREDENTIALS;
  1857. break;
  1858. case STATUS_INVALID_PARAMETER:
  1859. SecStatus = SEC_E_INVALID_TOKEN;
  1860. break;
  1861. case STATUS_PRIVILEGE_NOT_HELD:
  1862. SecStatus = SEC_E_NOT_OWNER;
  1863. break;
  1864. case STATUS_INVALID_HANDLE:
  1865. SecStatus = SEC_E_INVALID_HANDLE;
  1866. break;
  1867. case STATUS_BUFFER_TOO_SMALL:
  1868. // ???: there should be a better code
  1869. SecStatus = SEC_E_INSUFFICIENT_MEMORY;
  1870. break;
  1871. case STATUS_NOT_SUPPORTED:
  1872. SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
  1873. break;
  1874. case STATUS_OBJECT_NAME_NOT_FOUND:
  1875. SecStatus = SEC_E_TARGET_UNKNOWN;
  1876. break;
  1877. case STATUS_LOGON_FAILURE:
  1878. case STATUS_NO_SUCH_USER:
  1879. case STATUS_ACCOUNT_DISABLED:
  1880. case STATUS_ACCOUNT_RESTRICTION:
  1881. case STATUS_ACCOUNT_LOCKED_OUT:
  1882. case STATUS_WRONG_PASSWORD:
  1883. case STATUS_ACCOUNT_EXPIRED:
  1884. case STATUS_PASSWORD_EXPIRED:
  1885. SecStatus = SEC_E_LOGON_DENIED;
  1886. break;
  1887. case STATUS_NO_TRUST_SAM_ACCOUNT:
  1888. SecStatus = SEC_E_TARGET_UNKNOWN;
  1889. break;
  1890. case STATUS_BAD_NETWORK_PATH:
  1891. case STATUS_TRUST_FAILURE:
  1892. case STATUS_TRUSTED_RELATIONSHIP_FAILURE:
  1893. // ???: what should this be?
  1894. SecStatus = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  1895. break;
  1896. case STATUS_NAME_TOO_LONG:
  1897. case STATUS_ILL_FORMED_PASSWORD:
  1898. // ???: what should this be?
  1899. SecStatus = SEC_E_INVALID_TOKEN;
  1900. break;
  1901. case STATUS_INTERNAL_ERROR:
  1902. SecStatus = SEC_E_INTERNAL_ERROR;
  1903. break;
  1904. default:
  1905. NlPrint(( NL_CRITICAL, "\n\n\n Unable to map error code 0x%x\n\n\n\n",Status));
  1906. SecStatus = SEC_E_INTERNAL_ERROR;
  1907. }
  1908. return(SecStatus);
  1909. }
  1910. SECURITY_STATUS
  1911. NlpSignOrSeal(
  1912. IN PCtxtHandle phContext,
  1913. IN ULONG fQOP,
  1914. IN OUT PSecBufferDesc MessageBuffers,
  1915. IN ULONG MessageSeqNo,
  1916. IN BOOLEAN SealIt
  1917. )
  1918. /*++
  1919. Routine Description:
  1920. Common routine to sign or seal a message (Client or server side)
  1921. Arguments:
  1922. Standard.
  1923. SealIt - True to seal the message.
  1924. FALSE to sign the message.
  1925. Return Value:
  1926. --*/
  1927. {
  1928. SECURITY_STATUS SecStatus = SEC_E_OK;
  1929. NTSTATUS Status = STATUS_SUCCESS;
  1930. PCHECKSUM_FUNCTION Check;
  1931. PCRYPTO_SYSTEM CryptSystem;
  1932. PCHECKSUM_BUFFER CheckBuffer = NULL;
  1933. PCRYPT_STATE_BUFFER CryptBuffer = NULL;
  1934. ULONG Index;
  1935. PSecBuffer SignatureBuffer = NULL;
  1936. PNL_AUTH_SIGNATURE Signature;
  1937. UCHAR LocalChecksum[24]; // ??? need better constant
  1938. NETLOGON_SESSION_KEY EncryptionSessionKey;
  1939. ULONG OutputSize;
  1940. PNL_AUTH_CONTEXT Context;
  1941. BOOLEAN ChecksumOnly;
  1942. //
  1943. // Locate the context.
  1944. //
  1945. Context = LocateContext( phContext );
  1946. if (Context == NULL) {
  1947. NlPrint(( NL_CRITICAL,
  1948. "NlpSignOrSeal: %lx.%lx: Cannot LocateContext\n",
  1949. phContext->dwUpper, phContext->dwLower ));
  1950. SecStatus = SEC_E_INVALID_HANDLE;
  1951. goto Cleanup;
  1952. }
  1953. //
  1954. // Find a buffer to put the signature in.
  1955. //
  1956. SignatureBuffer = LocateSigBuffer( MessageBuffers );
  1957. if (SignatureBuffer == NULL) {
  1958. NlPrint(( NL_CRITICAL,
  1959. "NlpSignOrSeal: %lx.%lx: No signature buffer found\n",
  1960. phContext->dwUpper, phContext->dwLower ));
  1961. SecStatus = SEC_E_INVALID_TOKEN;
  1962. goto Cleanup;
  1963. }
  1964. if ( SealIt ) {
  1965. if ( SignatureBuffer->cbBuffer < sizeof(PACKAGE_SIGNATURE_SIZE) ) {
  1966. NlPrint(( NL_CRITICAL,
  1967. "NlpVerifyOrUnseal: %lx.%lx: buffer too small for sealing\n",
  1968. phContext->dwUpper, phContext->dwLower ));
  1969. SecStatus = SEC_E_MESSAGE_ALTERED;
  1970. goto Cleanup;
  1971. }
  1972. }
  1973. //
  1974. // Build the signature.
  1975. Signature = (PNL_AUTH_SIGNATURE) SignatureBuffer->pvBuffer;
  1976. Signature->SignatureAlgorithm[0] = (UCHAR) NL_AUTH_CHECKSUM;
  1977. Signature->SignatureAlgorithm[1] = 0;
  1978. if ( SealIt ) {
  1979. Signature->SealAlgorithm[0] = (UCHAR) NL_AUTH_ETYPE;
  1980. Signature->SealAlgorithm[1] = 0;
  1981. memset(Signature->SealFiller, 0xff, sizeof(Signature->SealFiller));
  1982. NlGenerateRandomBits( Signature->Confounder, NL_AUTH_CONFOUNDER_SIZE );
  1983. SignatureBuffer->cbBuffer = PACKAGE_SIGNATURE_SIZE;
  1984. } else {
  1985. memset(Signature->SignFiller, 0xff, sizeof(Signature->SignFiller));
  1986. SignatureBuffer->cbBuffer = PACKAGE_SIGNATURE_SIZE - NL_AUTH_CONFOUNDER_SIZE;
  1987. }
  1988. Signature->Flags[0] = 0;
  1989. Signature->Flags[1] = 0;
  1990. Signature->SequenceNumber[0] = (UCHAR) ((Context->Nonce.LowPart & 0xff000000) >> 24);
  1991. Signature->SequenceNumber[1] = (UCHAR) ((Context->Nonce.LowPart & 0x00ff0000) >> 16);
  1992. Signature->SequenceNumber[2] = (UCHAR) ((Context->Nonce.LowPart & 0x0000ff00) >> 8);
  1993. Signature->SequenceNumber[3] = (UCHAR) (Context->Nonce.LowPart & 0x000000ff);
  1994. Signature->SequenceNumber[4] = (UCHAR) ((Context->Nonce.HighPart & 0xff000000) >> 24);
  1995. Signature->SequenceNumber[5] = (UCHAR) ((Context->Nonce.HighPart & 0x00ff0000) >> 16);
  1996. Signature->SequenceNumber[6] = (UCHAR) ((Context->Nonce.HighPart & 0x0000ff00) >> 8);
  1997. Signature->SequenceNumber[7] = (UCHAR) (Context->Nonce.HighPart & 0x000000ff);
  1998. if ( !Context->Inbound ) {
  1999. Signature->SequenceNumber[4] |= 0x80; // Discriminate between inbound and outbound messages
  2000. }
  2001. Context->Nonce.QuadPart ++;
  2002. //
  2003. // Initialize the checksum routines.
  2004. //
  2005. Status = CDLocateCheckSum( (ULONG)NL_AUTH_CHECKSUM, &Check);
  2006. if (!NT_SUCCESS(Status)) {
  2007. NlPrint(( NL_CRITICAL,
  2008. "NlpSignOrSeal: %lx.%lx: Failed to load checksum routines: 0x%x\n",
  2009. phContext->dwUpper, phContext->dwLower,
  2010. Status));
  2011. goto Cleanup;
  2012. }
  2013. NlAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  2014. NlPrint(( NL_ENCRYPT,
  2015. "NlpSignOrSeal: %lx.%lx: Session Key: ",
  2016. phContext->dwUpper, phContext->dwLower ));
  2017. NlpDumpBuffer(NL_ENCRYPT, &Context->SessionInfo.SessionKey, sizeof( Context->SessionInfo.SessionKey) );
  2018. Status = Check->InitializeEx(
  2019. (LPBYTE)&Context->SessionInfo.SessionKey,
  2020. sizeof( Context->SessionInfo.SessionKey),
  2021. 0, // no message type
  2022. &CheckBuffer );
  2023. if (!NT_SUCCESS(Status)) {
  2024. NlPrint(( NL_CRITICAL,
  2025. "NlpSignOrSeal: %lx.%lx: Failed to initialize checksum routines: 0x%x\n",
  2026. phContext->dwUpper, phContext->dwLower,
  2027. Status));
  2028. goto Cleanup;
  2029. }
  2030. //
  2031. // Locate the encryption routines.
  2032. //
  2033. Status = CDLocateCSystem( (ULONG)NL_AUTH_ETYPE, &CryptSystem);
  2034. if (!NT_SUCCESS(Status)) {
  2035. NlPrint(( NL_CRITICAL,
  2036. "NlpSignOrSeal: %lx.%lx: Failed to load crypt system: 0x%x\n",
  2037. phContext->dwUpper, phContext->dwLower,
  2038. Status));
  2039. goto Cleanup;
  2040. }
  2041. //
  2042. // Sum first several bytes of the signature
  2043. //
  2044. Check->Sum( CheckBuffer,
  2045. NL_AUTH_SIGNED_BYTES,
  2046. (PUCHAR)Signature );
  2047. //
  2048. // Sum and encrypt the confounder
  2049. //
  2050. if ( SealIt ) {
  2051. //
  2052. // Sum the confounder
  2053. //
  2054. Check->Sum(
  2055. CheckBuffer,
  2056. NL_AUTH_CONFOUNDER_SIZE,
  2057. Signature->Confounder );
  2058. //
  2059. // Create the encryption key by xoring the session key with 0xf0f0f0f0
  2060. //
  2061. for ( Index=0; Index < sizeof(EncryptionSessionKey); Index++ ) {
  2062. ((LPBYTE)(&EncryptionSessionKey))[Index] =
  2063. ((LPBYTE)(&Context->SessionInfo.SessionKey))[Index] ^0xf0f0f0f0;
  2064. }
  2065. //
  2066. // Pass the key to the encryption routines.
  2067. //
  2068. Status = CryptSystem->Initialize(
  2069. (LPBYTE)&EncryptionSessionKey,
  2070. sizeof( EncryptionSessionKey ),
  2071. 0, // no message type
  2072. &CryptBuffer );
  2073. if (!NT_SUCCESS(Status)) {
  2074. NlPrint(( NL_CRITICAL,
  2075. "NlpSignOrSeal: %lx.%lx: Failed to initialize crypt routines: 0x%x\n",
  2076. phContext->dwUpper, phContext->dwLower,
  2077. Status));
  2078. goto Cleanup;
  2079. }
  2080. //
  2081. // Set the initial vector to ensure the key is different for each message
  2082. //
  2083. Status = CryptSystem->Control(
  2084. CRYPT_CONTROL_SET_INIT_VECT,
  2085. CryptBuffer,
  2086. Signature->SequenceNumber,
  2087. sizeof(Signature->SequenceNumber) );
  2088. if (!NT_SUCCESS(Status)) {
  2089. NlPrint(( NL_CRITICAL,
  2090. "NlpSignOrSeal: %lx.%lx: Failed to set IV: 0x%x\n",
  2091. phContext->dwUpper, phContext->dwLower,
  2092. Status));
  2093. goto Cleanup;
  2094. }
  2095. //
  2096. // Encrypt the confounder
  2097. //
  2098. Status = CryptSystem->Encrypt(
  2099. CryptBuffer,
  2100. Signature->Confounder,
  2101. NL_AUTH_CONFOUNDER_SIZE,
  2102. Signature->Confounder,
  2103. &OutputSize );
  2104. if (!NT_SUCCESS(Status)) {
  2105. NlPrint(( NL_CRITICAL,
  2106. "NlpSignOrSeal: %lx.%lx: Failed to encrypt confounder: 0x%x\n",
  2107. phContext->dwUpper, phContext->dwLower,
  2108. Status));
  2109. goto Cleanup;
  2110. }
  2111. NlAssert( OutputSize == NL_AUTH_CONFOUNDER_SIZE );
  2112. }
  2113. //
  2114. // Sum and encrypt the caller's message.
  2115. //
  2116. for (Index = 0; Index < MessageBuffers->cBuffers; Index++ ) {
  2117. if ((BUFFERTYPE(MessageBuffers->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  2118. (!(MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY)) &&
  2119. (MessageBuffers->pBuffers[Index].cbBuffer != 0)) {
  2120. ChecksumOnly = ((MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY_WITH_CHECKSUM) != 0);
  2121. Check->Sum(
  2122. CheckBuffer,
  2123. MessageBuffers->pBuffers[Index].cbBuffer,
  2124. (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer );
  2125. //
  2126. // Now encrypt the buffer
  2127. //
  2128. if ( SealIt && !ChecksumOnly ) {
  2129. Status = CryptSystem->Encrypt(
  2130. CryptBuffer,
  2131. (PUCHAR) MessageBuffers->pBuffers[Index].pvBuffer,
  2132. MessageBuffers->pBuffers[Index].cbBuffer,
  2133. (PUCHAR) MessageBuffers->pBuffers[Index].pvBuffer,
  2134. &OutputSize );
  2135. if (!NT_SUCCESS(Status)) {
  2136. NlPrint(( NL_CRITICAL,
  2137. "NlpSignOrSeal: %lx.%lx: Failed to encrypt buffer: 0x%x\n",
  2138. phContext->dwUpper, phContext->dwLower,
  2139. Status));
  2140. goto Cleanup;
  2141. }
  2142. NlAssert(OutputSize == MessageBuffers->pBuffers[Index].cbBuffer);
  2143. }
  2144. }
  2145. }
  2146. //
  2147. // Finish the checksum
  2148. //
  2149. (void) Check->Finalize(CheckBuffer, LocalChecksum);
  2150. #ifdef notdef
  2151. Status = Check->Finish(&CheckBuffer);
  2152. if (!NT_SUCCESS(Status)) {
  2153. NlPrint(( NL_CRITICAL,"NlpSignOrSeal: Failed to finish checksum: 0x%x\n", Status));
  2154. goto Cleanup;
  2155. }
  2156. CheckBuffer = NULL;
  2157. #endif // notdef
  2158. //
  2159. // Copy the checksum into the message.
  2160. //
  2161. NlAssert( sizeof(LocalChecksum) >= sizeof(Signature->Checksum) );
  2162. RtlCopyMemory( Signature->Checksum, LocalChecksum, sizeof(Signature->Checksum) );
  2163. //
  2164. // Always encrypt the sequence number, using the checksum as the IV
  2165. //
  2166. if ( SealIt ) {
  2167. CryptSystem->Discard( &CryptBuffer );
  2168. CryptBuffer = NULL;
  2169. }
  2170. Status = CryptSystem->Initialize(
  2171. (LPBYTE)&Context->SessionInfo.SessionKey,
  2172. sizeof( Context->SessionInfo.SessionKey),
  2173. 0, // no message type
  2174. &CryptBuffer );
  2175. if (!NT_SUCCESS(Status)) {
  2176. NlPrint(( NL_CRITICAL,
  2177. "NlpSignOrSeal: %lx.%lx: Failed initialize crypt routines: 0x%x\n",
  2178. phContext->dwUpper, phContext->dwLower,
  2179. Status));
  2180. goto Cleanup;
  2181. }
  2182. //
  2183. // Set the initial vector
  2184. //
  2185. NlPrint(( NL_ENCRYPT,
  2186. "NlpSignOrSeal: %lx.%lx: IV: ",
  2187. phContext->dwUpper, phContext->dwLower ));
  2188. NlpDumpBuffer(NL_ENCRYPT, Signature->Checksum, sizeof(Signature->Checksum) );
  2189. Status = CryptSystem->Control(
  2190. CRYPT_CONTROL_SET_INIT_VECT,
  2191. CryptBuffer,
  2192. Signature->Checksum,
  2193. sizeof(Signature->Checksum) );
  2194. if (!NT_SUCCESS(Status)) {
  2195. NlPrint(( NL_CRITICAL,
  2196. "NlpSignOrSeal: %lx.%lx: Failed to set IV: 0x%x\n",
  2197. phContext->dwUpper, phContext->dwLower,
  2198. Status));
  2199. goto Cleanup;
  2200. }
  2201. //
  2202. // Now encrypt the sequence number
  2203. //
  2204. NlPrint(( NL_ENCRYPT,
  2205. "NlpSignOrSeal: %lx.%lx: Clear Seq: ",
  2206. phContext->dwUpper, phContext->dwLower ));
  2207. NlpDumpBuffer(NL_ENCRYPT, Signature->SequenceNumber, sizeof(Signature->SequenceNumber) );
  2208. Status = CryptSystem->Encrypt(
  2209. CryptBuffer,
  2210. Signature->SequenceNumber,
  2211. sizeof(Signature->SequenceNumber),
  2212. Signature->SequenceNumber,
  2213. &OutputSize
  2214. );
  2215. if (!NT_SUCCESS(Status)) {
  2216. NlPrint(( NL_CRITICAL,
  2217. "NlpSignOrSeal: %lx.%lx: Failed to encrypt sequence number: 0x%x\n",
  2218. phContext->dwUpper, phContext->dwLower,
  2219. Status));
  2220. goto Cleanup;
  2221. }
  2222. NlPrint(( NL_ENCRYPT,
  2223. "NlpSignOrSeal: %lx.%lx: Encrypted Seq: ",
  2224. phContext->dwUpper, phContext->dwLower ));
  2225. NlpDumpBuffer(NL_ENCRYPT, Signature->SequenceNumber, sizeof(Signature->SequenceNumber) );
  2226. NlAssert(OutputSize == sizeof(Signature->SequenceNumber));
  2227. Cleanup:
  2228. if (CryptBuffer != NULL) {
  2229. CryptSystem->Discard(&CryptBuffer);
  2230. }
  2231. if (CheckBuffer != NULL) {
  2232. Check->Finish(&CheckBuffer);
  2233. }
  2234. if ( SecStatus == SEC_E_OK ) {
  2235. SecStatus = KerbMapNtStatusToSecStatus(Status);
  2236. }
  2237. return SecStatus;
  2238. UNREFERENCED_PARAMETER( MessageSeqNo );
  2239. UNREFERENCED_PARAMETER( fQOP );
  2240. }
  2241. SECURITY_STATUS
  2242. NlpVerifyOrUnseal(
  2243. IN PCtxtHandle phContext,
  2244. IN PSecBufferDesc MessageBuffers,
  2245. IN ULONG MessageSequenceNumber,
  2246. OUT PULONG QualityOfProtection,
  2247. IN BOOLEAN UnsealIt
  2248. )
  2249. /*++
  2250. Routine Description:
  2251. Common routine to verify or unseal a message (Client or server side)
  2252. Arguments:
  2253. Standard.
  2254. UnSealIt - True to unseal the message.
  2255. FALSE to verify the message.
  2256. Return Value:
  2257. --*/
  2258. {
  2259. SECURITY_STATUS SecStatus = SEC_E_OK;
  2260. NTSTATUS Status = STATUS_SUCCESS;
  2261. PCHECKSUM_FUNCTION Check;
  2262. PCRYPTO_SYSTEM CryptSystem;
  2263. PCHECKSUM_BUFFER CheckBuffer = NULL;
  2264. PCRYPT_STATE_BUFFER CryptBuffer = NULL;
  2265. ULONG Index;
  2266. PSecBuffer SignatureBuffer = NULL;
  2267. PNL_AUTH_SIGNATURE Signature;
  2268. UCHAR LocalChecksum[24]; // ??? need better constant
  2269. BYTE LocalNonce[ NL_AUTH_SEQUENCE_SIZE ];
  2270. NETLOGON_SESSION_KEY EncryptionSessionKey;
  2271. BOOLEAN ChecksumOnly;
  2272. ULONG OutputSize;
  2273. PNL_AUTH_CONTEXT Context;
  2274. //
  2275. // Locate the context.
  2276. //
  2277. Context = LocateContext( phContext );
  2278. if (Context == NULL) {
  2279. NlPrint(( NL_CRITICAL,
  2280. "NlpVerifyOrUnseal: %lx.%lx: Cannot LocateContext\n",
  2281. phContext->dwUpper, phContext->dwLower ));
  2282. SecStatus = SEC_E_INVALID_HANDLE;
  2283. goto Cleanup;
  2284. }
  2285. //
  2286. // Find a buffer to put the signature in.
  2287. //
  2288. SignatureBuffer = LocateSigBuffer( MessageBuffers );
  2289. if (SignatureBuffer == NULL) {
  2290. NlPrint(( NL_CRITICAL,
  2291. "NlpVerifyOrUnseal: %lx.%lx: No signature buffer found\n",
  2292. phContext->dwUpper, phContext->dwLower ));
  2293. SecStatus = SEC_E_INVALID_TOKEN;
  2294. goto Cleanup;
  2295. }
  2296. //
  2297. // Verify the signature.
  2298. //
  2299. Signature = (PNL_AUTH_SIGNATURE) SignatureBuffer->pvBuffer;
  2300. if ( Signature->SignatureAlgorithm[0] != (BYTE)NL_AUTH_CHECKSUM ||
  2301. Signature->SignatureAlgorithm[1] != 0 ) {
  2302. NlPrint(( NL_CRITICAL,
  2303. "NlpVerifyOrUnseal: %lx.%lx: signature alg different\n",
  2304. phContext->dwUpper, phContext->dwLower ));
  2305. SecStatus = SEC_E_MESSAGE_ALTERED;
  2306. goto Cleanup;
  2307. }
  2308. if ( UnsealIt ) {
  2309. if ( SignatureBuffer->cbBuffer < sizeof(PACKAGE_SIGNATURE_SIZE) ) {
  2310. NlPrint(( NL_CRITICAL,
  2311. "NlpVerifyOrUnseal: %lx.%lx: buffer too small for sealing\n",
  2312. phContext->dwUpper, phContext->dwLower ));
  2313. SecStatus = SEC_E_MESSAGE_ALTERED;
  2314. goto Cleanup;
  2315. }
  2316. if ( Signature->SealAlgorithm[0] != (BYTE)NL_AUTH_ETYPE ||
  2317. Signature->SealAlgorithm[1] != 0 ) {
  2318. NlPrint(( NL_CRITICAL,
  2319. "NlpVerifyOrUnseal: %lx.%lx: seal alg different\n",
  2320. phContext->dwUpper, phContext->dwLower ));
  2321. SecStatus = SEC_E_MESSAGE_ALTERED;
  2322. goto Cleanup;
  2323. }
  2324. if ( *((USHORT UNALIGNED *)Signature->SealFiller) != 0xffff) {
  2325. NlPrint(( NL_CRITICAL,
  2326. "NlpVerifyOrUnseal: %lx.%lx: Filler different\n",
  2327. phContext->dwUpper, phContext->dwLower ));
  2328. SecStatus = SEC_E_MESSAGE_ALTERED;
  2329. goto Cleanup;
  2330. }
  2331. } else {
  2332. if ( *((ULONG UNALIGNED *) Signature->SignFiller) != 0xffffffff) {
  2333. NlPrint(( NL_CRITICAL,
  2334. "NlpVerifyOrUnseal: %lx.%lx: Filler different\n",
  2335. phContext->dwUpper, phContext->dwLower ));
  2336. SecStatus = SEC_E_MESSAGE_ALTERED;
  2337. goto Cleanup;
  2338. }
  2339. }
  2340. //
  2341. // Verify the sequence number.
  2342. //
  2343. // It is sent encrypted using the checksum as the IV, so decrypt it before
  2344. // checking it.
  2345. //
  2346. // Locate the encryption routines.
  2347. //
  2348. Status = CDLocateCSystem( (ULONG)NL_AUTH_ETYPE, &CryptSystem);
  2349. if (!NT_SUCCESS(Status)) {
  2350. NlPrint(( NL_CRITICAL,
  2351. "NlpVerifyOrUnseal: %lx.%lx: Failed to load crypt system: 0x%x\n",
  2352. phContext->dwUpper, phContext->dwLower,
  2353. Status));
  2354. goto Cleanup;
  2355. }
  2356. NlPrint(( NL_ENCRYPT,
  2357. "NlpVerifyOrUnseal: %lx.%lx: Session Key: ",
  2358. phContext->dwUpper, phContext->dwLower ));
  2359. NlpDumpBuffer(NL_ENCRYPT, &Context->SessionInfo.SessionKey, sizeof( Context->SessionInfo.SessionKey) );
  2360. Status = CryptSystem->Initialize(
  2361. (LPBYTE)&Context->SessionInfo.SessionKey,
  2362. sizeof( Context->SessionInfo.SessionKey),
  2363. 0, // no message type
  2364. &CryptBuffer );
  2365. if (!NT_SUCCESS(Status)) {
  2366. NlPrint(( NL_CRITICAL,
  2367. "NlpVerifyOrUnseal: %lx.%lx: Failed initialize crypt routines: 0x%x\n",
  2368. phContext->dwUpper, phContext->dwLower,
  2369. Status));
  2370. goto Cleanup;
  2371. }
  2372. //
  2373. // Set the initial vector
  2374. //
  2375. NlPrint(( NL_ENCRYPT,
  2376. "NlpVerifyOrUnseal: %lx.%lx: IV: ",
  2377. phContext->dwUpper, phContext->dwLower ));
  2378. NlpDumpBuffer(NL_ENCRYPT, Signature->Checksum, sizeof(Signature->Checksum) );
  2379. Status = CryptSystem->Control(
  2380. CRYPT_CONTROL_SET_INIT_VECT,
  2381. CryptBuffer,
  2382. Signature->Checksum,
  2383. sizeof(Signature->Checksum) );
  2384. if (!NT_SUCCESS(Status)) {
  2385. NlPrint(( NL_CRITICAL,
  2386. "NlpVerifyOrUnseal: %lx.%lx: Failed to set IV: 0x%x\n",
  2387. phContext->dwUpper, phContext->dwLower,
  2388. Status));
  2389. goto Cleanup;
  2390. }
  2391. //
  2392. // Now decrypt the sequence number
  2393. //
  2394. NlPrint(( NL_ENCRYPT,
  2395. "NlpVerifyOrUnseal: %lx.%lx: Encrypted Seq: ",
  2396. phContext->dwUpper, phContext->dwLower ));
  2397. NlpDumpBuffer(NL_ENCRYPT, Signature->SequenceNumber, sizeof(Signature->SequenceNumber) );
  2398. Status = CryptSystem->Decrypt(
  2399. CryptBuffer,
  2400. Signature->SequenceNumber,
  2401. sizeof(Signature->SequenceNumber),
  2402. Signature->SequenceNumber,
  2403. &OutputSize );
  2404. if (!NT_SUCCESS(Status)) {
  2405. NlPrint(( NL_CRITICAL,
  2406. "NlpVerifyOrUnseal: %lx.%lx: Cannot decrypt sequence number: 0x%x\n",
  2407. phContext->dwUpper, phContext->dwLower,
  2408. Status));
  2409. goto Cleanup;
  2410. }
  2411. NlPrint(( NL_ENCRYPT,
  2412. "NlpVerifyOrUnseal: %lx.%lx: Clear Seq: ",
  2413. phContext->dwUpper, phContext->dwLower ));
  2414. NlpDumpBuffer(NL_ENCRYPT, Signature->SequenceNumber, sizeof(Signature->SequenceNumber) );
  2415. LocalNonce[0] = (UCHAR) ((Context->Nonce.LowPart & 0xff000000) >> 24);
  2416. LocalNonce[1] = (UCHAR) ((Context->Nonce.LowPart & 0x00ff0000) >> 16);
  2417. LocalNonce[2] = (UCHAR) ((Context->Nonce.LowPart & 0x0000ff00) >> 8);
  2418. LocalNonce[3] = (UCHAR) (Context->Nonce.LowPart & 0x000000ff);
  2419. LocalNonce[4] = (UCHAR) ((Context->Nonce.HighPart & 0xff000000) >> 24);
  2420. LocalNonce[5] = (UCHAR) ((Context->Nonce.HighPart & 0x00ff0000) >> 16);
  2421. LocalNonce[6] = (UCHAR) ((Context->Nonce.HighPart & 0x0000ff00) >> 8);
  2422. LocalNonce[7] = (UCHAR) (Context->Nonce.HighPart & 0x000000ff);
  2423. if ( Context->Inbound ) {
  2424. LocalNonce[4] |= 0x80; // Discriminate between inbound and outbound messages
  2425. }
  2426. if (!RtlEqualMemory( LocalNonce,
  2427. Signature->SequenceNumber,
  2428. NL_AUTH_SEQUENCE_SIZE )) {
  2429. NlPrint(( NL_CRITICAL,
  2430. "NlpVerifyOrUnseal: %lx.%lx: Out of sequence\n",
  2431. phContext->dwUpper, phContext->dwLower ));
  2432. NlPrint(( NL_CRITICAL,"NlpVerifyOrUnseal: Local Sequence: " ));
  2433. NlpDumpBuffer(NL_CRITICAL, LocalNonce, NL_AUTH_SEQUENCE_SIZE );
  2434. NlPrint(( NL_CRITICAL,"NlpVerifyOrUnseal: Remote Sequence: " ));
  2435. NlpDumpBuffer(NL_CRITICAL, Signature->SequenceNumber, NL_AUTH_SEQUENCE_SIZE );
  2436. Status = SEC_E_OUT_OF_SEQUENCE;
  2437. goto Cleanup;
  2438. }
  2439. Context->Nonce.QuadPart ++;
  2440. //
  2441. // Now compute the checksum and verify it
  2442. //
  2443. //
  2444. // Initialize the checksum routines.
  2445. //
  2446. Status = CDLocateCheckSum( (ULONG)NL_AUTH_CHECKSUM, &Check);
  2447. if (!NT_SUCCESS(Status)) {
  2448. NlPrint(( NL_CRITICAL,
  2449. "NlpVerifyOrUnseal: %lx.%lx: Failed to load checksum routines: 0x%x\n",
  2450. phContext->dwUpper, phContext->dwLower,
  2451. Status));
  2452. goto Cleanup;
  2453. }
  2454. NlAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
  2455. Status = Check->InitializeEx(
  2456. (LPBYTE)&Context->SessionInfo.SessionKey,
  2457. sizeof( Context->SessionInfo.SessionKey),
  2458. 0, // no message type
  2459. &CheckBuffer );
  2460. if (!NT_SUCCESS(Status)) {
  2461. NlPrint(( NL_CRITICAL,
  2462. "NlpVerifyOrUnseal: %lx.%lx: Failed to initialize checksum routines: 0x%x\n",
  2463. phContext->dwUpper, phContext->dwLower,
  2464. Status));
  2465. goto Cleanup;
  2466. }
  2467. //
  2468. // Sum first several bytes of the signature
  2469. //
  2470. NlPrint(( NL_ENCRYPT,
  2471. "NlpVerifyOrUnseal: %lx.%lx: First Several of signature: ",
  2472. phContext->dwUpper, phContext->dwLower ));
  2473. NlpDumpBuffer(NL_ENCRYPT, Signature, NL_AUTH_SIGNED_BYTES );
  2474. Check->Sum( CheckBuffer,
  2475. NL_AUTH_SIGNED_BYTES,
  2476. (PUCHAR)Signature );
  2477. //
  2478. // Sum and decrypt the confounder
  2479. //
  2480. if ( UnsealIt ) {
  2481. //
  2482. // Discard the previous CryptBuffer
  2483. //
  2484. CryptSystem->Discard( &CryptBuffer );
  2485. CryptBuffer = NULL;
  2486. //
  2487. // Create the encryption key by xoring the session key with 0xf0f0f0f0
  2488. //
  2489. for ( Index=0; Index < sizeof(EncryptionSessionKey); Index++ ) {
  2490. ((LPBYTE)(&EncryptionSessionKey))[Index] =
  2491. ((LPBYTE)(&Context->SessionInfo.SessionKey))[Index] ^0xf0f0f0f0;
  2492. }
  2493. //
  2494. // Pass the key to the encryption routines.
  2495. //
  2496. Status = CryptSystem->Initialize(
  2497. (LPBYTE)&EncryptionSessionKey,
  2498. sizeof( EncryptionSessionKey ),
  2499. 0, // no message type
  2500. &CryptBuffer );
  2501. if (!NT_SUCCESS(Status)) {
  2502. NlPrint(( NL_CRITICAL,
  2503. "NlpVerifyOrUnseal: %lx.%lx: Failed to initialize crypt routines: 0x%x\n",
  2504. phContext->dwUpper, phContext->dwLower,
  2505. Status));
  2506. goto Cleanup;
  2507. }
  2508. //
  2509. // Set the initial vector to ensure the key is different for each message
  2510. //
  2511. Status = CryptSystem->Control(
  2512. CRYPT_CONTROL_SET_INIT_VECT,
  2513. CryptBuffer,
  2514. Signature->SequenceNumber,
  2515. sizeof(Signature->SequenceNumber) );
  2516. if (!NT_SUCCESS(Status)) {
  2517. NlPrint(( NL_CRITICAL,
  2518. "NlpVerifyOrUnseal: %lx.%lx: Failed to set IV: 0x%x\n",
  2519. phContext->dwUpper, phContext->dwLower,
  2520. Status));
  2521. goto Cleanup;
  2522. }
  2523. //
  2524. // Decrypt the confounder
  2525. //
  2526. Status = CryptSystem->Decrypt(
  2527. CryptBuffer,
  2528. Signature->Confounder,
  2529. NL_AUTH_CONFOUNDER_SIZE,
  2530. Signature->Confounder,
  2531. &OutputSize );
  2532. if (!NT_SUCCESS(Status)) {
  2533. NlPrint(( NL_CRITICAL,
  2534. "NlpVerifyOrUnseal: %lx.%lx: Failed to encrypt confounder: 0x%x\n",
  2535. phContext->dwUpper, phContext->dwLower,
  2536. Status));
  2537. goto Cleanup;
  2538. }
  2539. NlAssert( OutputSize == NL_AUTH_CONFOUNDER_SIZE );
  2540. //
  2541. // Sum the decrypted confounder
  2542. //
  2543. Check->Sum(
  2544. CheckBuffer,
  2545. NL_AUTH_CONFOUNDER_SIZE,
  2546. Signature->Confounder );
  2547. }
  2548. //
  2549. // Sum and decrypt the caller's message.
  2550. //
  2551. for (Index = 0; Index < MessageBuffers->cBuffers; Index++ ) {
  2552. if ((BUFFERTYPE(MessageBuffers->pBuffers[Index]) != SECBUFFER_TOKEN) &&
  2553. (!(MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY)) &&
  2554. (MessageBuffers->pBuffers[Index].cbBuffer != 0)) {
  2555. //
  2556. // Now decrypt the buffer
  2557. //
  2558. ChecksumOnly = ((MessageBuffers->pBuffers[Index].BufferType & SECBUFFER_READONLY_WITH_CHECKSUM) != 0);
  2559. if ( UnsealIt && !ChecksumOnly ) {
  2560. Status = CryptSystem->Decrypt(
  2561. CryptBuffer,
  2562. (PUCHAR) MessageBuffers->pBuffers[Index].pvBuffer,
  2563. MessageBuffers->pBuffers[Index].cbBuffer,
  2564. (PUCHAR) MessageBuffers->pBuffers[Index].pvBuffer,
  2565. &OutputSize );
  2566. if (!NT_SUCCESS(Status)) {
  2567. NlPrint(( NL_CRITICAL,
  2568. "NlpVerifyOrUnseal: %lx.%lx: Failed to encrypt buffer: 0x%x\n",
  2569. phContext->dwUpper, phContext->dwLower,
  2570. Status));
  2571. goto Cleanup;
  2572. }
  2573. NlAssert(OutputSize == MessageBuffers->pBuffers[Index].cbBuffer);
  2574. }
  2575. //
  2576. // Checksum the decrypted buffer.
  2577. //
  2578. Check->Sum(
  2579. CheckBuffer,
  2580. MessageBuffers->pBuffers[Index].cbBuffer,
  2581. (PBYTE) MessageBuffers->pBuffers[Index].pvBuffer );
  2582. }
  2583. }
  2584. //
  2585. // Finish the checksum
  2586. //
  2587. (void) Check->Finalize(CheckBuffer, LocalChecksum);
  2588. if (!RtlEqualMemory(
  2589. LocalChecksum,
  2590. Signature->Checksum,
  2591. sizeof(Signature->Checksum) )) {
  2592. NlPrint(( NL_CRITICAL,
  2593. "NlpVerifyOrUnseal: %lx.%lx: Checksum mismatch\n",
  2594. phContext->dwUpper, phContext->dwLower ));
  2595. Status = SEC_E_MESSAGE_ALTERED;
  2596. goto Cleanup;
  2597. }
  2598. Cleanup:
  2599. if (CheckBuffer != NULL) {
  2600. Check->Finish(&CheckBuffer);
  2601. }
  2602. if (CryptBuffer != NULL) {
  2603. CryptSystem->Discard(&CryptBuffer);
  2604. }
  2605. if ( SecStatus == SEC_E_OK ) {
  2606. SecStatus = KerbMapNtStatusToSecStatus(Status);
  2607. }
  2608. return SecStatus;
  2609. UNREFERENCED_PARAMETER( QualityOfProtection );
  2610. UNREFERENCED_PARAMETER( MessageSequenceNumber );
  2611. }
  2612. SECURITY_STATUS SEC_ENTRY
  2613. MakeSignature( PCtxtHandle phContext,
  2614. ULONG fQOP,
  2615. PSecBufferDesc pMessage,
  2616. ULONG MessageSeqNo)
  2617. /*++
  2618. Routine Description:
  2619. Routine to sign a message (Client or server side)
  2620. Arguments:
  2621. Standard.
  2622. Return Value:
  2623. --*/
  2624. {
  2625. SECURITY_STATUS SecStatus;
  2626. //
  2627. // If caller is calling when the netlogon service isn't running,
  2628. // tell it so.
  2629. //
  2630. if ( !NlStartNetlogonCall() ) {
  2631. return SEC_E_SECPKG_NOT_FOUND;
  2632. }
  2633. SecStatus = NlpSignOrSeal(
  2634. phContext,
  2635. fQOP,
  2636. pMessage,
  2637. MessageSeqNo,
  2638. FALSE ); // Just sign the message
  2639. NlPrint(( NL_SESSION_MORE,
  2640. "MakeSignature: %lx.%lx: returns 0x%lx\n",
  2641. phContext->dwUpper, phContext->dwLower,
  2642. SecStatus ));
  2643. // Let netlogon service exit.
  2644. NlEndNetlogonCall();
  2645. return SecStatus;
  2646. }
  2647. SECURITY_STATUS SEC_ENTRY
  2648. VerifySignature(PCtxtHandle phContext,
  2649. PSecBufferDesc pMessage,
  2650. ULONG MessageSeqNo,
  2651. ULONG * pfQOP)
  2652. /*++
  2653. Routine Description:
  2654. Routine to verify a signed message (Client or server side)
  2655. Arguments:
  2656. Standard.
  2657. Return Value:
  2658. --*/
  2659. {
  2660. SECURITY_STATUS SecStatus;
  2661. //
  2662. // If caller is calling when the netlogon service isn't running,
  2663. // tell it so.
  2664. //
  2665. if ( !NlStartNetlogonCall() ) {
  2666. return SEC_E_SECPKG_NOT_FOUND;
  2667. }
  2668. SecStatus = NlpVerifyOrUnseal(
  2669. phContext,
  2670. pMessage,
  2671. MessageSeqNo,
  2672. pfQOP,
  2673. FALSE ); // Just verify the signature
  2674. NlPrint(( NL_SESSION_MORE,
  2675. "VerifySignature: %lx.%lx: returns 0x%lx\n",
  2676. phContext->dwUpper, phContext->dwLower,
  2677. SecStatus ));
  2678. // Let netlogon service exit.
  2679. NlEndNetlogonCall();
  2680. return SecStatus;
  2681. }
  2682. SECURITY_STATUS SEC_ENTRY
  2683. SealMessage( PCtxtHandle phContext,
  2684. ULONG fQOP,
  2685. PSecBufferDesc pMessage,
  2686. ULONG MessageSeqNo)
  2687. /*++
  2688. Routine Description:
  2689. Routine to encrypt a message (Client or server side)
  2690. Arguments:
  2691. Standard.
  2692. Return Value:
  2693. --*/
  2694. {
  2695. SECURITY_STATUS SecStatus;
  2696. //
  2697. // If caller is calling when the netlogon service isn't running,
  2698. // tell it so.
  2699. //
  2700. if ( !NlStartNetlogonCall() ) {
  2701. return SEC_E_SECPKG_NOT_FOUND;
  2702. }
  2703. SecStatus = NlpSignOrSeal(
  2704. phContext,
  2705. fQOP,
  2706. pMessage,
  2707. MessageSeqNo,
  2708. TRUE ); // Seal the message
  2709. NlPrint(( NL_SESSION_MORE,
  2710. "SealMessage: %lx.%lx: returns 0x%lx\n",
  2711. phContext->dwUpper, phContext->dwLower,
  2712. SecStatus ));
  2713. // Let netlogon service exit.
  2714. NlEndNetlogonCall();
  2715. return SecStatus;
  2716. }
  2717. SECURITY_STATUS SEC_ENTRY
  2718. UnsealMessage( PCtxtHandle phContext,
  2719. PSecBufferDesc pMessage,
  2720. ULONG MessageSeqNo,
  2721. ULONG * pfQOP)
  2722. /*++
  2723. Routine Description:
  2724. Routine to un-encrypt a message (client or server side)
  2725. Arguments:
  2726. Standard.
  2727. Return Value:
  2728. --*/
  2729. {
  2730. SECURITY_STATUS SecStatus;
  2731. //
  2732. // If caller is calling when the netlogon service isn't running,
  2733. // tell it so.
  2734. //
  2735. if ( !NlStartNetlogonCall() ) {
  2736. return SEC_E_SECPKG_NOT_FOUND;
  2737. }
  2738. SecStatus = NlpVerifyOrUnseal(
  2739. phContext,
  2740. pMessage,
  2741. MessageSeqNo,
  2742. pfQOP,
  2743. TRUE ); // unseal the message
  2744. NlPrint(( NL_SESSION_MORE,
  2745. "UnsealMessage: %lx.%lx: returns 0x%lx\n",
  2746. phContext->dwUpper, phContext->dwLower,
  2747. SecStatus ));
  2748. // Let netlogon service exit.
  2749. NlEndNetlogonCall();
  2750. return SecStatus;
  2751. }