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.

281 lines
6.7 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. if (info != NULL)
  42. {
  43. UnmapViewOfFile(info);
  44. }
  45. if (fileMap != NULL)
  46. {
  47. CloseHandle(fileMap);
  48. }
  49. if (monitor != NULL)
  50. {
  51. CloseHandle(monitor);
  52. }
  53. }
  54. RadiusClientEntry* InfoShare::findClientEntry(PCWSTR inetAddress) throw ()
  55. {
  56. if (!info) { return NULL; }
  57. DWORD address = ias_inet_wtoh(inetAddress);
  58. ClientMap::iterator i = clients.find(address);
  59. // If we found it, return it. Otherwise add a new entry.
  60. return i != clients.end() ? i->second : addClientEntry(address);
  61. }
  62. void InfoShare::onReset() throw ()
  63. {
  64. if (info)
  65. {
  66. GetSystemTimeAsFileTime((LPFILETIME)&info->seServer.liResetTime);
  67. }
  68. }
  69. bool InfoShare::initialize() throw ()
  70. {
  71. // Create the SID for local Administrators.
  72. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  73. PSID adminSid = (PSID)_alloca(GetSidLengthRequired(2));
  74. InitializeSid(
  75. adminSid,
  76. &sia,
  77. 2
  78. );
  79. *GetSidSubAuthority(adminSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
  80. *GetSidSubAuthority(adminSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
  81. // Create an ACL giving Administrators all access.
  82. ULONG cbAcl = sizeof(ACL) +
  83. (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  84. GetLengthSid(adminSid);
  85. PACL acl = (PACL)_alloca(cbAcl);
  86. InitializeAcl(
  87. acl,
  88. cbAcl,
  89. ACL_REVISION
  90. );
  91. AddAccessAllowedAce(
  92. acl,
  93. ACL_REVISION,
  94. MUTEX_ALL_ACCESS,
  95. adminSid
  96. );
  97. // Create a security descriptor with the above ACL.
  98. PSECURITY_DESCRIPTOR pSD;
  99. BYTE buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
  100. pSD = (PSECURITY_DESCRIPTOR)buffer;
  101. InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
  102. SetSecurityDescriptorDacl(pSD, TRUE, acl, FALSE);
  103. // Fill in the SECURITY_ATTRIBUTES struct.
  104. SECURITY_ATTRIBUTES sa;
  105. sa.nLength = sizeof(sa);
  106. sa.lpSecurityDescriptor = pSD;
  107. sa.bInheritHandle = TRUE;
  108. // Create the mutex.
  109. monitor = CreateMutex(
  110. &sa,
  111. FALSE,
  112. RadiusStatisticsMutex
  113. );
  114. if (!monitor) { return false; }
  115. // Determine the page size for this platform.
  116. SYSTEM_INFO si;
  117. GetSystemInfo(&si);
  118. pageSize = si.dwPageSize;
  119. // Determine the number of pages to reserve.
  120. reserved = (MAX_INFO_SIZE + pageSize - 1)/pageSize;
  121. // Create the mapping in the pagefile ...
  122. PVOID view;
  123. fileMap = CreateFileMappingW(
  124. INVALID_HANDLE_VALUE,
  125. NULL,
  126. PAGE_READWRITE | SEC_RESERVE,
  127. 0,
  128. reserved * pageSize,
  129. RadiusStatisticsName
  130. );
  131. if (!fileMap) { goto close_mutex; }
  132. // ... and map it into our process.
  133. view = MapViewOfFile(
  134. fileMap,
  135. FILE_MAP_WRITE,
  136. 0,
  137. 0,
  138. 0
  139. );
  140. if (!view) { goto close_map; }
  141. // Commit the first page.
  142. info = (RadiusStatistics*)VirtualAlloc(
  143. view,
  144. pageSize,
  145. MEM_COMMIT,
  146. PAGE_READWRITE
  147. );
  148. if (!info) { goto unmap_view; }
  149. committed = 1;
  150. Lock();
  151. // Zero out any data from a previous incarnation.
  152. clear();
  153. // Record our start and reset times.
  154. GetSystemTimeAsFileTime((LPFILETIME)&info->seServer.liStartTime);
  155. info->seServer.liResetTime = info->seServer.liStartTime;
  156. Unlock();
  157. return true;
  158. unmap_view:
  159. UnmapViewOfFile(view);
  160. close_map:
  161. CloseHandle(fileMap);
  162. fileMap = NULL;
  163. close_mutex:
  164. CloseHandle(monitor);
  165. monitor = NULL;
  166. return false;
  167. }
  168. void InfoShare::finalize()
  169. {
  170. clear();
  171. UnmapViewOfFile(info);
  172. info = NULL;
  173. CloseHandle(fileMap);
  174. fileMap = NULL;
  175. CloseHandle(monitor);
  176. monitor = NULL;
  177. }
  178. RadiusClientEntry* InfoShare::addClientEntry(DWORD address) throw ()
  179. {
  180. Guard<InfoShare> guard(*this);
  181. // Double check that the client doesn't exist now that we're serialized.
  182. ClientMap::iterator i = clients.find(address);
  183. if (i != clients.end()) { return i->second; }
  184. // How many bytes will we need to add the new entry?
  185. DWORD newSize = (info->dwNumClients) * sizeof(RadiusClientEntry) +
  186. sizeof(RadiusStatistics);
  187. // How many pages will we need to add the new entry?
  188. DWORD pagesNeeded = (newSize + pageSize - 1)/pageSize;
  189. // Do we have to commit more memory?
  190. if (pagesNeeded > committed)
  191. {
  192. // If we've hit the max or we can't commit anymore, we're done.
  193. if (pagesNeeded > reserved ||
  194. !VirtualAlloc(info,
  195. pageSize * pagesNeeded,
  196. MEM_COMMIT,
  197. PAGE_READWRITE))
  198. {
  199. return NULL;
  200. }
  201. committed = pagesNeeded;
  202. }
  203. // Get the next client entry.
  204. RadiusClientEntry* pce = info->ceClients + info->dwNumClients;
  205. // Make sure it's zero'ed.
  206. memset(pce, 0, sizeof(RadiusClientEntry));
  207. // Set the address.
  208. pce->dwAddress = address;
  209. try
  210. {
  211. // Insert it into the index.
  212. clients[address] = pce;
  213. }
  214. catch (std::bad_alloc)
  215. {
  216. return NULL;
  217. }
  218. // Safefly inserted into the index, so increment the number of clients.
  219. ++(info->dwNumClients);
  220. return pce;
  221. }
  222. void InfoShare::clear() throw ()
  223. {
  224. Lock();
  225. if (info)
  226. {
  227. memset(info, 0, sizeof(RadiusStatistics));
  228. }
  229. Unlock();
  230. }