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