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