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.

1494 lines
40 KiB

  1. /********************************************************************/
  2. /** Copyright(c) 1985-1998 Microsoft Corporation. **/
  3. /********************************************************************/
  4. //***
  5. //
  6. // Filename: radsrvrs.c
  7. //
  8. // Description: Routines to manipulate the radius server list
  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 <ntlsa.h>
  16. #include <ntmsv1_0.h>
  17. #include <windows.h>
  18. #include <lmcons.h>
  19. #include <lmapibuf.h>
  20. #include <lmaccess.h>
  21. #include <raserror.h>
  22. #include <string.h>
  23. #include <rasauth.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <rtutils.h>
  27. #include <mprlog.h>
  28. #include <mprerror.h>
  29. #define INCL_RASAUTHATTRIBUTES
  30. #define INCL_HOSTWIRE
  31. #include <ppputil.h>
  32. #include "md5.h"
  33. #include "radclnt.h"
  34. #include "rasman.h"
  35. #define STRSAFE_NO_DEPRECATE
  36. #include "strsafe.h"
  37. //**
  38. //
  39. // Call: InitializeRadiusServerList
  40. //
  41. // Returns: NO_ERROR - Success
  42. // Non-zero returns - Failure
  43. //
  44. // Description:
  45. //
  46. VOID
  47. InitializeRadiusServerList(
  48. IN BOOL fAuthentication
  49. )
  50. {
  51. if ( fAuthentication )
  52. {
  53. if ( g_AuthServerListHead.Flink == NULL )
  54. {
  55. InitializeListHead( &g_AuthServerListHead );
  56. InitializeCriticalSection( &g_csAuth );
  57. }
  58. }
  59. else
  60. {
  61. if ( g_AcctServerListHead.Flink == NULL )
  62. {
  63. InitializeListHead( &g_AcctServerListHead );
  64. InitializeCriticalSection( &g_csAcct );
  65. }
  66. }
  67. g_pszCurrentServer = NULL;
  68. g_pszCurrentAcctServer = NULL;
  69. }
  70. //**
  71. //
  72. // Call: FreeRadiusServerList
  73. //
  74. // Returns: NO_ERROR - Success
  75. // Non-zero returns - Failure
  76. //
  77. // Description:
  78. //
  79. VOID
  80. FreeRadiusServerList(
  81. IN BOOL fAuthentication
  82. )
  83. {
  84. RADIUSSERVER * pServer;
  85. CRITICAL_SECTION * pcs;
  86. LIST_ENTRY * pListHead;
  87. if ( fAuthentication )
  88. {
  89. pcs = &g_csAuth;
  90. pListHead = &g_AuthServerListHead;
  91. }
  92. else
  93. {
  94. pcs = &g_csAcct;
  95. pListHead = &g_AcctServerListHead;
  96. }
  97. EnterCriticalSection( pcs );
  98. if ( pListHead->Flink != NULL )
  99. {
  100. //
  101. // free all items in linked list
  102. //
  103. while( !IsListEmpty( pListHead ) )
  104. {
  105. pServer = (RADIUSSERVER *)RemoveHeadList( pListHead );
  106. if ( !fAuthentication )
  107. {
  108. //
  109. // Notify Accounting server of NAS going down
  110. //
  111. NotifyServer( FALSE, pServer );
  112. }
  113. LocalFree( pServer );
  114. }
  115. }
  116. LeaveCriticalSection( pcs );
  117. DeleteCriticalSection( pcs );
  118. if ( fAuthentication )
  119. {
  120. g_AuthServerListHead.Flink = NULL;
  121. g_AuthServerListHead.Blink = NULL;
  122. }
  123. else
  124. {
  125. g_AcctServerListHead.Flink = NULL;
  126. g_AcctServerListHead.Blink = NULL;
  127. }
  128. if(NULL != g_pszCurrentServer)
  129. {
  130. LocalFree(g_pszCurrentServer);
  131. g_pszCurrentServer = NULL;
  132. }
  133. if(NULL != g_pszCurrentAcctServer)
  134. {
  135. LocalFree(g_pszCurrentAcctServer);
  136. g_pszCurrentAcctServer = NULL;
  137. }
  138. }
  139. //**
  140. //
  141. // Call: RetrievePrivateData
  142. //
  143. // Returns: NO_ERROR - Success
  144. // Non-zero returns - Failure
  145. //
  146. // Description:
  147. //
  148. DWORD
  149. RetrievePrivateData(
  150. IN WCHAR *pwszServerName,
  151. OUT WCHAR *pwszSecret,
  152. IN DWORD cbSecretSize
  153. )
  154. {
  155. LSA_HANDLE hLSA = NULL;
  156. NTSTATUS ntStatus;
  157. LSA_OBJECT_ATTRIBUTES objectAttributes;
  158. LSA_UNICODE_STRING *pLSAPrivData;
  159. LSA_UNICODE_STRING LSAPrivDataDesc;
  160. WCHAR wszPrivData[MAX_PATH+1];
  161. WCHAR wszPrivDataDesc[MAX_PATH+1];
  162. WCHAR *pwszPrefix = L"RADIUSServer.";
  163. DWORD dwPrefixLen = wcslen(pwszPrefix);
  164. InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
  165. ntStatus = LsaOpenPolicy(NULL, &objectAttributes, POLICY_ALL_ACCESS, &hLSA);
  166. if ( !NT_SUCCESS( ntStatus) )
  167. {
  168. return( RtlNtStatusToDosError( ntStatus ) );
  169. }
  170. wcscpy(wszPrivDataDesc, pwszPrefix);
  171. wcsncat(wszPrivDataDesc, pwszServerName, MAX_PATH-dwPrefixLen);
  172. LSAPrivDataDesc.Length = (wcslen(wszPrivDataDesc) + 1) * sizeof(WCHAR);
  173. LSAPrivDataDesc.MaximumLength = sizeof(wszPrivDataDesc);
  174. LSAPrivDataDesc.Buffer = wszPrivDataDesc;
  175. ntStatus = LsaRetrievePrivateData(hLSA, &LSAPrivDataDesc, &pLSAPrivData);
  176. if ( !NT_SUCCESS( ntStatus ) )
  177. {
  178. LsaClose(hLSA);
  179. return( RtlNtStatusToDosError( ntStatus ) );
  180. }
  181. else
  182. {
  183. if ( pLSAPrivData )
  184. {
  185. ZeroMemory(pwszSecret, cbSecretSize);
  186. CopyMemory(pwszSecret,
  187. pLSAPrivData->Buffer,
  188. (pLSAPrivData->Length > cbSecretSize) ?
  189. cbSecretSize : pLSAPrivData->Length);
  190. LsaFreeMemory(pLSAPrivData);
  191. LsaClose(hLSA);
  192. }
  193. else
  194. {
  195. LsaClose(hLSA);
  196. //
  197. // API succeeded but did not return any private data
  198. //
  199. if ( ntStatus )
  200. {
  201. return ( RtlNtStatusToDosError(ntStatus) );
  202. }
  203. else
  204. return ERROR_INVALID_DATA;
  205. }
  206. }
  207. return( NO_ERROR );
  208. }
  209. //**
  210. //
  211. // Call: LoadRadiusServers
  212. //
  213. // Returns: NO_ERROR - Success
  214. // Non-zero returns - Failure
  215. //
  216. // Description:
  217. //
  218. DWORD
  219. LoadRadiusServers(
  220. IN BOOL fAuthenticationServers
  221. )
  222. {
  223. HKEY hKeyServers = NULL;
  224. HKEY hKeyServer = NULL;
  225. DWORD dwErrorCode;
  226. BOOL fValidServerFound = FALSE;
  227. do
  228. {
  229. DWORD dwKeyIndex, cbKeyServer, cbValue, dwType;
  230. CHAR szNASIPAddress[20];
  231. SHORT sPort;
  232. WCHAR wszKeyServer[MAX_PATH+1];
  233. CHAR szName[MAX_PATH+1];
  234. RADIUSSERVER RadiusServer;
  235. dwErrorCode = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  236. ( fAuthenticationServers )
  237. ? PSZAUTHRADIUSSERVERS
  238. : PSZACCTRADIUSSERVERS,
  239. 0,
  240. KEY_READ,
  241. &hKeyServers );
  242. if ( dwErrorCode != NO_ERROR )
  243. {
  244. break;
  245. }
  246. //
  247. // Get the retry value
  248. //
  249. cbValue = sizeof( DWORD );
  250. dwErrorCode = RegQueryValueEx( hKeyServers,
  251. PSZRETRIES,
  252. NULL,
  253. NULL,
  254. ( fAuthenticationServers )
  255. ? (PBYTE)&g_cAuthRetries
  256. : (PBYTE)&g_cAcctRetries,
  257. &cbValue );
  258. if ( dwErrorCode != NO_ERROR )
  259. {
  260. dwErrorCode = NO_ERROR;
  261. if ( fAuthenticationServers )
  262. {
  263. g_cAuthRetries = 2;
  264. }
  265. else
  266. {
  267. g_cAcctRetries = 2;
  268. }
  269. }
  270. dwKeyIndex = 0;
  271. cbKeyServer = sizeof(wszKeyServer)/sizeof(TCHAR);
  272. while( RegEnumKeyEx( hKeyServers,
  273. dwKeyIndex,
  274. wszKeyServer,
  275. &cbKeyServer,
  276. NULL,
  277. NULL,
  278. NULL,
  279. NULL ) == NO_ERROR )
  280. {
  281. dwErrorCode = RegOpenKeyEx( hKeyServers,
  282. wszKeyServer,
  283. 0,
  284. KEY_READ,
  285. &hKeyServer );
  286. if ( dwErrorCode != NO_ERROR )
  287. {
  288. break;
  289. }
  290. ZeroMemory( &RadiusServer, sizeof( RadiusServer ) );
  291. wcscpy( RadiusServer.wszName, wszKeyServer );
  292. RadiusServer.Timeout.tv_usec = 0;
  293. cbValue = sizeof( RadiusServer.Timeout.tv_sec );
  294. dwErrorCode = RegQueryValueEx( hKeyServer,
  295. PSZTIMEOUT,
  296. NULL,
  297. NULL,
  298. (PBYTE)&RadiusServer.Timeout.tv_sec,
  299. &cbValue );
  300. if ( dwErrorCode != NO_ERROR )
  301. {
  302. RadiusServer.Timeout.tv_sec = DEFTIMEOUT;
  303. }
  304. //
  305. // Secret Value is required
  306. //
  307. dwErrorCode = RetrievePrivateData(
  308. RadiusServer.wszName,
  309. RadiusServer.wszSecret,
  310. sizeof(WCHAR) * (MAX_PATH + 1));
  311. if ( dwErrorCode != NO_ERROR )
  312. {
  313. break;
  314. }
  315. RadiusServer.szSecret[0] = 0;
  316. WideCharToMultiByte( CP_ACP,
  317. 0,
  318. RadiusServer.wszSecret,
  319. -1,
  320. RadiusServer.szSecret,
  321. MAX_PATH,
  322. NULL,
  323. NULL );
  324. RadiusServer.cbSecret = lstrlenA(RadiusServer.szSecret);
  325. if ( fAuthenticationServers )
  326. {
  327. //
  328. // Get the SendSignature value
  329. //
  330. cbValue = sizeof( BOOL );
  331. dwErrorCode = RegQueryValueEx(
  332. hKeyServer,
  333. PSZSENDSIGNATURE,
  334. NULL,
  335. NULL,
  336. (PBYTE)&RadiusServer.fSendSignature,
  337. &cbValue );
  338. if ( dwErrorCode != NO_ERROR )
  339. {
  340. RadiusServer.fSendSignature = FALSE;
  341. }
  342. //
  343. // read in port numbers
  344. //
  345. cbValue = sizeof( RadiusServer.AuthPort );
  346. dwErrorCode = RegQueryValueEx(
  347. hKeyServer,
  348. PSZAUTHPORT,
  349. NULL,
  350. NULL,
  351. (PBYTE)&RadiusServer.AuthPort,
  352. &cbValue );
  353. if ( dwErrorCode != NO_ERROR )
  354. {
  355. RadiusServer.AuthPort = DEFAUTHPORT;
  356. }
  357. sPort = (SHORT)RadiusServer.AuthPort;
  358. }
  359. else
  360. {
  361. cbValue = sizeof(RadiusServer.AcctPort);
  362. dwErrorCode = RegQueryValueEx(
  363. hKeyServer,
  364. PSZACCTPORT,
  365. NULL,
  366. NULL,
  367. (PBYTE)&RadiusServer.AcctPort,
  368. &cbValue );
  369. if ( dwErrorCode != NO_ERROR )
  370. {
  371. RadiusServer.AcctPort = DEFACCTPORT;
  372. }
  373. sPort = (SHORT)RadiusServer.AcctPort;
  374. cbValue = sizeof( RadiusServer.fAccountingOnOff );
  375. dwErrorCode = RegQueryValueEx(
  376. hKeyServer,
  377. PSZENABLEACCTONOFF,
  378. NULL,
  379. NULL,
  380. (PBYTE)&RadiusServer.fAccountingOnOff,
  381. &cbValue );
  382. if ( dwErrorCode != NO_ERROR )
  383. {
  384. RadiusServer.fAccountingOnOff = TRUE;
  385. }
  386. }
  387. cbValue = sizeof( RadiusServer.cScore );
  388. dwErrorCode = RegQueryValueEx( hKeyServer,
  389. PSZSCORE,
  390. NULL,
  391. NULL,
  392. (PBYTE)&RadiusServer.cScore,
  393. &cbValue );
  394. if ( dwErrorCode != NO_ERROR )
  395. {
  396. RadiusServer.cScore = MAXSCORE;
  397. }
  398. //
  399. // See if we need to bind to a particular IP address. This is
  400. // useful if there are multiple NICs on the RAS server.
  401. //
  402. cbValue = sizeof( szNASIPAddress );
  403. dwErrorCode = RegQueryValueExA( hKeyServer,
  404. PSZNASIPADDRESS,
  405. NULL,
  406. &dwType,
  407. (PBYTE)szNASIPAddress,
  408. &cbValue );
  409. if ( ( dwErrorCode != NO_ERROR )
  410. || ( dwType != REG_SZ ) )
  411. {
  412. RadiusServer.nboNASIPAddress = INADDR_NONE;
  413. dwErrorCode = NO_ERROR;
  414. }
  415. else
  416. {
  417. RadiusServer.nboNASIPAddress = inet_addr(szNASIPAddress);
  418. RadiusServer.NASIPAddress.sin_family = AF_INET;
  419. RadiusServer.NASIPAddress.sin_port = 0;
  420. RadiusServer.NASIPAddress.sin_addr.S_un.S_addr =
  421. RadiusServer.nboNASIPAddress;
  422. }
  423. RadiusServer.nboBestIf = INADDR_NONE;
  424. //
  425. // Convert name to ip address.
  426. //
  427. szName[0] = 0;
  428. WideCharToMultiByte( CP_ACP,
  429. 0,
  430. RadiusServer.wszName,
  431. -1,
  432. szName,
  433. MAX_PATH,
  434. NULL,
  435. NULL );
  436. if ( inet_addr( szName ) == INADDR_NONE )
  437. {
  438. //
  439. // resolve name
  440. //
  441. struct hostent * phe = gethostbyname( szName );
  442. if ( phe != NULL )
  443. {
  444. //
  445. // host could have multiple addresses
  446. //
  447. DWORD iAddress = 0;
  448. while( phe->h_addr_list[iAddress] != NULL )
  449. {
  450. RadiusServer.IPAddress.sin_family = AF_INET;
  451. RadiusServer.IPAddress.sin_port = htons(sPort);
  452. RadiusServer.IPAddress.sin_addr.S_un.S_addr =
  453. *((PDWORD) phe->h_addr_list[iAddress]);
  454. if ( AddRadiusServerToList( &RadiusServer ,
  455. fAuthenticationServers )
  456. == NO_ERROR )
  457. {
  458. fValidServerFound = TRUE;
  459. }
  460. iAddress++;
  461. }
  462. }
  463. else
  464. {
  465. LPWSTR lpwsRadiusServerName = RadiusServer.wszName;
  466. RadiusLogWarning( ROUTERLOG_RADIUS_SERVER_NAME,
  467. 1, &lpwsRadiusServerName );
  468. }
  469. }
  470. else
  471. {
  472. //
  473. // use specified ip address
  474. //
  475. RadiusServer.IPAddress.sin_family = AF_INET;
  476. RadiusServer.IPAddress.sin_port = htons(sPort);
  477. RadiusServer.IPAddress.sin_addr.S_un.S_addr = inet_addr(szName);
  478. if ( AddRadiusServerToList(&RadiusServer,
  479. fAuthenticationServers) == NO_ERROR)
  480. {
  481. fValidServerFound = TRUE;
  482. }
  483. }
  484. RegCloseKey( hKeyServer );
  485. hKeyServer = NULL;
  486. dwKeyIndex ++;
  487. cbKeyServer = sizeof(wszKeyServer);
  488. }
  489. } while( FALSE );
  490. RegCloseKey( hKeyServers );
  491. RegCloseKey( hKeyServer );
  492. //
  493. // if no servers entries are found in registry return error code.
  494. //
  495. if ( ( !fValidServerFound ) && ( dwErrorCode == NO_ERROR ) )
  496. {
  497. dwErrorCode = ERROR_NO_RADIUS_SERVERS;
  498. }
  499. return( dwErrorCode );
  500. }
  501. //**
  502. //
  503. // Call: AddRadiusServerToList
  504. //
  505. // Returns: NO_ERROR - Success, Server Node added successfully
  506. // Non-zero returns - Failure,unsuccessfully in adding server node.
  507. //
  508. // Description: Adds a RADIUS server node into the linked list of avialable
  509. // servers.
  510. //
  511. // INPUT:
  512. // pRadiusServer - struct defining attributes for RADIUS server
  513. //
  514. DWORD
  515. AddRadiusServerToList(
  516. IN RADIUSSERVER * pRadiusServer,
  517. IN BOOL fAuthentication
  518. )
  519. {
  520. RADIUSSERVER * pNewServer;
  521. DWORD dwRetCode = NO_ERROR;
  522. CRITICAL_SECTION * pcs;
  523. LIST_ENTRY * pListHead;
  524. BOOL fServerFound = FALSE;
  525. if ( fAuthentication )
  526. {
  527. pcs = &g_csAuth;
  528. }
  529. else
  530. {
  531. pcs = &g_csAcct;
  532. }
  533. EnterCriticalSection( pcs );
  534. if ( fAuthentication )
  535. {
  536. pListHead = &g_AuthServerListHead;
  537. }
  538. else
  539. {
  540. pListHead = &g_AcctServerListHead;
  541. }
  542. //
  543. // First check to see if this server already exists in the list
  544. //
  545. if ( !IsListEmpty( pListHead ) )
  546. {
  547. RADIUSSERVER * pServer;
  548. for ( pServer = (RADIUSSERVER *)pListHead->Flink;
  549. pServer != (RADIUSSERVER *)pListHead;
  550. pServer = (RADIUSSERVER *)(pServer->ListEntry.Flink) )
  551. {
  552. if ( _wcsicmp( pServer->wszName, pRadiusServer->wszName ) == 0 )
  553. {
  554. pServer->fDelete = FALSE;
  555. fServerFound = TRUE;
  556. break;
  557. }
  558. }
  559. }
  560. //
  561. // If the server doesn't exist in the list, add it.
  562. //
  563. if ( !fServerFound )
  564. {
  565. //
  566. // Allocate space for node
  567. //
  568. pNewServer = (RADIUSSERVER *)LocalAlloc( LPTR, sizeof( RADIUSSERVER ) );
  569. if ( pNewServer == NULL )
  570. {
  571. dwRetCode = GetLastError();
  572. }
  573. else
  574. {
  575. //
  576. // Copy server data
  577. //
  578. *pNewServer = *pRadiusServer;
  579. //
  580. // Add node to linked list
  581. //
  582. InsertHeadList( pListHead, (LIST_ENTRY*)pNewServer );
  583. pNewServer->fDelete = FALSE;
  584. }
  585. }
  586. else
  587. {
  588. pNewServer = pRadiusServer;
  589. }
  590. //
  591. // Notify it if this is an accounting server and accounting is turned on.
  592. //
  593. if ( dwRetCode == NO_ERROR )
  594. {
  595. if ( !fAuthentication )
  596. {
  597. if ( !NotifyServer( TRUE, pNewServer ) )
  598. {
  599. dwRetCode = ERROR_NO_RADIUS_SERVERS;
  600. }
  601. }
  602. }
  603. LeaveCriticalSection( pcs );
  604. return( dwRetCode );
  605. }
  606. //**
  607. //
  608. // Call: ChooseRadiusServer
  609. //
  610. // Returns: NO_ERROR - Success
  611. // Non-zero returns - Failure
  612. //
  613. // Description: Selects a RADIUS server to send requests to based on the
  614. // servers with the highest score. If multiple server have the
  615. // same score they are selected in a roundrobin fashion.
  616. //
  617. // OUTPUT:
  618. // RADIUSSERVER *pServer - pointer to a struct defining
  619. // the server.
  620. //
  621. RADIUSSERVER *
  622. ChooseRadiusServer(
  623. IN RADIUSSERVER * pRadiusServer,
  624. IN BOOL fAccounting,
  625. IN LONG lPacketID
  626. )
  627. {
  628. RADIUSSERVER * pServer = NULL;
  629. CRITICAL_SECTION * pcs;
  630. LIST_ENTRY * pListHead;
  631. RADIUSSERVER * pCurrentServer;
  632. BOOL fAllScoresEqual = TRUE;
  633. DWORD dwNumServers = 0;
  634. LIST_ENTRY * ple;
  635. WCHAR ** ppszCurrentServer;
  636. RADIUSSERVER * pTempServer = NULL;
  637. if ( !fAccounting )
  638. {
  639. pcs = &g_csAuth;
  640. ppszCurrentServer = &g_pszCurrentServer;
  641. }
  642. else
  643. {
  644. pcs = &g_csAcct;
  645. ppszCurrentServer = &g_pszCurrentAcctServer;
  646. }
  647. EnterCriticalSection( pcs );
  648. if ( !fAccounting )
  649. {
  650. pListHead = &g_AuthServerListHead;
  651. }
  652. else
  653. {
  654. pListHead = &g_AcctServerListHead;
  655. }
  656. if ( IsListEmpty( pListHead ) )
  657. {
  658. LeaveCriticalSection( pcs );
  659. return( NULL );
  660. }
  661. pCurrentServer = (RADIUSSERVER *)(pListHead->Flink);
  662. //
  663. // Find server with highest score
  664. //
  665. for ( ple = pListHead->Flink;
  666. ple != pListHead;
  667. ple = ple->Flink)
  668. {
  669. pServer = CONTAINING_RECORD(ple, RADIUSSERVER, ListEntry);
  670. if( pCurrentServer->cScore != pServer->cScore)
  671. {
  672. fAllScoresEqual = FALSE;
  673. }
  674. if ( pCurrentServer->cScore < pServer->cScore )
  675. {
  676. pCurrentServer = pServer;
  677. }
  678. if( (NULL == pTempServer)
  679. && (NULL != *ppszCurrentServer)
  680. && (0 == _wcsicmp(*ppszCurrentServer, pServer->wszName)))
  681. {
  682. pTempServer = pServer;
  683. }
  684. dwNumServers += 1;
  685. }
  686. if( (fAllScoresEqual)
  687. && (dwNumServers > 1))
  688. {
  689. //
  690. // If all servers have the same score round-robin. We ignore when
  691. // list has only one server.
  692. //
  693. if(NULL != pTempServer)
  694. {
  695. pCurrentServer = (RADIUSSERVER *) pTempServer->ListEntry.Flink;
  696. }
  697. if(pCurrentServer == (RADIUSSERVER *)pListHead)
  698. {
  699. pCurrentServer = (RADIUSSERVER *) pCurrentServer->ListEntry.Flink;
  700. }
  701. RADIUS_TRACE("AllScoresEqual.");
  702. }
  703. pServer = pCurrentServer;
  704. //
  705. // Make a copy of the values & pass them back to the caller.
  706. // Increment unique packet id counter only if its an Accounting packet
  707. // or not a retry packet. If its an Accounting packet and a retry packet,
  708. // then we update AcctDelayTime; so Identifier must change.
  709. //
  710. if ( fAccounting
  711. || ( pServer->lPacketID != lPacketID ) )
  712. {
  713. pServer->bIdentifier++;
  714. }
  715. pServer->lPacketID = lPacketID;
  716. //
  717. // Retrieve the secret from lsa - it might have changed. In the absence
  718. // of a good notification mechanism from mmc, this is the best we can
  719. // do to not require a reboot of ras service when the secret is
  720. // changed.
  721. //
  722. if(NO_ERROR == RetrievePrivateData(
  723. pServer->wszName,
  724. pServer->wszSecret,
  725. sizeof(WCHAR) * (MAX_PATH + 1)))
  726. {
  727. pServer->szSecret[0] = 0;
  728. WideCharToMultiByte( CP_ACP,
  729. 0,
  730. pServer->wszSecret,
  731. -1,
  732. pServer->szSecret,
  733. MAX_PATH,
  734. NULL,
  735. NULL );
  736. pServer->cbSecret = lstrlenA(pServer->szSecret);
  737. RADIUS_TRACE("ChooseRadiusServer: updated secret");
  738. }
  739. *pRadiusServer = *pServer;
  740. pServer = pRadiusServer;
  741. if(pServer->nboNASIPAddress == INADDR_NONE)
  742. {
  743. DWORD retcode;
  744. DWORD dwMask;
  745. //
  746. // Get the best interface if there is no nboNASIPAddress
  747. // configured for this server
  748. //
  749. retcode = RasGetBestInterface(
  750. pServer->IPAddress.sin_addr.S_un.S_addr,
  751. &pServer->nboBestIf,
  752. &dwMask);
  753. RADIUS_TRACE2("ChooseRadiusServer: rc = 0x%x, BestIf=0x%x",
  754. retcode, pServer->nboBestIf);
  755. }
  756. if( (NULL == *ppszCurrentServer)
  757. || (0 != _wcsicmp(*ppszCurrentServer,pServer->wszName)))
  758. {
  759. LPWSTR auditstrp[1];
  760. if(NULL == *ppszCurrentServer)
  761. {
  762. *ppszCurrentServer = LocalAlloc(
  763. LPTR,
  764. (MAX_PATH+1) * sizeof(WCHAR));
  765. }
  766. if(NULL != *ppszCurrentServer)
  767. {
  768. if(!fAccounting)
  769. {
  770. //
  771. // This means radius server changed or we are choosing the
  772. // server for the first time. In both these cases log an event.
  773. //
  774. auditstrp[0] = pServer->wszName;
  775. RadiusLogInformation(
  776. ROUTERLOG_RADIUS_SERVER_CHANGED,
  777. 1,
  778. auditstrp);
  779. }
  780. wcscpy(*ppszCurrentServer,pServer->wszName);
  781. }
  782. }
  783. LeaveCriticalSection( pcs );
  784. RADIUS_TRACE2("Choosing RADIUS server %ws with score %d",
  785. pServer->wszName, pServer->cScore);
  786. return( pServer );
  787. }
  788. //**
  789. //
  790. // Call: GetPointerToServer
  791. //
  792. // Returns: NO_ERROR - Success
  793. // Non-zero returns - Failure
  794. //
  795. // Description:
  796. //
  797. RADIUSSERVER *
  798. GetPointerToServer(
  799. IN BOOL fAuthentication,
  800. IN LPWSTR lpwsName
  801. )
  802. {
  803. RADIUSSERVER * pServer = NULL;
  804. CRITICAL_SECTION * pcs;
  805. LIST_ENTRY * pListHead;
  806. BOOL fServerFound = FALSE;
  807. if ( fAuthentication )
  808. {
  809. pcs = &g_csAuth;
  810. }
  811. else
  812. {
  813. pcs = &g_csAcct;
  814. }
  815. EnterCriticalSection( pcs );
  816. if ( fAuthentication )
  817. {
  818. pListHead = &g_AuthServerListHead;
  819. }
  820. else
  821. {
  822. pListHead = &g_AcctServerListHead;
  823. }
  824. if ( IsListEmpty( pListHead ) )
  825. {
  826. LeaveCriticalSection( pcs );
  827. return( NULL );
  828. }
  829. for ( pServer = (RADIUSSERVER *)pListHead->Flink;
  830. pServer != (RADIUSSERVER *)pListHead;
  831. pServer = (RADIUSSERVER *)(pServer->ListEntry.Flink) )
  832. {
  833. if ( _wcsicmp( pServer->wszName, lpwsName ) == 0 )
  834. {
  835. fServerFound = TRUE;
  836. break;
  837. }
  838. }
  839. LeaveCriticalSection( pcs );
  840. if ( fServerFound )
  841. {
  842. return( pServer );
  843. }
  844. else
  845. {
  846. return( NULL );
  847. }
  848. }
  849. //**
  850. //
  851. // Call: ValidateRadiusServer
  852. //
  853. // Returns: None
  854. //
  855. // Description: Used to update the status of the RADIUS servers.
  856. // All servers start with a score of MAXSCORE
  857. // Every time a server responding the score is increased by
  858. // INCSCORE to a max of MAXSCORE. Every time a server fails to
  859. // respond the score is decreased by DECSCORE to a min of MINSCORE
  860. // Servers with the highest score are selected in a roundrobin
  861. // method for servers with equal score
  862. //
  863. // INPUT:
  864. // fResponding - Indicates if the server is responding or not
  865. //
  866. VOID
  867. ValidateRadiusServer(
  868. IN RADIUSSERVER * pServer,
  869. IN BOOL fResponding,
  870. IN BOOL fAuthentication
  871. )
  872. {
  873. RADIUSSERVER * pRadiusServer;
  874. CRITICAL_SECTION * pcs;
  875. if ( fAuthentication )
  876. {
  877. pcs = &g_csAuth;
  878. }
  879. else
  880. {
  881. pcs = &g_csAcct;
  882. }
  883. EnterCriticalSection( pcs );
  884. pRadiusServer = GetPointerToServer( fAuthentication, pServer->wszName );
  885. if ( pRadiusServer != NULL )
  886. {
  887. if ( fResponding )
  888. {
  889. pRadiusServer->cScore=min(MAXSCORE,pRadiusServer->cScore+INCSCORE);
  890. RADIUS_TRACE1("Incrementing score for RADIUS server %ws",
  891. pRadiusServer->wszName );
  892. }
  893. else
  894. {
  895. pRadiusServer->cScore=max(MINSCORE,pRadiusServer->cScore-DECSCORE);
  896. RADIUS_TRACE1("Decrementing score for RADIUS server %ws",
  897. pRadiusServer->wszName );
  898. }
  899. }
  900. LeaveCriticalSection( pcs );
  901. }
  902. //**
  903. //
  904. // Call: ReloadConfig
  905. //
  906. // Returns: NO_ERROR - Success
  907. // Non-zero returns - Failure
  908. //
  909. // Description: Used to dynamically reload configuration information of the
  910. // server lists.
  911. DWORD
  912. ReloadConfig(
  913. IN BOOL fAuthentication
  914. )
  915. {
  916. DWORD dwError = NO_ERROR;
  917. RADIUSSERVER * pServer = NULL;
  918. LIST_ENTRY * pListHead;
  919. CRITICAL_SECTION * pcs;
  920. if ( fAuthentication )
  921. {
  922. pcs = &g_csAuth;
  923. pListHead = &g_AuthServerListHead;
  924. }
  925. else
  926. {
  927. pcs = &g_csAcct;
  928. pListHead = &g_AcctServerListHead;
  929. }
  930. EnterCriticalSection( pcs );
  931. //
  932. // First mark all servers as to be deleted
  933. //
  934. for ( pServer = (RADIUSSERVER *)pListHead->Flink;
  935. pServer != (RADIUSSERVER *)pListHead;
  936. pServer = (RADIUSSERVER *)(pServer->ListEntry.Flink) )
  937. {
  938. pServer->fDelete = TRUE;
  939. }
  940. //
  941. // Now reload server list, don't return on error since we have to
  942. // cleanup the list of deleted servers first.
  943. //
  944. dwError = LoadRadiusServers( fAuthentication );
  945. //
  946. // Now delete the ones that are to be removed
  947. //
  948. pServer = (RADIUSSERVER *)pListHead->Flink;
  949. while( pServer != (RADIUSSERVER *)pListHead )
  950. {
  951. if ( pServer->fDelete )
  952. {
  953. RADIUSSERVER * pServerToBeDeleted = pServer;
  954. pServer = (RADIUSSERVER *)(pServer->ListEntry.Flink);
  955. RemoveEntryList( (LIST_ENTRY *)pServerToBeDeleted );
  956. if ( !fAuthentication )
  957. {
  958. NotifyServer( FALSE, pServerToBeDeleted );
  959. }
  960. LocalFree( pServerToBeDeleted );
  961. }
  962. else
  963. {
  964. pServer = (RADIUSSERVER *)(pServer->ListEntry.Flink);
  965. }
  966. }
  967. LeaveCriticalSection( pcs );
  968. return( dwError );
  969. }
  970. //**
  971. //
  972. // Call: NotifyServer
  973. //
  974. // Returns: NO_ERROR - Success
  975. // Non-zero returns - Failure
  976. //
  977. // Description: Notifies the specified RADIUS server of this device is starting
  978. // up or shuting down by sending Accounting Start/Stop records.
  979. // INPUT:
  980. // fStart - TRUE - Accounting Start
  981. // - FALSE - Accounting Stop
  982. //
  983. BOOL
  984. NotifyServer(
  985. IN BOOL fStart,
  986. IN RADIUSSERVER * pServer
  987. )
  988. {
  989. SOCKET SockServer = INVALID_SOCKET;
  990. DWORD dwError = NO_ERROR;
  991. BOOL fRadiusServerResponded = FALSE;
  992. do
  993. {
  994. RADIUS_PACKETHEADER UNALIGNED *pSendHeader;
  995. RADIUS_PACKETHEADER UNALIGNED *pRecvHeader;
  996. BYTE szSendBuffer[MAXBUFFERSIZE];
  997. BYTE szRecvBuffer[MAXBUFFERSIZE];
  998. BYTE UNALIGNED *prgBuffer;
  999. RADIUS_ATTRIBUTE UNALIGNED *pAttribute;
  1000. fd_set fdsSocketRead;
  1001. DWORD cRetries;
  1002. INT AttrLength;
  1003. RAS_AUTH_ATTRIBUTE * pServerAttribute;
  1004. //
  1005. // send start/stop records only to servers that have
  1006. // accounting On/Off set.
  1007. //
  1008. if ( !pServer->fAccountingOnOff )
  1009. {
  1010. fRadiusServerResponded = TRUE;
  1011. break;
  1012. }
  1013. pSendHeader = (PRADIUS_PACKETHEADER) szSendBuffer;
  1014. pSendHeader->bCode = ptAccountingRequest;
  1015. pSendHeader->bIdentifier = pServer->bIdentifier;
  1016. pSendHeader->wLength = sizeof(RADIUS_PACKETHEADER);
  1017. ZeroMemory( pSendHeader->rgAuthenticator,
  1018. sizeof(pSendHeader->rgAuthenticator));
  1019. //
  1020. // set attribute for accounting On/Off
  1021. //
  1022. pAttribute = (RADIUS_ATTRIBUTE *) (pSendHeader + 1);
  1023. pAttribute->bType = ptAcctStatusType;
  1024. pAttribute->bLength = sizeof(RADIUS_ATTRIBUTE) + sizeof(DWORD);
  1025. *((DWORD UNALIGNED *) (pAttribute + 1)) =
  1026. htonl(fStart == TRUE ? atAccountingOn : atAccountingOff);
  1027. pSendHeader->wLength += pAttribute->bLength;
  1028. //
  1029. // Set NAS IP address or Identifier attribute
  1030. //
  1031. pAttribute = (RADIUS_ATTRIBUTE *)( (PBYTE)pAttribute +
  1032. pAttribute->bLength );
  1033. pServerAttribute = RasAuthAttributeGet( raatNASIPAddress,
  1034. g_pServerAttributes );
  1035. if ( pServerAttribute != NULL )
  1036. {
  1037. pAttribute->bType = (BYTE)(pServerAttribute->raaType);
  1038. if ( pServer->nboNASIPAddress == INADDR_NONE )
  1039. {
  1040. HostToWireFormat32( PtrToUlong(pServerAttribute->Value),
  1041. (BYTE *)(pAttribute + 1) );
  1042. }
  1043. else
  1044. {
  1045. CopyMemory( (BYTE*)(pAttribute + 1),
  1046. (BYTE*)&(pServer->nboNASIPAddress),
  1047. sizeof( DWORD ) );
  1048. }
  1049. pAttribute->bLength = (BYTE) (sizeof( RADIUS_ATTRIBUTE ) +
  1050. pServerAttribute->dwLength);
  1051. pSendHeader->wLength += pAttribute->bLength;
  1052. pAttribute = (RADIUS_ATTRIBUTE *)( (PBYTE)pAttribute +
  1053. pAttribute->bLength );
  1054. }
  1055. else
  1056. {
  1057. pServerAttribute = RasAuthAttributeGet( raatNASIdentifier,
  1058. g_pServerAttributes );
  1059. if ( pServerAttribute != NULL )
  1060. {
  1061. pAttribute->bType = (BYTE)(pServerAttribute->raaType);
  1062. CopyMemory( (BYTE *)(pAttribute + 1),
  1063. (BYTE *)(pServerAttribute->Value),
  1064. pServerAttribute->dwLength );
  1065. pAttribute->bLength = (BYTE) (sizeof( RADIUS_ATTRIBUTE ) +
  1066. pServerAttribute->dwLength);
  1067. pSendHeader->wLength += pAttribute->bLength;
  1068. pAttribute = (RADIUS_ATTRIBUTE *)( (PBYTE)pAttribute +
  1069. pAttribute->bLength );
  1070. }
  1071. }
  1072. //
  1073. // Set Account session Id
  1074. //
  1075. pServerAttribute = RasAuthAttributeGet( raatAcctSessionId,
  1076. g_pServerAttributes );
  1077. if ( pServerAttribute != NULL )
  1078. {
  1079. pAttribute->bType = (BYTE)(pServerAttribute->raaType);
  1080. CopyMemory( (BYTE *)(pAttribute + 1),
  1081. (BYTE *)(pServerAttribute->Value),
  1082. pServerAttribute->dwLength );
  1083. pAttribute->bLength = (BYTE)(sizeof( RADIUS_ATTRIBUTE ) +
  1084. pServerAttribute->dwLength);
  1085. pSendHeader->wLength += pAttribute->bLength;
  1086. }
  1087. //
  1088. // convert to network order
  1089. //
  1090. pSendHeader->wLength = htons(pSendHeader->wLength);
  1091. //
  1092. // Set encryption block
  1093. //
  1094. {
  1095. MD5_CTX MD5c;
  1096. pServer->IPAddress.sin_port = htons((SHORT)(pServer->AcctPort));
  1097. ZeroMemory( pSendHeader->rgAuthenticator,
  1098. sizeof(pSendHeader->rgAuthenticator));
  1099. MD5Init(&MD5c);
  1100. MD5Update(&MD5c, szSendBuffer, ntohs(pSendHeader->wLength));
  1101. MD5Update(&MD5c, (PBYTE)pServer->szSecret, pServer->cbSecret);
  1102. MD5Final(&MD5c);
  1103. CopyMemory( pSendHeader->rgAuthenticator,
  1104. MD5c.digest,
  1105. sizeof(pSendHeader->rgAuthenticator));
  1106. }
  1107. //
  1108. // Create a Datagram socket
  1109. //
  1110. SockServer = socket(AF_INET, SOCK_DGRAM, 0);
  1111. if (SockServer == INVALID_SOCKET)
  1112. {
  1113. break;
  1114. }
  1115. if ( pServer->nboNASIPAddress != INADDR_NONE )
  1116. {
  1117. if ( bind( SockServer,
  1118. (PSOCKADDR)&pServer->NASIPAddress,
  1119. sizeof(pServer->NASIPAddress) ) == SOCKET_ERROR )
  1120. {
  1121. break;
  1122. }
  1123. }
  1124. if ( connect( SockServer,
  1125. (PSOCKADDR) &(pServer->IPAddress),
  1126. sizeof(pServer->IPAddress)) == SOCKET_ERROR)
  1127. {
  1128. break;
  1129. }
  1130. //
  1131. // Send packet if server doesn't respond within a give amount of
  1132. // time.
  1133. //
  1134. cRetries = g_cAcctRetries+1;
  1135. while( cRetries-- > 0 )
  1136. {
  1137. if ( send( SockServer,
  1138. (PCSTR) szSendBuffer,
  1139. ntohs(pSendHeader->wLength), 0) == SOCKET_ERROR)
  1140. {
  1141. break;
  1142. }
  1143. RADIUS_TRACE1("Sending Accounting request packet to server %ws",
  1144. pServer->wszName );
  1145. TraceSendPacket(szSendBuffer, ntohs(pSendHeader->wLength));
  1146. FD_ZERO(&fdsSocketRead);
  1147. FD_SET(SockServer, &fdsSocketRead);
  1148. if ( select( 0,
  1149. &fdsSocketRead,
  1150. NULL,
  1151. NULL,
  1152. ( pServer->Timeout.tv_sec == 0 )
  1153. ? NULL
  1154. : &(pServer->Timeout) ) < 1 )
  1155. {
  1156. if ( cRetries == 0 )
  1157. {
  1158. LPWSTR lpwsRadiusServerName = pServer->wszName;
  1159. //
  1160. // Server didn't respond to any of the requests.
  1161. // time to quit asking
  1162. //
  1163. RADIUS_TRACE1( "Timeout:Radius server %ws did not respond",
  1164. lpwsRadiusServerName );
  1165. if ( fStart )
  1166. {
  1167. RadiusLogWarning( ROUTERLOG_RADIUS_SERVER_NO_RESPONSE,
  1168. 1, &lpwsRadiusServerName );
  1169. }
  1170. dwError = ERROR_AUTH_SERVER_TIMEOUT;
  1171. break;
  1172. }
  1173. }
  1174. else
  1175. {
  1176. //
  1177. // Response received
  1178. //
  1179. break;
  1180. }
  1181. }
  1182. if ( dwError != NO_ERROR )
  1183. {
  1184. break;
  1185. }
  1186. AttrLength = recv( SockServer, (PSTR) szRecvBuffer, MAXBUFFERSIZE, 0 );
  1187. if ( AttrLength == SOCKET_ERROR )
  1188. {
  1189. LPWSTR lpwsRadiusServerName = pServer->wszName;
  1190. //
  1191. // Server didn't respond to any of the requests.
  1192. // time to quit asking
  1193. //
  1194. RADIUS_TRACE1( "Timeout:Radius server %ws did not respond",
  1195. lpwsRadiusServerName );
  1196. if ( fStart )
  1197. {
  1198. RadiusLogWarning( ROUTERLOG_RADIUS_SERVER_NO_RESPONSE,
  1199. 1, &lpwsRadiusServerName );
  1200. }
  1201. dwError = ERROR_AUTH_SERVER_TIMEOUT;
  1202. break;
  1203. }
  1204. //
  1205. // Got a response from a RADIUS server.
  1206. //
  1207. fRadiusServerResponded = TRUE;
  1208. pRecvHeader = (PRADIUS_PACKETHEADER) szRecvBuffer;
  1209. //
  1210. // Convert length from network order
  1211. //
  1212. pRecvHeader->wLength = ntohs(pRecvHeader->wLength);
  1213. //
  1214. // Ignore return packet
  1215. //
  1216. RADIUS_TRACE1("Response received from server %ws", pServer->wszName);
  1217. TraceRecvPacket(szRecvBuffer, pRecvHeader->wLength );
  1218. } while( FALSE );
  1219. if ( SockServer != INVALID_SOCKET )
  1220. {
  1221. closesocket( SockServer );
  1222. SockServer = INVALID_SOCKET;
  1223. }
  1224. return( fRadiusServerResponded );
  1225. }