+ntoskrnl/se/token.c
[reactos.git] / ntoskrnl / se / token.c
1 /* $Id$
2  *
3  * COPYRIGHT:         See COPYING in the top level directory
4  * PROJECT:           ReactOS kernel
5  * PURPOSE:           Security manager
6  * FILE:              kernel/se/token.c
7  * PROGRAMER:         David Welch <welch@cwcom.net>
8  * REVISION HISTORY:
9  *                 26/07/98: Added stubs for security functions
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <limits.h>
15 #include <ddk/ntddk.h>
16 #include <internal/ps.h>
17 #include <internal/se.h>
18 #include <internal/safe.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 /* GLOBALS *******************************************************************/
24
25 POBJECT_TYPE SepTokenObjectType = NULL;
26
27 static GENERIC_MAPPING SepTokenMapping = {TOKEN_READ,
28                                           TOKEN_WRITE,
29                                           TOKEN_EXECUTE,
30                                           TOKEN_ALL_ACCESS};
31
32 #define SYSTEM_LUID                      0x3E7;
33
34 /* FUNCTIONS *****************************************************************/
35
36 #ifndef LIBCAPTIVE
37
38 VOID SepFreeProxyData(PVOID ProxyData)
39 {
40    UNIMPLEMENTED;
41 }
42
43 NTSTATUS SepCopyProxyData(PVOID* Dest, PVOID Src)
44 {
45    UNIMPLEMENTED;
46 }
47
48 NTSTATUS SeExchangePrimaryToken(PEPROCESS Process,
49                                 PACCESS_TOKEN NewToken,
50                                 PACCESS_TOKEN* OldTokenP)
51 {
52    PACCESS_TOKEN OldToken;
53    
54    if (NewToken->TokenType != TokenPrimary)
55      {
56         return(STATUS_UNSUCCESSFUL);
57      }
58    if (NewToken->TokenInUse != 0)
59      {
60         return(STATUS_UNSUCCESSFUL);
61      }
62    OldToken = Process->Token;
63    Process->Token = NewToken;
64    NewToken->TokenInUse = 1;
65    ObReferenceObjectByPointer(NewToken,
66                               TOKEN_ALL_ACCESS,
67                               SepTokenObjectType,
68                               KernelMode);
69    OldToken->TokenInUse = 0;
70    *OldTokenP = OldToken;
71    return(STATUS_SUCCESS);
72 }
73
74 static ULONG
75 RtlLengthSidAndAttributes(ULONG Count,
76                           PSID_AND_ATTRIBUTES Src)
77 {
78   ULONG i;
79   ULONG uLength;
80
81   uLength = Count * sizeof(SID_AND_ATTRIBUTES);
82   for (i = 0; i < Count; i++)
83     uLength += RtlLengthSid(Src[i].Sid);
84
85   return(uLength);
86 }
87
88
89 NTSTATUS
90 SepFindPrimaryGroupAndDefaultOwner(PACCESS_TOKEN Token,
91                                    PSID PrimaryGroup,
92                                    PSID DefaultOwner)
93 {
94   ULONG i;
95
96   Token->PrimaryGroup = 0;
97
98   if (DefaultOwner)
99     {
100       Token->DefaultOwnerIndex = Token->UserAndGroupCount;
101     }
102
103   /* Validate and set the primary group and user pointers */
104   for (i = 0; i < Token->UserAndGroupCount; i++)
105     {
106       if (DefaultOwner &&
107           RtlEqualSid(Token->UserAndGroups[i].Sid, DefaultOwner))
108         {
109           Token->DefaultOwnerIndex = i;
110         }
111
112       if (RtlEqualSid(Token->UserAndGroups[i].Sid, PrimaryGroup))
113         {
114           Token->PrimaryGroup = Token->UserAndGroups[i].Sid;
115         }
116     }
117
118   if (Token->DefaultOwnerIndex == Token->UserAndGroupCount)
119     {
120       return(STATUS_INVALID_OWNER);
121     }
122
123   if (Token->PrimaryGroup == 0)
124     {
125       return(STATUS_INVALID_PRIMARY_GROUP);
126     }
127
128   return(STATUS_SUCCESS);
129 }
130
131
132 NTSTATUS
133 SepDuplicateToken(PACCESS_TOKEN Token,
134                   POBJECT_ATTRIBUTES ObjectAttributes,
135                   TOKEN_TYPE TokenType,
136                   SECURITY_IMPERSONATION_LEVEL Level,
137                   SECURITY_IMPERSONATION_LEVEL ExistingLevel,
138                   KPROCESSOR_MODE PreviousMode,
139                   PACCESS_TOKEN* NewAccessToken)
140 {
141   NTSTATUS Status;
142   ULONG uLength;
143   ULONG i;
144   
145   PVOID EndMem;
146
147   PACCESS_TOKEN AccessToken;
148
149   Status = ObCreateObject(0,
150                           TOKEN_ALL_ACCESS,
151                           ObjectAttributes,
152                           SepTokenObjectType,
153                           (PVOID*)&AccessToken);
154   if (!NT_SUCCESS(Status))
155     {
156       DPRINT1("ObCreateObject() failed (Status %lx)\n");
157       return(Status);
158     }
159
160   Status = ZwAllocateLocallyUniqueId(&AccessToken->TokenId);
161   if (!NT_SUCCESS(Status))
162     {
163       ObDereferenceObject(AccessToken);
164       return(Status);
165     }
166
167   Status = ZwAllocateLocallyUniqueId(&AccessToken->ModifiedId);
168   if (!NT_SUCCESS(Status))
169     {
170       ObDereferenceObject(AccessToken);
171       return(Status);
172     }
173
174   AccessToken->TokenInUse = 0;
175   AccessToken->TokenType  = TokenType;
176   AccessToken->ImpersonationLevel = Level;
177   AccessToken->AuthenticationId.QuadPart = SYSTEM_LUID;
178
179   AccessToken->TokenSource.SourceIdentifier.QuadPart = Token->TokenSource.SourceIdentifier.QuadPart;
180   memcpy(AccessToken->TokenSource.SourceName, Token->TokenSource.SourceName, sizeof(Token->TokenSource.SourceName));
181   AccessToken->ExpirationTime.QuadPart = Token->ExpirationTime.QuadPart;
182   AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
183   AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
184
185   uLength = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
186   for (i = 0; i < Token->UserAndGroupCount; i++)
187     uLength += RtlLengthSid(Token->UserAndGroups[i].Sid);
188
189   AccessToken->UserAndGroups = 
190     (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
191                                                uLength,
192                                                TAG('T', 'O', 'K', 'u'));
193
194   EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
195
196   Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
197                                         Token->UserAndGroups,
198                                         uLength,
199                                         AccessToken->UserAndGroups,
200                                         EndMem,
201                                         &EndMem,
202                                         &uLength);
203   if (NT_SUCCESS(Status))
204     {
205       Status = SepFindPrimaryGroupAndDefaultOwner(
206         AccessToken,
207         Token->PrimaryGroup,
208         0);
209     }
210
211   if (NT_SUCCESS(Status))
212     {
213       AccessToken->PrivilegeCount = Token->PrivilegeCount;
214
215       uLength = AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
216       AccessToken->Privileges =
217         (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
218                                                     uLength,
219                                                     TAG('T', 'O', 'K', 'p'));
220
221       for (i = 0; i < AccessToken->PrivilegeCount; i++)
222         {
223           RtlCopyLuid(&AccessToken->Privileges[i].Luid,
224             &Token->Privileges[i].Luid);
225           AccessToken->Privileges[i].Attributes = 
226             Token->Privileges[i].Attributes;
227         }
228
229       if ( Token->DefaultDacl )
230         {
231           AccessToken->DefaultDacl =
232             (PACL) ExAllocatePoolWithTag(NonPagedPool,
233                                          Token->DefaultDacl->AclSize,
234                                          TAG('T', 'O', 'K', 'd'));
235           memcpy(AccessToken->DefaultDacl,
236                  Token->DefaultDacl,
237                  Token->DefaultDacl->AclSize);
238         }
239       else
240         {
241           AccessToken->DefaultDacl = 0;
242         }
243     }
244
245   if ( NT_SUCCESS(Status) )
246     {
247       *NewAccessToken = AccessToken;
248       return(STATUS_SUCCESS);
249     }
250
251   ObDereferenceObject(AccessToken);
252   return(Status);
253 }
254
255
256 NTSTATUS
257 SepInitializeNewProcess(struct _EPROCESS* NewProcess,
258                         struct _EPROCESS* ParentProcess)
259 {
260   NTSTATUS Status;
261   PACCESS_TOKEN pNewToken;
262   PACCESS_TOKEN pParentToken;
263   
264   OBJECT_ATTRIBUTES ObjectAttributes;
265
266   pParentToken = (PACCESS_TOKEN) ParentProcess->Token;
267
268   InitializeObjectAttributes(&ObjectAttributes,
269                             NULL,
270                             0,
271                             NULL,
272                             NULL);
273
274   Status = SepDuplicateToken(pParentToken,
275                              &ObjectAttributes,
276                              TokenPrimary,
277                              pParentToken->ImpersonationLevel,
278                              pParentToken->ImpersonationLevel,
279                              KernelMode,
280                              &pNewToken);
281   if ( ! NT_SUCCESS(Status) )
282     return Status;
283
284   NewProcess->Token = pNewToken;
285   return(STATUS_SUCCESS);
286 }
287
288
289 NTSTATUS SeCopyClientToken(PACCESS_TOKEN Token,
290                            SECURITY_IMPERSONATION_LEVEL Level,
291                            KPROCESSOR_MODE PreviousMode,
292                            PACCESS_TOKEN* NewToken)
293 {
294    NTSTATUS Status;
295    OBJECT_ATTRIBUTES ObjectAttributes;
296      
297    InitializeObjectAttributes(&ObjectAttributes,
298                               NULL,
299                               0,
300                               NULL,
301                               NULL);
302    Status = SepDuplicateToken(Token,
303                                 &ObjectAttributes,
304                                 0,
305                                 SecurityIdentification,
306                                 Level,
307                                 PreviousMode,
308                                 NewToken);
309    return(Status);
310 }
311
312
313 NTSTATUS STDCALL
314 SeCreateClientSecurity(IN struct _ETHREAD *Thread,
315                        IN PSECURITY_QUALITY_OF_SERVICE Qos,
316                        IN BOOLEAN RemoteClient,
317                        OUT PSECURITY_CLIENT_CONTEXT ClientContext)
318 {
319    TOKEN_TYPE TokenType;
320    UCHAR b;
321    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
322    PACCESS_TOKEN Token;
323    ULONG g;
324    PACCESS_TOKEN NewToken;
325    
326    Token = PsReferenceEffectiveToken(Thread,
327                                      &TokenType,
328                                      &b,
329                                      &ImpersonationLevel);
330    if (TokenType != 2)
331      {
332         ClientContext->DirectAccessEffectiveOnly = Qos->EffectiveOnly;
333      }
334    else
335      {
336         if (Qos->ImpersonationLevel > ImpersonationLevel)
337           {
338              if (Token != NULL)
339                {
340                   ObDereferenceObject(Token);
341                }
342              return(STATUS_UNSUCCESSFUL);
343           }
344         if (ImpersonationLevel == 0 ||
345             ImpersonationLevel == 1 ||
346             (RemoteClient != FALSE && ImpersonationLevel != 3))
347           {
348              if (Token != NULL)
349                {
350                   ObDereferenceObject(Token);
351                }
352              return(STATUS_UNSUCCESSFUL);
353           }
354         if (b != 0 ||
355             Qos->EffectiveOnly != 0)
356           {
357              ClientContext->DirectAccessEffectiveOnly = TRUE;
358           }
359         else
360           {
361              ClientContext->DirectAccessEffectiveOnly = FALSE;
362           }
363      }
364    
365    if (Qos->ContextTrackingMode == 0)
366      {
367         ClientContext->DirectlyAccessClientToken = FALSE;
368         g = SeCopyClientToken(Token, ImpersonationLevel, 0, &NewToken);
369         if (g >= 0)
370           {
371 //           ObDeleteCapturedInsertInfo(NewToken);
372           }
373         if (TokenType == TokenPrimary || Token != NULL)
374           {
375              ObDereferenceObject(Token);
376           }
377         if (g < 0)
378           {
379              return(g);
380           }
381     }
382   else
383     {
384         ClientContext->DirectlyAccessClientToken = TRUE;
385         if (RemoteClient != FALSE)
386           {
387 //           SeGetTokenControlInformation(Token, &ClientContext->Unknown11);
388           }
389         NewToken = Token;
390     }
391   ClientContext->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
392   ClientContext->SecurityQos.ImpersonationLevel = Qos->ImpersonationLevel;
393   ClientContext->SecurityQos.ContextTrackingMode = Qos->ContextTrackingMode;
394   ClientContext->SecurityQos.EffectiveOnly = Qos->EffectiveOnly;
395   ClientContext->ServerIsRemote = RemoteClient;
396   ClientContext->Token = NewToken;
397
398   return(STATUS_SUCCESS);
399 }
400
401
402 VOID STDCALL
403 SeImpersonateClient(IN PSECURITY_CLIENT_CONTEXT ClientContext,
404                     IN PETHREAD ServerThread OPTIONAL)
405 {
406   UCHAR b;
407   
408   if (ClientContext->DirectlyAccessClientToken == FALSE)
409     {
410       b = ClientContext->SecurityQos.EffectiveOnly;
411     }
412   else
413     {
414       b = ClientContext->DirectAccessEffectiveOnly;
415     }
416   if (ServerThread == NULL)
417     {
418       ServerThread = PsGetCurrentThread();
419     }
420   PsImpersonateClient(ServerThread,
421                       ClientContext->Token,
422                       1,
423                       (ULONG)b,
424                       ClientContext->SecurityQos.ImpersonationLevel);
425 }
426
427 #endif /* LIBCAPTIVE */
428
429 VOID STDCALL
430 SepDeleteToken(PVOID ObjectBody)
431 {
432   PACCESS_TOKEN AccessToken = (PACCESS_TOKEN)ObjectBody;
433
434   if (AccessToken->UserAndGroups)
435     ExFreePool(AccessToken->UserAndGroups);
436
437   if (AccessToken->Privileges)
438     ExFreePool(AccessToken->Privileges);
439
440   if (AccessToken->DefaultDacl)
441     ExFreePool(AccessToken->DefaultDacl);
442 }
443
444
445 VOID
446 SepInitializeTokenImplementation(VOID)
447 {
448   SepTokenObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
449
450   SepTokenObjectType->Tag = TAG('T', 'O', 'K', 'T');
451   SepTokenObjectType->MaxObjects = ULONG_MAX;
452   SepTokenObjectType->MaxHandles = ULONG_MAX;
453   SepTokenObjectType->TotalObjects = 0;
454   SepTokenObjectType->TotalHandles = 0;
455   SepTokenObjectType->PagedPoolCharge = 0;
456   SepTokenObjectType->NonpagedPoolCharge = sizeof(ACCESS_TOKEN);
457   SepTokenObjectType->Mapping = &SepTokenMapping;
458   SepTokenObjectType->Dump = NULL;
459   SepTokenObjectType->Open = NULL;
460   SepTokenObjectType->Close = NULL;
461   SepTokenObjectType->Delete = SepDeleteToken;
462   SepTokenObjectType->Parse = NULL;
463   SepTokenObjectType->Security = NULL;
464   SepTokenObjectType->QueryName = NULL;
465   SepTokenObjectType->OkayToClose = NULL;
466   SepTokenObjectType->Create = NULL;
467   SepTokenObjectType->DuplicationNotify = NULL;
468
469   RtlCreateUnicodeString(&SepTokenObjectType->TypeName,
470                          REACTOS_UCS2(L"Token"));
471 }
472
473 #ifndef LIBCAPTIVE
474
475 NTSTATUS STDCALL
476 NtQueryInformationToken(IN HANDLE TokenHandle,
477                         IN TOKEN_INFORMATION_CLASS TokenInformationClass,
478                         OUT PVOID TokenInformation,
479                         IN ULONG TokenInformationLength,
480                         OUT PULONG ReturnLength)
481 {
482   NTSTATUS Status;
483   PACCESS_TOKEN Token;
484   PVOID UnusedInfo;
485   PVOID EndMem;
486   PTOKEN_GROUPS PtrTokenGroups;
487   PTOKEN_DEFAULT_DACL PtrDefaultDacl;
488   PTOKEN_STATISTICS PtrTokenStatistics;
489   ULONG uLength;
490
491   Status = ObReferenceObjectByHandle(TokenHandle,
492                                      (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY,
493                                      SepTokenObjectType,
494                                      UserMode,
495                                      (PVOID*)&Token,
496                                      NULL);
497   if (!NT_SUCCESS(Status))
498     {
499       return(Status);
500     }
501
502   switch (TokenInformationClass)
503     {
504       case TokenUser:
505         DPRINT("NtQueryInformationToken(TokenUser)\n");
506         uLength = RtlLengthSidAndAttributes(1, Token->UserAndGroups);
507         if (TokenInformationLength < uLength)
508           {
509             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
510             if (NT_SUCCESS(Status))
511               Status = STATUS_BUFFER_TOO_SMALL;
512           }
513         else
514           {
515             Status = RtlCopySidAndAttributesArray(1,
516                                                   Token->UserAndGroups,
517                                                   TokenInformationLength,
518                                                   TokenInformation,
519                                                   TokenInformation + 8,
520                                                   &UnusedInfo,
521                                                   &uLength);
522             if (NT_SUCCESS(Status))
523               {
524                 uLength = TokenInformationLength - uLength;
525                 Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
526               }
527           }
528         break;
529         
530       case TokenGroups:
531         DPRINT("NtQueryInformationToken(TokenGroups)\n");
532         uLength = RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]) + sizeof(DWORD);
533         if (TokenInformationLength < uLength)
534           {
535             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
536             if (NT_SUCCESS(Status))
537               Status = STATUS_BUFFER_TOO_SMALL;
538           }
539         else
540           {
541             EndMem = TokenInformation + Token->UserAndGroupCount * sizeof(SID_AND_ATTRIBUTES);
542             PtrTokenGroups = (PTOKEN_GROUPS)TokenInformation;
543             PtrTokenGroups->GroupCount = Token->UserAndGroupCount - 1;
544             Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
545                                                   &Token->UserAndGroups[1],
546                                                   TokenInformationLength,
547                                                   PtrTokenGroups->Groups,
548                                                   EndMem,
549                                                   &UnusedInfo,
550                                                   &uLength);
551             if (NT_SUCCESS(Status))
552               {
553                 uLength = TokenInformationLength - uLength;
554                 Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
555               }
556           }
557         break;
558
559       case TokenPrivileges:
560         DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
561         uLength = sizeof(DWORD) + Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
562         if (TokenInformationLength < uLength)
563           {
564             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
565             if (NT_SUCCESS(Status))
566               Status = STATUS_BUFFER_TOO_SMALL;
567           }
568         else
569           {
570             ULONG i;
571             TOKEN_PRIVILEGES* pPriv = (TOKEN_PRIVILEGES*)TokenInformation;
572
573             pPriv->PrivilegeCount = Token->PrivilegeCount;
574             for (i = 0; i < Token->PrivilegeCount; i++)
575               {
576                 RtlCopyLuid(&pPriv->Privileges[i].Luid, &Token->Privileges[i].Luid);
577                 pPriv->Privileges[i].Attributes = Token->Privileges[i].Attributes;
578               }
579             Status = STATUS_SUCCESS;
580           }
581         break;
582
583       case TokenOwner:
584         DPRINT("NtQueryInformationToken(TokenOwner)\n");
585         uLength = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid) + sizeof(TOKEN_OWNER);
586         if (TokenInformationLength < uLength)
587           {
588             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
589             if (NT_SUCCESS(Status))
590               Status = STATUS_BUFFER_TOO_SMALL;
591           }
592         else
593           {
594             ((PTOKEN_OWNER)TokenInformation)->Owner = 
595               (PSID)(((PTOKEN_OWNER)TokenInformation) + 1);
596             RtlCopySid(TokenInformationLength - sizeof(TOKEN_OWNER),
597                        ((PTOKEN_OWNER)TokenInformation)->Owner,
598                        Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
599             Status = STATUS_SUCCESS;
600           }
601         break;
602
603       case TokenPrimaryGroup:
604         DPRINT("NtQueryInformationToken(TokenPrimaryGroup),"
605                "Token->PrimaryGroup = 0x%08x\n", Token->PrimaryGroup);
606         uLength = RtlLengthSid(Token->PrimaryGroup) + sizeof(TOKEN_PRIMARY_GROUP);
607         if (TokenInformationLength < uLength)
608           {
609             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
610             if (NT_SUCCESS(Status))
611               Status = STATUS_BUFFER_TOO_SMALL;
612           }
613         else
614           {
615             ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup = 
616               (PSID)(((PTOKEN_PRIMARY_GROUP)TokenInformation) + 1);
617             RtlCopySid(TokenInformationLength - sizeof(TOKEN_PRIMARY_GROUP),
618                        ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup,
619                        Token->PrimaryGroup);
620             Status = STATUS_SUCCESS;
621           }
622         break;
623
624       case TokenDefaultDacl:
625         DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
626         PtrDefaultDacl = (PTOKEN_DEFAULT_DACL) TokenInformation;
627         uLength = (Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0) + sizeof(TOKEN_DEFAULT_DACL);
628         if (TokenInformationLength < uLength)
629           {
630             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
631             if (NT_SUCCESS(Status))
632               Status = STATUS_BUFFER_TOO_SMALL;
633           }
634         else if (!Token->DefaultDacl)
635           {
636             PtrDefaultDacl->DefaultDacl = 0;
637             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
638           }
639         else
640           {
641             PtrDefaultDacl->DefaultDacl = (PACL) (PtrDefaultDacl + 1);
642             memmove(PtrDefaultDacl->DefaultDacl,
643                     Token->DefaultDacl,
644                     Token->DefaultDacl->AclSize);
645             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
646           }
647         break;
648
649       case TokenSource:
650         DPRINT("NtQueryInformationToken(TokenSource)\n");
651         if (TokenInformationLength < sizeof(TOKEN_SOURCE))
652           {
653             uLength = sizeof(TOKEN_SOURCE);
654             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
655             if (NT_SUCCESS(Status))
656               Status = STATUS_BUFFER_TOO_SMALL;
657           }
658         else
659           {
660             Status = MmCopyToCaller(TokenInformation, &Token->TokenSource, sizeof(TOKEN_SOURCE));
661           }
662         break;
663
664       case TokenType:
665         DPRINT("NtQueryInformationToken(TokenType)\n");
666         if (TokenInformationLength < sizeof(TOKEN_TYPE))
667           {
668             uLength = sizeof(TOKEN_TYPE);
669             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
670             if (NT_SUCCESS(Status))
671               Status = STATUS_BUFFER_TOO_SMALL;
672           }
673         else
674           {
675             Status = MmCopyToCaller(TokenInformation, &Token->TokenType, sizeof(TOKEN_TYPE));
676           }
677         break;
678
679       case TokenImpersonationLevel:
680         DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
681         if (TokenInformationLength < sizeof(SECURITY_IMPERSONATION_LEVEL))
682           {
683             uLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
684             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
685             if (NT_SUCCESS(Status))
686               Status = STATUS_BUFFER_TOO_SMALL;
687           }
688         else
689           {
690             Status = MmCopyToCaller(TokenInformation, &Token->ImpersonationLevel, sizeof(SECURITY_IMPERSONATION_LEVEL));
691           }
692         break;
693
694       case TokenStatistics:
695         DPRINT("NtQueryInformationToken(TokenStatistics)\n");
696         if (TokenInformationLength < sizeof(TOKEN_STATISTICS))
697           {
698             uLength = sizeof(TOKEN_STATISTICS);
699             Status = MmCopyToCaller(ReturnLength, &uLength, sizeof(ULONG));
700             if (NT_SUCCESS(Status))
701               Status = STATUS_BUFFER_TOO_SMALL;
702           }
703         else
704           {
705             PtrTokenStatistics = (PTOKEN_STATISTICS)TokenInformation;
706             PtrTokenStatistics->TokenId = Token->TokenId;
707             PtrTokenStatistics->AuthenticationId = Token->AuthenticationId;
708             PtrTokenStatistics->ExpirationTime = Token->ExpirationTime;
709             PtrTokenStatistics->TokenType = Token->TokenType;
710             PtrTokenStatistics->ImpersonationLevel = Token->ImpersonationLevel;
711             PtrTokenStatistics->DynamicCharged = Token->DynamicCharged;
712             PtrTokenStatistics->DynamicAvailable = Token->DynamicAvailable;
713             PtrTokenStatistics->GroupCount = Token->UserAndGroupCount - 1;
714             PtrTokenStatistics->PrivilegeCount = Token->PrivilegeCount;
715             PtrTokenStatistics->ModifiedId = Token->ModifiedId;
716
717             Status = STATUS_SUCCESS;
718           }
719         break;
720     }
721
722   ObDereferenceObject(Token);
723
724   return(Status);
725 }
726
727
728 NTSTATUS STDCALL
729 NtSetInformationToken(IN HANDLE TokenHandle,
730                       IN TOKEN_INFORMATION_CLASS TokenInformationClass,
731                       OUT PVOID TokenInformation,
732                       IN ULONG TokenInformationLength)
733 {
734   UNIMPLEMENTED;
735 }
736
737
738 NTSTATUS STDCALL
739 NtDuplicateToken(IN HANDLE ExistingTokenHandle,
740                  IN ACCESS_MASK DesiredAccess,
741                  IN POBJECT_ATTRIBUTES ObjectAttributes,
742                  IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
743                  IN TOKEN_TYPE TokenType,
744                  OUT PHANDLE NewTokenHandle)
745 {
746 #if 0
747    PACCESS_TOKEN Token;
748    PACCESS_TOKEN NewToken;
749    NTSTATUS Status;
750    ULONG ExistingImpersonationLevel;
751    
752    Status = ObReferenceObjectByHandle(ExistingTokenHandle,
753                                       TOKEN_DUPLICATE,
754                                       SepTokenObjectType,
755                                       UserMode,
756                                       (PVOID*)&Token,
757                                       NULL);
758    
759    ExistingImpersonationLevel = Token->ImpersonationLevel;
760    SepDuplicateToken(Token,
761                      ObjectAttributes,
762                      ImpersonationLevel,
763                      TokenType,
764                      ExistingImpersonationLevel,
765                      KeGetPreviousMode(),
766                      &NewToken);
767 #else
768    UNIMPLEMENTED;
769 #endif
770 }
771
772 VOID SepAdjustGroups(PACCESS_TOKEN Token,
773                      ULONG a,
774                      BOOLEAN ResetToDefault,
775                      PSID_AND_ATTRIBUTES Groups,
776                      ULONG b,
777                      KPROCESSOR_MODE PreviousMode,
778                      ULONG c,
779                      PULONG d,
780                      PULONG e,
781                      PULONG f)
782 {
783    UNIMPLEMENTED;
784 }
785
786
787 NTSTATUS STDCALL
788 NtAdjustGroupsToken(IN HANDLE TokenHandle,
789                     IN BOOLEAN ResetToDefault,
790                     IN PTOKEN_GROUPS NewState,
791                     IN ULONG BufferLength,
792                     OUT PTOKEN_GROUPS PreviousState OPTIONAL,
793                     OUT PULONG ReturnLength)
794 {
795 #if 0
796    NTSTATUS Status;
797    PACCESS_TOKEN Token;
798    ULONG a;
799    ULONG b;
800    ULONG c;
801    
802    Status = ObReferenceObjectByHandle(TokenHandle,
803                                       ?,
804                                       SepTokenObjectType,
805                                       UserMode,
806                                       (PVOID*)&Token,
807                                       NULL);
808    
809    
810    SepAdjustGroups(Token,
811                    0,
812                    ResetToDefault,
813                    NewState->Groups,
814                    ?,
815                    PreviousState,
816                    0,
817                    &a,
818                    &b,
819                    &c);
820 #else
821    UNIMPLEMENTED;
822 #endif
823 }
824
825
826 #if 0
827 NTSTATUS SepAdjustPrivileges(PACCESS_TOKEN Token,           // 0x8
828                              ULONG a,                       // 0xC
829                              KPROCESSOR_MODE PreviousMode,  // 0x10
830                              ULONG PrivilegeCount,          // 0x14
831                              PLUID_AND_ATTRIBUTES Privileges, // 0x18
832                              PTOKEN_PRIVILEGES* PreviousState, // 0x1C
833                              PULONG b, // 0x20
834                              PULONG c, // 0x24
835                              PULONG d) // 0x28
836 {
837    ULONG i;
838    
839    *c = 0;
840    if (Token->PrivilegeCount > 0)
841      {
842         for (i=0; i<Token->PrivilegeCount; i++)
843           {
844              if (PreviousMode != 0)
845                {
846                   if (!(Token->Privileges[i]->Attributes & 
847                         SE_PRIVILEGE_ENABLED))
848                     {
849                        if (a != 0)
850                          {
851                             if (PreviousState != NULL)
852                               {
853                                  memcpy(&PreviousState[i],
854                                         &Token->Privileges[i],
855                                         sizeof(LUID_AND_ATTRIBUTES));
856                               }
857                             Token->Privileges[i].Attributes = 
858                               Token->Privileges[i].Attributes & 
859                               (~SE_PRIVILEGE_ENABLED);
860                          }
861                     }
862                }
863           }
864      }
865    if (PreviousMode != 0)
866      {
867         Token->TokenFlags = Token->TokenFlags & (~1);
868      }
869    else
870      {
871         if (PrivilegeCount <= ?)
872           {
873              
874           }
875      }
876    if (
877 }
878 #endif
879
880
881 NTSTATUS STDCALL
882 NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
883                         IN BOOLEAN DisableAllPrivileges,
884                         IN PTOKEN_PRIVILEGES NewState,
885                         IN ULONG BufferLength,
886                         OUT PTOKEN_PRIVILEGES PreviousState,
887                         OUT PULONG ReturnLength)
888 {
889 #if 0
890    ULONG PrivilegeCount;
891    ULONG Length;
892    PSID_AND_ATTRIBUTES Privileges;
893    ULONG a;
894    ULONG b;
895    ULONG c;
896    
897    PrivilegeCount = NewState->PrivilegeCount;
898    
899    SeCaptureLuidAndAttributesArray(NewState->Privileges,
900                                    &PrivilegeCount,
901                                    KeGetPreviousMode(),
902                                    NULL,
903                                    0,
904                                    NonPagedPool,
905                                    1,
906                                    &Privileges.
907                                    &Length);
908    SepAdjustPrivileges(Token,
909                        0,
910                        KeGetPreviousMode(),
911                        PrivilegeCount,
912                        Privileges,
913                        PreviousState,
914                        &a,
915                        &b,
916                        &c);
917 #else
918    UNIMPLEMENTED;
919 #endif
920 }
921
922 #endif /* LIBCAPTIVE */
923
924 NTSTATUS
925 SepCreateSystemProcessToken(struct _EPROCESS* Process)
926 {
927   NTSTATUS Status;
928   ULONG uSize;
929   ULONG i;
930
931   ULONG uLocalSystemLength = RtlLengthSid(SeLocalSystemSid);
932   ULONG uWorldLength       = RtlLengthSid(SeWorldSid);
933   ULONG uAuthUserLength    = RtlLengthSid(SeAuthenticatedUserSid);
934   ULONG uAdminsLength      = RtlLengthSid(SeAliasAdminsSid);
935
936   PACCESS_TOKEN AccessToken;
937
938   PVOID SidArea;
939
940  /*
941   * Initialize the token
942   */
943   Status = ObCreateObject(NULL,
944                          TOKEN_ALL_ACCESS,
945                          NULL,
946                          SepTokenObjectType,
947                          (PVOID*)&AccessToken);
948
949   Status = NtAllocateLocallyUniqueId(&AccessToken->TokenId);
950   if (!NT_SUCCESS(Status))
951     {
952       ObDereferenceObject(AccessToken);
953       return(Status);
954     }
955
956   Status = NtAllocateLocallyUniqueId(&AccessToken->ModifiedId);
957   if (!NT_SUCCESS(Status))
958     {
959       ObDereferenceObject(AccessToken);
960       return(Status);
961     }
962
963   AccessToken->AuthenticationId.QuadPart = SYSTEM_LUID;
964
965   AccessToken->TokenType = TokenPrimary;
966   AccessToken->ImpersonationLevel = SecurityDelegation;
967   AccessToken->TokenSource.SourceIdentifier.QuadPart = 0;
968   memcpy(AccessToken->TokenSource.SourceName, "SeMgr\0\0\0", 8);
969   AccessToken->ExpirationTime.QuadPart = -1;
970   AccessToken->UserAndGroupCount = 4;
971
972   uSize = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
973   uSize += uLocalSystemLength;
974   uSize += uWorldLength;
975   uSize += uAuthUserLength;
976   uSize += uAdminsLength;
977
978   AccessToken->UserAndGroups = 
979     (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
980                                                uSize,
981                                                TAG('T', 'O', 'K', 'u'));
982   SidArea = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
983
984   i = 0;
985   AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
986   AccessToken->UserAndGroups[i++].Attributes = 0;
987   RtlCopySid(uLocalSystemLength, SidArea, SeLocalSystemSid);
988   SidArea += uLocalSystemLength;
989
990   AccessToken->DefaultOwnerIndex = i;
991   AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
992   AccessToken->PrimaryGroup = (PSID) SidArea;
993   AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT;
994   Status = RtlCopySid(uAdminsLength, SidArea, SeAliasAdminsSid);
995   SidArea += uAdminsLength;
996
997   AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
998   AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY;
999   RtlCopySid(uWorldLength, SidArea, SeWorldSid);
1000   SidArea += uWorldLength;
1001
1002   AccessToken->UserAndGroups[i].Sid = (PSID) SidArea;
1003   AccessToken->UserAndGroups[i++].Attributes = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY;
1004   RtlCopySid(uAuthUserLength, SidArea, SeAuthenticatedUserSid);
1005   SidArea += uAuthUserLength;
1006
1007   AccessToken->PrivilegeCount = 20;
1008
1009   uSize = AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1010   AccessToken->Privileges =
1011         (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
1012                                                     uSize,
1013                                                     TAG('T', 'O', 'K', 'p'));
1014
1015   i = 0;
1016   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1017   AccessToken->Privileges[i++].Luid = SeTcbPrivilege;
1018
1019   AccessToken->Privileges[i].Attributes = 0;
1020   AccessToken->Privileges[i++].Luid = SeCreateTokenPrivilege;
1021
1022   AccessToken->Privileges[i].Attributes = 0;
1023   AccessToken->Privileges[i++].Luid = SeTakeOwnershipPrivilege;
1024   
1025   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1026   AccessToken->Privileges[i++].Luid = SeCreatePagefilePrivilege;
1027   
1028   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1029   AccessToken->Privileges[i++].Luid = SeLockMemoryPrivilege;
1030   
1031   AccessToken->Privileges[i].Attributes = 0;
1032   AccessToken->Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
1033   
1034   AccessToken->Privileges[i].Attributes = 0;
1035   AccessToken->Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
1036   
1037   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1038   AccessToken->Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
1039   
1040   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1041   AccessToken->Privileges[i++].Luid = SeCreatePermanentPrivilege;
1042   
1043   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1044   AccessToken->Privileges[i++].Luid = SeDebugPrivilege;
1045   
1046   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1047   AccessToken->Privileges[i++].Luid = SeAuditPrivilege;
1048   
1049   AccessToken->Privileges[i].Attributes = 0;
1050   AccessToken->Privileges[i++].Luid = SeSecurityPrivilege;
1051   
1052   AccessToken->Privileges[i].Attributes = 0;
1053   AccessToken->Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
1054   
1055   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1056   AccessToken->Privileges[i++].Luid = SeChangeNotifyPrivilege;
1057   
1058   AccessToken->Privileges[i].Attributes = 0;
1059   AccessToken->Privileges[i++].Luid = SeBackupPrivilege;
1060   
1061   AccessToken->Privileges[i].Attributes = 0;
1062   AccessToken->Privileges[i++].Luid = SeRestorePrivilege;
1063   
1064   AccessToken->Privileges[i].Attributes = 0;
1065   AccessToken->Privileges[i++].Luid = SeShutdownPrivilege;
1066   
1067   AccessToken->Privileges[i].Attributes = 0;
1068   AccessToken->Privileges[i++].Luid = SeLoadDriverPrivilege;
1069   
1070   AccessToken->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT|SE_PRIVILEGE_ENABLED;
1071   AccessToken->Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
1072   
1073   AccessToken->Privileges[i].Attributes = 0;
1074   AccessToken->Privileges[i++].Luid = SeSystemtimePrivilege;
1075 #if 0
1076   AccessToken->Privileges[i].Attributes = 0;
1077   AccessToken->Privileges[i++].Luid = SeUndockPrivilege;
1078
1079   AccessToken->Privileges[i].Attributes = 0;
1080   AccessToken->Privileges[i++].Luid = SeManageVolumePrivilege;
1081 #endif
1082
1083   assert( i == 20 );
1084
1085   uSize = sizeof(ACL);
1086   uSize += sizeof(ACE) + uLocalSystemLength;
1087   uSize += sizeof(ACE) + uAdminsLength;
1088   uSize = (uSize & (~3)) + 8;
1089   AccessToken->DefaultDacl =
1090     (PACL) ExAllocatePoolWithTag(NonPagedPool,
1091                                  uSize,
1092                                  TAG('T', 'O', 'K', 'd'));
1093   Status = RtlCreateAcl(AccessToken->DefaultDacl, uSize, ACL_REVISION);
1094   if ( NT_SUCCESS(Status) )
1095     {
1096       Status = RtlAddAccessAllowedAce(AccessToken->DefaultDacl, ACL_REVISION, GENERIC_ALL, SeLocalSystemSid);
1097     }
1098
1099   if ( NT_SUCCESS(Status) )
1100     {
1101       Status = RtlAddAccessAllowedAce(AccessToken->DefaultDacl, ACL_REVISION, GENERIC_READ|GENERIC_EXECUTE|READ_CONTROL, SeAliasAdminsSid);
1102     }
1103
1104   if ( ! NT_SUCCESS(Status) )
1105     {
1106       ObDereferenceObject(AccessToken);
1107       return Status;
1108     }
1109
1110   Process->Token = AccessToken;
1111   return(STATUS_SUCCESS);
1112 }
1113
1114 #ifndef LIBCAPTIVE
1115
1116 NTSTATUS STDCALL
1117 NtCreateToken(OUT PHANDLE UnsafeTokenHandle,
1118               IN ACCESS_MASK DesiredAccess,
1119               IN POBJECT_ATTRIBUTES UnsafeObjectAttributes,
1120               IN TOKEN_TYPE TokenType,
1121               IN PLUID AuthenticationId,
1122               IN PLARGE_INTEGER ExpirationTime,
1123               IN PTOKEN_USER TokenUser,
1124               IN PTOKEN_GROUPS TokenGroups,
1125               IN PTOKEN_PRIVILEGES TokenPrivileges,
1126               IN PTOKEN_OWNER TokenOwner,
1127               IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
1128               IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
1129               IN PTOKEN_SOURCE TokenSource)
1130 {
1131   HANDLE TokenHandle;
1132   PACCESS_TOKEN AccessToken;
1133   NTSTATUS Status;
1134   OBJECT_ATTRIBUTES SafeObjectAttributes;
1135   POBJECT_ATTRIBUTES ObjectAttributes;
1136   LUID TokenId;
1137   LUID ModifiedId;
1138   PVOID EndMem;
1139   ULONG uLength;
1140   ULONG i;
1141
1142   Status = MmCopyFromCaller(&SafeObjectAttributes,
1143                             UnsafeObjectAttributes,
1144                             sizeof(OBJECT_ATTRIBUTES));
1145   if (!NT_SUCCESS(Status))
1146     return(Status);
1147
1148   ObjectAttributes = &SafeObjectAttributes;
1149
1150   Status = ZwAllocateLocallyUniqueId(&TokenId);
1151   if (!NT_SUCCESS(Status))
1152     return(Status);
1153
1154   Status = ZwAllocateLocallyUniqueId(&ModifiedId);
1155   if (!NT_SUCCESS(Status))
1156     return(Status);
1157
1158   Status = ObCreateObject(&TokenHandle,
1159                           DesiredAccess,
1160                           ObjectAttributes,
1161                           SepTokenObjectType,
1162                           (PVOID*)&AccessToken);
1163   if (!NT_SUCCESS(Status))
1164     {
1165       DPRINT1("ObCreateObject() failed (Status %lx)\n");
1166       return(Status);
1167     }
1168
1169   RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
1170               &TokenSource->SourceIdentifier);
1171   memcpy(AccessToken->TokenSource.SourceName,
1172          TokenSource->SourceName,
1173          sizeof(TokenSource->SourceName));
1174
1175   RtlCopyLuid(&AccessToken->TokenId, &TokenId);
1176   RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
1177   AccessToken->ExpirationTime = *ExpirationTime;
1178   RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
1179
1180   AccessToken->UserAndGroupCount = TokenGroups->GroupCount + 1;
1181   AccessToken->PrivilegeCount    = TokenPrivileges->PrivilegeCount;
1182   AccessToken->UserAndGroups     = 0;
1183   AccessToken->Privileges        = 0;
1184
1185   AccessToken->TokenType = TokenType;
1186   AccessToken->ImpersonationLevel = ObjectAttributes->SecurityQualityOfService->ImpersonationLevel;
1187
1188   /*
1189    * Normally we would just point these members into the variable information
1190    * area; however, our ObCreateObject() call can't allocate a variable information
1191    * area, so we allocate them seperately and provide a destroy function.
1192    */
1193
1194   uLength = sizeof(SID_AND_ATTRIBUTES) * AccessToken->UserAndGroupCount;
1195   uLength += RtlLengthSid(TokenUser->User.Sid);
1196   for (i = 0; i < TokenGroups->GroupCount; i++)
1197     uLength += RtlLengthSid(TokenGroups->Groups[i].Sid);
1198
1199   AccessToken->UserAndGroups = 
1200     (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
1201                                                uLength,
1202                                                TAG('T', 'O', 'K', 'u'));
1203
1204   EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1205
1206   Status = RtlCopySidAndAttributesArray(1,
1207                                         &TokenUser->User,
1208                                         uLength,
1209                                         AccessToken->UserAndGroups,
1210                                         EndMem,
1211                                         &EndMem,
1212                                         &uLength);
1213   if (NT_SUCCESS(Status))
1214     {
1215       Status = RtlCopySidAndAttributesArray(TokenGroups->GroupCount,
1216                                             TokenGroups->Groups,
1217                                             uLength,
1218                                             &AccessToken->UserAndGroups[1],
1219                                             EndMem,
1220                                             &EndMem,
1221                                             &uLength);
1222     }
1223
1224   if (NT_SUCCESS(Status))
1225     {
1226       Status = SepFindPrimaryGroupAndDefaultOwner(
1227         AccessToken, 
1228         TokenPrimaryGroup->PrimaryGroup,
1229         TokenOwner->Owner);
1230     }
1231
1232   if (NT_SUCCESS(Status))
1233     {
1234       uLength = TokenPrivileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1235       AccessToken->Privileges =
1236         (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(NonPagedPool,
1237                                                     uLength,
1238                                                     TAG('T', 'O', 'K', 'p'));
1239
1240       for (i = 0; i < TokenPrivileges->PrivilegeCount; i++)
1241         {
1242           Status = MmCopyFromCaller(&AccessToken->Privileges[i],
1243                                     &TokenPrivileges->Privileges[i],
1244                                     sizeof(LUID_AND_ATTRIBUTES));
1245           if (!NT_SUCCESS(Status))
1246             break;
1247         }
1248     }
1249
1250   if (NT_SUCCESS(Status))
1251     {
1252       AccessToken->DefaultDacl =
1253         (PACL) ExAllocatePoolWithTag(NonPagedPool,
1254                                      TokenDefaultDacl->DefaultDacl->AclSize,
1255                                      TAG('T', 'O', 'K', 'd'));
1256       memcpy(AccessToken->DefaultDacl,
1257              TokenDefaultDacl->DefaultDacl,
1258              TokenDefaultDacl->DefaultDacl->AclSize);
1259     }
1260
1261   ObDereferenceObject(AccessToken);
1262
1263   if (NT_SUCCESS(Status))
1264     {
1265       Status = MmCopyToCaller(UnsafeTokenHandle,
1266                               &TokenHandle,
1267                               sizeof(HANDLE));
1268     }
1269
1270   if (!NT_SUCCESS(Status))
1271     {
1272       ZwClose(TokenHandle);
1273       return(Status);
1274     }
1275
1276   return(STATUS_SUCCESS);
1277 }
1278
1279
1280 SECURITY_IMPERSONATION_LEVEL STDCALL
1281 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
1282 {
1283   return(Token->ImpersonationLevel);
1284 }
1285
1286
1287 TOKEN_TYPE STDCALL
1288 SeTokenType(IN PACCESS_TOKEN Token)
1289 {
1290   return(Token->TokenType);
1291 }
1292
1293 #endif /* LIBCAPTIVE */
1294
1295 /* EOF */