migrate substitution keywords to SVN
[reactos.git] / reactos / ntoskrnl / ob / sdcache.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/kill.c
6 * PURPOSE: Terminating a thread
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18
19 /* TYPES ********************************************************************/
20
21 typedef struct _SD_CACHE_ENTRY
22 {
23 LIST_ENTRY ListEntry;
24 ULONG HashValue;
25 ULONG Index;
26 ULONG RefCount;
27 } SD_CACHE_ENTRY, *PSD_CACHE_ENTRY;
28
29
30 /* GLOBALS ******************************************************************/
31
32 PLIST_ENTRY ObpSdCache;
33 KSPIN_LOCK ObpSdCacheSpinLock;
34 KIRQL ObpSdCacheIrql;
35
36
37 #define SD_CACHE_ENTRIES 0x100
38
39 /* FUNCTIONS ****************************************************************/
40
41 NTSTATUS
42 ObpInitSdCache(VOID)
43 {
44 ULONG i;
45
46 ObpSdCache = ExAllocatePool(NonPagedPool,
47 SD_CACHE_ENTRIES * sizeof(LIST_ENTRY));
48 if (ObpSdCache == NULL)
49 {
50 return STATUS_INSUFFICIENT_RESOURCES;
51 }
52
53 for (i = 0; i < SD_CACHE_ENTRIES; i++)
54 {
55 InitializeListHead(&ObpSdCache[i]);
56 }
57
58 KeInitializeSpinLock(&ObpSdCacheSpinLock);
59
60 return STATUS_SUCCESS;
61 }
62
63
64 static VOID
65 ObpSdCacheLock(VOID)
66 {
67 KeAcquireSpinLock(&ObpSdCacheSpinLock,
68 &ObpSdCacheIrql);
69 }
70
71
72 static VOID
73 ObpSdCacheUnlock(VOID)
74 {
75 KeReleaseSpinLock(&ObpSdCacheSpinLock,
76 ObpSdCacheIrql);
77 }
78
79
80 static ULONG
81 ObpHash(PVOID Buffer,
82 ULONG Length)
83 {
84 PUCHAR Ptr;
85 ULONG Value;
86 ULONG i;
87
88 Ptr = (PUCHAR)Buffer;
89 Value = 0;
90 for (i = 0; i < Length; i++)
91 {
92 Value += *Ptr;
93 Ptr++;
94 }
95
96 return Value;
97 }
98
99
100 static ULONG
101 ObpHashSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
102 {
103 ULONG Value;
104 BOOLEAN Defaulted;
105 BOOLEAN DaclPresent;
106 BOOLEAN SaclPresent;
107 PSID Owner = NULL;
108 PSID Group = NULL;
109 PACL Dacl = NULL;
110 PACL Sacl = NULL;
111
112 RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
113 &Owner,
114 &Defaulted);
115
116 RtlGetGroupSecurityDescriptor(SecurityDescriptor,
117 &Group,
118 &Defaulted);
119
120 RtlGetDaclSecurityDescriptor(SecurityDescriptor,
121 &DaclPresent,
122 &Dacl,
123 &Defaulted);
124
125 RtlGetSaclSecurityDescriptor(SecurityDescriptor,
126 &SaclPresent,
127 &Sacl,
128 &Defaulted);
129
130 Value = 0;
131 if (Owner != NULL)
132 {
133 Value += ObpHash(Owner, RtlLengthSid(Owner));
134 }
135
136 if (Group != NULL)
137 {
138 Value += ObpHash(Group, RtlLengthSid(Group));
139 }
140
141 if (DaclPresent == TRUE && Dacl != NULL)
142 {
143 Value += ObpHash(Dacl, Dacl->AclSize);
144 }
145
146 if (SaclPresent == TRUE && Sacl != NULL)
147 {
148 Value += ObpHash(Sacl, Sacl->AclSize);
149 }
150
151 return Value;
152 }
153
154
155 static PSD_CACHE_ENTRY
156 ObpCreateCacheEntry(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
157 IN ULONG HashValue,
158 IN ULONG Index,
159 OUT PSECURITY_DESCRIPTOR *NewSD)
160 {
161 PSECURITY_DESCRIPTOR Sd;
162 PSD_CACHE_ENTRY CacheEntry;
163 ULONG Length;
164
165 DPRINT("ObpCreateCacheEntry() called\n");
166
167 Length = RtlLengthSecurityDescriptor(SecurityDescriptor);
168
169 CacheEntry = ExAllocatePool(NonPagedPool,
170 sizeof(SD_CACHE_ENTRY) + Length);
171 if (CacheEntry == NULL)
172 {
173 DPRINT1("ExAllocatePool() failed\n");
174 return NULL;
175 }
176
177 CacheEntry->HashValue = HashValue;
178 CacheEntry->Index = Index;
179 CacheEntry->RefCount = 1;
180
181 Sd = (PSECURITY_DESCRIPTOR)(CacheEntry + 1);
182 RtlCopyMemory(Sd,
183 SecurityDescriptor,
184 Length);
185
186 *NewSD = Sd;
187
188 DPRINT("ObpCreateCacheEntry() done\n");
189
190 return CacheEntry;
191 }
192
193
194 static BOOLEAN
195 ObpCompareSecurityDescriptors(IN PSECURITY_DESCRIPTOR Sd1,
196 IN PSECURITY_DESCRIPTOR Sd2)
197 {
198 ULONG Length1;
199 ULONG Length2;
200
201 Length1 = RtlLengthSecurityDescriptor(Sd1);
202 Length2 = RtlLengthSecurityDescriptor(Sd2);
203 if (Length1 != Length2)
204 return FALSE;
205
206 if (RtlCompareMemory(Sd1, Sd2, Length1) != Length1)
207 return FALSE;
208
209 return TRUE;
210 }
211
212
213 NTSTATUS
214 ObpAddSecurityDescriptor(IN PSECURITY_DESCRIPTOR SourceSD,
215 OUT PSECURITY_DESCRIPTOR *DestinationSD)
216 {
217 PSECURITY_DESCRIPTOR Sd;
218 PLIST_ENTRY CurrentEntry;
219 PSD_CACHE_ENTRY CacheEntry;
220 ULONG HashValue;
221 ULONG Index;
222 NTSTATUS Status;
223
224 DPRINT("ObpAddSecurityDescriptor() called\n");
225
226 HashValue = ObpHashSecurityDescriptor(SourceSD);
227 Index = HashValue & 0xFF;
228
229 ObpSdCacheLock();
230
231 if (!IsListEmpty(&ObpSdCache[Index]))
232 {
233 CurrentEntry = ObpSdCache[Index].Flink;
234 while (CurrentEntry != &ObpSdCache[Index])
235 {
236 CacheEntry = CONTAINING_RECORD(CurrentEntry,
237 SD_CACHE_ENTRY,
238 ListEntry);
239 Sd = (PSECURITY_DESCRIPTOR)(CacheEntry + 1);
240
241 if (CacheEntry->HashValue == HashValue &&
242 ObpCompareSecurityDescriptors(SourceSD, Sd))
243 {
244 CacheEntry->RefCount++;
245 DPRINT("RefCount %lu\n", CacheEntry->RefCount);
246 *DestinationSD = Sd;
247
248 ObpSdCacheUnlock();
249
250 DPRINT("ObpAddSecurityDescriptor() done\n");
251
252 return STATUS_SUCCESS;
253 }
254
255 CurrentEntry = CurrentEntry->Flink;
256 }
257 }
258
259 CacheEntry = ObpCreateCacheEntry(SourceSD,
260 HashValue,
261 Index,
262 DestinationSD);
263 if (CacheEntry == NULL)
264 {
265 DPRINT1("ObpCreateCacheEntry() failed\n");
266 Status = STATUS_INSUFFICIENT_RESOURCES;
267 }
268 else
269 {
270 DPRINT("RefCount 1\n");
271 InsertTailList(&ObpSdCache[Index], &CacheEntry->ListEntry);
272 Status = STATUS_SUCCESS;
273 }
274
275 ObpSdCacheUnlock();
276
277 DPRINT("ObpAddSecurityDescriptor() done\n");
278
279 return Status;
280 }
281
282
283 NTSTATUS
284 ObpRemoveSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
285 {
286 PSD_CACHE_ENTRY CacheEntry;
287
288 DPRINT("ObpRemoveSecurityDescriptor() called\n");
289
290 ObpSdCacheLock();
291
292 CacheEntry = (PSD_CACHE_ENTRY)((ULONG_PTR)SecurityDescriptor - sizeof(SD_CACHE_ENTRY));
293
294 CacheEntry->RefCount--;
295 DPRINT("RefCount %lu\n", CacheEntry->RefCount);
296 if (CacheEntry->RefCount == 0)
297 {
298 DPRINT("Remove cache entry\n");
299 RemoveEntryList(&CacheEntry->ListEntry);
300 ExFreePool(CacheEntry);
301 }
302
303 ObpSdCacheUnlock();
304
305 DPRINT("ObpRemoveSecurityDescriptor() done\n");
306
307 return STATUS_SUCCESS;
308 }
309
310
311 VOID
312 ObpReferenceCachedSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
313 {
314 PSD_CACHE_ENTRY CacheEntry;
315
316 DPRINT("ObpReferenceCachedSecurityDescriptor() called\n");
317
318 ObpSdCacheLock();
319
320 CacheEntry = (PSD_CACHE_ENTRY)((ULONG_PTR)SecurityDescriptor - sizeof(SD_CACHE_ENTRY));
321
322 CacheEntry->RefCount++;
323 DPRINT("RefCount %lu\n", CacheEntry->RefCount);
324
325 ObpSdCacheUnlock();
326
327 DPRINT("ObpReferenceCachedSecurityDescriptor() done\n");
328 }
329
330
331 VOID
332 ObpDereferenceCachedSecurityDescriptor(IN PSECURITY_DESCRIPTOR SecurityDescriptor)
333 {
334 DPRINT("ObpDereferenceCachedSecurityDescriptor() called\n");
335
336 ObpRemoveSecurityDescriptor(SecurityDescriptor);
337
338 DPRINT("ObpDereferenceCachedSecurityDescriptor() done\n");
339 }
340
341 /* EOF */