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.

346 lines
8.2 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // SYNOPSIS
  6. //
  7. // Defines the class Accountant.
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "ias.h"
  11. #include "account.h"
  12. #include <algorithm>
  13. #include "sdoias.h"
  14. #define STACK_ALLOC(type, num) (type*)_alloca(sizeof(type) * (num))
  15. Accountant::Accountant() throw ()
  16. : logAuth(false),
  17. logAcct(false),
  18. logInterim(false),
  19. logAuthInterim(false)
  20. {
  21. }
  22. Accountant::~Accountant() throw ()
  23. {
  24. }
  25. STDMETHODIMP Accountant::Initialize()
  26. {
  27. return schema.initialize();
  28. }
  29. STDMETHODIMP Accountant::Shutdown()
  30. {
  31. schema.shutdown();
  32. return S_OK;
  33. }
  34. HRESULT Accountant::PutProperty(LONG id, VARIANT* value) throw ()
  35. {
  36. if (value == 0)
  37. {
  38. return E_INVALIDARG;
  39. }
  40. HRESULT hr = S_OK;
  41. switch (id)
  42. {
  43. case PROPERTY_ACCOUNTING_LOG_ACCOUNTING:
  44. {
  45. if (V_VT(value) == VT_BOOL)
  46. {
  47. logAcct = (V_BOOL(value) != 0);
  48. }
  49. else
  50. {
  51. hr = DISP_E_TYPEMISMATCH;
  52. }
  53. break;
  54. }
  55. case PROPERTY_ACCOUNTING_LOG_ACCOUNTING_INTERIM:
  56. {
  57. if (V_VT(value) == VT_BOOL)
  58. {
  59. logInterim = (V_BOOL(value) != 0);
  60. }
  61. else
  62. {
  63. hr = DISP_E_TYPEMISMATCH;
  64. }
  65. break;
  66. }
  67. case PROPERTY_ACCOUNTING_LOG_AUTHENTICATION:
  68. {
  69. if (V_VT(value) == VT_BOOL)
  70. {
  71. logAuth = (V_BOOL(value) != 0);
  72. }
  73. else
  74. {
  75. hr = DISP_E_TYPEMISMATCH;
  76. }
  77. break;
  78. }
  79. case PROPERTY_ACCOUNTING_LOG_AUTHENTICATION_INTERIM:
  80. {
  81. if (V_VT(value) == VT_BOOL)
  82. {
  83. logAuthInterim = (V_BOOL(value) != 0);
  84. }
  85. else
  86. {
  87. hr = DISP_E_TYPEMISMATCH;
  88. }
  89. break;
  90. }
  91. default:
  92. {
  93. // We just ignore properties that we don't understand.
  94. break;
  95. }
  96. }
  97. return hr;
  98. }
  99. void Accountant::RecordEvent(void* context, IASTL::IASRequest& request)
  100. {
  101. // Array of PacketTypes to be inserted. PKT_UNKNOWN indicates no record.
  102. PacketType types[3] =
  103. {
  104. PKT_UNKNOWN,
  105. PKT_UNKNOWN,
  106. PKT_UNKNOWN
  107. };
  108. // Determine packet types based on request type and the configuration.
  109. switch (request.get_Request())
  110. {
  111. case IAS_REQUEST_ACCOUNTING:
  112. {
  113. if (IsInterimRecord(request) ? logInterim : logAcct)
  114. {
  115. types[0] = PKT_ACCOUNTING_REQUEST;
  116. }
  117. break;
  118. }
  119. case IAS_REQUEST_ACCESS_REQUEST:
  120. {
  121. switch (request.get_Response())
  122. {
  123. case IAS_RESPONSE_ACCESS_ACCEPT:
  124. {
  125. if (logAuth)
  126. {
  127. types[0] = PKT_ACCESS_REQUEST;
  128. types[1] = PKT_ACCESS_ACCEPT;
  129. }
  130. break;
  131. }
  132. case IAS_RESPONSE_ACCESS_REJECT:
  133. {
  134. if (logAuth)
  135. {
  136. types[0] = PKT_ACCESS_REQUEST;
  137. types[1] = PKT_ACCESS_REJECT;
  138. }
  139. break;
  140. }
  141. case IAS_RESPONSE_ACCESS_CHALLENGE:
  142. {
  143. if (logAuthInterim)
  144. {
  145. types[0] = PKT_ACCESS_REQUEST;
  146. types[1] = PKT_ACCESS_CHALLENGE;
  147. }
  148. break;
  149. }
  150. default:
  151. {
  152. break;
  153. }
  154. }
  155. break;
  156. }
  157. default:
  158. {
  159. break;
  160. }
  161. }
  162. // Get the local SYSTEMTIME.
  163. SYSTEMTIME localTime;
  164. GetLocalTime(&localTime);
  165. // Insert the appropriate records.
  166. for (const PacketType* type = types; *type != PKT_UNKNOWN; ++type)
  167. {
  168. InsertRecord(context, request, localTime, *type);
  169. }
  170. // Flush the accounting stream.
  171. Flush(context, request, localTime);
  172. }
  173. void Accountant::InsertRecord(
  174. void* context,
  175. IASTL::IASRequest& request,
  176. const SYSTEMTIME& localTime,
  177. PacketType packetType
  178. )
  179. {
  180. //////////
  181. // Retrieve all the attributes from the request. Save room for three extra
  182. // attributes: Packet-Type, Reason-Code, and a null-terminator.
  183. //////////
  184. PATTRIBUTEPOSITION firstPos, curPos, lastPos;
  185. DWORD nattr = request.GetAttributeCount();
  186. firstPos = STACK_ALLOC(ATTRIBUTEPOSITION, nattr + 3);
  187. nattr = request.GetAttributes(nattr, firstPos, 0, NULL);
  188. lastPos = firstPos + nattr;
  189. //////////
  190. // Compute the attribute filter and reason code.
  191. //////////
  192. DWORD always, never, reason = 0;
  193. switch (packetType)
  194. {
  195. case PKT_ACCESS_REQUEST:
  196. always = IAS_RECVD_FROM_CLIENT | IAS_RECVD_FROM_PROTOCOL;
  197. never = IAS_INCLUDE_IN_RESPONSE;
  198. break;
  199. case PKT_ACCESS_ACCEPT:
  200. always = IAS_INCLUDE_IN_ACCEPT;
  201. never = IAS_RECVD_FROM_CLIENT |
  202. IAS_INCLUDE_IN_REJECT | IAS_INCLUDE_IN_CHALLENGE;
  203. break;
  204. case PKT_ACCESS_REJECT:
  205. always = IAS_INCLUDE_IN_REJECT;
  206. never = IAS_RECVD_FROM_CLIENT |
  207. IAS_INCLUDE_IN_ACCEPT | IAS_INCLUDE_IN_CHALLENGE;
  208. reason = request.get_Reason();
  209. break;
  210. case PKT_ACCESS_CHALLENGE:
  211. always = IAS_INCLUDE_IN_CHALLENGE;
  212. never = IAS_RECVD_FROM_CLIENT |
  213. IAS_INCLUDE_IN_ACCEPT | IAS_INCLUDE_IN_REJECT;
  214. break;
  215. case PKT_ACCOUNTING_REQUEST:
  216. always = IAS_INCLUDE_IN_ACCEPT | IAS_RECVD_FROM_CLIENT |
  217. IAS_RECVD_FROM_PROTOCOL;
  218. never = IAS_INCLUDE_IN_RESPONSE;
  219. reason = request.get_Reason();
  220. break;
  221. }
  222. //////////
  223. // Filter the attributes based on flags.
  224. //////////
  225. for (curPos = firstPos; curPos != lastPos; )
  226. {
  227. // We can release here since the request still holds a reference.
  228. IASAttributeRelease(curPos->pAttribute);
  229. if (!(curPos->pAttribute->dwFlags & always) &&
  230. (curPos->pAttribute->dwFlags & never ) &&
  231. (curPos->pAttribute->dwId != RADIUS_ATTRIBUTE_CLASS))
  232. {
  233. --lastPos;
  234. std::swap(lastPos->pAttribute, curPos->pAttribute);
  235. }
  236. else
  237. {
  238. ++curPos;
  239. }
  240. }
  241. //////////
  242. // Add the Packet-Type pseudo-attribute.
  243. //////////
  244. IASATTRIBUTE packetTypeAttr;
  245. packetTypeAttr.dwId = IAS_ATTRIBUTE_PACKET_TYPE;
  246. packetTypeAttr.dwFlags = (DWORD)-1;
  247. packetTypeAttr.Value.itType = IASTYPE_ENUM;
  248. packetTypeAttr.Value.Enumerator = packetType;
  249. lastPos->pAttribute = &packetTypeAttr;
  250. ++lastPos;
  251. //////////
  252. // Add the Reason-Code pseudo-attribute.
  253. //////////
  254. IASATTRIBUTE reasonCodeAttr;
  255. reasonCodeAttr.dwId = IAS_ATTRIBUTE_REASON_CODE;
  256. reasonCodeAttr.dwFlags = (DWORD)-1;
  257. reasonCodeAttr.Value.itType = IASTYPE_INTEGER;
  258. reasonCodeAttr.Value.Integer = reason;
  259. lastPos->pAttribute = &reasonCodeAttr;
  260. ++lastPos;
  261. //////////
  262. // Invoke the derived class.
  263. //////////
  264. InsertRecord(context, request, localTime, firstPos, lastPos);
  265. }
  266. IASREQUESTSTATUS Accountant::onSyncRequest(IRequest* pRequest) throw ()
  267. {
  268. try
  269. {
  270. Process(IASTL::IASRequest(pRequest));
  271. }
  272. catch (...)
  273. {
  274. pRequest->SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_NO_RECORD);
  275. return IAS_REQUEST_STATUS_ABORT;
  276. }
  277. return IAS_REQUEST_STATUS_CONTINUE;
  278. }
  279. bool Accountant::IsInterimRecord(IAttributesRaw* attrs) throw ()
  280. {
  281. const DWORD accountingInterim = 3;
  282. IASATTRIBUTE* attr = IASPeekAttribute(
  283. attrs,
  284. RADIUS_ATTRIBUTE_ACCT_STATUS_TYPE,
  285. IASTYPE_ENUM
  286. );
  287. return (attr != 0) && (attr->Value.Enumerator == accountingInterim);
  288. }