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.

507 lines
13 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // radproxy.h
  8. //
  9. // SYNOPSIS
  10. //
  11. // Declares the interface into the reusable RadiusProxy engine. This should
  12. // have no IAS specific dependencies.
  13. //
  14. // MODIFICATION HISTORY
  15. //
  16. // 02/08/2000 Original version.
  17. // 05/30/2000 Eliminate QUESTIONABLE state.
  18. //
  19. ///////////////////////////////////////////////////////////////////////////////
  20. #ifndef RADPROXY_H
  21. #define RADPROXY_H
  22. #if _MSC_VER >= 1000
  23. #pragma once
  24. #endif
  25. #include <iascache.h>
  26. #include <iasobj.h>
  27. #include <radshare.h>
  28. #include <timerq.h>
  29. #include <udpsock.h>
  30. struct RadiusAttribute;
  31. struct RadiusPacket;
  32. class Request;
  33. class Session;
  34. ///////////////////////////////////////////////////////////////////////////////
  35. //
  36. // CLASS
  37. //
  38. // RemotePort
  39. //
  40. // DESCRIPTION
  41. //
  42. // Describes a remote endpoint for a RADIUS conversation.
  43. //
  44. ///////////////////////////////////////////////////////////////////////////////
  45. class RemotePort
  46. {
  47. public:
  48. // Read-only properties.
  49. const InternetAddress address;
  50. const RadiusOctets secret;
  51. RemotePort(
  52. ULONG ipAddress,
  53. USHORT port,
  54. PCSTR sharedSecret
  55. );
  56. RemotePort(const RemotePort& port);
  57. // Returns a packet identifier to use when sending a request to this port.
  58. BYTE getIdentifier() throw ()
  59. { return (BYTE)++nextIdentifier; }
  60. // Synchronizes this with the state of 'port', i.e., use the same next
  61. // identifier.
  62. void copyState(const RemotePort& port) throw ()
  63. { nextIdentifier = port.nextIdentifier; }
  64. bool operator==(const RemotePort& p) const throw ()
  65. { return address == p.address && secret == p.secret; }
  66. private:
  67. Count nextIdentifier;
  68. // Not implemented.
  69. RemotePort& operator=(RemotePort&);
  70. };
  71. ///////////////////////////////////////////////////////////////////////////////
  72. //
  73. // struct
  74. //
  75. // RemoteServerConfig
  76. //
  77. // DESCRIPTION
  78. //
  79. // Plain ol' data holding all the configuration associated with a
  80. // RemoteServer. This spares clients from having to call a monster
  81. // contructor when creating a remote server.
  82. //
  83. ///////////////////////////////////////////////////////////////////////////////
  84. struct RemoteServerConfig
  85. {
  86. GUID guid;
  87. ULONG ipAddress;
  88. USHORT authPort;
  89. USHORT acctPort;
  90. PCSTR authSecret;
  91. PCSTR acctSecret;
  92. ULONG priority;
  93. ULONG weight;
  94. ULONG timeout;
  95. ULONG maxLost;
  96. ULONG blackout;
  97. bool sendSignature;
  98. bool sendAcctOnOff;
  99. };
  100. ///////////////////////////////////////////////////////////////////////////////
  101. //
  102. // CLASS
  103. //
  104. // RemoteServer
  105. //
  106. // DESCRIPTION
  107. //
  108. // Describes a remote RADIUS server and maintains the state of that server.
  109. //
  110. ///////////////////////////////////////////////////////////////////////////////
  111. class RemoteServer
  112. {
  113. public:
  114. DECLARE_REFERENCE_COUNT();
  115. // Unique ID for this server.
  116. const GUID guid;
  117. // Authentication and accounting ports.
  118. RemotePort authPort;
  119. RemotePort acctPort;
  120. // Read-only properties for load-balancing and failover.
  121. const ULONG priority;
  122. const ULONG weight;
  123. // Read-only properties for determining server state.
  124. const ULONG timeout;
  125. const LONG maxLost;
  126. const ULONG blackout;
  127. // Should we always send a Signature attribute?
  128. const bool sendSignature;
  129. // Should we formard Accounting-On/Off requests?
  130. const bool sendAcctOnOff;
  131. RemoteServer(const RemoteServerConfig& config);
  132. // Returns the servers IP address.
  133. ULONG getAddress() const throw ()
  134. { return authPort.address.sin_addr.s_addr; }
  135. // Returns 'true' if the server is available for use.
  136. bool isAvailable() const throw ()
  137. { return state == AVAILABLE; }
  138. // Returns 'true' if the server should receive a broadcast.
  139. bool shouldBroadcast() throw ();
  140. // Notifies the RemoteServer that a valid packet has been received. Returns
  141. // true if this triggers a state change.
  142. bool onReceive() throw ();
  143. // Notfies the RemoteServer that a request has timed out. Returns true if
  144. // this triggers a state change.
  145. bool onTimeout() throw ();
  146. // Synchronize the state of this server with target.
  147. void copyState(const RemoteServer& target) throw ();
  148. bool operator==(const RemoteServer& s) const throw ();
  149. protected:
  150. // This is virtual so that RemoteServer can server as a base class.
  151. virtual ~RemoteServer() throw () { }
  152. private:
  153. // Possible states of the server.
  154. enum State
  155. {
  156. AVAILABLE, // Server is available for use.
  157. UNAVAILABLE, // Not available but may receive broadcasts.
  158. LOCKED // Locked by a thread; prevents multiple threads from
  159. // simultaneously broadcasting to a server.
  160. };
  161. // Transition the server state; returns 'true' if successful.
  162. bool changeState(State from, State to) throw ();
  163. State state; // Current state of the server.
  164. LONG lostCount; // Number of packets lost since last received.
  165. ULONG64 expiry; // Time when blackout interval expires.
  166. // Not implemented.
  167. RemoteServer& operator=(RemoteServer&);
  168. };
  169. typedef ObjectPointer<RemoteServer> RemoteServerPtr;
  170. typedef ObjectVector<RemoteServer> RemoteServers;
  171. class RequestStack;
  172. class ProxyContext;
  173. ///////////////////////////////////////////////////////////////////////////////
  174. //
  175. // CLASS
  176. //
  177. // ServerGroup
  178. //
  179. // DESCRIPTION
  180. //
  181. // Load balances requests among a group of RemoteServers.
  182. //
  183. ///////////////////////////////////////////////////////////////////////////////
  184. class ServerGroup
  185. {
  186. public:
  187. DECLARE_REFERENCE_COUNT();
  188. ServerGroup(
  189. PCWSTR groupName,
  190. RemoteServer* const* first,
  191. RemoteServer* const* last
  192. );
  193. // Returns the number of servers in the group.
  194. ULONG size() const throw ()
  195. { return servers.size(); }
  196. bool isEmpty() const throw ()
  197. { return servers.empty(); }
  198. // Name used to identify the group.
  199. PCWSTR getName() const throw ()
  200. { return name; }
  201. // Returns a collection of servers that should receive the request.
  202. void getServersForRequest(
  203. ProxyContext* context,
  204. BYTE packetCode,
  205. RequestStack& result
  206. ) const;
  207. // Methods for iterating the servers in the group.
  208. RemoteServers::iterator begin() const throw ()
  209. { return servers.begin(); }
  210. RemoteServers::iterator end() const throw ()
  211. { return servers.end(); }
  212. private:
  213. ~ServerGroup() throw () { }
  214. // Pick a server from the list. The list must not be empty, and all the
  215. // servers must have the same priority.
  216. static RemoteServer* pickServer(
  217. RemoteServers::iterator first,
  218. RemoteServers::iterator last
  219. ) throw ();
  220. // Array of servers in priority order.
  221. RemoteServers servers;
  222. // End of top priority level in array.
  223. RemoteServers::iterator endTopPriority;
  224. // Maximum number of bytes required to hold the server candidates.
  225. ULONG maxCandidatesSize;
  226. RadiusString name;
  227. static ULONG theSeed;
  228. // Not implemented.
  229. ServerGroup(const ServerGroup&);
  230. ServerGroup& operator=(const ServerGroup&);
  231. };
  232. typedef ObjectPointer<ServerGroup> ServerGroupPtr;
  233. typedef ObjectVector<ServerGroup> ServerGroups;
  234. ///////////////////////////////////////////////////////////////////////////////
  235. //
  236. // CLASS
  237. //
  238. // ServerGroupManager
  239. //
  240. // DESCRIPTION
  241. //
  242. // Manages a collection of ServerGroups.
  243. //
  244. ///////////////////////////////////////////////////////////////////////////////
  245. class ServerGroupManager
  246. {
  247. public:
  248. ServerGroupManager() throw () { }
  249. // Set the server groups to be managed.
  250. bool setServerGroups(
  251. ServerGroups::iterator begin,
  252. ServerGroups::iterator end
  253. ) throw ();
  254. // Returns a server with the given IP address.
  255. RemoteServerPtr findServer(
  256. ULONG address
  257. ) const throw ();
  258. void getServersByGroup(
  259. ProxyContext* context,
  260. BYTE packetCode,
  261. PCWSTR name,
  262. RequestStack& result
  263. ) const;
  264. void getServersForAcctOnOff(
  265. ProxyContext* context,
  266. RequestStack& result
  267. ) const;
  268. private:
  269. // Synchronize access.
  270. mutable RWLock monitor;
  271. // Server groups being managed sorted by name.
  272. ServerGroups groups;
  273. // All servers sorted by guid.
  274. RemoteServers byAddress;
  275. // All servers sorted by guid.
  276. RemoteServers byGuid;
  277. // Servers to receive Accounting-On/Off requests.
  278. RemoteServers acctServers;
  279. // Not implemented.
  280. ServerGroupManager(const ServerGroupManager&);
  281. ServerGroupManager& operator=(const ServerGroupManager&);
  282. };
  283. class RadiusProxyClient;
  284. ///////////////////////////////////////////////////////////////////////////////
  285. //
  286. // CLASS
  287. //
  288. // RadiusProxyEngine
  289. //
  290. // DESCRIPTION
  291. //
  292. // Implements a RADIUS proxy.
  293. //
  294. ///////////////////////////////////////////////////////////////////////////////
  295. class RadiusProxyEngine : PacketReceiver
  296. {
  297. public:
  298. // Final result of processing a request.
  299. enum Result
  300. {
  301. resultSuccess,
  302. resultNotEnoughMemory,
  303. resultUnknownServerGroup,
  304. resultUnknownServer,
  305. resultInvalidRequest,
  306. resultSendError,
  307. resultRequestTimeout
  308. };
  309. RadiusProxyEngine(RadiusProxyClient* source);
  310. ~RadiusProxyEngine() throw ();
  311. // Set the server groups to be used by the proxy.
  312. bool setServerGroups(
  313. ServerGroup* const* begin,
  314. ServerGroup* const* end
  315. ) throw ();
  316. // Forward a request to the given server group.
  317. void forwardRequest(
  318. PVOID context,
  319. PCWSTR serverGroup,
  320. BYTE code,
  321. const BYTE* requestAuthenticator,
  322. const RadiusAttribute* begin,
  323. const RadiusAttribute* end
  324. ) throw ();
  325. // Callback when a request context has been abandoned.
  326. static void onRequestAbandoned(
  327. PVOID context,
  328. RemoteServer* server
  329. ) throw ();
  330. // Callback when a request has timed out.
  331. static void onRequestTimeout(
  332. Request* request
  333. ) throw ();
  334. private:
  335. // Methods for associating a stateful authentication session with a
  336. // particular server.
  337. RemoteServerPtr getServerAffinity(
  338. const RadiusPacket& packet
  339. ) throw ();
  340. void setServerAffinity(
  341. const RadiusPacket& packet,
  342. RemoteServer& server
  343. ) throw ();
  344. // PacketReceiver callbacks.
  345. virtual void onReceive(
  346. UDPSocket& socket,
  347. ULONG_PTR key,
  348. const SOCKADDR_IN& remoteAddress,
  349. BYTE* buffer,
  350. ULONG bufferLength
  351. ) throw ();
  352. virtual void onReceiveError(
  353. UDPSocket& socket,
  354. ULONG_PTR key,
  355. ULONG errorCode
  356. ) throw ();
  357. // Forward a request to an individual RemoteServer.
  358. Result sendRequest(
  359. RadiusPacket& packet,
  360. Request* request
  361. );
  362. // Report an event to the client.
  363. void reportEvent(
  364. const RadiusEvent& event
  365. ) const throw ();
  366. void reportEvent(
  367. RadiusEvent& event,
  368. RadiusEventType type
  369. ) const throw ();
  370. // Callback when a timer has expired.
  371. static VOID NTAPI onTimerExpiry(PVOID context, BOOLEAN flag) throw ();
  372. // The object supplying us with requests.
  373. RadiusProxyClient* client;
  374. // The local address of the proxy. Used when forming Proxy-State.
  375. ULONG proxyAddress;
  376. // UDP sockets used for network I/O.
  377. UDPSocket authSock;
  378. UDPSocket acctSock;
  379. // Server groups used for processing groups.
  380. ServerGroupManager groups;
  381. // Table of pending requests.
  382. HashTable< LONG, Request > pending;
  383. // Queue of pending requests.
  384. TimerQueue timers;
  385. // Table of current authentication sessions.
  386. Cache< RadiusRawOctets, Session > sessions;
  387. // Global pointer to the RadiusProxyEngine. This is a hack, but it saves me
  388. // from having to give every Request and Context object a back pointer.
  389. static RadiusProxyEngine* theProxy;
  390. // Not implemented.
  391. RadiusProxyEngine(const RadiusProxyEngine&);
  392. RadiusProxyEngine& operator=(const RadiusProxyEngine&);
  393. };
  394. ///////////////////////////////////////////////////////////////////////////////
  395. //
  396. // CLASS
  397. //
  398. // RadiusProxyClient
  399. //
  400. // DESCRIPTION
  401. //
  402. // Abstract base class for clients of the RadiusProxy engine.
  403. //
  404. ///////////////////////////////////////////////////////////////////////////////
  405. class __declspec(novtable) RadiusProxyClient
  406. {
  407. public:
  408. // Invoked to report one of the above events.
  409. virtual void onEvent(
  410. const RadiusEvent& event
  411. ) throw () = 0;
  412. // Invoked exactly once for each call to RadiusProxyEngine::forwardRequest.
  413. virtual void onComplete(
  414. RadiusProxyEngine::Result result,
  415. PVOID context,
  416. RemoteServer* server,
  417. BYTE code,
  418. const RadiusAttribute* begin,
  419. const RadiusAttribute* end
  420. ) throw () = 0;
  421. };
  422. #endif // RADPROXY_H