Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2787 lines
84 KiB

  1. /* Copyright (c) 1993, Microsoft Corporation, all rights reserved
  2. **
  3. ** raschap.c
  4. ** Remote Access PPP Challenge Handshake Authentication Protocol
  5. ** Core routines
  6. **
  7. ** 11/05/93 Steve Cobb
  8. **
  9. **
  10. ** ---------------------------------------------------------------------------
  11. ** Regular
  12. ** Client Server
  13. ** ---------------------------------------------------------------------------
  14. **
  15. ** <- Challenge (SendWithTimeout,ID)
  16. ** Response (SendWithTimeout,ID) ->
  17. ** <- Result (OK:SendAndDone, ID)
  18. **
  19. ** ---------------------------------------------------------------------------
  20. ** Retry logon
  21. ** Client Server
  22. ** ---------------------------------------------------------------------------
  23. **
  24. ** <- Challenge (SendWithTimeout,ID)
  25. ** Response (SendWithTimeout,ID) ->
  26. ** <- Result (Fail:SendWithTimeout2,ID,R=1)
  27. ** R=1 implies challenge of last+23
  28. ** Response (SendWithTimeout,++ID) ->
  29. ** to last challenge+23
  30. ** or C=xxxxxxxx if present
  31. ** e.g. Chicago server
  32. ** <- Result (Fail:SendAndDone,ID,R=0)
  33. **
  34. ** ---------------------------------------------------------------------------
  35. ** Change password
  36. ** Client Server
  37. ** ---------------------------------------------------------------------------
  38. **
  39. ** <- Challenge (SendWithTimeout,ID)
  40. ** Response (SendWithTimeout,ID) ->
  41. ** <- Result (Fail:SendWithTimeout2,ID,R=1,V=2)
  42. ** E=ERROR_PASSWD_EXPIRED
  43. ** ChangePw (SendWithTimeout,++ID) ->
  44. ** to last challenge
  45. ** <- Result (Fail:SendAndDone,ID,R=0)
  46. **
  47. ** Note: Retry is never allowed after Change Password. Change Password may
  48. ** occur on a retry. ChangePw2 is sent if Result included V=2 (or
  49. ** higher), while ChangePw1 is sent if V<2 or is not provided.
  50. **
  51. ** ---------------------------------------------------------------------------
  52. ** ChangePw1 packet
  53. ** ---------------------------------------------------------------------------
  54. **
  55. ** 1-octet : Code (=CHAP_ChangePw1)
  56. ** 1-octet : Identifier
  57. ** 2-octet : Length (=72)
  58. ** 16-octets : New LM OWF password encrypted with challenge
  59. ** 16-octets : Old LM OWF password encrypted with challenge
  60. ** 16-octets : New NT OWF password encrypted with challenge
  61. ** 16-octets : Old NT OWF password encrypted with challenge
  62. ** 2-octets : New password length in bytes
  63. ** 2-octets : Flags (1=NT forms present)
  64. **
  65. ** Note: Encrypting with the challenge is not good because it is not secret
  66. ** from line snoopers. This bug got ported to NT 3.5 from AMB. It is
  67. ** fixed in the V2 packet where everything depends on knowledge of the
  68. ** old NT OWF password, which is a proper secret.
  69. **
  70. ** ---------------------------------------------------------------------------
  71. ** ChangePw2 packet
  72. ** ---------------------------------------------------------------------------
  73. **
  74. ** 1-octet : Code (=CHAP_ChangePw2)
  75. ** 1-octet : Identifier
  76. ** 2-octet : Length (=1070)
  77. ** 516-octets : New password encrypted with old NT OWF password
  78. ** 16-octets : Old NT OWF password encrypted with new NT OWF password
  79. ** 516-octets : New password encrypted with old LM OWF password
  80. ** 16-octets : Old LM OWF password encrypted with new NT OWF password
  81. ** 24-octets : LM challenge response
  82. ** 24-octets : NT challenge response
  83. ** 2-octet : Flags
  84. */
  85. #include <nt.h>
  86. #include <ntrtl.h>
  87. #include <nturtl.h>
  88. #include <ntlsa.h>
  89. #include <ntmsv1_0.h>
  90. #include <ntsamp.h>
  91. #include <crypt.h>
  92. #include <windows.h>
  93. #include <lmcons.h>
  94. #include <string.h>
  95. #include <stdlib.h>
  96. #include <rasman.h>
  97. #include <pppcp.h>
  98. #include <raserror.h>
  99. #include <rtutils.h>
  100. #include <rasauth.h>
  101. #define INCL_PWUTIL
  102. #define INCL_HOSTWIRE
  103. #define INCL_CLSA
  104. #define INCL_RASAUTHATTRIBUTES
  105. #define INCL_MISC
  106. #include <ppputil.h>
  107. #define RASCHAPGLOBALS
  108. #include "sha.h"
  109. #include "raschap.h"
  110. /*---------------------------------------------------------------------------
  111. ** External entry points
  112. **---------------------------------------------------------------------------
  113. */
  114. DWORD
  115. ChapInit(
  116. IN BOOL fInitialize )
  117. /* Called to initialize/uninitialize this CP. In the former case,
  118. ** fInitialize will be TRUE; in the latter case, it will be FALSE.
  119. */
  120. {
  121. DWORD dwRetCode;
  122. if ( fInitialize )
  123. {
  124. if (0 == g_dwRefCount)
  125. {
  126. g_dwTraceIdChap = TraceRegisterA( "RASCHAP" );
  127. if ( g_hLsa == INVALID_HANDLE_VALUE )
  128. {
  129. if ( ( dwRetCode = InitLSA() ) != NO_ERROR )
  130. {
  131. return( dwRetCode );
  132. }
  133. }
  134. //
  135. // Get the computer name for local identification to send in
  136. // chap challenges
  137. //
  138. {
  139. DWORD dwLength = sizeof( szComputerName );
  140. if ( !GetComputerNameA( szComputerName, &dwLength ) )
  141. {
  142. return( GetLastError() );
  143. }
  144. }
  145. ChapChangeNotification();
  146. }
  147. g_dwRefCount++;
  148. }
  149. else
  150. {
  151. g_dwRefCount--;
  152. if (0 == g_dwRefCount)
  153. {
  154. if ( g_dwTraceIdChap != INVALID_TRACEID )
  155. {
  156. TraceDeregisterA( g_dwTraceIdChap );
  157. g_dwTraceIdChap = INVALID_TRACEID;
  158. }
  159. if ( g_hLsa != INVALID_HANDLE_VALUE )
  160. {
  161. EndLSA();
  162. g_hLsa = INVALID_HANDLE_VALUE;
  163. }
  164. }
  165. }
  166. return(NO_ERROR);
  167. }
  168. DWORD
  169. ChapChangeNotification(
  170. VOID
  171. )
  172. {
  173. return( NO_ERROR );
  174. }
  175. DWORD APIENTRY
  176. RasCpEnumProtocolIds(
  177. OUT DWORD* pdwProtocolIds,
  178. OUT DWORD* pcProtocolIds )
  179. /* RasCpEnumProtocolIds entry point called by the PPP engine by name. See
  180. ** RasCp interface documentation.
  181. */
  182. {
  183. TRACE("RasCpEnumProtocolIds");
  184. pdwProtocolIds[ 0 ] = (DWORD )PPP_CHAP_PROTOCOL;
  185. *pcProtocolIds = 1;
  186. return 0;
  187. }
  188. DWORD
  189. RasCpGetInfo(
  190. IN DWORD dwProtocolId,
  191. OUT PPPCP_INFO* pInfo )
  192. /* ChapGetInfo entry point called by the PPP engine. See RasCp
  193. ** interface documentation.
  194. */
  195. {
  196. memset( pInfo, '\0', sizeof(*pInfo) );
  197. lstrcpy( pInfo->SzProtocolName, "CHAP" );
  198. pInfo->Protocol = (DWORD )PPP_CHAP_PROTOCOL;
  199. pInfo->Recognize = MAXCHAPCODE + 1;
  200. pInfo->RasCpInit = ChapInit;
  201. pInfo->RasCpBegin = ChapBegin;
  202. pInfo->RasCpEnd = ChapEnd;
  203. pInfo->RasApMakeMessage = ChapMakeMessage;
  204. pInfo->RasCpChangeNotification = ChapChangeNotification;
  205. return 0;
  206. }
  207. DWORD
  208. ChapBegin(
  209. OUT VOID** ppWorkBuf,
  210. IN VOID* pInfo )
  211. /* RasCpBegin entry point called by the PPP engine thru the passed
  212. ** address. See RasCp interface documentation.
  213. */
  214. {
  215. DWORD dwErr;
  216. PPPAP_INPUT* pInput = (PPPAP_INPUT* )pInfo;
  217. CHAPWB* pwb;
  218. TRACE2("ChapBegin(fS=%d,bA=0x%x)",pInput->fServer,*(pInput->pAPData));
  219. if ( ( *(pInput->pAPData) != PPP_CHAP_DIGEST_MSEXT ) &&
  220. ( *(pInput->pAPData) != PPP_CHAP_DIGEST_MD5 ) &&
  221. ( *(pInput->pAPData) != PPP_CHAP_DIGEST_MSEXT_NEW ) )
  222. {
  223. TRACE("Bogus digest");
  224. return ERROR_INVALID_PARAMETER;
  225. }
  226. /* Allocate work buffer.
  227. */
  228. if (!(pwb = (CHAPWB* )LocalAlloc( LPTR, sizeof(CHAPWB) )))
  229. return ERROR_NOT_ENOUGH_MEMORY;
  230. pwb->fServer = pInput->fServer;
  231. pwb->hport = pInput->hPort;
  232. pwb->bAlgorithm = *(pInput->pAPData);
  233. pwb->fConfigInfo = pInput->fConfigInfo;
  234. pwb->chSeed = GEN_RAND_ENCODE_SEED;
  235. if (pwb->fServer)
  236. {
  237. pwb->dwTriesLeft = pInput->dwRetries;
  238. pwb->hPort = pInput->hPort;
  239. pwb->dwInitialPacketId = pInput->dwInitialPacketId;
  240. }
  241. else
  242. {
  243. if ((dwErr = StoreCredentials( pwb, pInput )) != 0)
  244. {
  245. LocalFree( (HLOCAL )pwb);
  246. return dwErr;
  247. }
  248. pwb->Luid = pInput->Luid;
  249. }
  250. pwb->state = CS_Initial;
  251. /* Register work buffer with engine.
  252. */
  253. *ppWorkBuf = pwb;
  254. TRACE("ChapBegin done.");
  255. return 0;
  256. }
  257. DWORD
  258. ChapEnd(
  259. IN VOID* pWorkBuf )
  260. /* RasCpEnd entry point called by the PPP engine thru the passed address.
  261. ** See RasCp interface documentation.
  262. */
  263. {
  264. TRACE("ChapEnd");
  265. if ( pWorkBuf != NULL )
  266. {
  267. CHAPWB* pwb = (CHAPWB* )pWorkBuf;
  268. if ( pwb->pUserAttributes != NULL )
  269. {
  270. RasAuthAttributeDestroy( pwb->pUserAttributes );
  271. }
  272. if ( pwb->pMPPEKeys != NULL )
  273. {
  274. RasAuthAttributeDestroy( pwb->pMPPEKeys );
  275. }
  276. /* Nuke any credentials in memory.
  277. */
  278. ZeroMemory( pWorkBuf, sizeof(CHAPWB) );
  279. LocalFree( (HLOCAL )pWorkBuf );
  280. }
  281. return 0;
  282. }
  283. DWORD
  284. ChapMakeMessage(
  285. IN VOID* pWorkBuf,
  286. IN PPP_CONFIG* pReceiveBuf,
  287. OUT PPP_CONFIG* pSendBuf,
  288. IN DWORD cbSendBuf,
  289. OUT PPPAP_RESULT* pResult,
  290. IN PPPAP_INPUT* pInput )
  291. /* RasApMakeMessage entry point called by the PPP engine thru the passed
  292. ** address. See RasCp interface documentation.
  293. */
  294. {
  295. CHAPWB* pwb = (CHAPWB* )pWorkBuf;
  296. TRACE1("ChapMakeMessage,RBuf=%p",pReceiveBuf);
  297. return
  298. (pwb->fServer)
  299. ? ChapSMakeMessage(
  300. pwb, pReceiveBuf, pSendBuf, cbSendBuf, pResult, pInput )
  301. : ChapCMakeMessage(
  302. pwb, pReceiveBuf, pSendBuf, cbSendBuf, pResult, pInput );
  303. }
  304. /*---------------------------------------------------------------------------
  305. ** Internal routines
  306. **---------------------------------------------------------------------------
  307. */
  308. VOID
  309. ChapExtractMessage(
  310. IN PPP_CONFIG* pReceiveBuf,
  311. IN BYTE bAlgorithm,
  312. OUT PPPAP_RESULT* pResult )
  313. {
  314. WORD cbPacket;
  315. DWORD dwNumBytes;
  316. CHAR* pszReplyMessage = NULL;
  317. DWORD cbMessage;
  318. CHAR szBuf[ MAXINFOLEN + 1 ];
  319. CHAR* pszValue;
  320. cbPacket = WireToHostFormat16(pReceiveBuf->Length);
  321. if (PPP_CONFIG_HDR_LEN >= cbPacket)
  322. {
  323. goto LDone;
  324. }
  325. cbMessage = min( cbPacket - PPP_CONFIG_HDR_LEN, MAXINFOLEN );
  326. CopyMemory( szBuf, pReceiveBuf->Data, cbMessage );
  327. szBuf[ cbMessage ] = '\0';
  328. if (PPP_CHAP_DIGEST_MD5 == bAlgorithm)
  329. {
  330. pszValue = szBuf;
  331. dwNumBytes = cbMessage;
  332. }
  333. else
  334. {
  335. pszValue = strstr(szBuf, "M=");
  336. if (pszValue == NULL)
  337. {
  338. dwNumBytes = 0;
  339. }
  340. else
  341. {
  342. //
  343. // Eat the "M="
  344. //
  345. pszValue += 2;
  346. dwNumBytes = strlen(pszValue);
  347. }
  348. }
  349. if (0 == dwNumBytes)
  350. {
  351. goto LDone;
  352. }
  353. //
  354. // One more for the terminating NULL.
  355. //
  356. pszReplyMessage = LocalAlloc(LPTR, dwNumBytes + 1);
  357. if (NULL == pszReplyMessage)
  358. {
  359. TRACE("LocalAlloc failed. Cannot extract server's message.");
  360. goto LDone;
  361. }
  362. CopyMemory(pszReplyMessage, pszValue, dwNumBytes);
  363. LocalFree(pResult->szReplyMessage);
  364. pResult->szReplyMessage = pszReplyMessage;
  365. pszReplyMessage = NULL;
  366. LDone:
  367. LocalFree(pszReplyMessage);
  368. return;
  369. }
  370. BOOL
  371. IsSuccessPacketValid(
  372. IN CHAPWB* pwb,
  373. IN PPP_CONFIG* pReceiveBuf
  374. )
  375. {
  376. A_SHA_CTX SHAContext1;
  377. A_SHA_CTX SHAContext2;
  378. BYTE SHADigest1[A_SHA_DIGEST_LEN];
  379. BYTE SHADigest2[A_SHA_DIGEST_LEN];
  380. DWORD cbSignature;
  381. CHAR szBuf[ MAXINFOLEN + 2];
  382. CHAR* pszValue;
  383. DWORD dwLength = WireToHostFormat16( pReceiveBuf->Length );
  384. BYTE bSignature[sizeof(SHADigest2)];
  385. if ( dwLength < PPP_CONFIG_HDR_LEN )
  386. {
  387. return( FALSE );
  388. }
  389. cbSignature = min( dwLength - PPP_CONFIG_HDR_LEN, MAXINFOLEN );
  390. CopyMemory( szBuf, pReceiveBuf->Data, cbSignature );
  391. szBuf[ cbSignature ] = szBuf[ cbSignature + 1 ] = '\0';
  392. pszValue = strstr( szBuf, "S=" );
  393. if ( pszValue == NULL )
  394. {
  395. return( FALSE );
  396. }
  397. else
  398. {
  399. CHAR* pchIn = pszValue + 2;
  400. CHAR* pchOut = (CHAR* )bSignature;
  401. INT i;
  402. ZeroMemory( bSignature, sizeof( bSignature ) );
  403. for (i = 0; i < sizeof( bSignature ) + sizeof( bSignature ); ++i)
  404. {
  405. BYTE bHexCharValue = HexCharValue( *pchIn++ );
  406. if (bHexCharValue == 0xFF)
  407. break;
  408. if (i & 1)
  409. *pchOut++ += bHexCharValue;
  410. else
  411. *pchOut = bHexCharValue << 4;
  412. }
  413. }
  414. A_SHAInit( &SHAContext1 );
  415. A_SHAUpdate( &SHAContext1, (PBYTE)&(pwb->keyUser), sizeof( pwb->keyUser) );
  416. A_SHAUpdate( &SHAContext1,
  417. pwb->abResponse + LM_RESPONSE_LENGTH,
  418. NT_RESPONSE_LENGTH );
  419. A_SHAUpdate( &SHAContext1,
  420. "Magic server to client signing constant",
  421. strlen( "Magic server to client signing constant" ) );
  422. A_SHAFinal( &SHAContext1, SHADigest1 );
  423. A_SHAInit( &SHAContext2 );
  424. A_SHAUpdate( &SHAContext2, SHADigest1, sizeof( SHADigest1 ) );
  425. A_SHAUpdate( &SHAContext2, pwb->abComputedChallenge, 8 );
  426. A_SHAUpdate( &SHAContext2,
  427. "Pad to make it do more than one iteration",
  428. strlen( "Pad to make it do more than one iteration" ) );
  429. A_SHAFinal( &SHAContext2, SHADigest2 );
  430. if ( memcmp( SHADigest2, bSignature, sizeof( SHADigest2 ) ) != 0 )
  431. {
  432. TRACE(("CHAP: Signature received...\n"));
  433. DUMPB(bSignature,(WORD)sizeof( SHADigest2 ) );
  434. TRACE(("CHAP: Signature should be...\n"));
  435. DUMPB( SHADigest2,(WORD)sizeof( SHADigest2 ) );
  436. return( FALSE );
  437. }
  438. return( TRUE );
  439. }
  440. DWORD
  441. ChapCMakeMessage(
  442. IN CHAPWB* pwb,
  443. IN PPP_CONFIG* pReceiveBuf,
  444. OUT PPP_CONFIG* pSendBuf,
  445. IN DWORD cbSendBuf,
  446. OUT PPPAP_RESULT* pResult,
  447. IN PPPAP_INPUT* pInput )
  448. /* Client side "make message" entry point. See RasCp interface
  449. ** documentation.
  450. */
  451. {
  452. DWORD dwErr;
  453. TRACE("ChapCMakeMessage...");
  454. switch (pwb->state)
  455. {
  456. case CS_Initial:
  457. {
  458. TRACE("CS_Initial");
  459. /* Tell engine we're waiting for the server to initiate the
  460. ** conversation.
  461. */
  462. pResult->Action = APA_NoAction;
  463. pwb->state = CS_WaitForChallenge;
  464. break;
  465. }
  466. case CS_WaitForChallenge:
  467. case CS_Done:
  468. {
  469. TRACE1("CS_%s",(pwb->state==CS_Done)?"Done":"WaitForChallenge");
  470. /*
  471. ** Should not receive Timeouts in this state. If we do simply
  472. ** ignore it.
  473. */
  474. if (!pReceiveBuf)
  475. {
  476. pResult->Action = APA_NoAction;
  477. break;
  478. }
  479. /* Note: Done state is same as WaitForChallenge per CHAP spec.
  480. ** Must be ready to respond to new Challenge at any time during
  481. ** Network Protocol phase.
  482. */
  483. if (pReceiveBuf->Code != CHAPCODE_Challenge)
  484. {
  485. /* Everything but a Challenge is garbage at this point, and is
  486. ** silently discarded.
  487. */
  488. pResult->Action = APA_NoAction;
  489. break;
  490. }
  491. if ((dwErr = GetChallengeFromChallenge( pwb, pReceiveBuf )))
  492. {
  493. TRACE1("GetChallengeFromChallenge=%d",dwErr);
  494. return dwErr;
  495. }
  496. /* Build a Response to the Challenge and send it.
  497. */
  498. pwb->fNewChallengeProvided = FALSE;
  499. pwb->bIdToSend = pwb->bIdExpected = pReceiveBuf->Id;
  500. if ((dwErr = MakeResponseMessage(
  501. pwb, pSendBuf, cbSendBuf, FALSE )) != 0)
  502. {
  503. TRACE1("MakeResponseMessage(WC)=%d",dwErr);
  504. return dwErr;
  505. }
  506. pResult->Action = APA_SendWithTimeout;
  507. pResult->bIdExpected = pwb->bIdExpected;
  508. pwb->state = CS_ResponseSent;
  509. break;
  510. }
  511. case CS_ResponseSent:
  512. case CS_ChangePw1Sent:
  513. case CS_ChangePw2Sent:
  514. {
  515. TRACE1("CS_%sSent",
  516. (pwb->state==CS_ResponseSent)
  517. ?"Response"
  518. :(pwb->state==CS_ChangePw1Sent)
  519. ?"ChangePw1"
  520. :"ChangePw2");
  521. if (!pReceiveBuf)
  522. {
  523. /* Timed out, resend our message.
  524. */
  525. if (pwb->state == CS_ResponseSent)
  526. {
  527. if ((dwErr = MakeResponseMessage(
  528. pwb, pSendBuf, cbSendBuf, TRUE )) != 0)
  529. {
  530. TRACE1("MakeResponseMessage(RS)=%d",dwErr);
  531. return dwErr;
  532. }
  533. }
  534. else if (pwb->state == CS_ChangePw1Sent)
  535. {
  536. if ((dwErr = MakeChangePw1Message(
  537. pwb, pSendBuf, cbSendBuf )) != 0)
  538. {
  539. TRACE1("MakeChangePw1Message(CPS)=%d",dwErr);
  540. return dwErr;
  541. }
  542. }
  543. else // if (pwb->state == CS_ChangePw2Sent)
  544. {
  545. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT )
  546. {
  547. if ((dwErr = MakeChangePw2Message(
  548. pwb, pSendBuf, cbSendBuf )) != 0)
  549. {
  550. TRACE1("MakeChangePw2Message(CPS)=%d",dwErr);
  551. return dwErr;
  552. }
  553. }
  554. else
  555. {
  556. if ((dwErr = MakeChangePw3Message(
  557. pwb, pSendBuf, cbSendBuf, TRUE )) != 0)
  558. {
  559. TRACE1("MakeChangePw3Message(CPS)=%d",dwErr);
  560. return dwErr;
  561. }
  562. }
  563. }
  564. pResult->Action = APA_SendWithTimeout;
  565. pResult->bIdExpected = pwb->bIdExpected;
  566. break;
  567. }
  568. TRACE("Message received...");
  569. DUMPB(pReceiveBuf,(WORD)(((BYTE*)pReceiveBuf)[3]));
  570. if (pReceiveBuf->Code == CHAPCODE_Challenge)
  571. {
  572. /* Restart when new challenge is received, per CHAP spec.
  573. */
  574. pwb->state = CS_WaitForChallenge;
  575. return ChapCMakeMessage(
  576. pwb, pReceiveBuf, pSendBuf, cbSendBuf, pResult, NULL );
  577. }
  578. if (pReceiveBuf->Id != pwb->bIdExpected)
  579. {
  580. /* Received a packet out of sequence. Silently discard it.
  581. */
  582. TRACE2("Got ID %d when expecting %d",
  583. pReceiveBuf->Id,pwb->bIdExpected);
  584. pResult->Action = APA_NoAction;
  585. break;
  586. }
  587. ChapExtractMessage( pReceiveBuf, pwb->bAlgorithm, pResult );
  588. if ( pReceiveBuf->Code == CHAPCODE_Success )
  589. {
  590. /* Passed authentication.
  591. **
  592. ** Get the session key for encryption.
  593. */
  594. if ( ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT ) ||
  595. ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW ) )
  596. {
  597. if ( !pwb->fSessionKeysObtained )
  598. {
  599. DecodePw( pwb->chSeed, pwb->szPassword );
  600. CGetSessionKeys(
  601. pwb->szPassword, &pwb->keyLm, &pwb->keyUser );
  602. EncodePw( pwb->chSeed, pwb->szPassword );
  603. pwb->fSessionKeysObtained = TRUE;
  604. }
  605. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  606. {
  607. if ( !IsSuccessPacketValid( pwb, pReceiveBuf ) )
  608. {
  609. pwb->state = CS_Done;
  610. pResult->dwError =
  611. ERROR_UNABLE_TO_AUTHENTICATE_SERVER;
  612. pResult->fRetry = FALSE;
  613. pResult->Action = APA_Done;
  614. break;
  615. }
  616. }
  617. if ( pwb->pMPPEKeys == NULL )
  618. {
  619. //
  620. // We set up the MPPE key attribute to be passed to
  621. // the PPP engine
  622. //
  623. BYTE MPPEKeys[6+8+16];
  624. pwb->pMPPEKeys = RasAuthAttributeCreate( 1 );
  625. if ( pwb->pMPPEKeys == NULL )
  626. {
  627. return( GetLastError() );
  628. }
  629. HostToWireFormat32( 311, MPPEKeys ); // Vendor Id
  630. MPPEKeys[4] = 12; // Vendor Type
  631. MPPEKeys[5] = 24; // Vendor Length
  632. CopyMemory( MPPEKeys+6, &(pwb->keyLm), 8 );
  633. CopyMemory( MPPEKeys+6+8, &(pwb->keyUser), 16 );
  634. dwErr = RasAuthAttributeInsert(
  635. 0,
  636. pwb->pMPPEKeys,
  637. raatVendorSpecific,
  638. FALSE,
  639. 6+8+16,
  640. MPPEKeys );
  641. if ( dwErr != NO_ERROR )
  642. {
  643. return( dwErr );
  644. }
  645. }
  646. pResult->pUserAttributes = pwb->pMPPEKeys;
  647. CopyMemory( pResult->abResponse,
  648. pwb->abResponse+LM_RESPONSE_LENGTH,
  649. NT_RESPONSE_LENGTH );
  650. CopyMemory( pResult->abChallenge,
  651. ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  652. ? pwb->abComputedChallenge
  653. : pwb->abChallenge,
  654. sizeof( pResult->abChallenge ) );
  655. }
  656. pResult->Action = APA_Done;
  657. pResult->dwError = 0;
  658. pResult->fRetry = FALSE;
  659. pwb->state = CS_Done;
  660. strcpy( pResult->szUserName, pwb->szUserName );
  661. TRACE("Done :)");
  662. }
  663. else if (pReceiveBuf->Code == CHAPCODE_Failure)
  664. {
  665. DWORD dwVersion = 1;
  666. /* Failed authentication.
  667. */
  668. if ( ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT ) ||
  669. ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW ) )
  670. {
  671. GetInfoFromFailure(
  672. pwb, pReceiveBuf,
  673. &pResult->dwError, &pResult->fRetry, &dwVersion );
  674. }
  675. else
  676. {
  677. pResult->dwError = ERROR_AUTHENTICATION_FAILURE;
  678. pResult->fRetry = 0;
  679. }
  680. pResult->Action = APA_Done;
  681. if (pResult->dwError == ERROR_PASSWD_EXPIRED)
  682. {
  683. pwb->state = (dwVersion < 2) ? CS_ChangePw1 : CS_ChangePw2;
  684. pwb->bIdToSend = pReceiveBuf->Id + 1;
  685. pwb->bIdExpected = pwb->bIdToSend;
  686. TRACE3("ChangePw(%d) :| ex=%d ts=%d",
  687. dwVersion,pwb->bIdExpected,pwb->bIdToSend);
  688. }
  689. else if (pResult->fRetry)
  690. {
  691. pwb->state = CS_Retry;
  692. pwb->bIdToSend = pReceiveBuf->Id + 1;
  693. pwb->bIdExpected = pwb->bIdToSend;
  694. pwb->fSessionKeysObtained = FALSE;
  695. TRACE2("Retry :| ex=%d ts=%d",
  696. pwb->bIdExpected,pwb->bIdToSend);
  697. }
  698. else
  699. {
  700. pwb->state = CS_Done;
  701. TRACE("Done :(");
  702. }
  703. }
  704. else
  705. {
  706. /* Received a CHAPCODE_* besides CHAPCODE_Challenge,
  707. ** CHAPCODE_Success, and CHAPCODE_Failure. The engine filters
  708. ** all non-CHAPCODEs. Shouldn't happen, but silently discard
  709. ** it.
  710. */
  711. ASSERT(!"Bogus pReceiveBuf->Code");
  712. pResult->Action = APA_NoAction;
  713. break;
  714. }
  715. break;
  716. }
  717. case CS_Retry:
  718. case CS_ChangePw1:
  719. case CS_ChangePw2:
  720. {
  721. TRACE1("CS_%s",
  722. (pwb->state==CS_Retry)
  723. ?"Retry"
  724. :(pwb->state==CS_ChangePw1)
  725. ?"ChangePw1"
  726. :"ChangePw2");
  727. if (pReceiveBuf)
  728. {
  729. if (pReceiveBuf->Code == CHAPCODE_Challenge)
  730. {
  731. /* Restart when new challenge is received, per CHAP spec.
  732. */
  733. pwb->state = CS_WaitForChallenge;
  734. return ChapCMakeMessage(
  735. pwb, pReceiveBuf, pSendBuf, cbSendBuf, pResult, NULL );
  736. }
  737. else
  738. {
  739. /* Silently discard.
  740. */
  741. pResult->Action = APA_NoAction;
  742. break;
  743. }
  744. }
  745. if (!pInput)
  746. {
  747. pResult->Action = APA_NoAction;
  748. break;
  749. }
  750. if ((dwErr = StoreCredentials( pwb, pInput )) != 0)
  751. return dwErr;
  752. if (pwb->state == CS_Retry)
  753. {
  754. /* Build a response to the challenge and send it.
  755. */
  756. if (!pwb->fNewChallengeProvided)
  757. {
  758. /* Implied challenge of old challenge + 23.
  759. */
  760. pwb->abChallenge[ 0 ] += 23;
  761. }
  762. if ((dwErr = MakeResponseMessage(
  763. pwb, pSendBuf, cbSendBuf, FALSE )) != 0)
  764. {
  765. return dwErr;
  766. }
  767. pwb->state = CS_ResponseSent;
  768. }
  769. else if (pwb->state == CS_ChangePw1)
  770. {
  771. /* Build a response to the NT35-style password expired
  772. ** notification and send it.
  773. */
  774. if ((dwErr = MakeChangePw1Message(
  775. pwb, pSendBuf, cbSendBuf )) != 0)
  776. {
  777. return dwErr;
  778. }
  779. pwb->state = CS_ChangePw1Sent;
  780. }
  781. else // if (pwb->state == CS_ChangePw2)
  782. {
  783. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT )
  784. {
  785. /* Build a response to the NT351-style password expired
  786. ** notification and send it.
  787. */
  788. if ((dwErr = MakeChangePw2Message(
  789. pwb, pSendBuf, cbSendBuf )) != 0)
  790. {
  791. return dwErr;
  792. }
  793. }
  794. else
  795. {
  796. if ((dwErr = MakeChangePw3Message(
  797. pwb, pSendBuf, cbSendBuf, FALSE )) != 0)
  798. {
  799. return dwErr;
  800. }
  801. }
  802. pwb->state = CS_ChangePw2Sent;
  803. }
  804. pResult->Action = APA_SendWithTimeout;
  805. pResult->bIdExpected = pwb->bIdExpected;
  806. break;
  807. }
  808. }
  809. return 0;
  810. }
  811. DWORD
  812. GetChallengeFromChallenge(
  813. OUT CHAPWB* pwb,
  814. IN PPP_CONFIG* pReceiveBuf )
  815. /* Fill work buffer challenge array and length from that received in the
  816. ** received Challenge message.
  817. **
  818. ** Returns 0 if successful, or ERRORBADPACKET if the packet is
  819. ** misformatted in any way.
  820. */
  821. {
  822. WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
  823. if (cbPacket < PPP_CONFIG_HDR_LEN + 1)
  824. return ERRORBADPACKET;
  825. pwb->cbChallenge = *pReceiveBuf->Data;
  826. if (cbPacket < PPP_CONFIG_HDR_LEN + 1 + pwb->cbChallenge)
  827. return ERRORBADPACKET;
  828. memcpy( pwb->abChallenge, pReceiveBuf->Data + 1, pwb->cbChallenge );
  829. return 0;
  830. }
  831. DWORD
  832. GetCredentialsFromResponse(
  833. IN PPP_CONFIG* pReceiveBuf,
  834. IN BYTE bAlgorithm,
  835. OUT CHAR* pszIdentity,
  836. OUT BYTE* pbResponse )
  837. /* Fill caller's 'pszUserName' and 'pbResponse' buffers with
  838. ** the username, and response in the Response packet. Caller's
  839. ** buffers should be at least UNLEN+DNLEN+1, and MSRESPONSELEN bytes long,
  840. ** respectively. 'BAlgorithm' is the CHAP algorithm code for either
  841. ** MS-CHAP or MD5.
  842. **
  843. ** Returns 0 if successful, or ERRORBADPACKET if the packet is
  844. ** misformatted in any way.
  845. */
  846. {
  847. BYTE cbIdentity;
  848. CHAR* pchIdentity;
  849. BYTE* pcbResponse;
  850. CHAR* pchResponse;
  851. WORD cbPacket;
  852. cbPacket = WireToHostFormat16( pReceiveBuf->Length );
  853. /* Extract the response.
  854. */
  855. if (cbPacket < PPP_CONFIG_HDR_LEN + 1)
  856. return ERRORBADPACKET;
  857. pcbResponse = pReceiveBuf->Data;
  858. pchResponse = pcbResponse + 1;
  859. ASSERT(MSRESPONSELEN<=255);
  860. ASSERT(MD5RESPONSELEN<=255);
  861. if ( ( ( ( bAlgorithm == PPP_CHAP_DIGEST_MSEXT ) ||
  862. ( bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW ) )
  863. && *pcbResponse != MSRESPONSELEN )
  864. || ( ( bAlgorithm == PPP_CHAP_DIGEST_MD5 )
  865. && ( *pcbResponse != MD5RESPONSELEN ) )
  866. || ( cbPacket < ( PPP_CONFIG_HDR_LEN + 1 + *pcbResponse ) ) )
  867. {
  868. return ERRORBADPACKET;
  869. }
  870. memcpy( pbResponse, pchResponse, *pcbResponse );
  871. /* Parse out username
  872. */
  873. pchIdentity = pchResponse + *pcbResponse;
  874. cbIdentity = (BYTE) (((BYTE* )pReceiveBuf) + cbPacket - pchIdentity);
  875. /* Extract the username.
  876. */
  877. ASSERT(cbIdentity<=(UNLEN+DNLEN+1));
  878. memcpy( pszIdentity, pchIdentity, cbIdentity );
  879. pszIdentity[ cbIdentity ] = '\0';
  880. return 0;
  881. }
  882. DWORD
  883. GetInfoFromChangePw1(
  884. IN PPP_CONFIG* pReceiveBuf,
  885. OUT CHANGEPW1* pchangepw1 )
  886. /* Loads caller's '*pchangepw' buffer with the information from the
  887. ** version 1 change password packet.
  888. **
  889. ** Returns 0 if successful, or ERRORBADPACKET if the packet is
  890. ** misformatted in any way.
  891. */
  892. {
  893. WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
  894. TRACE("GetInfoFromChangePw1...");
  895. if (cbPacket < ( PPP_CONFIG_HDR_LEN + sizeof(CHANGEPW1) ) )
  896. return ERRORBADPACKET;
  897. CopyMemory( pchangepw1, pReceiveBuf->Data, sizeof(CHANGEPW1) );
  898. TRACE("GetInfoFromChangePw done(0)");
  899. return 0;
  900. }
  901. DWORD
  902. GetInfoFromChangePw2(
  903. IN PPP_CONFIG* pReceiveBuf,
  904. OUT CHANGEPW2* pchangepw2,
  905. OUT BYTE* pResponse )
  906. /* Loads caller's '*pchangepw2' buffer with the information from the
  907. ** version 2 change password packet, and caller's 'pResponse' buffer with
  908. ** the challenge response data from 'pchangepw2'.
  909. **
  910. ** Returns 0 if successful, or ERRORBADPACKET if the packet is
  911. ** misformatted in any way.
  912. */
  913. {
  914. WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
  915. WORD wFlags;
  916. TRACE("GetInfoFromChangePw2...");
  917. if (cbPacket < ( PPP_CONFIG_HDR_LEN + sizeof(CHANGEPW2) ) )
  918. return ERRORBADPACKET;
  919. CopyMemory( pchangepw2, pReceiveBuf->Data, sizeof(CHANGEPW2) );
  920. CopyMemory( pResponse, pchangepw2->abLmResponse, LM_RESPONSE_LENGTH );
  921. CopyMemory( pResponse + LM_RESPONSE_LENGTH, pchangepw2->abNtResponse,
  922. NT_RESPONSE_LENGTH );
  923. wFlags = WireToHostFormat16( pchangepw2->abFlags );
  924. pResponse[ LM_RESPONSE_LENGTH + NT_RESPONSE_LENGTH ] =
  925. (wFlags & CPW2F_UseNtResponse);
  926. TRACE("GetInfoFromChangePw2 done(0)");
  927. return 0;
  928. }
  929. DWORD
  930. GetInfoFromChangePw3(
  931. IN PPP_CONFIG* pReceiveBuf,
  932. OUT CHANGEPW3* pchangepw3,
  933. OUT BYTE* pResponse )
  934. /* Loads caller's '*pchangepw3' buffer with the information from the
  935. ** version 3 change password packet, and caller's 'pResponse' buffer with
  936. ** the challenge response data from 'pchangepw3'.
  937. **
  938. ** Returns 0 if successful, or ERRORBADPACKET if the packet is
  939. ** misformatted in any way.
  940. */
  941. {
  942. WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
  943. WORD wFlags;
  944. TRACE("GetInfoFromChangePw3...");
  945. if ( cbPacket < ( PPP_CONFIG_HDR_LEN + sizeof( CHANGEPW3 ) ) )
  946. return ERRORBADPACKET;
  947. memcpy( pchangepw3, pReceiveBuf->Data, sizeof(CHANGEPW3) );
  948. memcpy( pResponse, pchangepw3->abPeerChallenge, 16 );
  949. memcpy( pResponse + 16, pchangepw3->abNTResponse, 16 );
  950. pResponse[ 16 + 16 ] = 0;
  951. TRACE("GetInfoFromChangePw3 done(0)");
  952. return 0;
  953. }
  954. VOID
  955. GetInfoFromFailure(
  956. IN CHAPWB* pwb,
  957. IN PPP_CONFIG* pReceiveBuf,
  958. OUT DWORD* pdwError,
  959. OUT BOOL* pfRetry,
  960. OUT DWORD* pdwVersion )
  961. /* Returns the RAS error number, retry flag, version number, and new
  962. ** challenge (sets challenge info in pwb) out of the Message portion of
  963. ** the Failure message buffer 'pReceiveBuf' or 0 if none. This call
  964. ** applies to Microsoft extended CHAP Failure messages only.
  965. **
  966. ** Format of the message text portion of the result is a string of any of
  967. ** the following separated by a space.
  968. **
  969. ** "E=dddddddddd"
  970. ** "R=b"
  971. ** "C=xxxxxxxxxxxxxxxx"
  972. ** "V=v"
  973. **
  974. ** where
  975. **
  976. ** 'dddddddddd' is the decimal error code (need not be 10 digits).
  977. **
  978. ** 'b' is a boolean flag <0/1> that is set if a retry is allowed.
  979. **
  980. ** 'xxxxxxxxxxxxxxxx' is 16-hex digits representing a new challenge to
  981. ** be used in place of the previous challenge + 23. This is useful
  982. ** for pass-thru authentication where server may be unable to deal
  983. ** with the implicit challenge. (Win95 guys requested it).
  984. **
  985. ** 'v' is a version code where 2 indicates NT 3.51 level support. 'v'
  986. ** is assumed 1, i.e. NT 3.5 level support, if missing.
  987. */
  988. {
  989. #define MAXINFOLEN 1500
  990. WORD cbPacket = WireToHostFormat16( pReceiveBuf->Length );
  991. WORD cbError;
  992. CHAR szBuf[ MAXINFOLEN + 2 ];
  993. CHAR* pszValue;
  994. TRACE("GetInfoFromFailure...");
  995. *pdwError = ERROR_AUTHENTICATION_FAILURE;
  996. *pfRetry = 0;
  997. *pdwVersion = 2;
  998. if (cbPacket <= PPP_CONFIG_HDR_LEN)
  999. return;
  1000. /* Copy message to double-NUL-terminated 'szBuf' for convenient safe
  1001. ** strstr value scanning. For convenience, we assume that information
  1002. ** appearing beyond 1500 bytes in the packet in not interesting.
  1003. */
  1004. cbError = min( cbPacket - PPP_CONFIG_HDR_LEN, MAXINFOLEN );
  1005. memcpy( szBuf, pReceiveBuf->Data, cbError );
  1006. szBuf[ cbError ] = szBuf[ cbError + 1 ] = '\0';
  1007. pszValue = strstr( szBuf, "E=" );
  1008. if (pszValue)
  1009. *pdwError = (DWORD )atol( pszValue + 2 );
  1010. *pfRetry = (strstr( szBuf, "R=1" ) != NULL);
  1011. pszValue = strstr( szBuf, "V=" );
  1012. if (pszValue)
  1013. *pdwVersion = (DWORD )atol( pszValue + 2 );
  1014. pszValue = strstr( szBuf, "C=" );
  1015. pwb->fNewChallengeProvided = (pszValue != NULL);
  1016. if (pwb->fNewChallengeProvided)
  1017. {
  1018. CHAR* pchIn = pszValue + 2;
  1019. CHAR* pchOut = (CHAR* )pwb->abChallenge;
  1020. INT i;
  1021. memset( pwb->abChallenge, '\0', sizeof(pwb->abChallenge) );
  1022. for (i = 0; i < pwb->cbChallenge + pwb->cbChallenge; ++i)
  1023. {
  1024. BYTE bHexCharValue = HexCharValue( *pchIn++ );
  1025. if (bHexCharValue == 0xFF)
  1026. break;
  1027. if (i & 1)
  1028. *pchOut++ += bHexCharValue;
  1029. else
  1030. *pchOut = bHexCharValue << 4;
  1031. }
  1032. TRACE1("'C=' challenge provided,bytes=%d...",pwb->cbChallenge);
  1033. DUMPB(pwb->abChallenge,pwb->cbChallenge);
  1034. }
  1035. TRACE3("GetInfoFromFailure done,e=%d,r=%d,v=%d",*pdwError,*pfRetry,*pdwVersion);
  1036. }
  1037. BYTE
  1038. HexCharValue(
  1039. IN CHAR ch )
  1040. /* Returns the integer value of hexidecimal character 'ch' or 0xFF if 'ch'
  1041. ** is not a hexidecimal character.
  1042. */
  1043. {
  1044. if (ch >= '0' && ch <= '9')
  1045. return (BYTE )(ch - '0');
  1046. else if (ch >= 'A' && ch <= 'F')
  1047. return (BYTE )(ch - 'A'+ 10);
  1048. else if (ch >= 'a' && ch <= 'f')
  1049. return (BYTE )(ch - 'a' + 10);
  1050. else
  1051. return 0xFF;
  1052. }
  1053. DWORD
  1054. MakeChallengeMessage(
  1055. IN CHAPWB* pwb,
  1056. OUT PPP_CONFIG* pSendBuf,
  1057. IN DWORD cbSendBuf )
  1058. /* Builds a Challenge packet in caller's 'pSendBuf' buffer. 'cbSendBuf'
  1059. ** is the length of caller's buffer. 'pwb' is the address of the work
  1060. ** buffer associated with the port.
  1061. */
  1062. {
  1063. DWORD dwErr;
  1064. WORD wLength;
  1065. BYTE* pcbChallenge;
  1066. BYTE* pbChallenge;
  1067. TRACE("MakeChallengeMessage...");
  1068. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT )
  1069. {
  1070. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+1+MSV1_0_CHALLENGE_LENGTH);
  1071. /* Fill in the challenge.
  1072. */
  1073. pwb->cbChallenge = (BYTE )MSV1_0_CHALLENGE_LENGTH;
  1074. if ((dwErr = GetChallenge( pwb->abChallenge )) != 0)
  1075. return dwErr;
  1076. }
  1077. else if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  1078. {
  1079. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+1+16);
  1080. /* Fill in the challenge.
  1081. */
  1082. pwb->cbChallenge = (BYTE )16;
  1083. if ((dwErr = (DWORD )GetChallenge( pwb->abChallenge )) != 0)
  1084. return dwErr;
  1085. if ((dwErr = (DWORD )GetChallenge( pwb->abChallenge+8 )) != 0)
  1086. return dwErr;
  1087. }
  1088. else
  1089. {
  1090. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+1+16);
  1091. /* Fill in the challenge.
  1092. */
  1093. pwb->cbChallenge = (BYTE )16;
  1094. if ((dwErr = GetChallenge( pwb->abChallenge )) != 0)
  1095. return dwErr;
  1096. GetSystemTimeAsFileTime( (FILETIME*)(pwb->abChallenge+8));
  1097. }
  1098. pcbChallenge = pSendBuf->Data;
  1099. *pcbChallenge = pwb->cbChallenge;
  1100. pbChallenge = pcbChallenge + 1;
  1101. CopyMemory( pbChallenge, pwb->abChallenge, pwb->cbChallenge );
  1102. //
  1103. // Insert local identifcation at the end of the challenge
  1104. //
  1105. strcpy( pbChallenge + pwb->cbChallenge, szComputerName );
  1106. /* Fill in the header.
  1107. */
  1108. pSendBuf->Code = (BYTE )CHAPCODE_Challenge;
  1109. pSendBuf->Id = pwb->bIdToSend;
  1110. wLength = (WORD )(PPP_CONFIG_HDR_LEN + 1
  1111. + pwb->cbChallenge + strlen( szComputerName) );
  1112. HostToWireFormat16( wLength, pSendBuf->Length );
  1113. DUMPB(pSendBuf,wLength);
  1114. return 0;
  1115. }
  1116. DWORD
  1117. MakeChangePw1Message(
  1118. IN CHAPWB* pwb,
  1119. OUT PPP_CONFIG* pSendBuf,
  1120. IN DWORD cbSendBuf )
  1121. /* Builds a ChangePw1 response packet in caller's 'pSendBuf' buffer.
  1122. ** 'cbSendBuf' is the length of caller's buffer. 'pwb' is the address of
  1123. ** the work buffer associated with the port.
  1124. **
  1125. ** Returns 0 if successful, or a non-0 error code.
  1126. */
  1127. {
  1128. DWORD dwErr;
  1129. WORD wPwLength;
  1130. TRACE("MakeChangePw1Message...");
  1131. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+sizeof(CHANGEPW1));
  1132. (void )cbSendBuf;
  1133. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  1134. {
  1135. return( ERROR_NOT_SUPPORTED );
  1136. }
  1137. if ( !( pwb->fConfigInfo & PPPCFG_UseLmPassword ) )
  1138. {
  1139. return( ERROR_NOT_SUPPORTED );
  1140. }
  1141. DecodePw( pwb->chSeed, pwb->szOldPassword );
  1142. DecodePw( pwb->chSeed, pwb->szPassword );
  1143. dwErr =
  1144. GetEncryptedOwfPasswordsForChangePassword(
  1145. pwb->szOldPassword,
  1146. pwb->szPassword,
  1147. (PLM_SESSION_KEY )pwb->abChallenge,
  1148. (PENCRYPTED_LM_OWF_PASSWORD )pwb->changepw.v1.abEncryptedLmOwfOldPw,
  1149. (PENCRYPTED_LM_OWF_PASSWORD )pwb->changepw.v1.abEncryptedLmOwfNewPw,
  1150. (PENCRYPTED_NT_OWF_PASSWORD )pwb->changepw.v1.abEncryptedNtOwfOldPw,
  1151. (PENCRYPTED_NT_OWF_PASSWORD )pwb->changepw.v1.abEncryptedNtOwfNewPw);
  1152. wPwLength = (UCHAR) strlen( pwb->szPassword );
  1153. EncodePw( pwb->chSeed, pwb->szOldPassword );
  1154. EncodePw( pwb->chSeed, pwb->szPassword );
  1155. if (dwErr != 0)
  1156. return dwErr;
  1157. HostToWireFormat16( wPwLength, pwb->changepw.v1.abPasswordLength );
  1158. HostToWireFormat16( CPW1F_UseNtResponse, pwb->changepw.v1.abFlags );
  1159. CopyMemory( pSendBuf->Data, &pwb->changepw.v1, sizeof(CHANGEPW1) );
  1160. /* Fill in the header.
  1161. */
  1162. pSendBuf->Code = (BYTE )CHAPCODE_ChangePw1;
  1163. pSendBuf->Id = pwb->bIdToSend;
  1164. HostToWireFormat16(
  1165. PPP_CONFIG_HDR_LEN + sizeof(CHANGEPW1), pSendBuf->Length );
  1166. TRACE("MakeChangePw1Message done(0)");
  1167. return 0;
  1168. }
  1169. DWORD
  1170. MakeChangePw2Message(
  1171. IN CHAPWB* pwb,
  1172. OUT PPP_CONFIG* pSendBuf,
  1173. IN DWORD cbSendBuf )
  1174. /* Builds a ChangePw2 response packet in caller's 'pSendBuf' buffer.
  1175. ** 'cbSendBuf' is the length of caller's buffer. 'pwb' is the address of
  1176. ** the work buffer associated with the port.
  1177. **
  1178. ** Returns 0 if successful, or a non-0 error code.
  1179. */
  1180. {
  1181. DWORD dwErr;
  1182. BOOLEAN fLmPresent;
  1183. BYTE fbUseNtResponse;
  1184. BYTE bRandomNumber[MSV1_0_CHALLENGE_LENGTH];
  1185. TRACE("MakeChangePw2Message...");
  1186. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+sizeof(CHANGEPW2));
  1187. (void )cbSendBuf;
  1188. DecodePw( pwb->chSeed, pwb->szOldPassword );
  1189. DecodePw( pwb->chSeed, pwb->szPassword );
  1190. dwErr =
  1191. GetEncryptedPasswordsForChangePassword2(
  1192. pwb->szOldPassword,
  1193. pwb->szPassword,
  1194. (SAMPR_ENCRYPTED_USER_PASSWORD* )
  1195. pwb->changepw.v2.abNewEncryptedWithOldNtOwf,
  1196. (ENCRYPTED_NT_OWF_PASSWORD* )
  1197. pwb->changepw.v2.abOldNtOwfEncryptedWithNewNtOwf,
  1198. (SAMPR_ENCRYPTED_USER_PASSWORD* )
  1199. pwb->changepw.v2.abNewEncryptedWithOldLmOwf,
  1200. (ENCRYPTED_NT_OWF_PASSWORD* )
  1201. pwb->changepw.v2.abOldLmOwfEncryptedWithNewNtOwf,
  1202. &fLmPresent );
  1203. if (dwErr == 0)
  1204. {
  1205. BOOL fEmptyUserName = (pwb->szUserName[ 0 ] == '\0');
  1206. pwb->fSessionKeysObtained = FALSE;
  1207. dwErr =
  1208. GetChallengeResponse(
  1209. g_dwTraceIdChap,
  1210. pwb->szUserName,
  1211. pwb->szPassword,
  1212. &pwb->Luid,
  1213. pwb->abChallenge,
  1214. ( pwb->fConfigInfo & PPPCFG_MachineAuthentication ),
  1215. pwb->changepw.v2.abLmResponse,
  1216. pwb->changepw.v2.abNtResponse,
  1217. &fbUseNtResponse,
  1218. (PBYTE )&pwb->keyLm,
  1219. (PBYTE )&pwb->keyUser );
  1220. if (dwErr == 0 && fEmptyUserName)
  1221. pwb->fSessionKeysObtained = TRUE;
  1222. }
  1223. EncodePw( pwb->chSeed, pwb->szOldPassword );
  1224. EncodePw( pwb->chSeed, pwb->szPassword );
  1225. if (dwErr != 0)
  1226. return dwErr;
  1227. if ( !( pwb->fConfigInfo & PPPCFG_UseLmPassword ) )
  1228. {
  1229. //
  1230. // Zero out all the LM password stuff since this has been cracked
  1231. //
  1232. ZeroMemory( pwb->changepw.v2.abNewEncryptedWithOldLmOwf,
  1233. sizeof( pwb->changepw.v2.abNewEncryptedWithOldLmOwf ) );
  1234. ZeroMemory( pwb->changepw.v2.abOldLmOwfEncryptedWithNewNtOwf,
  1235. sizeof( pwb->changepw.v2.abOldLmOwfEncryptedWithNewNtOwf ));
  1236. ZeroMemory( pwb->changepw.v2.abLmResponse,
  1237. sizeof( pwb->changepw.v2.abLmResponse ) );
  1238. HostToWireFormat16( CPW2F_UseNtResponse, pwb->changepw.v2.abFlags );
  1239. }
  1240. else
  1241. {
  1242. WORD wf = 0;
  1243. if (fLmPresent)
  1244. wf |= CPW2F_LmPasswordPresent;
  1245. if (fbUseNtResponse)
  1246. wf |= CPW2F_UseNtResponse;
  1247. HostToWireFormat16( wf, pwb->changepw.v2.abFlags );
  1248. }
  1249. memcpy( pSendBuf->Data, &pwb->changepw.v2, sizeof(CHANGEPW2) );
  1250. /* Fill in the header.
  1251. */
  1252. pSendBuf->Code = (BYTE )CHAPCODE_ChangePw2;
  1253. pSendBuf->Id = pwb->bIdToSend;
  1254. HostToWireFormat16(
  1255. PPP_CONFIG_HDR_LEN + sizeof(CHANGEPW2), pSendBuf->Length );
  1256. TRACE("MakeChangePw2Message done(0)");
  1257. return 0;
  1258. }
  1259. DWORD
  1260. MakeChangePw3Message(
  1261. IN CHAPWB* pwb,
  1262. OUT PPP_CONFIG* pSendBuf,
  1263. IN DWORD cbSendBuf,
  1264. IN BOOL fTimeout )
  1265. /* Builds a ChangePw3 response packet in caller's 'pSendBuf' buffer.
  1266. ** 'cbSendBuf' is the length of caller's buffer. 'pwb' is the address of
  1267. ** the work buffer associated with the port.
  1268. **
  1269. ** Returns 0 if successful, or a non-0 error code.
  1270. */
  1271. {
  1272. DWORD dwErr;
  1273. BOOLEAN fLmPresent;
  1274. BYTE fbUseNtResponse;
  1275. BYTE bRandomNumber[16];
  1276. SAMPR_ENCRYPTED_USER_PASSWORD abNewEncryptedWithOldLmOwf;
  1277. ENCRYPTED_NT_OWF_PASSWORD abOldLmOwfEncryptedWithNewNtOwf;
  1278. TRACE("MakeChangePw3Message...");
  1279. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+sizeof(CHANGEPW2));
  1280. (void )cbSendBuf;
  1281. DecodePw( pwb->chSeed, pwb->szOldPassword );
  1282. DecodePw( pwb->chSeed, pwb->szPassword );
  1283. dwErr =
  1284. GetEncryptedPasswordsForChangePassword2(
  1285. pwb->szOldPassword,
  1286. pwb->szPassword,
  1287. (SAMPR_ENCRYPTED_USER_PASSWORD* )
  1288. pwb->changepw.v3.abEncryptedPassword,
  1289. (ENCRYPTED_NT_OWF_PASSWORD* )
  1290. pwb->changepw.v3.abEncryptedHash,
  1291. &abNewEncryptedWithOldLmOwf,
  1292. &abOldLmOwfEncryptedWithNewNtOwf,
  1293. &fLmPresent );
  1294. if (dwErr == 0)
  1295. {
  1296. BOOL fEmptyUserName = (pwb->szUserName[ 0 ] == '\0');
  1297. A_SHA_CTX SHAContext;
  1298. BYTE SHADigest[A_SHA_DIGEST_LEN];
  1299. //
  1300. // Get 16 byte random number and generate a new challenge if this is
  1301. // not a timeout
  1302. //
  1303. if ( !fTimeout )
  1304. {
  1305. if ((dwErr = (DWORD )GetChallenge( bRandomNumber )) != 0)
  1306. return dwErr;
  1307. if ((dwErr = (DWORD )GetChallenge( bRandomNumber+8 )) != 0)
  1308. return dwErr;
  1309. }
  1310. else
  1311. {
  1312. CopyMemory( bRandomNumber,
  1313. pwb->changepw.v3.abPeerChallenge,
  1314. sizeof( bRandomNumber ) );
  1315. }
  1316. A_SHAInit( &SHAContext );
  1317. A_SHAUpdate( &SHAContext, bRandomNumber, sizeof( bRandomNumber ) );
  1318. A_SHAUpdate( &SHAContext, pwb->abChallenge, pwb->cbChallenge );
  1319. A_SHAUpdate( &SHAContext, pwb->szUserName, strlen(pwb->szUserName));
  1320. A_SHAFinal( &SHAContext, SHADigest );
  1321. CopyMemory( pwb->abComputedChallenge, SHADigest, 8 );
  1322. pwb->fSessionKeysObtained = FALSE;
  1323. dwErr =
  1324. GetChallengeResponse(
  1325. g_dwTraceIdChap,
  1326. pwb->szUserName,
  1327. pwb->szPassword,
  1328. &pwb->Luid,
  1329. pwb->abComputedChallenge,
  1330. ( pwb->fConfigInfo & PPPCFG_MachineAuthentication ),
  1331. pwb->changepw.v3.abPeerChallenge,
  1332. pwb->changepw.v3.abNTResponse,
  1333. &fbUseNtResponse,
  1334. (PBYTE )&pwb->keyLm,
  1335. (PBYTE )&pwb->keyUser );
  1336. if (dwErr == 0 && fEmptyUserName)
  1337. pwb->fSessionKeysObtained = TRUE;
  1338. }
  1339. EncodePw( pwb->chSeed, pwb->szOldPassword );
  1340. EncodePw( pwb->chSeed, pwb->szPassword );
  1341. if (dwErr != 0)
  1342. return dwErr;
  1343. ZeroMemory( pwb->changepw.v3.abPeerChallenge,
  1344. sizeof( pwb->changepw.v3.abPeerChallenge ) );
  1345. HostToWireFormat16( 0, pwb->changepw.v3.abFlags );
  1346. //
  1347. // We are doing new MS-CHAP so fill the LM response field with an
  1348. // 16 byte random number
  1349. //
  1350. CopyMemory( pwb->changepw.v3.abPeerChallenge,
  1351. bRandomNumber,
  1352. sizeof( bRandomNumber ));
  1353. //
  1354. // Also copy the NtResponse into pwb->abResponse since this will be
  1355. // used by the IsSuccessPakcetValid call.
  1356. //
  1357. CopyMemory( pwb->abResponse + LM_RESPONSE_LENGTH,
  1358. pwb->changepw.v3.abNTResponse,
  1359. NT_RESPONSE_LENGTH );
  1360. CopyMemory( pSendBuf->Data, &pwb->changepw.v3, sizeof( CHANGEPW3 ) );
  1361. /* Fill in the header.
  1362. */
  1363. pSendBuf->Code = (BYTE )CHAPCODE_ChangePw3;
  1364. pSendBuf->Id = pwb->bIdToSend;
  1365. HostToWireFormat16(
  1366. PPP_CONFIG_HDR_LEN + sizeof(CHANGEPW3), pSendBuf->Length );
  1367. TRACE("MakeChangePw3Message done(0)");
  1368. return 0;
  1369. }
  1370. DWORD
  1371. MakeResponseMessage(
  1372. IN CHAPWB* pwb,
  1373. OUT PPP_CONFIG* pSendBuf,
  1374. IN DWORD cbSendBuf,
  1375. IN BOOL fTimeout )
  1376. /* Builds a Response packet in caller's 'pSendBuf' buffer. 'cbSendBuf' is
  1377. ** the length of caller's buffer. 'pwb' is the address of the work
  1378. ** buffer associated with the port.
  1379. **
  1380. ** Returns 0 if successful, or a non-0 error code.
  1381. */
  1382. {
  1383. DWORD dwErr;
  1384. WORD wLength;
  1385. BYTE* pcbResponse;
  1386. BYTE* pbResponse;
  1387. CHAR* pszName;
  1388. CHAR szUserName[ UNLEN + 1 ] = {0};
  1389. TRACE("MakeResponseMessage...");
  1390. (void )cbSendBuf;
  1391. /* Fill in the response.
  1392. */
  1393. if ( ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT ) ||
  1394. ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW ) )
  1395. {
  1396. BYTE bRandomNumber[16];
  1397. BOOL fEmptyUserName = (pwb->szUserName[ 0 ] == '\0');
  1398. /* Microsoft extended CHAP.
  1399. */
  1400. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+1+MSRESPONSELEN+UNLEN+1+DNLEN);
  1401. ASSERT(MSRESPONSELEN<=255);
  1402. DecodePw( pwb->chSeed, pwb->szPassword );
  1403. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  1404. {
  1405. A_SHA_CTX SHAContext;
  1406. BYTE SHADigest[A_SHA_DIGEST_LEN];
  1407. szUserName[ 0 ] = '\0';
  1408. //
  1409. // If we do not have a username since we are dialing out using
  1410. // the windows' password we get the username now by doing an
  1411. // extra call to get challenge response
  1412. //
  1413. /*
  1414. if ( lstrlenA( pwb->szUserName ) == 0 &&
  1415. !(pwb->fConfigInfo & PPPCFG_MachineAuthentication)
  1416. )
  1417. */
  1418. if ( lstrlenA( pwb->szUserName ) == 0 )
  1419. {
  1420. BYTE abLmResponse[ LM_RESPONSE_LENGTH ];
  1421. BYTE abNtResponse[ NT_RESPONSE_LENGTH ];
  1422. BYTE bUseNtResponse;
  1423. LM_SESSION_KEY keyLm;
  1424. USER_SESSION_KEY keyUser;
  1425. dwErr =
  1426. GetChallengeResponse(
  1427. g_dwTraceIdChap,
  1428. szUserName,
  1429. pwb->szPassword,
  1430. &pwb->Luid,
  1431. pwb->abChallenge,
  1432. ( pwb->fConfigInfo & PPPCFG_MachineAuthentication ),
  1433. abLmResponse,
  1434. abNtResponse,
  1435. &bUseNtResponse,
  1436. (PBYTE )&keyLm,
  1437. (PBYTE )&keyUser );
  1438. if ( dwErr != NO_ERROR )
  1439. {
  1440. return( dwErr );
  1441. }
  1442. }
  1443. else
  1444. {
  1445. strncpy( szUserName, pwb->szUserName, UNLEN );
  1446. }
  1447. //
  1448. // Get 16 byte random number and generate a new challenge if this
  1449. // is not a timeout
  1450. //
  1451. if ( !fTimeout )
  1452. {
  1453. if ((dwErr = (DWORD )GetChallenge( bRandomNumber )) != 0)
  1454. {
  1455. return dwErr;
  1456. }
  1457. if ((dwErr = (DWORD )GetChallenge( bRandomNumber+8 )) != 0)
  1458. {
  1459. return dwErr;
  1460. }
  1461. }
  1462. else
  1463. {
  1464. CopyMemory( bRandomNumber,
  1465. pwb->abResponse,
  1466. sizeof(bRandomNumber) );
  1467. }
  1468. {
  1469. CHAR szUserNameWoDomain[ UNLEN + DNLEN + 2 ];
  1470. CHAR szDomain[ DNLEN + 1 ];
  1471. //
  1472. //This sucks but the only hacky way of
  1473. //doing it without major change... Must look at it for BC
  1474. //
  1475. ExtractUsernameAndDomain( szUserName,
  1476. szUserNameWoDomain,
  1477. szDomain );
  1478. A_SHAInit( &SHAContext );
  1479. A_SHAUpdate( &SHAContext, bRandomNumber, sizeof( bRandomNumber ) );
  1480. A_SHAUpdate( &SHAContext, pwb->abChallenge, pwb->cbChallenge );
  1481. A_SHAUpdate( &SHAContext, szUserNameWoDomain, strlen( szUserNameWoDomain));
  1482. A_SHAFinal( &SHAContext, SHADigest );
  1483. CopyMemory( pwb->abComputedChallenge, SHADigest, 8 );
  1484. }
  1485. }
  1486. pwb->fSessionKeysObtained = FALSE;
  1487. if ( fEmptyUserName )
  1488. {
  1489. szUserName[ 0 ] = '\0';
  1490. }
  1491. else
  1492. {
  1493. strncpy( szUserName, pwb->szUserName, UNLEN );
  1494. }
  1495. dwErr = GetChallengeResponse(
  1496. g_dwTraceIdChap,
  1497. szUserName,
  1498. pwb->szPassword,
  1499. &pwb->Luid,
  1500. ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  1501. ? pwb->abComputedChallenge
  1502. : pwb->abChallenge,
  1503. ( pwb->fConfigInfo & PPPCFG_MachineAuthentication ),
  1504. pwb->abResponse,
  1505. pwb->abResponse + LM_RESPONSE_LENGTH,
  1506. pwb->abResponse + LM_RESPONSE_LENGTH + NT_RESPONSE_LENGTH,
  1507. (PBYTE )&pwb->keyLm,
  1508. (PBYTE )&pwb->keyUser );
  1509. TRACE1("GetChallengeResponse=%d",dwErr);
  1510. //
  1511. //check to see if the domain name in the same as
  1512. //local computer name. If so strip it out
  1513. //
  1514. {
  1515. CHAR szUserNameWoDomain[ UNLEN + DNLEN + 2 ];
  1516. CHAR szDomain[ DNLEN + 1 ];
  1517. //
  1518. //This sucks but the only hacky way of
  1519. //doing it without major change... Must look at it for BC
  1520. //
  1521. ExtractUsernameAndDomain( szUserName,
  1522. szUserNameWoDomain,
  1523. szDomain );
  1524. //if the domain name is local machine name
  1525. //dont send it across.
  1526. if ( !lstrcmpi ( szDomain, szComputerName ) )
  1527. {
  1528. strncpy ( szUserName, szUserNameWoDomain, UNLEN );
  1529. }
  1530. //
  1531. //Also, if use winlogon is specified
  1532. //and we have a domain in the username,
  1533. //and domain in domain name then
  1534. //strip the domain in username
  1535. //
  1536. if ( fEmptyUserName ) //winlogon specified
  1537. {
  1538. if ( szDomain[0] != '\0' &&
  1539. pwb->szDomain[ 0 ] != '\0'
  1540. )
  1541. {
  1542. //
  1543. //we have a domain in username
  1544. //and a domain passed in by the user
  1545. //
  1546. strncpy ( szUserName, szUserNameWoDomain, UNLEN );
  1547. }
  1548. }
  1549. }
  1550. EncodePw( pwb->chSeed, pwb->szPassword );
  1551. if (dwErr != 0)
  1552. return dwErr;
  1553. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  1554. {
  1555. ZeroMemory( pwb->abResponse, LM_RESPONSE_LENGTH );
  1556. CopyMemory(pwb->abResponse, bRandomNumber, sizeof(bRandomNumber));
  1557. *(pwb->abResponse+LM_RESPONSE_LENGTH+NT_RESPONSE_LENGTH) = 0;
  1558. }
  1559. else
  1560. {
  1561. if ( !( pwb->fConfigInfo & PPPCFG_UseLmPassword ) )
  1562. {
  1563. //
  1564. // Zero out all the LM password stuff since this has been
  1565. // cracked
  1566. //
  1567. ZeroMemory( pwb->abResponse, LM_RESPONSE_LENGTH );
  1568. }
  1569. }
  1570. if (fEmptyUserName || pwb->fConfigInfo & PPPCFG_MachineAuthentication )
  1571. pwb->fSessionKeysObtained = TRUE;
  1572. pwb->cbResponse = MSRESPONSELEN;
  1573. }
  1574. else
  1575. {
  1576. /* MD5 CHAP.
  1577. */
  1578. MD5_CTX md5ctx;
  1579. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+1+MD5RESPONSELEN+UNLEN+1+DNLEN);
  1580. ASSERT(MD5RESPONSELEN<=255);
  1581. DecodePw( pwb->chSeed, pwb->szPassword );
  1582. MD5Init( &md5ctx );
  1583. MD5Update( &md5ctx, &pwb->bIdToSend, 1 );
  1584. MD5Update( &md5ctx, pwb->szPassword, strlen( pwb->szPassword ) );
  1585. MD5Update( &md5ctx, pwb->abChallenge, pwb->cbChallenge );
  1586. MD5Final( &md5ctx );
  1587. EncodePw( pwb->chSeed, pwb->szPassword );
  1588. pwb->cbResponse = MD5RESPONSELEN;
  1589. memcpy( pwb->abResponse, md5ctx.digest, MD5RESPONSELEN );
  1590. strncpy( szUserName, pwb->szUserName, UNLEN );
  1591. }
  1592. pcbResponse = pSendBuf->Data;
  1593. *pcbResponse = pwb->cbResponse;
  1594. pbResponse = pcbResponse + 1;
  1595. memcpy( pbResponse, pwb->abResponse, *pcbResponse );
  1596. /* Fill in the Name in domain\username format. When domain is "", no "\"
  1597. ** is sent (to facilitate connecting to foreign systems which use a simple
  1598. ** string identifier). Otherwise when username is "", the "\" is sent,
  1599. ** i.e. "domain\". This form will currently fail, but could be mapped to
  1600. ** some sort of "guest" access in the future.
  1601. */
  1602. pszName = pbResponse + *pcbResponse;
  1603. pszName[ 0 ] = '\0';
  1604. if (pwb->szDomain[ 0 ] != '\0')
  1605. {
  1606. strcpy( pszName, pwb->szDomain );
  1607. strcat( pszName, "\\" );
  1608. }
  1609. strcat( pszName, szUserName );
  1610. /* Fill in the header.
  1611. */
  1612. pSendBuf->Code = (BYTE )CHAPCODE_Response;
  1613. pSendBuf->Id = pwb->bIdToSend;
  1614. wLength =
  1615. (WORD )(PPP_CONFIG_HDR_LEN + 1 + *pcbResponse + strlen( pszName ));
  1616. HostToWireFormat16( wLength, pSendBuf->Length );
  1617. DUMPB(pSendBuf,wLength);
  1618. return 0;
  1619. }
  1620. VOID
  1621. ChapMakeResultMessage(
  1622. IN CHAPWB* pwb,
  1623. IN DWORD dwError,
  1624. IN BOOL fRetry,
  1625. OUT PPP_CONFIG* pSendBuf,
  1626. IN DWORD cbSendBuf )
  1627. /* Builds a result packet (Success or Failure) in caller's 'pSendBuf'
  1628. ** buffer. 'cbSendBuf' is the length of caller's buffer. 'dwError'
  1629. ** indicates whether a Success or Failure should be generated, and for
  1630. ** Failure the failure code to include. 'fRetry' indicates if the client
  1631. ** should be told he can retry.
  1632. **
  1633. ** Format of the message text portion of the result is:
  1634. **
  1635. ** "E=dddddddddd R=b C=xxxxxxxxxxxxxxxx V=v"
  1636. **
  1637. ** where
  1638. **
  1639. ** 'dddddddddd' is the decimal error code (need not be 10 digits).
  1640. **
  1641. ** 'b' is a boolean flag that is set if a retry is allowed.
  1642. **
  1643. ** 'xxxxxxxxxxxxxxxx' is 16 hex digits representing a new challenge
  1644. ** value.
  1645. **
  1646. ** 'v' is our version level supported, currently 2.
  1647. **
  1648. ** Note: C=xxxxxxxxxxxxxxxxx not currently provided on server-side. To
  1649. ** provide what's needed for this routine, add the following two
  1650. ** parameters to this routine and enable the #if 0 code.
  1651. **
  1652. ** IN BYTE* pNewChallenge,
  1653. ** IN DWORD cbNewChallenge,
  1654. */
  1655. {
  1656. CHAR* pchMsg;
  1657. WORD wLength;
  1658. CHAR* pszReplyMessage = NULL;
  1659. DWORD dwNumBytes;
  1660. DWORD dwExtraBytes;
  1661. RAS_AUTH_ATTRIBUTE* pAttribute;
  1662. ASSERT(cbSendBuf>=PPP_CONFIG_HDR_LEN+35);
  1663. /* Fill in the header and message. The message is only used if
  1664. ** unsuccessful in which case it is the decimal RAS error code in ASCII.
  1665. */
  1666. pSendBuf->Id = pwb->bIdToSend;
  1667. pchMsg = pSendBuf->Data;
  1668. if (dwError == 0)
  1669. {
  1670. pSendBuf->Code = CHAPCODE_Success;
  1671. if (pwb->bAlgorithm == PPP_CHAP_DIGEST_MD5)
  1672. {
  1673. wLength = PPP_CONFIG_HDR_LEN;
  1674. }
  1675. else if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT )
  1676. {
  1677. wLength = PPP_CONFIG_HDR_LEN;
  1678. }
  1679. else
  1680. {
  1681. wLength = PPP_CONFIG_HDR_LEN;
  1682. //
  1683. // Search for MS-CHAP2-Success attributes
  1684. //
  1685. pAttribute = RasAuthAttributeGetVendorSpecific(
  1686. 311,
  1687. 26,
  1688. pwb->pAttributesFromAuthenticator );
  1689. if ( ( pAttribute != NULL )
  1690. && ( ((BYTE*)(pAttribute->Value))[5] == 45 ) )
  1691. {
  1692. CopyMemory(pSendBuf->Data, (BYTE*)(pAttribute->Value) + 7, 42);
  1693. wLength += 42;
  1694. }
  1695. }
  1696. }
  1697. else
  1698. {
  1699. pSendBuf->Code = CHAPCODE_Failure;
  1700. if (pwb->bAlgorithm == PPP_CHAP_DIGEST_MD5)
  1701. {
  1702. wLength = PPP_CONFIG_HDR_LEN;
  1703. }
  1704. else
  1705. {
  1706. CHAR* psz = pchMsg;
  1707. strcpy( psz, "E=" );
  1708. psz += 2;
  1709. _ltoa( (long )dwError, (char* )psz, 10 );
  1710. psz = strchr( psz, '\0' );
  1711. strcat( psz,
  1712. (dwError != ERROR_PASSWD_EXPIRED && fRetry)
  1713. ? " R=1 " : " R=0 " );
  1714. psz = strchr( psz, '\0' );
  1715. //
  1716. // Search for MS-CHAP Error attributes
  1717. //
  1718. pAttribute = RasAuthAttributeGetVendorSpecific(
  1719. 311,
  1720. 2,
  1721. pwb->pAttributesFromAuthenticator );
  1722. if ( pAttribute != NULL )
  1723. {
  1724. //
  1725. // If one was sent then use the C= portion onwards in the
  1726. // response
  1727. //
  1728. CHAR chErrorBuffer[150];
  1729. CHAR* pszValue;
  1730. DWORD cbError = (DWORD)*(((PBYTE)(pAttribute->Value))+5);
  1731. //
  1732. // Leave one byte for NULL terminator
  1733. //
  1734. if ( cbError > sizeof( chErrorBuffer ) - 1 )
  1735. {
  1736. cbError = sizeof( chErrorBuffer ) - 1;
  1737. }
  1738. ZeroMemory( chErrorBuffer, sizeof( chErrorBuffer ) );
  1739. CopyMemory( chErrorBuffer,
  1740. (CHAR *)((PBYTE)(pAttribute->Value) + 7),
  1741. cbError );
  1742. if ( ( pszValue = strstr( chErrorBuffer, "C=" ) ) != NULL )
  1743. {
  1744. strcat( psz, pszValue );
  1745. }
  1746. else
  1747. {
  1748. if ( ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW ) &&
  1749. ( ( fRetry ) || ( dwError == ERROR_PASSWD_EXPIRED ) ) )
  1750. {
  1751. CHAR* pszHex = "0123456789ABCDEF";
  1752. INT i;
  1753. BYTE * pNewChallenge;
  1754. strcat( psz, "C=" );
  1755. if ( !(pwb->fNewChallengeProvided ) )
  1756. {
  1757. (DWORD )GetChallenge( pwb->abChallenge );
  1758. (DWORD )GetChallenge( pwb->abChallenge+8 );
  1759. pwb->fNewChallengeProvided = TRUE;
  1760. }
  1761. psz = strchr( psz, '\0' );
  1762. pNewChallenge = pwb->abChallenge;
  1763. for (i = 0; i < pwb->cbChallenge; ++i)
  1764. {
  1765. *psz++ = pszHex[ *pNewChallenge / 16 ];
  1766. *psz++ = pszHex[ *pNewChallenge % 16 ];
  1767. ++pNewChallenge;
  1768. }
  1769. *psz = '\0';
  1770. strcat( psz, " V=3" );
  1771. }
  1772. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT )
  1773. {
  1774. if (( pszValue=strstr( chErrorBuffer, "V=" ) ) != NULL )
  1775. {
  1776. strcat( psz, " " );
  1777. strcat( psz, pszValue );
  1778. }
  1779. }
  1780. }
  1781. }
  1782. else
  1783. {
  1784. if ( dwError == ERROR_PASSWD_EXPIRED )
  1785. {
  1786. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT )
  1787. {
  1788. strcat( psz, " V=2" );
  1789. }
  1790. else
  1791. {
  1792. strcat( psz, " V=3" );
  1793. }
  1794. psz = strchr( psz, '\0' );
  1795. }
  1796. }
  1797. wLength = (WORD)(PPP_CONFIG_HDR_LEN + strlen( pchMsg ));
  1798. }
  1799. }
  1800. pszReplyMessage = RasAuthAttributeGetConcatString(
  1801. raatReplyMessage, pwb->pAttributesFromAuthenticator,
  1802. &dwNumBytes );
  1803. if ( ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT )
  1804. || ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW ) )
  1805. {
  1806. //
  1807. // For the string "M="
  1808. //
  1809. dwExtraBytes = 2;
  1810. }
  1811. else
  1812. {
  1813. dwExtraBytes = 0;
  1814. }
  1815. if (NULL != pszReplyMessage)
  1816. {
  1817. if (wLength + dwNumBytes > cbSendBuf)
  1818. {
  1819. dwNumBytes = cbSendBuf - wLength;
  1820. }
  1821. if (wLength + dwNumBytes + dwExtraBytes > cbSendBuf)
  1822. {
  1823. if (dwNumBytes > dwExtraBytes)
  1824. {
  1825. //
  1826. // For the string "M="
  1827. //
  1828. dwNumBytes -= dwExtraBytes;
  1829. }
  1830. else
  1831. {
  1832. //
  1833. // If we cannot insert "M=", we will not insert the reply
  1834. // message.
  1835. //
  1836. dwNumBytes = 0;
  1837. }
  1838. }
  1839. if (dwNumBytes)
  1840. {
  1841. if (dwExtraBytes)
  1842. {
  1843. CopyMemory((BYTE*)pSendBuf + wLength, "M=", dwExtraBytes);
  1844. }
  1845. CopyMemory((BYTE*)pSendBuf + wLength + dwExtraBytes,
  1846. pszReplyMessage, dwNumBytes);
  1847. wLength += (WORD)(dwNumBytes + dwExtraBytes);
  1848. }
  1849. }
  1850. LocalFree(pszReplyMessage);
  1851. HostToWireFormat16( wLength, pSendBuf->Length );
  1852. DUMPB(pSendBuf,wLength);
  1853. }
  1854. DWORD
  1855. ChapSMakeMessage(
  1856. IN CHAPWB* pwb,
  1857. IN PPP_CONFIG* pReceiveBuf,
  1858. OUT PPP_CONFIG* pSendBuf,
  1859. IN DWORD cbSendBuf,
  1860. OUT PPPAP_RESULT* pResult,
  1861. IN PPPAP_INPUT* pInput )
  1862. /* Server side "make message" entry point. See RasCp interface
  1863. ** documentation.
  1864. */
  1865. {
  1866. DWORD dwErr = 0;
  1867. switch (pwb->state)
  1868. {
  1869. case CS_Initial:
  1870. {
  1871. TRACE("CS_Initial...");
  1872. pwb->bIdToSend = (BYTE)(pwb->dwInitialPacketId++);
  1873. pwb->bIdExpected = pwb->bIdToSend;
  1874. if ((dwErr = MakeChallengeMessage(
  1875. pwb, pSendBuf, cbSendBuf )) != 0)
  1876. {
  1877. return dwErr;
  1878. }
  1879. pResult->Action = APA_SendWithTimeout;
  1880. pwb->result.bIdExpected = pwb->bIdExpected;
  1881. pwb->state = CS_ChallengeSent;
  1882. break;
  1883. }
  1884. case CS_ChallengeSent:
  1885. case CS_Retry:
  1886. case CS_ChangePw:
  1887. {
  1888. TRACE1("CS_%s...",(pwb->state==CS_Retry)
  1889. ?"Retry"
  1890. :(pwb->state==CS_ChallengeSent)?"ChallengeSent":"ChangePw");
  1891. if (!pReceiveBuf)
  1892. {
  1893. //
  1894. // Ignore this event if in these states
  1895. //
  1896. if ( ( pInput != NULL ) && ( pInput->fAuthenticationComplete ) )
  1897. {
  1898. pResult->Action = APA_NoAction;
  1899. break;
  1900. }
  1901. if (pwb->state != CS_ChallengeSent)
  1902. {
  1903. ChapMakeResultMessage(
  1904. pwb, pwb->result.dwError, pwb->result.fRetry,
  1905. pSendBuf, cbSendBuf );
  1906. *pResult = pwb->result;
  1907. break;
  1908. }
  1909. /* Timeout waiting for a Response message. Send a new
  1910. ** Challenge.
  1911. */
  1912. pwb->state = CS_Initial;
  1913. return ChapSMakeMessage(
  1914. pwb, pReceiveBuf, pSendBuf, cbSendBuf, pResult, NULL );
  1915. }
  1916. if ((pwb->state == CS_ChangePw
  1917. && pReceiveBuf->Code != CHAPCODE_ChangePw1
  1918. && pReceiveBuf->Code != CHAPCODE_ChangePw2
  1919. && pReceiveBuf->Code != CHAPCODE_ChangePw3)
  1920. || (pwb->state != CS_ChangePw
  1921. && pReceiveBuf->Code != CHAPCODE_Response)
  1922. || pReceiveBuf->Id != pwb->bIdExpected)
  1923. {
  1924. /* Not the packet we're looking for, wrong code or sequence
  1925. ** number. Silently discard it.
  1926. */
  1927. TRACE2("Got ID %d when expecting %d",
  1928. pReceiveBuf->Id,pwb->bIdExpected);
  1929. pResult->Action = APA_NoAction;
  1930. break;
  1931. }
  1932. if (pwb->state == CS_ChangePw)
  1933. {
  1934. if (pReceiveBuf->Code == CHAPCODE_ChangePw1)
  1935. {
  1936. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  1937. {
  1938. return( ERROR_AUTHENTICATION_FAILURE );
  1939. }
  1940. /* Extract encrypted passwords and options from received
  1941. ** packet.
  1942. */
  1943. if ((dwErr = GetInfoFromChangePw1(
  1944. pReceiveBuf, &pwb->changepw.v1 )) != 0)
  1945. {
  1946. /* The packet is corrupt. Silently discard it.
  1947. */
  1948. TRACE("Corrupt packet");
  1949. pResult->Action = APA_NoAction;
  1950. break;
  1951. }
  1952. /* Change the user's password.
  1953. */
  1954. {
  1955. WORD wPwLen =
  1956. WireToHostFormat16(
  1957. pwb->changepw.v1.abPasswordLength );
  1958. WORD wFlags =
  1959. WireToHostFormat16( pwb->changepw.v1.abFlags )
  1960. & CPW1F_UseNtResponse;
  1961. if ( MakeChangePasswordV1RequestAttributes(
  1962. pwb,
  1963. pReceiveBuf->Id,
  1964. pwb->szUserName,
  1965. pwb->abChallenge,
  1966. (PENCRYPTED_LM_OWF_PASSWORD )
  1967. pwb->changepw.v1.abEncryptedLmOwfOldPw,
  1968. (PENCRYPTED_LM_OWF_PASSWORD )
  1969. pwb->changepw.v1.abEncryptedLmOwfNewPw,
  1970. (PENCRYPTED_NT_OWF_PASSWORD )
  1971. pwb->changepw.v1.abEncryptedNtOwfOldPw,
  1972. (PENCRYPTED_NT_OWF_PASSWORD )
  1973. pwb->changepw.v1.abEncryptedNtOwfNewPw,
  1974. wPwLen, wFlags,
  1975. pwb->cbChallenge,
  1976. pwb->abChallenge ) != NO_ERROR )
  1977. {
  1978. dwErr = pwb->result.dwError =
  1979. ERROR_CHANGING_PASSWORD;
  1980. }
  1981. *(pwb->abResponse + LM_RESPONSE_LENGTH +
  1982. NT_RESPONSE_LENGTH) = TRUE;
  1983. }
  1984. }
  1985. else if ( pReceiveBuf->Code == CHAPCODE_ChangePw2 )
  1986. {
  1987. /* Extract encrypted passwords and options from received
  1988. ** packet.
  1989. */
  1990. if ((dwErr = GetInfoFromChangePw2(
  1991. pReceiveBuf, &pwb->changepw.v2,
  1992. pwb->abResponse )) != 0)
  1993. {
  1994. /* The packet is corrupt. Silently discard it.
  1995. */
  1996. TRACE("Corrupt packet");
  1997. pResult->Action = APA_NoAction;
  1998. break;
  1999. }
  2000. if ( dwErr == NO_ERROR )
  2001. {
  2002. /* Change the user's password.
  2003. */
  2004. if ( MakeChangePasswordV2RequestAttributes(
  2005. pwb,
  2006. pReceiveBuf->Id,
  2007. pwb->szUserName,
  2008. (SAMPR_ENCRYPTED_USER_PASSWORD* )
  2009. pwb->changepw.v2.abNewEncryptedWithOldNtOwf,
  2010. (ENCRYPTED_NT_OWF_PASSWORD* )
  2011. pwb->changepw.v2.abOldNtOwfEncryptedWithNewNtOwf,
  2012. (SAMPR_ENCRYPTED_USER_PASSWORD* )
  2013. pwb->changepw.v2.abNewEncryptedWithOldLmOwf,
  2014. (ENCRYPTED_NT_OWF_PASSWORD* )
  2015. pwb->changepw.v2.abOldLmOwfEncryptedWithNewNtOwf,
  2016. pwb->cbChallenge,
  2017. pwb->abChallenge,
  2018. pwb->abResponse,
  2019. WireToHostFormat16( pwb->changepw.v2.abFlags )
  2020. ) != NO_ERROR )
  2021. {
  2022. dwErr = pwb->result.dwError =
  2023. ERROR_CHANGING_PASSWORD;
  2024. }
  2025. }
  2026. }
  2027. else if ( pReceiveBuf->Code == CHAPCODE_ChangePw3 )
  2028. {
  2029. /* Extract encrypted passwords and options from received
  2030. ** packet.
  2031. */
  2032. if ((dwErr = GetInfoFromChangePw3(
  2033. pReceiveBuf, &pwb->changepw.v3,
  2034. pwb->abResponse )) != 0)
  2035. {
  2036. /* The packet is corrupt. Silently discard it.
  2037. */
  2038. TRACE("Corrupt packet");
  2039. pResult->Action = APA_NoAction;
  2040. break;
  2041. }
  2042. /* Change the user's password.
  2043. */
  2044. if ( MakeChangePasswordV3RequestAttributes(
  2045. pwb,
  2046. pReceiveBuf->Id,
  2047. pwb->szUserName,
  2048. &pwb->changepw.v3,
  2049. pwb->cbChallenge,
  2050. pwb->abChallenge
  2051. ) != NO_ERROR )
  2052. {
  2053. dwErr = pwb->result.dwError = ERROR_CHANGING_PASSWORD;
  2054. }
  2055. }
  2056. else
  2057. {
  2058. /* The packet is corrupt. Silently discard it.
  2059. */
  2060. TRACE("Corrupt packet");
  2061. pResult->Action = APA_NoAction;
  2062. break;
  2063. }
  2064. if ( dwErr == 0 )
  2065. {
  2066. pResult->pUserAttributes = pwb->pUserAttributes;
  2067. pResult->Action = APA_Authenticate;
  2068. pwb->state = CS_WaitForAuthenticationToComplete1;
  2069. }
  2070. else
  2071. {
  2072. pwb->result.bIdExpected = pwb->bIdToSend = pwb->bIdExpected;
  2073. pwb->result.Action = APA_SendAndDone;
  2074. pwb->result.fRetry = FALSE;
  2075. pwb->state = CS_Done;
  2076. }
  2077. break;
  2078. }
  2079. else
  2080. {
  2081. /* Extract user's credentials from received packet.
  2082. */
  2083. if ((dwErr = GetCredentialsFromResponse(
  2084. pReceiveBuf, pwb->bAlgorithm,
  2085. pwb->szUserName, pwb->abResponse )) != 0)
  2086. {
  2087. if (dwErr == ERRORBADPACKET)
  2088. {
  2089. /* The packet is corrupt. Silently discard it.
  2090. */
  2091. TRACE("Corrupt packet");
  2092. pResult->Action = APA_NoAction;
  2093. break;
  2094. }
  2095. }
  2096. if ( ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT ) ||
  2097. ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW ) )
  2098. {
  2099. /* Update to the implied challenge if processing a retry.
  2100. */
  2101. if ( ( pwb->state == CS_Retry ) &&
  2102. ( !pwb->fNewChallengeProvided ) )
  2103. pwb->abChallenge[ 0 ] += 23;
  2104. /* Check user's credentials with the system, recording the
  2105. ** outcome in the work buffer in case the result packet
  2106. ** must be regenerated later.
  2107. */
  2108. if ((dwErr = MakeAuthenticationRequestAttributes(
  2109. pwb,
  2110. TRUE,
  2111. pwb->bAlgorithm,
  2112. pwb->szUserName,
  2113. pwb->abChallenge,
  2114. pwb->cbChallenge,
  2115. pwb->abResponse,
  2116. MSRESPONSELEN,
  2117. pReceiveBuf->Id )) != 0)
  2118. {
  2119. return dwErr;
  2120. }
  2121. }
  2122. else
  2123. {
  2124. /* Check user's credentials with the system, recording the
  2125. ** outcome in the work buffer in case the result packet
  2126. ** must be regenerated later.
  2127. */
  2128. if ((dwErr = MakeAuthenticationRequestAttributes(
  2129. pwb,
  2130. FALSE,
  2131. pwb->bAlgorithm,
  2132. pwb->szUserName,
  2133. pwb->abChallenge,
  2134. pwb->cbChallenge,
  2135. pwb->abResponse,
  2136. MD5RESPONSELEN,
  2137. pReceiveBuf->Id )) != 0)
  2138. {
  2139. return dwErr;
  2140. }
  2141. }
  2142. strcpy( pwb->result.szUserName, pwb->szUserName );
  2143. pResult->pUserAttributes = pwb->pUserAttributes;
  2144. pResult->Action = APA_Authenticate;
  2145. pwb->state = CS_WaitForAuthenticationToComplete2;
  2146. }
  2147. break;
  2148. }
  2149. case CS_WaitForAuthenticationToComplete1:
  2150. case CS_WaitForAuthenticationToComplete2:
  2151. {
  2152. if ( pInput != NULL )
  2153. {
  2154. if ( pInput->fAuthenticationComplete )
  2155. {
  2156. strcpy( pResult->szUserName, pwb->result.szUserName );
  2157. if ( pInput->dwAuthError != NO_ERROR )
  2158. {
  2159. return( pInput->dwAuthError );
  2160. }
  2161. }
  2162. else
  2163. {
  2164. pResult->Action = APA_NoAction;
  2165. break;
  2166. }
  2167. pwb->pAttributesFromAuthenticator =
  2168. pInput->pAttributesFromAuthenticator;
  2169. if ( pInput->dwAuthResultCode != NO_ERROR )
  2170. {
  2171. if ( ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT ) ||
  2172. ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW ) )
  2173. {
  2174. dwErr = GetErrorCodeFromAttributes( pwb );
  2175. if ( dwErr != NO_ERROR )
  2176. {
  2177. return( dwErr );
  2178. }
  2179. }
  2180. else
  2181. {
  2182. pwb->result.dwError = pInput->dwAuthResultCode;
  2183. }
  2184. }
  2185. else
  2186. {
  2187. pwb->result.dwError = NO_ERROR;
  2188. }
  2189. }
  2190. else
  2191. {
  2192. pResult->Action = APA_NoAction;
  2193. break;
  2194. }
  2195. if ( pwb->state == CS_WaitForAuthenticationToComplete1 )
  2196. {
  2197. pwb->result.bIdExpected = pwb->bIdToSend = pwb->bIdExpected;
  2198. pwb->result.Action = APA_SendAndDone;
  2199. pwb->result.fRetry = FALSE;
  2200. pwb->state = CS_Done;
  2201. }
  2202. else
  2203. {
  2204. pwb->bIdToSend = pwb->bIdExpected;
  2205. TRACE2("Result=%d,Tries=%d",pwb->result.dwError,
  2206. pwb->dwTriesLeft);
  2207. if (pwb->result.dwError == ERROR_PASSWD_EXPIRED)
  2208. {
  2209. pwb->fNewChallengeProvided = FALSE;
  2210. pwb->dwTriesLeft = 0;
  2211. ++pwb->bIdExpected;
  2212. pwb->result.bIdExpected = pwb->bIdExpected;
  2213. pwb->result.Action = APA_SendWithTimeout2;
  2214. pwb->result.fRetry = FALSE;
  2215. pwb->state = CS_ChangePw;
  2216. }
  2217. else if (pwb->bAlgorithm == PPP_CHAP_DIGEST_MD5
  2218. || pwb->result.dwError != ERROR_AUTHENTICATION_FAILURE
  2219. || pwb->dwTriesLeft == 0)
  2220. {
  2221. /* Passed or failed in a non-retry-able manner.
  2222. */
  2223. pwb->result.Action = APA_SendAndDone;
  2224. pwb->result.fRetry = FALSE;
  2225. pwb->state = CS_Done;
  2226. }
  2227. else
  2228. {
  2229. /* Retry-able failure.
  2230. */
  2231. pwb->fNewChallengeProvided = FALSE;
  2232. --pwb->dwTriesLeft;
  2233. ++pwb->bIdExpected;
  2234. pwb->result.bIdExpected = pwb->bIdExpected;
  2235. pwb->result.Action = APA_SendWithTimeout2;
  2236. pwb->result.fRetry = TRUE;
  2237. pwb->state = CS_Retry;
  2238. }
  2239. }
  2240. }
  2241. /* ...fall thru...
  2242. */
  2243. case CS_Done:
  2244. {
  2245. TRACE("CS_Done...");
  2246. //
  2247. // If we received a packet or the back-end authenticator completed
  2248. //
  2249. if ( ( pReceiveBuf != NULL ) ||
  2250. ( ( pInput != NULL ) && ( pInput->fAuthenticationComplete ) ) )
  2251. {
  2252. /* Build the Success or Failure packet. The same packet sent in
  2253. ** response to the first Response message with this ID is sent
  2254. ** regardless of any change in credentials (per CHAP spec).
  2255. */
  2256. ChapMakeResultMessage(
  2257. pwb, pwb->result.dwError,
  2258. pwb->result.fRetry, pSendBuf, cbSendBuf );
  2259. *pResult = pwb->result;
  2260. CopyMemory( pResult->abResponse,
  2261. pwb->abResponse+LM_RESPONSE_LENGTH,
  2262. NT_RESPONSE_LENGTH );
  2263. CopyMemory( pResult->abChallenge,
  2264. pwb->abChallenge,
  2265. sizeof( pResult->abChallenge ) );
  2266. break;
  2267. }
  2268. else
  2269. {
  2270. pResult->Action = APA_NoAction;
  2271. break;
  2272. }
  2273. }
  2274. }
  2275. return 0;
  2276. }
  2277. DWORD
  2278. StoreCredentials(
  2279. OUT CHAPWB* pwb,
  2280. IN PPPAP_INPUT* pInput )
  2281. /* Transfer credentials from 'pInput' format to 'pwb' format.
  2282. **
  2283. ** Returns 0 if successful, false otherwise.
  2284. */
  2285. {
  2286. /* Validate credential lengths. The credential strings will never be
  2287. ** NULL, but may be "".
  2288. */
  2289. if (strlen( pInput->pszUserName ) > UNLEN
  2290. || strlen( pInput->pszDomain ) > DNLEN
  2291. || strlen( pInput->pszPassword ) > PWLEN
  2292. || strlen( pInput->pszOldPassword ) > PWLEN)
  2293. {
  2294. return ERROR_INVALID_PARAMETER;
  2295. }
  2296. //
  2297. // If are doing MS-CHAP V2, then we need to parse the username field if no
  2298. // domain was supplied.
  2299. // Bug# 310113 RAS: "domain\username" syntax fails to authenticate
  2300. //
  2301. if ( pwb->bAlgorithm == PPP_CHAP_DIGEST_MSEXT_NEW )
  2302. {
  2303. //
  2304. // If there is no domain, then parse the username to see if it contains the
  2305. // domain field.
  2306. //
  2307. if ( strlen( pInput->pszDomain ) == 0 )
  2308. {
  2309. if ( ExtractUsernameAndDomain( pInput->pszUserName,
  2310. pwb->szUserName,
  2311. pwb->szDomain ) != NO_ERROR )
  2312. {
  2313. strcpy( pwb->szUserName, pInput->pszUserName );
  2314. strcpy( pwb->szDomain, pInput->pszDomain );
  2315. }
  2316. }
  2317. else
  2318. {
  2319. strcpy( pwb->szUserName, pInput->pszUserName );
  2320. strcpy( pwb->szDomain, pInput->pszDomain );
  2321. }
  2322. }
  2323. else
  2324. {
  2325. strcpy( pwb->szUserName, pInput->pszUserName );
  2326. strcpy( pwb->szDomain, pInput->pszDomain );
  2327. }
  2328. strcpy( pwb->szPassword, pInput->pszPassword );
  2329. strcpy( pwb->szOldPassword, pInput->pszOldPassword );
  2330. EncodePw( pwb->chSeed, pwb->szPassword );
  2331. EncodePw( pwb->chSeed, pwb->szOldPassword );
  2332. return 0;
  2333. }