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