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.

345 lines
8.4 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2002
  3. Module Name:
  4. sidcache.cxx
  5. Abstract:
  6. This contains the SID_CACHE definition and wrappers to access the per process
  7. SIDCache.
  8. Author:
  9. Maurice Flanagan (mauricf) June 27, 2002
  10. Revision History:
  11. --*/
  12. #include <precomp.hxx>
  13. #include <sidcache.hxx>
  14. SID_CACHE *SIDCache = NULL;
  15. RPC_STATUS
  16. QuerySIDCache(
  17. IN RPC_CHAR *ServerPrincipalName,
  18. OUT PSID *Sid
  19. )
  20. /*++
  21. Routine Description:
  22. This wraps access to our global SIDCache object.
  23. Arguments, either:
  24. ServerPrincipalName - the server principal name to be translated to
  25. a SID
  26. Sid - On output contains a pointer to the allocated SID. On success (RPC_S_OK) this will be
  27. NULL if the SPN was not found in our cache. Undefined on failure.
  28. Pointer must be freed with delete.
  29. Return Value:
  30. RPC_S_OK or RPC_S_* error
  31. --*/
  32. {
  33. ASSERT(ServerPrincipalName != NULL);
  34. ASSERT(Sid != NULL);
  35. if (SIDCache == NULL)
  36. {
  37. return RPC_S_OUT_OF_MEMORY;
  38. }
  39. return SIDCache->Query(ServerPrincipalName, Sid);
  40. }
  41. RPC_STATUS
  42. AddToSIDCache(
  43. IN RPC_CHAR *ServerPrincipalName,
  44. IN PSID Sid
  45. )
  46. /*++
  47. Routine Description:
  48. This wraps access to our global SIDCache object.
  49. Arguments, either:
  50. ServerPrincipalName - The server principal name which we want to add to our cache.
  51. Sid - The SID associated with this server principal name.
  52. Return Value:
  53. RPC_S_OK or RPC_S_* error
  54. --*/
  55. {
  56. ASSERT(ServerPrincipalName != NULL);
  57. ASSERT(Sid != NULL);
  58. if (SIDCache == NULL)
  59. {
  60. return RPC_S_OUT_OF_MEMORY;
  61. }
  62. return SIDCache->Add(ServerPrincipalName, Sid);
  63. }
  64. RPC_STATUS
  65. RemoveFromSIDCache(
  66. IN RPC_CHAR *ServerPrincipalName
  67. )
  68. /*++
  69. Routine Description:
  70. This wraps access to our global SIDCache object.
  71. Arguments, either:
  72. ServerPrincipalName - The server principal name which we want to remove from our cache
  73. Return Value:
  74. RPC_S_OK or RPC_S_* error
  75. --*/
  76. {
  77. if (SIDCache == NULL)
  78. {
  79. return RPC_S_OUT_OF_MEMORY;
  80. }
  81. return SIDCache->Remove(ServerPrincipalName);
  82. }
  83. RPC_STATUS
  84. SID_CACHE::Query (
  85. IN RPC_CHAR *ServerPrincipalName,
  86. OUT PSID *Sid
  87. )
  88. /*++
  89. Routine Description:
  90. This checks the chache for a matching ServerPrincipalName and if found it returns the SID.
  91. The goal of the cache is to maintain the last N (N is currently 4) most recently accessed entries.
  92. We must loop through the entire cache and increment the Age of every entry. If there is a matching
  93. entry (a hit) then we start the age over again at zero. Every SPN in the cache is unique in the cache.
  94. Arguments, either:
  95. ServerPrincipalName - The server principal name which we want to lookup in our cache
  96. Sid - Filled in with the value found in the cache, or NULL if not found. Undefined on error return.
  97. Return Value:
  98. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  99. --*/
  100. {
  101. DWORD idx;
  102. BOOL fFound = FALSE;
  103. *Sid = NULL;
  104. CacheMutex.Request();
  105. for (idx = 0; idx < CacheSize; idx++)
  106. {
  107. if (Cache[idx].SPN != NULL)
  108. {
  109. if ((!fFound) && (RpcpStringCompare(ServerPrincipalName, Cache[idx].SPN) == 0))
  110. {
  111. ASSERT(Cache[idx].SID != NULL);
  112. Cache[idx].Age = 0;
  113. fFound = TRUE;
  114. *Sid = DuplicateSID(Cache[idx].SID);
  115. if (*Sid == NULL)
  116. {
  117. CacheMutex.Clear();
  118. return RPC_S_OUT_OF_MEMORY;
  119. }
  120. }
  121. else
  122. {
  123. Cache[idx].Age++;
  124. }
  125. }
  126. }
  127. CacheMutex.Clear();
  128. return RPC_S_OK;
  129. }
  130. RPC_STATUS
  131. SID_CACHE::Add (
  132. IN RPC_CHAR *ServerPrincipalName,
  133. IN PSID Sid
  134. )
  135. /*++
  136. Routine Description:
  137. This adds an entry to the cache for this SPN and sets this SID.
  138. We only have four slots, first we check if this SPN has an entry, if so we free the existing SID
  139. and add the new one in its place. Next we check for an empty slot, if so we use it. Lastly we
  140. find the first oldest slot and use that (freeing the existing SPN and SID).
  141. Arguments, either:
  142. ServerPrincipalName - The server principal name which we want to add to our cache, we
  143. make a copy of it.
  144. Sid - The SID to associate with this SPN, we make a copy of this (DuplicateSID)
  145. Return Value:
  146. RPC_S_OK or RPC_S_* error
  147. --*/
  148. {
  149. RPC_STATUS Status = RPC_S_OK;
  150. DWORD idx = 0;
  151. DWORD IdxToUse = -1;
  152. DWORD OldestIdx = -1, OldestAge;
  153. DWORD EmptyIdx = -1;
  154. // What slot to use, in order:
  155. // Slot with same SPN
  156. // Empty slot
  157. // Oldest slot
  158. CacheMutex.Request();
  159. for (idx = 0; idx < CacheSize; idx++)
  160. {
  161. // Is this SPN already in the cache?
  162. if (Cache[idx].SPN != NULL)
  163. {
  164. if (RpcpStringCompare(ServerPrincipalName, Cache[idx].SPN) == 0)
  165. {
  166. if (!EqualSid(Sid, Cache[idx].SID))
  167. {
  168. delete [] Cache[idx].SID;
  169. Cache[idx].SID = DuplicateSID(Sid);
  170. if (Cache[idx].SID == NULL)
  171. {
  172. delete [] Cache[idx].SPN;
  173. Cache[idx].SPN = NULL;
  174. CacheMutex.Clear();
  175. return RPC_S_OUT_OF_MEMORY;
  176. }
  177. }
  178. Cache[idx].Age = 0;
  179. CacheMutex.Clear();
  180. return RPC_S_OK;
  181. }
  182. }
  183. if (EmptyIdx == -1)
  184. {
  185. if (Cache[idx].SPN == NULL)
  186. {
  187. // remember this empty slot
  188. EmptyIdx = idx;
  189. }
  190. else
  191. {
  192. if (OldestIdx == -1)
  193. {
  194. OldestAge = Cache[idx].Age;
  195. OldestIdx = idx;
  196. }
  197. else if (OldestAge < Cache[idx].Age)
  198. {
  199. OldestAge = Cache[idx].Age;
  200. OldestIdx = idx;
  201. }
  202. }
  203. }
  204. }
  205. // We have either the oldest or an empty slot
  206. if (EmptyIdx == -1)
  207. {
  208. delete [] Cache[OldestIdx].SPN;
  209. delete [] Cache[OldestIdx].SID;
  210. Cache[OldestIdx].SPN = NULL;
  211. Cache[OldestIdx].SID = NULL;
  212. IdxToUse = OldestIdx;
  213. }
  214. else
  215. {
  216. IdxToUse = EmptyIdx;
  217. }
  218. ASSERT(IdxToUse != -1);
  219. Cache[IdxToUse].Age = 0;
  220. Cache[IdxToUse].SPN = new RPC_CHAR [RpcpStringLength(ServerPrincipalName) +1];
  221. if (Cache[IdxToUse].SPN == NULL)
  222. {
  223. CacheMutex.Clear();
  224. return RPC_S_OUT_OF_MEMORY;
  225. }
  226. RpcpStringNCopy(Cache[IdxToUse].SPN, ServerPrincipalName, RpcpStringLength(ServerPrincipalName) +1);
  227. Cache[IdxToUse].SID = DuplicateSID(Sid);
  228. if (Cache[IdxToUse].SID == NULL)
  229. {
  230. delete [] Cache[IdxToUse].SPN;
  231. Cache[IdxToUse].SPN = NULL;
  232. CacheMutex.Clear();
  233. return RPC_S_OUT_OF_MEMORY;
  234. }
  235. CacheMutex.Clear();
  236. return RPC_S_OK;
  237. }
  238. RPC_STATUS
  239. SID_CACHE::Remove (
  240. IN RPC_CHAR *ServerPrincipalName
  241. )
  242. {
  243. DWORD idx;
  244. if (ServerPrincipalName == NULL)
  245. return RPC_S_OK;
  246. CacheMutex.Request();
  247. for (idx = 0; idx < CacheSize; idx++)
  248. {
  249. if (Cache[idx].SPN != NULL)
  250. {
  251. if (RpcpStringCompare(ServerPrincipalName, Cache[idx].SPN) == 0)
  252. {
  253. ASSERT(Cache[idx].SID != NULL);
  254. delete [] Cache[idx].SPN;
  255. delete [] Cache[idx].SID;
  256. Cache[idx].SPN = NULL;
  257. Cache[idx].SID = NULL;
  258. Cache[idx].Age = 0;
  259. break;
  260. }
  261. }
  262. }
  263. CacheMutex.Clear();
  264. return RPC_S_OK;
  265. }