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.

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