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.

1318 lines
34 KiB

  1. /********************************************************************/
  2. /** Copyright(c) 1985-1998 Microsoft Corporation. **/
  3. /********************************************************************/
  4. //***
  5. //
  6. // Filename: radclnt.c
  7. //
  8. // Description: Main module of the RADIUS client
  9. //
  10. // History: Feb 11,1998 NarenG Created original version.
  11. //
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <lmcons.h>
  17. #include <lmapibuf.h>
  18. #include <lmaccess.h>
  19. #include <raserror.h>
  20. #include <time.h>
  21. #include <string.h>
  22. #include <rasauth.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <rtutils.h>
  26. #include <mprlog.h>
  27. #include <mprerror.h>
  28. #define INCL_RASAUTHATTRIBUTES
  29. #define INCL_HOSTWIRE
  30. #include <ppputil.h>
  31. #include "hmacmd5.h"
  32. #include "md5.h"
  33. #define ALLOCATE_GLOBALS
  34. #include "radclnt.h"
  35. //
  36. // Perfmon Counters
  37. //
  38. #pragma data_seg(".shdat")
  39. LONG g_cAuthReqSent = 0; // Auth Requests Sent
  40. LONG g_cAuthReqFailed = 0; // Auth Requests Failed
  41. LONG g_cAuthReqSucceded = 0; // Auth Requests Succeded
  42. LONG g_cAuthReqTimeout = 0; // Auth Requests timeouts
  43. LONG g_cAcctReqSent = 0; // Acct Requests Sent
  44. LONG g_cAcctBadPack = 0; // Acct Bad packets
  45. LONG g_cAcctReqSucceded = 0; // Acct Requests Succeded
  46. LONG g_cAcctReqTimeout = 0; // Acct Requests timeouts
  47. LONG g_cAuthBadPack = 0; // Auth Bad packets
  48. #pragma data_seg()
  49. //**
  50. //
  51. // Call: RasAuthProviderInitialize
  52. //
  53. // Returns: NO_ERROR - Success
  54. // Non-zero returns - Failure
  55. //
  56. // Description: Initialize all global parameters here.
  57. // Called up each process only once.
  58. // Each RAS_AuthInitialize should be matched with RAS_AuthTerminate
  59. //
  60. DWORD APIENTRY
  61. RasAuthProviderInitialize(
  62. IN RAS_AUTH_ATTRIBUTE * pServerAttributes,
  63. IN HANDLE hLogEvents,
  64. IN DWORD dwLoggingLevel
  65. )
  66. {
  67. WSADATA WSAData;
  68. DWORD dwErrorCode = NO_ERROR;
  69. do
  70. {
  71. if ( g_dwTraceID == INVALID_TRACEID )
  72. {
  73. g_dwTraceID = TraceRegister( TEXT("RADIUS") );
  74. }
  75. if ( g_hLogEvents == INVALID_HANDLE_VALUE )
  76. {
  77. g_hLogEvents = RouterLogRegister( TEXT("RemoteAccess") );
  78. }
  79. //
  80. // Init Winsock
  81. //
  82. if ( !fWinsockInitialized )
  83. {
  84. dwErrorCode = WSAStartup(MAKEWORD(1, 1), &WSAData);
  85. if ( dwErrorCode != ERROR_SUCCESS )
  86. {
  87. break;
  88. }
  89. fWinsockInitialized = TRUE;
  90. }
  91. //
  92. // Init Crypto
  93. //
  94. if ( !g_hCryptProv )
  95. {
  96. if (!CryptAcquireContext(
  97. &g_hCryptProv,
  98. 0,
  99. 0,
  100. PROV_RSA_FULL,
  101. CRYPT_VERIFYCONTEXT
  102. ))
  103. {
  104. dwErrorCode = GetLastError();
  105. break;
  106. }
  107. }
  108. if ( g_AuthServerListHead.Flink == NULL )
  109. {
  110. //
  111. // Load global list of RADIUS servers
  112. //
  113. InitializeRadiusServerList( TRUE );
  114. }
  115. dwErrorCode = LoadRadiusServers( TRUE );
  116. if ( dwErrorCode != ERROR_SUCCESS )
  117. {
  118. break;
  119. }
  120. }while( FALSE );
  121. if ( dwErrorCode != NO_ERROR )
  122. {
  123. RasAuthProviderTerminate();
  124. }
  125. return( dwErrorCode );
  126. }
  127. //**
  128. //
  129. // Call: RasAuthProviderTerminate
  130. //
  131. // Returns: NO_ERROR - Success
  132. // Non-zero returns - Failure
  133. //
  134. // Description: Cleanup for entire process
  135. // Called once per process
  136. //
  137. DWORD APIENTRY
  138. RasAuthProviderTerminate(
  139. VOID
  140. )
  141. {
  142. if ( g_AuthServerListHead.Flink != NULL )
  143. {
  144. FreeRadiusServerList( TRUE );
  145. }
  146. if ( fWinsockInitialized )
  147. {
  148. WSACleanup();
  149. fWinsockInitialized = FALSE;
  150. }
  151. if ( g_dwTraceID != INVALID_TRACEID )
  152. {
  153. TraceDeregister( g_dwTraceID );
  154. g_dwTraceID = INVALID_TRACEID;
  155. }
  156. if ( !g_hCryptProv )
  157. {
  158. CryptReleaseContext(g_hCryptProv, 0);
  159. g_hCryptProv = 0;
  160. }
  161. if ( g_hLogEvents != INVALID_HANDLE_VALUE )
  162. {
  163. RouterLogDeregister( g_hLogEvents );
  164. g_hLogEvents = INVALID_HANDLE_VALUE;
  165. }
  166. return( NO_ERROR );
  167. }
  168. //**
  169. //
  170. // Call: RasAuthProviderFreeAttributes
  171. //
  172. // Returns: NO_ERROR - Success
  173. // Non-zero returns - Failure
  174. //
  175. // Description:
  176. //
  177. DWORD APIENTRY
  178. RasAuthProviderFreeAttributes(
  179. IN RAS_AUTH_ATTRIBUTE * pAttributes
  180. )
  181. {
  182. RasAuthAttributeDestroy( pAttributes );
  183. return( NO_ERROR );
  184. }
  185. //**
  186. //
  187. // Call: RasAuthProviderAuthenticateUser
  188. //
  189. // Returns: NO_ERROR - Success
  190. // Non-zero returns - Failure
  191. //
  192. // Description: Takes a list of radius attributes and tries to authenticate
  193. // with a radius server.
  194. // INPUT: Array of RADIUS attributes RAS_AUTH_ATTRIBUTE[]
  195. // OUTPUT: Header packet followed by array of RADIUS attributes
  196. // RAS_AUTH_ATTRIBUTE[]
  197. //
  198. DWORD APIENTRY
  199. RasAuthProviderAuthenticateUser(
  200. IN RAS_AUTH_ATTRIBUTE * prgInAttributes,
  201. OUT RAS_AUTH_ATTRIBUTE ** pprgOutAttributes,
  202. OUT DWORD * lpdwResultCode
  203. )
  204. {
  205. DWORD dwError = NO_ERROR;
  206. BYTE bCode;
  207. BOOL fEapMessageReceived;
  208. RADIUS_TRACE("RasAuthenticateUser called");
  209. do
  210. {
  211. if (lpdwResultCode == NULL)
  212. {
  213. dwError = ERROR_INVALID_PARAMETER;
  214. break;
  215. }
  216. bCode = ptAccessRequest;
  217. if ((dwError = SendData2ServerWRetry( prgInAttributes,
  218. pprgOutAttributes,
  219. &bCode,
  220. atInvalid,
  221. &fEapMessageReceived )
  222. ) == NO_ERROR )
  223. {
  224. switch (bCode)
  225. {
  226. case ptAccessAccept:
  227. InterlockedIncrement( &g_cAuthReqSucceded );
  228. *lpdwResultCode = ERROR_SUCCESS;
  229. break;
  230. case ptAccessChallenge:
  231. if ( fEapMessageReceived )
  232. {
  233. *lpdwResultCode = ERROR_SUCCESS;
  234. }
  235. else
  236. {
  237. *lpdwResultCode = ERROR_AUTHENTICATION_FAILURE;
  238. }
  239. break;
  240. case ptAccessReject:
  241. InterlockedIncrement(&g_cAuthReqFailed);
  242. *lpdwResultCode = ERROR_AUTHENTICATION_FAILURE;
  243. break;
  244. default:
  245. InterlockedIncrement(&g_cAuthBadPack);
  246. *lpdwResultCode = ERROR_AUTHENTICATION_FAILURE;
  247. break;
  248. }
  249. }
  250. else
  251. {
  252. if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
  253. {
  254. InterlockedIncrement(&g_cAuthBadPack);
  255. }
  256. }
  257. }while( FALSE );
  258. return( dwError );
  259. }
  260. //**
  261. //
  262. // Call: RasAuthConfigChangeNotification
  263. //
  264. // Returns: NO_ERROR - Success
  265. // Non-zero returns - Failure
  266. //
  267. // Description: Reloads config information dynamically
  268. //
  269. DWORD APIENTRY
  270. RasAuthConfigChangeNotification(
  271. IN DWORD dwLoggingLevel
  272. )
  273. {
  274. DWORD dwError = NO_ERROR;
  275. RADIUS_TRACE("RasAuthConfigChangeNotification called");
  276. return( ReloadConfig( TRUE ) );
  277. }
  278. //**
  279. //
  280. // Call: RasAcctProviderInitialize
  281. //
  282. // Returns: NO_ERROR - Success
  283. // Non-zero returns - Failure
  284. //
  285. // Description: Do nothing since all the work is done by
  286. // RasAuthProviderInitialize
  287. //
  288. DWORD APIENTRY
  289. RasAcctProviderInitialize(
  290. IN RAS_AUTH_ATTRIBUTE * pServerAttributes,
  291. IN HANDLE hLogEvents,
  292. IN DWORD dwLoggingLevel
  293. )
  294. {
  295. WSADATA WSAData;
  296. DWORD dwErrorCode = NO_ERROR;
  297. do
  298. {
  299. if ( g_dwTraceID == INVALID_TRACEID )
  300. {
  301. g_dwTraceID = TraceRegister( TEXT("RADIUS") );
  302. }
  303. if ( g_hLogEvents == INVALID_HANDLE_VALUE )
  304. {
  305. g_hLogEvents = RouterLogRegister( TEXT("RemoteAccess") );
  306. }
  307. //
  308. // Init Winsock
  309. //
  310. if ( !fWinsockInitialized )
  311. {
  312. dwErrorCode = WSAStartup(MAKEWORD(1, 1), &WSAData);
  313. if ( dwErrorCode != ERROR_SUCCESS )
  314. {
  315. break;
  316. }
  317. fWinsockInitialized = TRUE;
  318. }
  319. //
  320. // Load global list of RADIUS servers
  321. //
  322. if ( g_AcctServerListHead.Flink == NULL )
  323. {
  324. InitializeRadiusServerList( FALSE );
  325. }
  326. //
  327. // Make a copy of the Server attributes
  328. //
  329. g_pServerAttributes = RasAuthAttributeCopy( pServerAttributes );
  330. if ( g_pServerAttributes == NULL )
  331. {
  332. dwErrorCode = GetLastError();
  333. break;
  334. }
  335. dwErrorCode = LoadRadiusServers( FALSE );
  336. if ( dwErrorCode != ERROR_SUCCESS )
  337. {
  338. break;
  339. }
  340. }while( FALSE );
  341. if ( dwErrorCode != ERROR_SUCCESS )
  342. {
  343. RasAuthProviderTerminate();
  344. }
  345. return( dwErrorCode );
  346. }
  347. //**
  348. //
  349. // Call: RasAcctProviderTerminate
  350. //
  351. // Returns: NO_ERROR - Success
  352. // Non-zero returns - Failure
  353. //
  354. // Description: Do nothing since all the work is done by
  355. // RasAuthProviderTerminate
  356. //
  357. DWORD APIENTRY
  358. RasAcctProviderTerminate(
  359. VOID
  360. )
  361. {
  362. if ( g_AcctServerListHead.Flink != NULL )
  363. {
  364. FreeRadiusServerList( FALSE );
  365. }
  366. if ( fWinsockInitialized )
  367. {
  368. WSACleanup();
  369. fWinsockInitialized = FALSE;
  370. }
  371. if ( g_pServerAttributes != NULL )
  372. {
  373. RasAuthAttributeDestroy( g_pServerAttributes );
  374. g_pServerAttributes = NULL;
  375. }
  376. if ( g_dwTraceID != INVALID_TRACEID )
  377. {
  378. TraceDeregister( g_dwTraceID );
  379. g_dwTraceID = INVALID_TRACEID;
  380. }
  381. if ( g_hLogEvents != INVALID_HANDLE_VALUE )
  382. {
  383. RouterLogDeregister( g_hLogEvents );
  384. g_hLogEvents = INVALID_HANDLE_VALUE;
  385. }
  386. return( NO_ERROR );
  387. }
  388. //**
  389. //
  390. // Call: RasAcctProviderFreeAttributes
  391. //
  392. // Returns: NO_ERROR - Success
  393. // Non-zero returns - Failure
  394. //
  395. // Description:
  396. //
  397. DWORD APIENTRY
  398. RasAcctProviderFreeAttributes(
  399. IN RAS_AUTH_ATTRIBUTE * pAttributes
  400. )
  401. {
  402. RasAuthAttributeDestroy( pAttributes );
  403. return( NO_ERROR );
  404. }
  405. //**
  406. //
  407. // Call: RasAcctProviderStartAccounting
  408. //
  409. // Returns: NO_ERROR - Success
  410. // Non-zero returns - Failure
  411. //
  412. // Description:
  413. //
  414. DWORD APIENTRY
  415. RasAcctProviderStartAccounting(
  416. IN RAS_AUTH_ATTRIBUTE *prgInAttributes,
  417. OUT RAS_AUTH_ATTRIBUTE **pprgOutAttributes
  418. )
  419. {
  420. DWORD dwError = NO_ERROR;
  421. BYTE bCode;
  422. BOOL fEapMessageReceived;
  423. RADIUS_TRACE("RasStartAccounting called");
  424. do
  425. {
  426. bCode = ptAccountingRequest;
  427. if ((dwError = SendData2ServerWRetry( prgInAttributes,
  428. pprgOutAttributes,
  429. &bCode,
  430. atStart,
  431. &fEapMessageReceived )
  432. ) == NO_ERROR )
  433. {
  434. if (bCode == ptAccountingResponse)
  435. {
  436. InterlockedIncrement(&g_cAcctReqSucceded);
  437. }
  438. else
  439. {
  440. InterlockedIncrement(&g_cAcctBadPack);
  441. }
  442. }
  443. else
  444. {
  445. if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
  446. {
  447. InterlockedIncrement(&g_cAcctBadPack);
  448. }
  449. }
  450. }while( FALSE );
  451. return( dwError );
  452. }
  453. //**
  454. //
  455. // Call: RasAcctProviderStopAccounting
  456. //
  457. // Returns: NO_ERROR - Success
  458. // Non-zero returns - Failure
  459. //
  460. // Description:
  461. //
  462. DWORD APIENTRY
  463. RasAcctProviderStopAccounting(
  464. IN RAS_AUTH_ATTRIBUTE *prgInAttributes,
  465. OUT RAS_AUTH_ATTRIBUTE **pprgOutAttributes
  466. )
  467. {
  468. DWORD dwError = NO_ERROR;
  469. BYTE bCode;
  470. BOOL fEapMessageReceived;
  471. RADIUS_TRACE("RasStopAccounting called");
  472. do
  473. {
  474. bCode = ptAccountingRequest;
  475. if ((dwError = SendData2ServerWRetry( prgInAttributes,
  476. pprgOutAttributes,
  477. &bCode,
  478. atStop,
  479. &fEapMessageReceived)
  480. ) == NO_ERROR )
  481. {
  482. if (bCode == ptAccountingResponse)
  483. {
  484. InterlockedIncrement(&g_cAcctReqSucceded);
  485. }
  486. else
  487. {
  488. InterlockedIncrement(&g_cAcctBadPack);
  489. }
  490. }
  491. else
  492. {
  493. if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
  494. {
  495. InterlockedIncrement(&g_cAcctBadPack);
  496. }
  497. }
  498. }while( FALSE );
  499. return( dwError );
  500. }
  501. //**
  502. //
  503. // Call: RasAcctProviderInterimAccounting
  504. //
  505. // Returns: NO_ERROR - Success
  506. // Non-zero returns - Failure
  507. //
  508. // Description:
  509. //
  510. DWORD APIENTRY
  511. RasAcctProviderInterimAccounting(
  512. IN RAS_AUTH_ATTRIBUTE *prgInAttributes,
  513. OUT RAS_AUTH_ATTRIBUTE **pprgOutAttributes
  514. )
  515. {
  516. DWORD dwError = NO_ERROR;
  517. BYTE bCode;
  518. BOOL fEapMessageReceived;
  519. RADIUS_TRACE("RasInterimAccounting called");
  520. do
  521. {
  522. bCode = ptAccountingRequest;
  523. if ((dwError = SendData2ServerWRetry( prgInAttributes,
  524. pprgOutAttributes,
  525. &bCode,
  526. atInterimUpdate,
  527. &fEapMessageReceived ))
  528. == NO_ERROR )
  529. {
  530. if ( bCode == ptAccountingResponse )
  531. {
  532. InterlockedIncrement( &g_cAcctReqSucceded );
  533. }
  534. else
  535. {
  536. InterlockedIncrement( &g_cAcctBadPack );
  537. }
  538. }
  539. else
  540. {
  541. if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
  542. {
  543. InterlockedIncrement( &g_cAcctBadPack );
  544. }
  545. }
  546. }while( FALSE );
  547. return( dwError );
  548. }
  549. //**
  550. //
  551. // Call: RasAcctConfigChangeNotification
  552. //
  553. // Returns: NO_ERROR - Success
  554. // Non-zero returns - Failure
  555. //
  556. // Description: Reloads config information dynamically
  557. //
  558. DWORD APIENTRY
  559. RasAcctConfigChangeNotification(
  560. IN DWORD dwLoggingLevel
  561. )
  562. {
  563. DWORD dwError = NO_ERROR;
  564. RADIUS_TRACE("RasAcctConfigChangeNotification called");
  565. return( ReloadConfig( FALSE ) );
  566. }
  567. //**
  568. //
  569. // Call: SendData2Server
  570. //
  571. // Returns: NO_ERROR - Success
  572. // Non-zero returns - Failure
  573. //
  574. // Description: Will do the real work of sending the Access/Accounting Request
  575. // packets to the server and receive the reponse back
  576. //
  577. DWORD
  578. SendData2Server(
  579. IN PRAS_AUTH_ATTRIBUTE prgInAttributes,
  580. OUT PRAS_AUTH_ATTRIBUTE * pprgOutAttributes,
  581. IN BYTE * pbCode,
  582. IN BYTE bSubCode,
  583. IN LONG lPacketID,
  584. IN DWORD dwRetryCount,
  585. OUT BOOL * pfEapMessageReceived
  586. )
  587. {
  588. SOCKET SockServer = INVALID_SOCKET;
  589. DWORD dwError = NO_ERROR;
  590. DWORD dwExtError = 0;
  591. DWORD dwNumAttributes = 0;
  592. do
  593. {
  594. BYTE szSendBuffer[MAXBUFFERSIZE];
  595. BYTE szRecvBuffer[MAXBUFFERSIZE];
  596. RADIUS_PACKETHEADER UNALIGNED * pSendHeader = NULL;
  597. RADIUS_PACKETHEADER UNALIGNED * pRecvHeader = NULL;
  598. BYTE UNALIGNED * pSignature = NULL;
  599. BYTE UNALIGNED * prgBuffer = NULL;
  600. INT AttrLength = 0;
  601. PRAS_AUTH_ATTRIBUTE pAttribute = NULL;
  602. RADIUS_ATTRIBUTE UNALIGNED * pRadiusAttribute;
  603. fd_set fdsSocketRead;
  604. RADIUSSERVER RadiusServer;
  605. MD5_CTX MD5c;
  606. DWORD dwLength = 0;
  607. if (prgInAttributes == NULL || pprgOutAttributes == NULL)
  608. {
  609. dwError = ERROR_INVALID_PARAMETER;
  610. break;
  611. }
  612. *pprgOutAttributes = NULL;
  613. //
  614. // Pick a RADIUS server
  615. //
  616. if ( ChooseRadiusServer( &RadiusServer,
  617. (*pbCode == ptAccessRequest )
  618. ? FALSE
  619. : TRUE,
  620. lPacketID ) == NULL )
  621. {
  622. dwError = ERROR_NO_RADIUS_SERVERS;
  623. break;
  624. }
  625. //
  626. // Set packet type to Access-Request
  627. //
  628. pSendHeader = (PRADIUS_PACKETHEADER)szSendBuffer;
  629. pSendHeader->bCode = *pbCode;
  630. pSendHeader->bIdentifier = RadiusServer.bIdentifier;
  631. pSendHeader->wLength = sizeof(RADIUS_PACKETHEADER);
  632. //
  633. // Set the request authenticator to a random value
  634. //
  635. //Bugid:507955 - need to do CryptGenRandom to get the Authenticator
  636. if (!CryptGenRandom(
  637. g_hCryptProv,
  638. MAX_AUTHENTICATOR,
  639. pSendHeader->rgAuthenticator
  640. ))
  641. {
  642. dwError = GetLastError();
  643. break;
  644. }
  645. #if 0
  646. srand( (unsigned)time( NULL ) );
  647. *((WORD*)(pSendHeader->rgAuthenticator)) = (WORD)rand();
  648. *((WORD*)(pSendHeader->rgAuthenticator+2)) = (WORD)rand();
  649. *((WORD*)(pSendHeader->rgAuthenticator+4)) = (WORD)rand();
  650. *((WORD*)(pSendHeader->rgAuthenticator+6)) = (WORD)rand();
  651. *((WORD*)(pSendHeader->rgAuthenticator+8)) = (WORD)rand();
  652. *((WORD*)(pSendHeader->rgAuthenticator+10)) = (WORD)rand();
  653. *((WORD*)(pSendHeader->rgAuthenticator+12)) = (WORD)rand();
  654. *((WORD*)(pSendHeader->rgAuthenticator+14)) = (WORD)rand();
  655. #endif
  656. //
  657. // Find length of all attribute values
  658. //
  659. pAttribute = prgInAttributes;
  660. prgBuffer = (PBYTE) (pSendHeader + 1);
  661. //
  662. // Convert Attributes to RADIUS format
  663. //
  664. dwError = Router2Radius( prgInAttributes,
  665. (RADIUS_ATTRIBUTE *) prgBuffer,
  666. &RadiusServer,
  667. pSendHeader,
  668. bSubCode,
  669. dwRetryCount,
  670. &pSignature,
  671. &dwLength );
  672. if ( dwError != NO_ERROR )
  673. {
  674. break;
  675. }
  676. pSendHeader->wLength += (WORD)dwLength;
  677. //
  678. // Convert length to network order
  679. //
  680. pSendHeader->wLength = htons( pSendHeader->wLength );
  681. //
  682. // set encryption block for accounting packets
  683. //
  684. if ( pSendHeader->bCode == ptAccountingRequest )
  685. {
  686. RadiusServer.IPAddress.sin_port =
  687. htons((SHORT)RadiusServer.AcctPort);
  688. ZeroMemory( pSendHeader->rgAuthenticator,
  689. sizeof(pSendHeader->rgAuthenticator));
  690. MD5Init( &MD5c );
  691. MD5Update( &MD5c, szSendBuffer, ntohs(pSendHeader->wLength ));
  692. MD5Update( &MD5c,
  693. (PBYTE) RadiusServer.szSecret,
  694. RadiusServer.cbSecret);
  695. MD5Final(&MD5c);
  696. CopyMemory( pSendHeader->rgAuthenticator,
  697. MD5c.digest,
  698. sizeof(pSendHeader->rgAuthenticator));
  699. }
  700. else
  701. {
  702. RadiusServer.IPAddress.sin_port =
  703. htons((SHORT) RadiusServer.AuthPort);
  704. }
  705. //
  706. // If a Signature field is present we need to sign it
  707. //
  708. if ( pSignature != NULL )
  709. {
  710. HmacContext HmacMD5c;
  711. BYTE MD5d[MD5_LEN];
  712. HmacMD5Init( &HmacMD5c,
  713. (PBYTE) RadiusServer.szSecret,
  714. RadiusServer.cbSecret);
  715. HmacMD5Update( &HmacMD5c,
  716. szSendBuffer,
  717. ntohs(pSendHeader->wLength) );
  718. HmacMD5Final( MD5d, &HmacMD5c );
  719. CopyMemory( (pSignature+2), MD5d, 16 );
  720. }
  721. //
  722. // Create a Datagram socket
  723. //
  724. SockServer = socket( AF_INET, SOCK_DGRAM, 0 );
  725. if ( SockServer == INVALID_SOCKET )
  726. {
  727. dwError = WSAGetLastError();
  728. RADIUS_TRACE1("Socket failed with error %d", dwError );
  729. break;
  730. }
  731. if ( RadiusServer.nboNASIPAddress != INADDR_NONE )
  732. {
  733. if ( bind( SockServer,
  734. (PSOCKADDR)&RadiusServer.NASIPAddress,
  735. sizeof(RadiusServer.NASIPAddress) ) == SOCKET_ERROR )
  736. {
  737. dwError = WSAGetLastError();
  738. RADIUS_TRACE1("Bind failed with error %d", dwError );
  739. break;
  740. }
  741. }
  742. if ( connect( SockServer,
  743. (PSOCKADDR)&RadiusServer.IPAddress,
  744. sizeof(RadiusServer.IPAddress) ) == SOCKET_ERROR )
  745. {
  746. dwError = WSAGetLastError();
  747. RADIUS_TRACE1("Connect failed with error %d", dwError );
  748. break;
  749. }
  750. RADIUS_TRACE("Sending packet to radius server");
  751. TraceSendPacket( szSendBuffer, ntohs( pSendHeader->wLength ) );
  752. //
  753. // Send packet if server doesn't respond within a give amount of time.
  754. //
  755. if ( send( SockServer,
  756. (PCSTR)szSendBuffer,
  757. ntohs(pSendHeader->wLength), 0) == SOCKET_ERROR )
  758. {
  759. dwError = GetLastError();
  760. break;
  761. }
  762. FD_ZERO(&fdsSocketRead);
  763. FD_SET(SockServer, &fdsSocketRead);
  764. if ( select( 0, &fdsSocketRead, NULL, NULL,
  765. RadiusServer.Timeout.tv_sec == 0
  766. ? NULL
  767. : &RadiusServer.Timeout ) < 1 )
  768. {
  769. //
  770. // Server didn't respond to any of the requests.
  771. // time to quit asking
  772. //
  773. ValidateRadiusServer(
  774. &RadiusServer,
  775. FALSE,
  776. !( pSendHeader->bCode == ptAccountingRequest ) );
  777. RADIUS_TRACE("Timeout: Radius server did not respond");
  778. dwError = ERROR_AUTH_SERVER_TIMEOUT;
  779. break;
  780. }
  781. AttrLength = recv( SockServer, (PSTR)szRecvBuffer, MAXBUFFERSIZE, 0 );
  782. if ( AttrLength == SOCKET_ERROR )
  783. {
  784. //
  785. // A response from the machine that the server is not
  786. // running at the designated port.
  787. //
  788. ValidateRadiusServer( &RadiusServer,
  789. FALSE,
  790. !(pSendHeader->bCode == ptAccountingRequest));
  791. RADIUS_TRACE( "Radius server not running at specifed IPaddr/port");
  792. dwError = ERROR_AUTH_SERVER_TIMEOUT;
  793. break;
  794. }
  795. //
  796. // Response received from server. First update the score for
  797. // this server
  798. //
  799. ValidateRadiusServer( &RadiusServer,
  800. TRUE,
  801. !( pSendHeader->bCode == ptAccountingRequest ));
  802. pRecvHeader = (PRADIUS_PACKETHEADER) szRecvBuffer;
  803. RADIUS_TRACE("Received packet from radius server");
  804. TraceRecvPacket(szRecvBuffer, ntohs(pRecvHeader->wLength));
  805. dwError = VerifyPacketIntegrity( AttrLength,
  806. pRecvHeader,
  807. pSendHeader,
  808. &RadiusServer,
  809. pRecvHeader->bCode,
  810. &dwExtError,
  811. &dwNumAttributes );
  812. if ( dwError == NO_ERROR )
  813. {
  814. //
  815. // Convert to Router attribute format
  816. //
  817. dwError = Radius2Router(
  818. pRecvHeader,
  819. &RadiusServer,
  820. (PBYTE)(pSendHeader->rgAuthenticator),
  821. dwNumAttributes,
  822. &dwExtError,
  823. pprgOutAttributes,
  824. pfEapMessageReceived );
  825. }
  826. if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
  827. {
  828. LPWSTR auditstrp[2];
  829. auditstrp[0] = RadiusServer.wszName;
  830. RadiusLogWarningString( ROUTERLOG_INVALID_RADIUS_RESPONSE,
  831. 1, auditstrp, dwExtError, 1 );
  832. dwError = ERROR_AUTH_SERVER_TIMEOUT;
  833. }
  834. else
  835. {
  836. *pbCode = pRecvHeader->bCode;
  837. }
  838. } while( FALSE );
  839. if ( SockServer != INVALID_SOCKET )
  840. {
  841. closesocket( SockServer );
  842. }
  843. return( dwError );
  844. }
  845. //**
  846. //
  847. // Call: VerifyPacketIntegrity
  848. //
  849. // Returns: NO_ERROR - Success
  850. // Non-zero returns - Failure
  851. //
  852. // Description:
  853. //
  854. DWORD
  855. VerifyPacketIntegrity(
  856. IN DWORD cbPacketLength,
  857. IN RADIUS_PACKETHEADER UNALIGNED * pRecvHeader,
  858. IN RADIUS_PACKETHEADER UNALIGNED * pSendHeader,
  859. IN RADIUSSERVER * pRadiusServer,
  860. IN BYTE bCode,
  861. OUT DWORD * pdwExtError,
  862. OUT DWORD * lpdwNumAttributes
  863. )
  864. {
  865. MD5_CTX MD5c;
  866. RADIUS_ATTRIBUTE UNALIGNED * prgRadiusWalker;
  867. LONG cbLengthOfRadiusAttributes;
  868. LONG cbLength;
  869. *pdwExtError = 0;
  870. *lpdwNumAttributes = 0;
  871. if ( ( cbPacketLength < 20 ) ||
  872. ( ntohs( pRecvHeader->wLength ) != cbPacketLength ) ||
  873. ( pRecvHeader->bIdentifier != pSendHeader->bIdentifier ) )
  874. {
  875. RADIUS_TRACE("Recvd packet with invalid length/Id from server");
  876. *pdwExtError = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  877. return( ERROR_INVALID_RADIUS_RESPONSE );
  878. }
  879. //
  880. // Convert length from network order
  881. //
  882. cbLength = ntohs( pRecvHeader->wLength ) - sizeof( RADIUS_PACKETHEADER );
  883. cbLengthOfRadiusAttributes = cbLength;
  884. prgRadiusWalker = (PRADIUS_ATTRIBUTE)(pRecvHeader + 1);
  885. //
  886. // Count the number of attributes to determine the size of the out
  887. // parameters table. The length of each attribute has to be at least 2.
  888. //
  889. while ( cbLengthOfRadiusAttributes > 1 )
  890. {
  891. (*lpdwNumAttributes)++;
  892. if ( prgRadiusWalker->bLength < 2 )
  893. {
  894. RADIUS_TRACE("Recvd packet with attribute of length less than 2");
  895. *pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
  896. return( ERROR_INVALID_RADIUS_RESPONSE );
  897. }
  898. if ( prgRadiusWalker->bLength > cbLengthOfRadiusAttributes )
  899. {
  900. RADIUS_TRACE("Recvd packet with attribute with illegal length ");
  901. *pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
  902. return( ERROR_INVALID_RADIUS_RESPONSE );
  903. }
  904. //
  905. // If this is Microsoft VSA then validate it and findout how many
  906. // subattributes there are
  907. //
  908. if ( ( prgRadiusWalker->bType == raatVendorSpecific ) &&
  909. ( prgRadiusWalker->bLength > 6 ) &&
  910. ( WireToHostFormat32( (PBYTE)(prgRadiusWalker+1) ) == 311 ) )
  911. {
  912. PBYTE pVSAWalker = (PBYTE)(prgRadiusWalker+1)+4;
  913. DWORD cbVSALength = prgRadiusWalker->bLength -
  914. sizeof( RADIUS_ATTRIBUTE ) - 4;
  915. (*lpdwNumAttributes)--;
  916. while( cbVSALength > 1 )
  917. {
  918. (*lpdwNumAttributes)++;
  919. if ( *(pVSAWalker+1) < 2 )
  920. {
  921. RADIUS_TRACE("VSA attribute has incorrect length");
  922. *pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
  923. return( ERROR_INVALID_RADIUS_RESPONSE );
  924. }
  925. if ( *(pVSAWalker+1) > cbVSALength )
  926. {
  927. RADIUS_TRACE("VSA attribute has incorrect length");
  928. *pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
  929. return( ERROR_INVALID_RADIUS_RESPONSE );
  930. }
  931. cbVSALength -= *(pVSAWalker+1);
  932. pVSAWalker += *(pVSAWalker+1);
  933. }
  934. if ( cbVSALength != 0 )
  935. {
  936. RADIUS_TRACE("VSA attribute has incorrect length");
  937. *pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
  938. return( ERROR_INVALID_RADIUS_RESPONSE );
  939. }
  940. }
  941. cbLengthOfRadiusAttributes -= prgRadiusWalker->bLength;
  942. prgRadiusWalker = (PRADIUS_ATTRIBUTE)
  943. (((PBYTE)prgRadiusWalker)+prgRadiusWalker->bLength);
  944. }
  945. if ( cbLengthOfRadiusAttributes != 0 )
  946. {
  947. RADIUS_TRACE("Received invalid packet from radius server");
  948. *pdwExtError = ERROR_INVALID_PACKET;
  949. return( ERROR_INVALID_RADIUS_RESPONSE );
  950. }
  951. RADIUS_TRACE1("Total number of Radius attributes returned = %d",
  952. *lpdwNumAttributes );
  953. switch( bCode )
  954. {
  955. case ptAccessReject:
  956. case ptAccessAccept:
  957. case ptAccessChallenge:
  958. case ptAccountingResponse:
  959. //
  960. // Validate response authenticator with request authenticator
  961. //
  962. MD5Init( &MD5c );
  963. //
  964. // Code+Id+Length of Response
  965. //
  966. MD5Update( &MD5c, (PBYTE)pRecvHeader, 4 );
  967. //
  968. // Request authenticator
  969. //
  970. MD5Update( &MD5c, (PBYTE)(pSendHeader->rgAuthenticator), 16 );
  971. //
  972. // Response attributes
  973. //
  974. MD5Update( &MD5c,
  975. (PBYTE)(pRecvHeader+1),
  976. ntohs(pRecvHeader->wLength)-sizeof(RADIUS_PACKETHEADER));
  977. //
  978. // Shared secret
  979. //
  980. MD5Update( &MD5c,
  981. (PBYTE)(pRadiusServer->szSecret),
  982. pRadiusServer->cbSecret );
  983. MD5Final(&MD5c);
  984. //
  985. // This must match the Response Authenticator
  986. //
  987. if ( memcmp( MD5c.digest, pRecvHeader->rgAuthenticator, 16 ) != 0 )
  988. {
  989. RADIUS_TRACE("Authenticator does not match.");
  990. *pdwExtError = ERROR_AUTHENTICATOR_MISMATCH;
  991. return( ERROR_INVALID_RADIUS_RESPONSE );
  992. }
  993. break;
  994. case ptStatusServer:
  995. case ptStatusClient:
  996. case ptAcctStatusType:
  997. default:
  998. RADIUS_TRACE("Received invalid packet from radius server");
  999. *pdwExtError = ERROR_INVALID_PACKET;
  1000. return( ERROR_INVALID_RADIUS_RESPONSE );
  1001. break;
  1002. }
  1003. return( NO_ERROR );
  1004. }
  1005. //**
  1006. //
  1007. // Call: SendData2ServerWRetry
  1008. //
  1009. // Returns: NO_ERROR - Success
  1010. // Non-zero returns - Failure
  1011. //
  1012. // Description:
  1013. //
  1014. DWORD
  1015. SendData2ServerWRetry(
  1016. IN PRAS_AUTH_ATTRIBUTE prgInAttributes,
  1017. OUT PRAS_AUTH_ATTRIBUTE *pprgOutAttributes,
  1018. OUT BYTE * pbCode,
  1019. IN BYTE bSubCode,
  1020. OUT BOOL * pfEapMessageReceived
  1021. )
  1022. {
  1023. DWORD dwError = NO_ERROR;
  1024. DWORD dwRetryCount = 0;
  1025. DWORD cRetries = ( bSubCode == atInvalid)
  1026. ? g_cAuthRetries
  1027. : g_cAcctRetries;
  1028. LONG lPacketID;
  1029. InterlockedIncrement( &g_lPacketID );
  1030. lPacketID = InterlockedExchange( &g_lPacketID, g_lPacketID );
  1031. while( cRetries-- > 0 )
  1032. {
  1033. switch( *pbCode )
  1034. {
  1035. case ptAccountingRequest:
  1036. InterlockedIncrement( &g_cAcctReqSent );
  1037. break;
  1038. case ptAccessRequest:
  1039. InterlockedIncrement( &g_cAuthReqSent );
  1040. break;
  1041. default:
  1042. break;
  1043. }
  1044. dwError = SendData2Server( prgInAttributes,
  1045. pprgOutAttributes,
  1046. pbCode,
  1047. bSubCode,
  1048. lPacketID,
  1049. dwRetryCount++,
  1050. pfEapMessageReceived );
  1051. if ( dwError != ERROR_AUTH_SERVER_TIMEOUT )
  1052. {
  1053. break;
  1054. }
  1055. switch( *pbCode )
  1056. {
  1057. case ptAccountingRequest:
  1058. InterlockedIncrement( &g_cAcctReqTimeout );
  1059. break;
  1060. case ptAccessRequest:
  1061. InterlockedIncrement( &g_cAuthReqTimeout );
  1062. break;
  1063. default:
  1064. break;
  1065. }
  1066. }
  1067. return( dwError );
  1068. }