[CMAKE]
[reactos.git] / ntoskrnl / se / access.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/access.c
5 * PURPOSE: Access state functions
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) -
8 * Based on patch by Javier M. Mellid
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 ERESOURCE SepSubjectContextLock;
20
21 /* FUNCTIONS ******************************************************************/
22
23 /*
24 * @implemented
25 */
26 VOID
27 NTAPI
28 SeCaptureSubjectContextEx(IN PETHREAD Thread,
29 IN PEPROCESS Process,
30 OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
31 {
32 BOOLEAN CopyOnOpen, EffectiveOnly;
33
34 PAGED_CODE();
35
36 /* Save the unique ID */
37 SubjectContext->ProcessAuditId = Process->UniqueProcessId;
38
39 /* Check if we have a thread */
40 if (!Thread)
41 {
42 /* We don't, so no token */
43 SubjectContext->ClientToken = NULL;
44 }
45 else
46 {
47 /* Get the impersonation token */
48 SubjectContext->ClientToken = PsReferenceImpersonationToken(Thread,
49 &CopyOnOpen,
50 &EffectiveOnly,
51 &SubjectContext->ImpersonationLevel);
52 }
53
54 /* Get the primary token */
55 SubjectContext->PrimaryToken = PsReferencePrimaryToken(Process);
56 }
57
58 /*
59 * @implemented
60 */
61 VOID
62 NTAPI
63 SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
64 {
65 /* Call the extended API */
66 SeCaptureSubjectContextEx(PsGetCurrentThread(),
67 PsGetCurrentProcess(),
68 SubjectContext);
69 }
70
71 /*
72 * @implemented
73 */
74 VOID
75 NTAPI
76 SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
77 {
78 PAGED_CODE();
79
80 KeEnterCriticalRegion();
81 ExAcquireResourceExclusiveLite(&SepSubjectContextLock, TRUE);
82 }
83
84 /*
85 * @implemented
86 */
87 VOID
88 NTAPI
89 SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
90 {
91 PAGED_CODE();
92
93 ExReleaseResourceLite(&SepSubjectContextLock);
94 KeLeaveCriticalRegion();
95 }
96
97 /*
98 * @implemented
99 */
100 VOID
101 NTAPI
102 SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
103 {
104 PAGED_CODE();
105
106 if (SubjectContext->PrimaryToken != NULL)
107 {
108 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, SubjectContext->PrimaryToken);
109 }
110
111 if (SubjectContext->ClientToken != NULL)
112 {
113 ObDereferenceObject(SubjectContext->ClientToken);
114 }
115 }
116
117 /*
118 * @implemented
119 */
120 NTSTATUS
121 NTAPI
122 SeCreateAccessStateEx(IN PETHREAD Thread,
123 IN PEPROCESS Process,
124 IN OUT PACCESS_STATE AccessState,
125 IN PAUX_ACCESS_DATA AuxData,
126 IN ACCESS_MASK Access,
127 IN PGENERIC_MAPPING GenericMapping)
128 {
129 ACCESS_MASK AccessMask = Access;
130 PTOKEN Token;
131
132 PAGED_CODE();
133
134 /* Map the Generic Acess to Specific Access if we have a Mapping */
135 if ((Access & GENERIC_ACCESS) && (GenericMapping))
136 {
137 RtlMapGenericMask(&AccessMask, GenericMapping);
138 }
139
140 /* Initialize the Access State */
141 RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
142
143 /* Capture the Subject Context */
144 SeCaptureSubjectContextEx(Thread,
145 Process,
146 &AccessState->SubjectSecurityContext);
147
148 /* Set Access State Data */
149 AccessState->AuxData = AuxData;
150 AccessState->RemainingDesiredAccess = AccessMask;
151 AccessState->OriginalDesiredAccess = AccessMask;
152 ExpAllocateLocallyUniqueId(&AccessState->OperationID);
153
154 /* Get the Token to use */
155 Token = AccessState->SubjectSecurityContext.ClientToken ?
156 (PTOKEN)&AccessState->SubjectSecurityContext.ClientToken :
157 (PTOKEN)&AccessState->SubjectSecurityContext.PrimaryToken;
158
159 /* Check for Travers Privilege */
160 if (Token->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE)
161 {
162 /* Preserve the Traverse Privilege */
163 AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE;
164 }
165
166 /* Set the Auxiliary Data */
167 AuxData->PrivilegeSet = (PPRIVILEGE_SET)((ULONG_PTR)AccessState +
168 FIELD_OFFSET(ACCESS_STATE,
169 Privileges));
170 if (GenericMapping) AuxData->GenericMapping = *GenericMapping;
171
172 /* Return Sucess */
173 return STATUS_SUCCESS;
174 }
175
176 /*
177 * @implemented
178 */
179 NTSTATUS
180 NTAPI
181 SeCreateAccessState(IN OUT PACCESS_STATE AccessState,
182 IN PAUX_ACCESS_DATA AuxData,
183 IN ACCESS_MASK Access,
184 IN PGENERIC_MAPPING GenericMapping)
185 {
186 PAGED_CODE();
187
188 /* Call the extended API */
189 return SeCreateAccessStateEx(PsGetCurrentThread(),
190 PsGetCurrentProcess(),
191 AccessState,
192 AuxData,
193 Access,
194 GenericMapping);
195 }
196
197 /*
198 * @implemented
199 */
200 VOID
201 NTAPI
202 SeDeleteAccessState(IN PACCESS_STATE AccessState)
203 {
204 PAUX_ACCESS_DATA AuxData;
205
206 PAGED_CODE();
207
208 /* Get the Auxiliary Data */
209 AuxData = AccessState->AuxData;
210
211 /* Deallocate Privileges */
212 if (AccessState->PrivilegesAllocated) ExFreePool(AuxData->PrivilegeSet);
213
214 /* Deallocate Name and Type Name */
215 if (AccessState->ObjectName.Buffer)
216 {
217 ExFreePool(AccessState->ObjectName.Buffer);
218 }
219
220 if (AccessState->ObjectTypeName.Buffer)
221 {
222 ExFreePool(AccessState->ObjectTypeName.Buffer);
223 }
224
225 /* Release the Subject Context */
226 SeReleaseSubjectContext(&AccessState->SubjectSecurityContext);
227 }
228
229 /*
230 * @implemented
231 */
232 VOID
233 NTAPI
234 SeSetAccessStateGenericMapping(IN PACCESS_STATE AccessState,
235 IN PGENERIC_MAPPING GenericMapping)
236 {
237 PAGED_CODE();
238
239 /* Set the Generic Mapping */
240 ((PAUX_ACCESS_DATA)AccessState->AuxData)->GenericMapping = *GenericMapping;
241 }
242
243 /*
244 * @implemented
245 */
246 NTSTATUS
247 NTAPI
248 SeCreateClientSecurity(IN PETHREAD Thread,
249 IN PSECURITY_QUALITY_OF_SERVICE Qos,
250 IN BOOLEAN RemoteClient,
251 OUT PSECURITY_CLIENT_CONTEXT ClientContext)
252 {
253 TOKEN_TYPE TokenType;
254 BOOLEAN ThreadEffectiveOnly;
255 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
256 PACCESS_TOKEN Token;
257 NTSTATUS Status;
258 PACCESS_TOKEN NewToken;
259
260 PAGED_CODE();
261
262 Token = PsReferenceEffectiveToken(Thread,
263 &TokenType,
264 &ThreadEffectiveOnly,
265 &ImpersonationLevel);
266 if (TokenType != TokenImpersonation)
267 {
268 ClientContext->DirectAccessEffectiveOnly = Qos->EffectiveOnly;
269 }
270 else
271 {
272 if (Qos->ImpersonationLevel > ImpersonationLevel)
273 {
274 if (Token) ObDereferenceObject(Token);
275 return STATUS_BAD_IMPERSONATION_LEVEL;
276 }
277
278 if ((ImpersonationLevel == SecurityAnonymous) ||
279 (ImpersonationLevel == SecurityIdentification) ||
280 ((RemoteClient) && (ImpersonationLevel != SecurityDelegation)))
281 {
282 if (Token) ObDereferenceObject(Token);
283 return STATUS_BAD_IMPERSONATION_LEVEL;
284 }
285
286 ClientContext->DirectAccessEffectiveOnly = ((ThreadEffectiveOnly) ||
287 (Qos->EffectiveOnly)) ? TRUE : FALSE;
288 }
289
290 if (Qos->ContextTrackingMode == SECURITY_STATIC_TRACKING)
291 {
292 ClientContext->DirectlyAccessClientToken = FALSE;
293 Status = SeCopyClientToken(Token, ImpersonationLevel, 0, &NewToken);
294 if (!NT_SUCCESS(Status)) return Status;
295 }
296 else
297 {
298 ClientContext->DirectlyAccessClientToken = TRUE;
299 if (RemoteClient != FALSE)
300 {
301 #if 0
302 SeGetTokenControlInformation(Token,
303 &ClientContext->ClientTokenControl);
304 #endif
305 }
306
307 NewToken = Token;
308 }
309
310 ClientContext->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
311 ClientContext->SecurityQos.ImpersonationLevel = Qos->ImpersonationLevel;
312 ClientContext->SecurityQos.ContextTrackingMode = Qos->ContextTrackingMode;
313 ClientContext->SecurityQos.EffectiveOnly = Qos->EffectiveOnly;
314 ClientContext->ServerIsRemote = RemoteClient;
315 ClientContext->ClientToken = NewToken;
316 return STATUS_SUCCESS;
317 }
318
319 /*
320 * @unimplemented
321 */
322 NTSTATUS
323 NTAPI
324 SeCreateClientSecurityFromSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
325 IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
326 IN BOOLEAN ServerIsRemote,
327 OUT PSECURITY_CLIENT_CONTEXT ClientContext)
328 {
329 UNIMPLEMENTED;
330 return STATUS_NOT_IMPLEMENTED;
331 }
332
333 /*
334 * @implemented
335 */
336 NTSTATUS
337 NTAPI
338 SeImpersonateClientEx(IN PSECURITY_CLIENT_CONTEXT ClientContext,
339 IN PETHREAD ServerThread OPTIONAL)
340 {
341 BOOLEAN EffectiveOnly;
342
343 PAGED_CODE();
344
345 if (ClientContext->DirectlyAccessClientToken == FALSE)
346 {
347 EffectiveOnly = ClientContext->SecurityQos.EffectiveOnly;
348 }
349 else
350 {
351 EffectiveOnly = ClientContext->DirectAccessEffectiveOnly;
352 }
353
354 if (ServerThread == NULL)
355 {
356 ServerThread = PsGetCurrentThread();
357 }
358
359 return PsImpersonateClient(ServerThread,
360 ClientContext->ClientToken,
361 TRUE,
362 EffectiveOnly,
363 ClientContext->SecurityQos.ImpersonationLevel);
364 }
365
366 /*
367 * @implemented
368 */
369 VOID
370 NTAPI
371 SeImpersonateClient(IN PSECURITY_CLIENT_CONTEXT ClientContext,
372 IN PETHREAD ServerThread OPTIONAL)
373 {
374 PAGED_CODE();
375
376 SeImpersonateClientEx(ClientContext,
377 ServerThread);
378 }
379
380 /* EOF */