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