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.

264 lines
6.2 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1997, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // InfoShare.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file implements the class InfoShare.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 09/09/1997 Original version.
  16. // 03/17/1998 Clear data structure at startup and shutdown.
  17. // 04/20/1998 Check if the shared memory is mapped during finalize().
  18. // 09/09/1998 Protect client changes with a shared Mutex.
  19. // 09/17/1998 Fix resize bug.
  20. // 09/28/1999 Only allow Administrators access to mutex.
  21. // 05/19/2000 Fix bug calculating bytes needed.
  22. //
  23. ///////////////////////////////////////////////////////////////////////////////
  24. #include <iascore.h>
  25. #include <iasutil.h>
  26. #include <InfoShare.h>
  27. //////////
  28. // The maximum size of the shared memory segment.
  29. //////////
  30. const DWORD MAX_INFO_SIZE = 0x100000;
  31. InfoShare::InfoShare() throw ()
  32. : monitor(NULL),
  33. pageSize(0),
  34. committed(0),
  35. reserved(0),
  36. fileMap(NULL),
  37. info(NULL)
  38. { }
  39. InfoShare::~InfoShare() throw ()
  40. {
  41. CloseHandle(fileMap);
  42. CloseHandle(monitor);
  43. }
  44. RadiusClientEntry* InfoShare::findClientEntry(PCWSTR inetAddress) throw ()
  45. {
  46. if (!info) { return NULL; }
  47. DWORD address = ias_inet_wtoh(inetAddress);
  48. ClientMap::iterator i = clients.find(address);
  49. // If we found it, return it. Otherwise add a new entry.
  50. return i != clients.end() ? i->second : addClientEntry(address);
  51. }
  52. void InfoShare::onReset() throw ()
  53. {
  54. if (info)
  55. {
  56. GetSystemTimeAsFileTime((LPFILETIME)&info->seServer.liResetTime);
  57. }
  58. }
  59. bool InfoShare::initialize() throw ()
  60. {
  61. // Create the SID for local Administrators.
  62. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  63. PSID adminSid = (PSID)_alloca(GetSidLengthRequired(2));
  64. InitializeSid(
  65. adminSid,
  66. &sia,
  67. 2
  68. );
  69. *GetSidSubAuthority(adminSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
  70. *GetSidSubAuthority(adminSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
  71. // Create an ACL giving Administrators all access.
  72. ULONG cbAcl = sizeof(ACL) +
  73. (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  74. GetLengthSid(adminSid);
  75. PACL acl = (PACL)_alloca(cbAcl);
  76. InitializeAcl(
  77. acl,
  78. cbAcl,
  79. ACL_REVISION
  80. );
  81. AddAccessAllowedAce(
  82. acl,
  83. ACL_REVISION,
  84. MUTEX_ALL_ACCESS,
  85. adminSid
  86. );
  87. // Create a security descriptor with the above ACL.
  88. PSECURITY_DESCRIPTOR pSD;
  89. BYTE buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
  90. pSD = (PSECURITY_DESCRIPTOR)buffer;
  91. InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
  92. SetSecurityDescriptorDacl(pSD, TRUE, acl, FALSE);
  93. // Fill in the SECURITY_ATTRIBUTES struct.
  94. SECURITY_ATTRIBUTES sa;
  95. sa.nLength = sizeof(sa);
  96. sa.lpSecurityDescriptor = pSD;
  97. sa.bInheritHandle = TRUE;
  98. // Create the mutex.
  99. monitor = CreateMutex(
  100. &sa,
  101. FALSE,
  102. RadiusStatisticsMutex
  103. );
  104. if (!monitor) { return false; }
  105. // Determine the page size for this platform.
  106. SYSTEM_INFO si;
  107. GetSystemInfo(&si);
  108. pageSize = si.dwPageSize;
  109. // Determine the number of pages to reserve.
  110. reserved = (MAX_INFO_SIZE + pageSize - 1)/pageSize;
  111. // Create the mapping in the pagefile ...
  112. PVOID view;
  113. fileMap = CreateFileMappingW(
  114. INVALID_HANDLE_VALUE,
  115. NULL,
  116. PAGE_READWRITE | SEC_RESERVE,
  117. 0,
  118. reserved * pageSize,
  119. RadiusStatisticsName
  120. );
  121. if (!fileMap) { goto close_mutex; }
  122. // ... and map it into our process.
  123. view = MapViewOfFile(
  124. fileMap,
  125. FILE_MAP_WRITE,
  126. 0,
  127. 0,
  128. 0
  129. );
  130. if (!view) { goto close_map; }
  131. // Commit the first page.
  132. info = (RadiusStatistics*)VirtualAlloc(
  133. view,
  134. pageSize,
  135. MEM_COMMIT,
  136. PAGE_READWRITE
  137. );
  138. if (!info) { goto close_map; }
  139. committed = 1;
  140. Lock();
  141. // Zero out any data from a previous incarnation.
  142. clear();
  143. // Record our start and reset times.
  144. GetSystemTimeAsFileTime((LPFILETIME)&info->seServer.liStartTime);
  145. info->seServer.liResetTime = info->seServer.liStartTime;
  146. Unlock();
  147. return true;
  148. close_map:
  149. CloseHandle(fileMap);
  150. fileMap = NULL;
  151. close_mutex:
  152. CloseHandle(monitor);
  153. monitor = NULL;
  154. return false;
  155. }
  156. void InfoShare::finalize()
  157. {
  158. clear();
  159. info = NULL;
  160. CloseHandle(fileMap);
  161. fileMap = NULL;
  162. CloseHandle(monitor);
  163. monitor = NULL;
  164. }
  165. RadiusClientEntry* InfoShare::addClientEntry(DWORD address) throw ()
  166. {
  167. Guard<InfoShare> guard(*this);
  168. // Double check that the client doesn't exist now that we're serialized.
  169. ClientMap::iterator i = clients.find(address);
  170. if (i != clients.end()) { return i->second; }
  171. // How many bytes will we need to add the new entry?
  172. DWORD newSize = (info->dwNumClients) * sizeof(RadiusClientEntry) +
  173. sizeof(RadiusStatistics);
  174. // How many pages will we need to add the new entry?
  175. DWORD pagesNeeded = (newSize + pageSize - 1)/pageSize;
  176. // Do we have to commit more memory?
  177. if (pagesNeeded > committed)
  178. {
  179. // If we've hit the max or we can't commit anymore, we're done.
  180. if (pagesNeeded > reserved ||
  181. !VirtualAlloc(info,
  182. pageSize * pagesNeeded,
  183. MEM_COMMIT,
  184. PAGE_READWRITE))
  185. {
  186. return NULL;
  187. }
  188. committed = pagesNeeded;
  189. }
  190. // Get the next client entry.
  191. RadiusClientEntry* pce = info->ceClients + info->dwNumClients;
  192. // Make sure it's zero'ed.
  193. memset(pce, 0, sizeof(RadiusClientEntry));
  194. // Set the address.
  195. pce->dwAddress = address;
  196. try
  197. {
  198. // Insert it into the index.
  199. clients[address] = pce;
  200. }
  201. catch (std::bad_alloc)
  202. {
  203. return NULL;
  204. }
  205. // Safefly inserted into the index, so increment the number of clients.
  206. ++(info->dwNumClients);
  207. return pce;
  208. }
  209. void InfoShare::clear() throw ()
  210. {
  211. Lock();
  212. if (info)
  213. {
  214. memset(info, 0, sizeof(RadiusStatistics));
  215. }
  216. Unlock();
  217. }