test: tokenadj.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# tokenadj.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     tokenadj.c
    00008
    00009 Abstract:
    00010
    00011    This module implements the services that perform individual adjustments
    00012    on token objects.
    00013
    00014 Author:
    00015
    00016     Jim Kelly (JimK) 15-June-1990
    00017
    00018 Environment:
    00019
    00020     Kernel mode only.
    00021
    00022 Revision History:
    00023
    00024 --*/
    00025
    00026 #include "sep.h"
    00027 #include "sertlp.h"
    00028 #include "tokenp.h"
    00029
    00030 #ifdef ALLOC_PRAGMA
    00031 #pragma alloc_text(PAGE,NtAdjustPrivilegesToken)
    00032 #pragma alloc_text(PAGE,NtAdjustGroupsToken)
    00033 #pragma alloc_text(PAGE,SepAdjustPrivileges)
    00034 #pragma alloc_text(PAGE,SepAdjustGroups)
    00035 #endif
    00036
    00037
    00039 //                                                                    //
    00040 //           Token Object Routines & Methods                          //
    00041 //                                                                    //
    00043
    00044
    00045 NTSTATUS
    00046 NtAdjustPrivilegesToken (
    00047     IN HANDLE TokenHandle,
    00048     IN BOOLEAN DisableAllPrivileges,
    00049     IN PTOKEN_PRIVILEGES NewState OPTIONAL,
    00050     IN ULONG BufferLength OPTIONAL,
    00051     OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
    00052     OUT PULONG ReturnLength
    00053     )
    00054
    00055
    00056 /*++
    00057
    00058
    00059 Routine Description:
    00060
    00061     This routine is used to disable or enable privileges in the
    00062     specified token.  The absence of some of the privileges listed to
    00063     be changed won't effect the successful modification of the
    00064     privileges that are in the token.  The previous enabled/disabled
    00065     state of changed privileges may optionally be capture (for
    00066     resetting later).
    00067
    00068     TOKEN_ADJUST_PRIVILEGES access is required to enable or disable
    00069     privileges in a token.
    00070
    00071
    00072 Arguments:
    00073
    00074     TokenHandle - Provides a handle to the token to operate on.
    00075
    00076     DisableAllPrivileges - This boolean parameter may be
    00077         used to disable all privileges assigned to the token.  If
    00078         this parameter is specified as TRUE, then the NewState parameter is
    00079         ignored.
    00080
    00081     NewState - This (optional) parameter points to a TOKEN_PRIVILEGES
    00082         data structure containing the privileges whose states are to
    00083         be adjusted (disabled or enabled).  Only the Enabled flag of
    00084         the attributes associated with each privilege is used.  It
    00085         provides the new value that is to be assigned to the
    00086         privilege in the token.
    00087
    00088     BufferLength - This optional parameter indicates the length (in
    00089         bytes) of the PreviousState buffer.  This value must be
    00090         provided if the PreviousState parameter is provided.
    00091
    00092     PreviousState - This (optional) parameter points to a buffer to
    00093         receive the state of any privileges actually changed by this
    00094         request.  This information is formated as a TOKEN_PRIVILEGES
    00095         data structure which may be passed as the NewState parameter
    00096         in a subsequent call to this routine to restore the original
    00097         state of those privilges.  TOKEN_QUERY access is needed to
    00098         use this parameter.
    00099
    00100         If this buffer does not contain enough space to receive the
    00101         complete list of modified privileges, then no privilege
    00102         states are changed and STATUS_BUFFER_TOO_SMALL is returned.
    00103         In this case, the ReturnLength OUT parameter will
    00104         contain the actual number of bytes needed to hold the
    00105         information.
    00106
    00107     ReturnLength - Indicates the actual number of bytes needed to
    00108         contain the previous privilege state information.
    00109         This parameter is ignored if the PreviousState argument is not
    00110         passed.
    00111
    00112 Return Value:
    00113
    00114     STATUS_SUCCESS - The service successfully completed the requested
    00115         operation.
    00116
    00117     STATUS_NOT_ALL_ASSIGNED - This NT_SUCCESS severity return status
    00118         indicates that not all the specified privileges are currently
    00119         assigned to the caller.  All specified privileges that are
    00120         currently assigned have been successfully adjusted.
    00121
    00122     STATUS_BUFFER_TOO_SMALL - Indicates the optional buffer provided
    00123         to receive the previous states of changed privileges wasn't
    00124         large enough to receive that information.  No changes to
    00125         privilege states has been made.  The number of bytes needed
    00126         to hold the state change information is returned via the
    00127         ReturnLength parameter.
    00128
    00129     STATUS_INVALID_PARAMETER - Indicates neither the DisableAllPrivileges
    00130         parameter was specified as true, nor was an explicit NewState
    00131         provided.
    00132
    00133 --*/
    00134
    00135 {
    00136     KPROCESSOR_MODE PreviousMode;
    00137     NTSTATUS Status;
    00138
    00139     PTOKEN Token;
    00140
    00141     ACCESS_MASK DesiredAccess;
    00142
    00143     ULONG CapturedPrivilegeCount;
    00144     PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
    00145     ULONG CapturedPrivilegesLength;
    00146
    00147     ULONG LocalReturnLength;
    00148     ULONG ChangeCount;
    00149     BOOLEAN ChangesMade;
    00150
    00151     ULONG ParameterLength;
    00152
    00153     PAGED_CODE();
    00154
    00155     //
    00156     //  The semantics of the PreviousState parameter leads to a two-pass
    00157     //  approach to adjusting privileges.  The first pass simply checks
    00158     //  to see which privileges will change and counts them.  This allows
    00159     //  the amount of space needed to be calculated and returned.  If
    00160     //  the caller's PreviousState return buffer is not large enough, then
    00161     //  an error is returned without making any modifications.  Otherwise,
    00162     //  a second pass is made to actually make the changes.
    00163     //
    00164     //
    00165
    00166     if (!DisableAllPrivileges && !ARGUMENT_PRESENT(NewState)) {
    00167         return STATUS_INVALID_PARAMETER;
    00168     }
    00169
    00170     //
    00171     // Get previous processor mode and probe parameters if necessary.
    00172     //
    00173
    00174     PreviousMode = KeGetPreviousMode();
    00175     if (PreviousMode != KernelMode) {
    00176         try {
    00177
    00178             //
    00179             // Make sure we can see all of the new state
    00180             //
    00181
    00182             if (!DisableAllPrivileges) {
    00183
    00184                 ProbeForRead(
    00185                     NewState,
    00186                     sizeof(TOKEN_PRIVILEGES),
    00187                     sizeof(ULONG)
    00188                     );
    00189
    00190                 CapturedPrivilegeCount = NewState->PrivilegeCount;
    00191                 ParameterLength = (ULONG)sizeof(TOKEN_PRIVILEGES) +
    00192                                   ( (CapturedPrivilegeCount - ANYSIZE_ARRAY) *
    00193                                   (ULONG)sizeof(LUID_AND_ATTRIBUTES)  );
    00194
    00195                 ProbeForRead(
    00196                     NewState,
    00197                     ParameterLength,
    00198                     sizeof(ULONG)
    00199                     );
    00200
    00201             }
    00202
    00203
    00204             //
    00205             // Check the PreviousState buffer for writeability
    00206             //
    00207
    00208             if (ARGUMENT_PRESENT(PreviousState)) {
    00209
    00210                 ProbeForWrite(
    00211                     PreviousState,
    00212                     BufferLength,
    00213                     sizeof(ULONG)
    00214                     );
    00215
    00216                 ProbeForWriteUlong(ReturnLength);
    00217             }
    00218
    00219
    00220         } except(EXCEPTION_EXECUTE_HANDLER) {
    00221             return GetExceptionCode();
    00222         }
    00223
    00224     } else {
    00225
    00226         if (!DisableAllPrivileges) {
    00227
    00228             CapturedPrivilegeCount = NewState->PrivilegeCount;
    00229         }
    00230     }
    00231
    00232
    00233
    00234     //
    00235     // Capture NewState if passed.
    00236     //
    00237
    00238     if (!DisableAllPrivileges) {
    00239
    00240         try {
    00241
    00242
    00243             Status = SeCaptureLuidAndAttributesArray(
    00244                          (NewState->Privileges),
    00245                          CapturedPrivilegeCount,
    00246                          PreviousMode,
    00247                          NULL, 0,
    00248                          PagedPool,
    00249                          TRUE,
    00250                          &CapturedPrivileges,
    00251                          &CapturedPrivilegesLength
    00252                          );
    00253
    00254         } except(EXCEPTION_EXECUTE_HANDLER) {
    00255
    00256             return GetExceptionCode();
    00257
    00258         }
    00259
    00260         if (!NT_SUCCESS(Status)) {
    00261
    00262             return Status;
    00263
    00264         }
    00265
    00266     }
    00267
    00268
    00269     //
    00270     // Reference the token object and validate the caller's right
    00271     // to adjust the privileges.
    00272     //
    00273
    00274     if (ARGUMENT_PRESENT(PreviousState)) {
    00275         DesiredAccess = (TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY);
    00276     } else {
    00277         DesiredAccess = TOKEN_ADJUST_PRIVILEGES;
    00278     }
    00279
    00280     Status = ObReferenceObjectByHandle(
    00281              TokenHandle,             // Handle
    00282              DesiredAccess,           // DesiredAccess
    00283              SepTokenObjectType,      // ObjectType
    00284              PreviousMode,            // AccessMode
    00285              (PVOID *)&Token,         // Object
    00286              NULL                     // GrantedAccess
    00287              );
    00288
    00289     if ( !NT_SUCCESS(Status) ) {
    00290
    00291         if (CapturedPrivileges != NULL) {
    00292             SeReleaseLuidAndAttributesArray(
    00293                 CapturedPrivileges,
    00294                 PreviousMode,
    00295                 TRUE
    00296                 );
    00297         }
    00298
    00299         return Status;
    00300     }
    00301
    00302     //
    00303     //  Gain exclusive access to the token.
    00304     //
    00305
    00306     SepAcquireTokenWriteLock( Token );
    00307
    00308     //
    00309     // First pass through the privileges list - just count the changes
    00310     //
    00311
    00312
    00313     Status = SepAdjustPrivileges(
    00314                 Token,
    00315                 FALSE,                // Don't make changes this pass
    00316                 DisableAllPrivileges,
    00317                 CapturedPrivilegeCount,
    00318                 CapturedPrivileges,
    00319                 PreviousState,
    00320                 &LocalReturnLength,
    00321                 &ChangeCount,
    00322                 &ChangesMade
    00323                 );
    00324
    00325     if (ARGUMENT_PRESENT(PreviousState)) {
    00326
    00327         try {
    00328
    00329             (*ReturnLength) = LocalReturnLength;
    00330
    00331         } except(EXCEPTION_EXECUTE_HANDLER) {
    00332
    00333             SepReleaseTokenWriteLock( Token, FALSE );
    00334             ObDereferenceObject( Token );
    00335
    00336             if (CapturedPrivileges != NULL) {
    00337                 SeReleaseLuidAndAttributesArray(
    00338                     CapturedPrivileges,
    00339                     PreviousMode,
    00340                     TRUE
    00341                     );
    00342             }
    00343
    00344             return GetExceptionCode();
    00345         }
    00346
    00347     }
    00348
    00349
    00350     //
    00351     // Make sure there is enough room to return any  requested
    00352     // information.
    00353     //
    00354
    00355     if (ARGUMENT_PRESENT(PreviousState)) {
    00356         if (LocalReturnLength > BufferLength) {
    00357
    00358             SepReleaseTokenWriteLock( Token, FALSE );
    00359             ObDereferenceObject( Token );
    00360
    00361             if (CapturedPrivileges != NULL) {
    00362                 SeReleaseLuidAndAttributesArray(
    00363                     CapturedPrivileges,
    00364                     PreviousMode,
    00365                     TRUE
    00366                     );
    00367             }
    00368
    00369             return STATUS_BUFFER_TOO_SMALL;
    00370         }
    00371     }
    00372
    00373     //
    00374     // Second pass through the privileges list - Make the changes.
    00375     //
    00376     // Note that the internal routine attempts to write the previous
    00377     // state directly to the caller's buffer - and so may get an exception.
    00378     //
    00379
    00380     try {
    00381
    00382         Status = SepAdjustPrivileges(
    00383                     Token,
    00384                     TRUE,                 // Make the changes this pass
    00385                     DisableAllPrivileges,
    00386                     CapturedPrivilegeCount,
    00387                     CapturedPrivileges,
    00388                     PreviousState,
    00389                     &LocalReturnLength,
    00390                     &ChangeCount,
    00391                     &ChangesMade
    00392                     );
    00393
    00394
    00395         if (ARGUMENT_PRESENT(PreviousState)) {
    00396
    00397             PreviousState->PrivilegeCount = ChangeCount;
    00398         }
    00399
    00400     } except(EXCEPTION_EXECUTE_HANDLER) {
    00401
    00402         SepReleaseTokenWriteLock( Token, TRUE );
    00403         ObDereferenceObject( Token );
    00404         if (CapturedPrivileges != NULL) {
    00405             SeReleaseLuidAndAttributesArray(
    00406                 CapturedPrivileges,
    00407                 PreviousMode,
    00408                 TRUE
    00409                 );
    00410         }
    00411         return GetExceptionCode();
    00412
    00413     }
    00414
    00415
    00416     SepReleaseTokenWriteLock( Token, ChangesMade );
    00417     ObDereferenceObject( Token );
    00418     if (CapturedPrivileges != NULL) {
    00419         SeReleaseLuidAndAttributesArray(
    00420             CapturedPrivileges,
    00421             PreviousMode,
    00422             TRUE
    00423             );
    00424     }
    00425
    00426     return Status;
    00427
    00428 }
    00429
    00430
    00431 NTSTATUS
    00432 NtAdjustGroupsToken (
    00433     IN HANDLE TokenHandle,
    00434     IN BOOLEAN ResetToDefault,
    00435     IN PTOKEN_GROUPS NewState OPTIONAL,
    00436     IN ULONG BufferLength OPTIONAL,
    00437     OUT PTOKEN_GROUPS PreviousState OPTIONAL,
    00438     OUT PULONG ReturnLength
    00439     )
    00440
    00441 /*++
    00442
    00443
    00444 Routine Description:
    00445
    00446     This routine is used to disable or enable groups in the specified
    00447     token.  The absence of some of the groups listed to be changed
    00448     won't effect the successful modification of the groups that are in
    00449     the token.  The previous enabled/disabled state of changed groups
    00450     may optionally be capture (for resetting later).
    00451
    00452     TOKEN_ADJUST_GROUPS access is required to enable or disable groups
    00453     in a token
    00454
    00455     Note that mandatory groups can not be disabled.  An attempt
    00456     disable any mandatory groups will cause the call to fail, leaving
    00457     the state of all groups unchanged.
    00458
    00459
    00460 Arguments:
    00461
    00462     TokenHandle - Provides a handle to the token to operate on.
    00463
    00464     ResetToDefault - The parameter indicates whether all the groups
    00465         in the token are to be reset to their default enabled/disabled
    00466         state.
    00467
    00468     NewState - This parameter points to a TOKEN_GROUPS data structure
    00469         containing the groups whose states are to be adjusted
    00470         (disabled or enabled).  Only the Enabled flag of the
    00471         attributes associated with each group is used.  It provides
    00472         the new value that is to be assigned to the group in the
    00473         token.  If the ResetToDefault argument is specified as TRUE,
    00474         then this argument is ignored.  Otherwise, it must be passed.
    00475
    00476     BufferLength - This optional parameter indicates the length (in
    00477         bytes) of the PreviousState buffer.  This value must be
    00478         provided if the PreviousState parameter is provided.
    00479
    00480     PreviousState - This (optional) parameter points to a buffer to
    00481         receive the state of any groups actually changed by this
    00482         request.  This information is formated as a TOKEN_GROUPS data
    00483         structure which may be passed as the NewState parameter in a
    00484         subsequent call to NtAdjustGroups to restore the original state
    00485         of those groups.  TOKEN_QUERY access is needed to use this
    00486         parameter.
    00487
    00488         If this buffer does not contain enough space to receive the
    00489         complete list of modified groups, then no group states are
    00490         changed and STATUS_BUFFER_TOO_SMALL is returned.  In this
    00491         case, the ReturnLength return parameter will contain the
    00492         actual number of bytes needed to hold the information.
    00493
    00494     ReturnLength - Indicates the actual number of bytes needed to
    00495         contain the previous group state information.
    00496         This parameter is ignored if the PreviousState argument is not
    00497         passed.
    00498
    00499
    00500 Return Value:
    00501
    00502     STATUS_SUCCESS - The service successfully completed the requested
    00503         operation.
    00504
    00505     STATUS_NOT_ALL_ASSIGNED - This NT_SUCCESS severity return status
    00506         indicates that not all the specified groups are currently
    00507         assigned to the caller.  All specified groups that are
    00508         currently assigned have been successfully adjusted.
    00509
    00510     STATUS_CANT_DISABLE_MANDATORY - Indicates an attempt was made to
    00511         disable a mandatory group.  The states of all groups remains
    00512         unchanged.
    00513
    00514     STATUS_BUFFER_TOO_SMALL - Indicates the optional buffer provided
    00515         to receive the previous states of changed group wasn't large
    00516         enough to receive that information.  No changes to group
    00517         states has been made.  The number of bytes needed to hold the
    00518         state change information is returned via the ReturnLength
    00519         parameter.
    00520
    00521     STATUS_INVALID_PARAMETER - Indicates neither the ResetToDefault
    00522         parameter was specified as true, nor was an explicit NewState
    00523         provided.
    00524
    00525 --*/
    00526 {
    00527
    00528     KPROCESSOR_MODE PreviousMode;
    00529     NTSTATUS Status;
    00530
    00531     PTOKEN Token;
    00532
    00533     ACCESS_MASK DesiredAccess;
    00534
    00535     ULONG CapturedGroupCount;
    00536     PSID_AND_ATTRIBUTES CapturedGroups = NULL;
    00537     ULONG CapturedGroupsLength;
    00538
    00539     ULONG LocalReturnLength;
    00540     ULONG ChangeCount;
    00541     BOOLEAN ChangesMade;
    00542     PSID SidBuffer;
    00543
    00544     PAGED_CODE();
    00545
    00546     //
    00547     //  The semantics of the PreviousState parameter and the
    00548     //  STATUS_CANT_DISABLE_MANDATORY completion status leads to a two-pass
    00549     //  approach to adjusting groups.  The first pass simply checks
    00550     //  to see which groups will change and counts them.  This allows
    00551     //  the amount of space needed to be calculated and returned.  If
    00552     //  the caller's PreviousState return buffer is not large enough, or
    00553     //  one of the specified groups is a mandatory group, then an error
    00554     //  is returned without making any modifications.  Otherwise, a second
    00555     //  pass is made to actually make the changes.
    00556     //
    00557
    00558     if (!ResetToDefault && !ARGUMENT_PRESENT(NewState)) {
    00559         return STATUS_INVALID_PARAMETER;
    00560     }
    00561
    00562     //
    00563     // Get previous processor mode and probe parameters if necessary.
    00564     //
    00565
    00566     PreviousMode = KeGetPreviousMode();
    00567     if (PreviousMode != KernelMode) {
    00568         try {
    00569
    00570             if (!ResetToDefault) {
    00571                 ProbeForRead(
    00572                     NewState,
    00573                     sizeof(TOKEN_GROUPS),
    00574                     sizeof(ULONG)
    00575                     );
    00576             }
    00577
    00578             if (ARGUMENT_PRESENT(PreviousState)) {
    00579
    00580                 ProbeForWrite(
    00581                     PreviousState,
    00582                     BufferLength,
    00583                     sizeof(ULONG)
    00584                     );
    00585
    00586                 //
    00587                 // This parameter is only used if PreviousState
    00588                 // is present
    00589                 //
    00590
    00591                 ProbeForWriteUlong(ReturnLength);
    00592
    00593             }
    00594
    00595
    00596         } except(EXCEPTION_EXECUTE_HANDLER) {
    00597             return GetExceptionCode();
    00598         }
    00599     }
    00600
    00601     //
    00602     // Capture NewState.
    00603     //
    00604
    00605     if (!ResetToDefault) {
    00606
    00607         try {
    00608
    00609             CapturedGroupCount = NewState->GroupCount;
    00610             Status = SeCaptureSidAndAttributesArray(
    00611                          &(NewState->Groups[0]),
    00612                          CapturedGroupCount,
    00613                          PreviousMode,
    00614                          NULL, 0,
    00615                          PagedPool,
    00616                          TRUE,
    00617                          &CapturedGroups,
    00618                          &CapturedGroupsLength
    00619                          );
    00620
    00621             if (!NT_SUCCESS(Status)) {
    00622
    00623                 return Status;
    00624
    00625             }
    00626
    00627         } except(EXCEPTION_EXECUTE_HANDLER) {
    00628
    00629             return GetExceptionCode();
    00630
    00631         } // endtry
    00632     } // endif !ResetToDefault
    00633
    00634
    00635     //
    00636     // Reference the token object and validate the caller's right
    00637     // to adjust the groups.
    00638     //
    00639
    00640     if (ARGUMENT_PRESENT(PreviousState)) {
    00641         DesiredAccess = (TOKEN_ADJUST_GROUPS | TOKEN_QUERY);
    00642     } else {
    00643         DesiredAccess = TOKEN_ADJUST_GROUPS;
    00644     }
    00645
    00646     Status = ObReferenceObjectByHandle(
    00647              TokenHandle,             // Handle
    00648              DesiredAccess,           // DesiredAccess
    00649              SepTokenObjectType,      // ObjectType
    00650              PreviousMode,            // AccessMode
    00651              (PVOID *)&Token,         // Object
    00652              NULL                     // GrantedAccess
    00653              );
    00654
    00655     if ( !NT_SUCCESS(Status) ) {
    00656
    00657         if (ARGUMENT_PRESENT(CapturedGroups)) {
    00658             SeReleaseSidAndAttributesArray( CapturedGroups, PreviousMode, TRUE );
    00659         }
    00660
    00661         return Status;
    00662     }
    00663
    00664     //
    00665     //  Gain exclusive access to the token.
    00666     //
    00667
    00668     SepAcquireTokenWriteLock( Token );
    00669
    00670     //
    00671     // First pass through the groups list.
    00672     //
    00673     // This pass is always necessary for groups to make sure the caller
    00674     // isn't trying to do anything illegal to mandatory groups.
    00675     //
    00676
    00677     Status = SepAdjustGroups(
    00678                  Token,
    00679                  FALSE,                // Don't make changes this pass
    00680                  ResetToDefault,
    00681                  CapturedGroupCount,
    00682                  CapturedGroups,
    00683                  PreviousState,
    00684                  NULL,                // Not returning SIDs this call
    00685                  &LocalReturnLength,
    00686                  &ChangeCount,
    00687                  &ChangesMade
    00688                  );
    00689
    00690     if (ARGUMENT_PRESENT(PreviousState)) {
    00691
    00692         try {
    00693
    00694             (*ReturnLength) = LocalReturnLength;
    00695
    00696         } except(EXCEPTION_EXECUTE_HANDLER) {
    00697
    00698             SepReleaseTokenWriteLock( Token, FALSE );
    00699             ObDereferenceObject( Token );
    00700
    00701             if (ARGUMENT_PRESENT(CapturedGroups)) {
    00702                 SeReleaseSidAndAttributesArray(
    00703                     CapturedGroups,
    00704                     PreviousMode,
    00705                     TRUE
    00706                     );
    00707             }
    00708
    00709             return GetExceptionCode();
    00710         }
    00711     }
    00712
    00713     //
    00714     // Make sure we didn't encounter an error
    00715     //
    00716
    00717     if (!NT_SUCCESS(Status)) {
    00718
    00719         SepReleaseTokenWriteLock( Token, FALSE );
    00720         ObDereferenceObject( Token );
    00721
    00722         if (ARGUMENT_PRESENT(CapturedGroups)) {
    00723             SeReleaseSidAndAttributesArray(
    00724                 CapturedGroups,
    00725                 PreviousMode,
    00726                 TRUE
    00727                 );
    00728         }
    00729
    00730         return Status;
    00731
    00732     }
    00733
    00734     //
    00735     // Make sure there is enough room to return requested information.
    00736     // Also go on to calculate where the SID values go.
    00737     //
    00738
    00739     if (ARGUMENT_PRESENT(PreviousState)) {
    00740         if (LocalReturnLength > BufferLength) {
    00741
    00742             SepReleaseTokenWriteLock( Token, FALSE );
    00743             ObDereferenceObject( Token );
    00744
    00745             if (ARGUMENT_PRESENT(CapturedGroups)) {
    00746                 SeReleaseSidAndAttributesArray(
    00747                     CapturedGroups,
    00748                     PreviousMode,
    00749                     TRUE
    00750                     );
    00751             }
    00752
    00753
    00754             return STATUS_BUFFER_TOO_SMALL;
    00755         }
    00756
    00757         //
    00758         // Calculate where the SIDs can be placed in the PreviousState
    00759         // buffer.
    00760         //
    00761
    00762         SidBuffer = (PSID)(LongAlignPtr(
    00763                             (PCHAR)PreviousState + (ULONG)sizeof(TOKEN_GROUPS) +
    00764                             (ChangeCount * (ULONG)sizeof(SID_AND_ATTRIBUTES)) -
    00765                             (ANYSIZE_ARRAY * (ULONG)sizeof(SID_AND_ATTRIBUTES))
    00766                             ) );
    00767
    00768     }
    00769
    00770     //
    00771     // Second pass through the groups list.
    00772     //
    00773
    00774     try {
    00775
    00776         Status = SepAdjustGroups(
    00777                      Token,
    00778                      TRUE,                 // Make changes in this pass
    00779                      ResetToDefault,
    00780                      CapturedGroupCount,
    00781                      CapturedGroups,
    00782                      PreviousState,
    00783                      SidBuffer,
    00784                      &LocalReturnLength,
    00785                      &ChangeCount,
    00786                      &ChangesMade
    00787                      );
    00788
    00789         if (ARGUMENT_PRESENT(PreviousState)) {
    00790
    00791             PreviousState->GroupCount = ChangeCount;
    00792         }
    00793
    00794     } except(EXCEPTION_EXECUTE_HANDLER) {
    00795
    00796         //SepFreeToken( Token, TRUE );
    00797         SepReleaseTokenWriteLock( Token, TRUE );
    00798         ObDereferenceObject( Token );
    00799         if (ARGUMENT_PRESENT(CapturedGroups)) {
    00800             SeReleaseSidAndAttributesArray( CapturedGroups, PreviousMode, TRUE );
    00801         }
    00802         return GetExceptionCode();
    00803
    00804     }
    00805
    00806     //SepFreeToken( Token, ChangesMade );
    00807     SepReleaseTokenWriteLock( Token, ChangesMade );
    00808     ObDereferenceObject( Token );
    00809
    00810     if (ARGUMENT_PRESENT(CapturedGroups)) {
    00811         SeReleaseSidAndAttributesArray( CapturedGroups, PreviousMode, TRUE );
    00812     }
    00813
    00814     return Status;
    00815
    00816 }
    00817
    00818 NTSTATUS
    00819 SepAdjustPrivileges(
    00820     IN PTOKEN Token,
    00821     IN BOOLEAN MakeChanges,
    00822     IN BOOLEAN DisableAllPrivileges,
    00823     IN ULONG PrivilegeCount OPTIONAL,
    00824     IN PLUID_AND_ATTRIBUTES NewState OPTIONAL,
    00825     OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
    00826     OUT PULONG ReturnLength,
    00827     OUT PULONG ChangeCount,
    00828     OUT PBOOLEAN ChangesMade
    00829     )
    00830
    00831 /*++
    00832
    00833
    00834 Routine Description:
    00835
    00836     This routine is used to walk the privileges array in a token as a
    00837     result of a request to adjust privileges.
    00838
    00839     If the MakeChanges parameter is FALSE, this routine simply determines
    00840     what changes are needed and how much space is necessary to save the
    00841     current state of changed privileges.
    00842
    00843     If the MakeChanges parameter is TRUE, this routine will not only
    00844     calculate the space necessary to save the current state, but will
    00845     actually make the changes.
    00846
    00847     This routine makes the following assumptions:
    00848
    00849       1) The token is locked for exclusive access.
    00850
    00851       2) The PrivilegeCount and NewState parameters (if passed) are captured
    00852          and accesses to them will not result in access violations.
    00853
    00854       4) Any access violations encountered may leave the request
    00855          partially completed.  It is the calling routine's responsibility
    00856          to catch exceptions.
    00857
    00858       5) The calling routine is responsible for inrementing the token's
    00859          ModifiedId field.
    00860
    00861 Arguments:
    00862
    00863     Token - Pointer to the token to act upon.
    00864
    00865     MakeChanges - A boolean value indicating whether the changes should
    00866         actually be made, or just evaluated.  A value of TRUE indicates
    00867         the changes should be made.
    00868
    00869     DisableAllPrivilegs - A boolean value indicating whether all privileges
    00870         are to be disabled, or only select, specified privileges.  A value
    00871         of TRUE indicates all privileges are to be disabled.
    00872
    00873     PrivilegeCount - This parameter is required only if the NewState parameter
    00874         is used.  In that case, this parameter indicates how many entries are
    00875         in the NewState parameter.
    00876
    00877     NewState - This parameter is ignored if the DisableAllPrivileges
    00878         argument is TRUE.  If the DisableAllPrivileges argument is FALSE,
    00879         then this parameter must be provided and specifies the new state
    00880         to set privileges to (enabled or disabled).
    00881
    00882     PreviousState - This (optional) parameter points to a buffer to
    00883         receive the state of any privileges actually changed by this
    00884         request.  This information is formated as a TOKEN_PRIVILEGES data
    00885         structure which may be passed as the NewState parameter in a
    00886         subsequent call to NtAdjustPrivileges to restore the original state
    00887         of those privileges.  It is the caller's responsibility to make
    00888         sure this buffer is large enough to receive all the state
    00889         information.
    00890
    00891     ReturnLength - Points to a buffer to receive the number of bytes needed
    00892         to retrieve the previous state information of changed privileges.
    00893         This parameter is ignored if the PreviousState argument is not
    00894         passed.
    00895
    00896     ChangeCount - Points to a ULONG to receive the number of privileges
    00897         which were adjusted (or would be adjusted, if changes are made).
    00898
    00899     ChangesMade - Points to a boolean flag which is to receive an indication
    00900         as to whether any changes were made as a result of this call.  This
    00901         is expected to be used to decide whether or not to increment the
    00902         token's ModifiedId field.
    00903
    00904 Return Value:
    00905
    00906     STATUS_SUCCESS - Call completed sccessfully.
    00907
    00908     STATUS_NOT_ALL_ASSIGNED - Indicates not all the specified adjustments
    00909         have been made (or could be made, if update wasn't requested).
    00910
    00911 --*/
    00912 {
    00913     NTSTATUS CompletionStatus = STATUS_SUCCESS;
    00914
    00915     ULONG OldIndex;
    00916     ULONG NewIndex;
    00917     BOOLEAN Found;
    00918     ULONG MatchCount = 0;
    00919
    00920     LUID_AND_ATTRIBUTES CurrentPrivilege;
    00921
    00922     PAGED_CODE();
    00923
    00924     //
    00925     //  Walk through the privileges array to determine which need to be
    00926     //  adjusted.
    00927     //
    00928
    00929     OldIndex = 0;
    00930     (*ChangeCount) = 0;
    00931
    00932     while (OldIndex < Token->PrivilegeCount) {
    00933
    00934         CurrentPrivilege = (Token->Privileges)[OldIndex];
    00935
    00936         if (DisableAllPrivileges) {
    00937
    00938             if (SepTokenPrivilegeAttributes(Token,OldIndex) &
    00939                SE_PRIVILEGE_ENABLED ) {
    00940
    00941                 //
    00942                 // Change, if necessary (saving previous state if
    00943                 // appropriate).
    00944                 //
    00945
    00946                 if (MakeChanges) {
    00947
    00948                     if (ARGUMENT_PRESENT(PreviousState)) {
    00949
    00950                         PreviousState->Privileges[(*ChangeCount)] =
    00951                             CurrentPrivilege;
    00952                     }
    00953
    00954                     SepTokenPrivilegeAttributes(Token,OldIndex) &=
    00955                         ~SE_PRIVILEGE_ENABLED;
    00956
    00957
    00958
    00959                 } //endif make changes
    00960
    00961                 //
    00962                 // increment the number of changes
    00963                 //
    00964
    00965                 (*ChangeCount) += 1;
    00966
    00967             } // endif privilege enabled
    00968
    00969         } else {
    00970
    00971             //
    00972             //  Selective adjustments - this is a little trickier
    00973             //  Compare the current privilege to each of those in
    00974             //  the NewState array.  If a match is found, then adjust
    00975             //  the current privilege appropriately.
    00976             //
    00977
    00978             NewIndex = 0;
    00979             Found = FALSE;
    00980
    00981             while ( (NewIndex < PrivilegeCount) && !Found)  {
    00982
    00983                 //
    00984                 // Look for a comparison
    00985                 //
    00986
    00987                 if (RtlEqualLuid(&CurrentPrivilege.Luid,&NewState[NewIndex].Luid)) {
    00988
    00989                     Found = TRUE;
    00990                     MatchCount += 1;
    00991
    00992                     if ( (SepArrayPrivilegeAttributes( NewState, NewIndex ) &
    00993                           SE_PRIVILEGE_ENABLED)
    00994                         !=
    00995                          (SepTokenPrivilegeAttributes(Token,OldIndex) &
    00996                           SE_PRIVILEGE_ENABLED)  ) {
    00997
    00998                         //
    00999                         // Change, if necessary (saving previous state if
    01000                         // appropriate).
    01001                         //
    01002
    01003                         if (MakeChanges) {
    01004
    01005                             if (ARGUMENT_PRESENT(PreviousState)) {
    01006
    01007                                 PreviousState->Privileges[(*ChangeCount)] =
    01008                                     CurrentPrivilege;
    01009                             }
    01010
    01011                             SepTokenPrivilegeAttributes(Token,OldIndex) &=
    01012                                 ~(SepTokenPrivilegeAttributes(Token,OldIndex)
    01013                                   & SE_PRIVILEGE_ENABLED);
    01014                             SepTokenPrivilegeAttributes(Token,OldIndex) |=
    01015                                  (SepArrayPrivilegeAttributes(NewState,NewIndex)
    01016                                   & SE_PRIVILEGE_ENABLED);
    01017
    01018                             //
    01019                             // if this is SeChangeNotifyPrivilege, then
    01020                             // change its corresponding bit in TokenFlags
    01021                             //
    01022
    01023                             if (RtlEqualLuid(&CurrentPrivilege.Luid,
    01024                                               &SeChangeNotifyPrivilege)) {
    01025                                 Token->TokenFlags ^= TOKEN_HAS_TRAVERSE_PRIVILEGE;
    01026                             }
    01027
    01028
    01029
    01030                         } //endif make changes
    01031
    01032                         //
    01033                         // increment the number of changes
    01034                         //
    01035
    01036                         (*ChangeCount) += 1;
    01037
    01038
    01039                     } // endif change needed
    01040
    01041                 } // endif found
    01042
    01043                 NewIndex += 1;
    01044
    01045             } // endwhile searching NewState
    01046
    01047         } // endelse
    01048
    01049         OldIndex += 1;
    01050
    01051     } // endwhile privileges in token
    01052
    01053     //
    01054     // If we disabled all privileges, then clear the TokenFlags flag
    01055     // corresponding to the SeChangeNotifyPrivilege privilege.
    01056     //
    01057
    01058
    01059     if (DisableAllPrivileges) {
    01060         Token->TokenFlags &= ~TOKEN_HAS_TRAVERSE_PRIVILEGE;
    01061     }
    01062
    01063     //
    01064     // Set completion status appropriately if some not assigned
    01065     //
    01066
    01067     if (!DisableAllPrivileges) {
    01068
    01069         if (MatchCount < PrivilegeCount) {
    01070             CompletionStatus = STATUS_NOT_ALL_ASSIGNED;
    01071         }
    01072     }
    01073
    01074     //
    01075     //  Indicate whether changes were made
    01076     //
    01077
    01078     if ((*ChangeCount) > 0  &&  MakeChanges) {
    01079         (*ChangesMade) = TRUE;
    01080     } else {
    01081         (*ChangesMade) = FALSE;
    01082     }
    01083
    01084     //
    01085     // Calculate the space needed to return previous state information
    01086     //
    01087
    01088     if (ARGUMENT_PRESENT(PreviousState)) {
    01089
    01090         (*ReturnLength) = (ULONG)sizeof(TOKEN_PRIVILEGES) +
    01091                           ((*ChangeCount) *  (ULONG)sizeof(LUID_AND_ATTRIBUTES)) -
    01092                           (ANYSIZE_ARRAY * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
    01093     }
    01094
    01095    return CompletionStatus;
    01096 }
    01097
    01098 NTSTATUS
    01099 SepAdjustGroups(
    01100     IN PTOKEN Token,
    01101     IN BOOLEAN MakeChanges,
    01102     IN BOOLEAN ResetToDefault,
    01103     IN ULONG GroupCount,
    01104     IN PSID_AND_ATTRIBUTES NewState OPTIONAL,
    01105     OUT PTOKEN_GROUPS PreviousState OPTIONAL,
    01106     OUT PSID SidBuffer OPTIONAL,
    01107     OUT PULONG ReturnLength,
    01108     OUT PULONG ChangeCount,
    01109     OUT PBOOLEAN ChangesMade
    01110     )
    01111
    01112 /*++
    01113
    01114
    01115 Routine Description:
    01116
    01117     This routine is used to walk the groups array in a token as a
    01118     result of a request to adjust groups.
    01119
    01120     If the MakeChanges parameter is FALSE, this routine simply determines
    01121     what changes are needed and how much space is necessary to save the
    01122     current state of changed groups.
    01123
    01124     If the MakeChanges parameter is TRUE, this routine will not only
    01125     calculate the space necessary to save the current state, but will
    01126     actually make the changes.
    01127
    01128     This routine makes the following assumptions:
    01129
    01130       1) The token is locked for exclusive access.
    01131
    01132       2) The NewState parameter is captured and accesses
    01133          to it will not result in access violations.
    01134
    01135       4) Any access violations encountered may leave the request
    01136          partially completed.  It is the calling routine's responsibility
    01137          to catch exceptions.
    01138
    01139       5) The calling routine is responsible for inrementing the token's
    01140          ModifiedId field.
    01141
    01142 Arguments:
    01143
    01144     Token - Pointer to the token to act upon.
    01145
    01146     MakeChanges - A boolean value indicating whether the changes should
    01147         actually be made, or just evaluated.  A value of TRUE indicates
    01148         the changes should be made.
    01149
    01150     ResetToDefault - Indicates that the groups are to be reset to their
    01151         default enabled/disabled state.
    01152
    01153     GroupCount - This parameter is required only if the NewState parameter
    01154         is used.  In that case, this parameter indicates how many entries are
    01155         in the NewState parameter.
    01156
    01157     NewState - This parameter points to a SID_AND_ATTRIBUTES array
    01158         containing the groups whose states are to be adjusted
    01159         (disabled or enabled).  Only the Enabled flag of the
    01160         attributes associated with each group is used.  It provides
    01161         the new value that is to be assigned to the group in the
    01162         token.  If the ResetToDefault argument is specified as TRUE,
    01163         then this argument is ignored.  Otherwise, it must be passed.
    01164
    01165     PreviousState - This (optional) parameter points to a buffer to
    01166         receive the state of any groups actually changed by this
    01167         request.  This information is formated as a TOKEN_GROUPS data
    01168         structure which may be passed as the NewState parameter in a
    01169         subsequent call to NtAdjustGroups to restore the original state
    01170         of those groups.  It is the caller's responsibility to make
    01171         sure this buffer is large enough to receive all the state
    01172         information.
    01173
    01174     SidBuffer - Pointer to buffer to receive the SID values corresponding
    01175         to the groups returned in the PreviousState argument.
    01176
    01177     ReturnLength - Points to a buffer to receive the number of bytes needed
    01178         to retrieve the previous state information of changed privileges.
    01179         This parameter is ignored if the PreviousState argument is not
    01180         passed.
    01181
    01182     ChangeCount - Points to a ULONG to receive the number of groups
    01183         which were adjusted (or would be adjusted, if changes are made).
    01184
    01185     ChangesMade - Points to a boolean flag which is to receive an indication
    01186         as to whether any changes were made as a result of this call.  This
    01187         is expected to be used to decide whether or not to increment the
    01188         token's ModifiedId field.
    01189
    01190 Return Value:
    01191
    01192     STATUS_SUCCESS - Call completed sccessfully.
    01193
    01194     STATUS_NOT_ALL_ASSIGNED - Indicates not all the specified adjustments
    01195         have been made (or could be made, if update wasn't requested).
    01196
    01197     STATUS_CANT_DISABLE_MANDATORY - Not all adjustments were made (or could
    01198         be made, if update not requested) because an attempt was made to
    01199         disable a mandatory group.  The state of the groups is left
    01200         in an underterministic state if update was requested.
    01201
    01202
    01203 --*/
    01204 {
    01205
    01206     NTSTATUS CompletionStatus = STATUS_SUCCESS;
    01207
    01208     ULONG OldIndex;
    01209     ULONG NewIndex;
    01210     ULONG SidLength;
    01211     ULONG LocalReturnLength = 0;
    01212     PSID NextSid;
    01213     BOOLEAN Found;
    01214     ULONG MatchCount = 0;
    01215     BOOLEAN EnableGroup;
    01216     BOOLEAN DisableGroup;
    01217     ULONG TokenGroupAttributes;
    01218
    01219     SID_AND_ATTRIBUTES CurrentGroup;
    01220
    01221     PAGED_CODE();
    01222
    01223     //
    01224     // NextSid is used to copy group SID values if asked for previous state.
    01225     //
    01226
    01227     NextSid = SidBuffer;
    01228
    01229
    01230     //
    01231     //  Walk through the groups array to determine which need to be
    01232     //  adjusted.
    01233     //
    01234
    01235     OldIndex = 1;             // Don't evaluate the 0th entry (user ID)
    01236     (*ChangeCount) = 0;
    01237
    01238     while (OldIndex < Token->UserAndGroupCount) {
    01239
    01240         CurrentGroup = Token->UserAndGroups[OldIndex];
    01241
    01242         if (ResetToDefault) {
    01243
    01244             TokenGroupAttributes = SepTokenGroupAttributes(Token,OldIndex);
    01245
    01246             //
    01247             // If the group is enabled by default and currently disabled,
    01248             // then we must enable it.
    01249             //
    01250
    01251             EnableGroup = (BOOLEAN)( (TokenGroupAttributes & SE_GROUP_ENABLED_BY_DEFAULT)
    01252                 && !(TokenGroupAttributes & SE_GROUP_ENABLED));
    01253
    01254             //
    01255             // If the group is disabled by default and currently enabled,
    01256             // then we must disable it.
    01257             //
    01258
    01259             DisableGroup = (BOOLEAN)( !(TokenGroupAttributes & SE_GROUP_ENABLED_BY_DEFAULT)
    01260                 && (TokenGroupAttributes & SE_GROUP_ENABLED));
    01261
    01262             //
    01263             // Blow up if it's a mandatory group that is not both
    01264             // enabled by default and enabled (SepCreateToken should
    01265             // make sure that this never happens).
    01266             //
    01267
    01268             ASSERT(!(TokenGroupAttributes & SE_GROUP_MANDATORY)
    01269                    || (TokenGroupAttributes & (SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED)
    01270                        == (SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED)));
    01271
    01272             if ( EnableGroup || DisableGroup ) {
    01273
    01274                 SidLength = SeLengthSid( CurrentGroup.Sid );
    01275                 SidLength = (ULONG)LongAlignSize(SidLength);
    01276                 LocalReturnLength += SidLength;
    01277
    01278                 //
    01279                 // Change, if necessary (saving previous state if
    01280                 // appropriate).
    01281                 //
    01282
    01283                 if (MakeChanges) {
    01284
    01285                     if (ARGUMENT_PRESENT(PreviousState)) {
    01286
    01287                         (*(PreviousState)).Groups[(*ChangeCount)].Attributes =
    01288                             CurrentGroup.Attributes;
    01289
    01290                         (*(PreviousState)).Groups[(*ChangeCount)].Sid =
    01291                             NextSid;
    01292
    01293                         RtlCopySid( SidLength, NextSid, CurrentGroup.Sid );
    01294                         NextSid = (PSID)((ULONG_PTR)NextSid + SidLength);
    01295                     }
    01296
    01297                     if (EnableGroup) {
    01298                         SepTokenGroupAttributes(Token,OldIndex) |= SE_GROUP_ENABLED;
    01299                     } else {
    01300                         SepTokenGroupAttributes(Token,OldIndex) &= ~SE_GROUP_ENABLED;
    01301                     }
    01302
    01303
    01304
    01305                 } //endif make changes
    01306
    01307                 //
    01308                 // increment the number of changes
    01309                 //
    01310
    01311                 (*ChangeCount) += 1;
    01312
    01313             } // endif group enabled
    01314
    01315         } else {
    01316
    01317             //
    01318             //  Selective adjustments - this is a little trickier
    01319             //  Compare the current group to each of those in
    01320             //  the NewState array.  If a match is found, then adjust
    01321             //  the current group appropriately.
    01322             //
    01323
    01324             NewIndex = 0;
    01325             Found = FALSE;
    01326
    01327             while ( (NewIndex < GroupCount) && !Found)  {
    01328
    01329                 //
    01330                 // Look for a comparison
    01331                 //
    01332
    01333                 if (RtlEqualSid(
    01334                         CurrentGroup.Sid,
    01335                         NewState[NewIndex].Sid
    01336                         ) ) {
    01337
    01338                     Found = TRUE;
    01339                     MatchCount += 1;
    01340
    01341
    01342                     //
    01343                     // See if it needs to be changed
    01344                     //
    01345
    01346                     if ( (SepArrayGroupAttributes( NewState, NewIndex ) &
    01347                             SE_GROUP_ENABLED ) !=
    01348                          (SepTokenGroupAttributes(Token,OldIndex) &
    01349                             SE_GROUP_ENABLED ) ) {
    01350
    01351                         //
    01352                         // Make sure group is not mandatory
    01353                         //
    01354
    01355                         if (SepTokenGroupAttributes(Token,OldIndex) &
    01356                               SE_GROUP_MANDATORY ) {
    01357                             return STATUS_CANT_DISABLE_MANDATORY;
    01358                         }
    01359
    01360                         //
    01361                         // Make sure group is not deny-only
    01362                         //
    01363
    01364
    01365                         if (SepTokenGroupAttributes(Token,OldIndex) &
    01366                               SE_GROUP_USE_FOR_DENY_ONLY ) {
    01367                             return STATUS_CANT_ENABLE_DENY_ONLY;
    01368                         }
    01369
    01370                         SidLength = SeLengthSid( CurrentGroup.Sid );
    01371                         SidLength = (ULONG)LongAlignSize(SidLength);
    01372                         LocalReturnLength += SidLength;
    01373
    01374                         //
    01375                         // Change, if necessary (saving previous state if
    01376                         // appropriate).
    01377                         //
    01378
    01379                         if (MakeChanges) {
    01380
    01381                             if (ARGUMENT_PRESENT(PreviousState)) {
    01382
    01383                                 PreviousState->Groups[(*ChangeCount)].Attributes =
    01384                                     CurrentGroup.Attributes;
    01385
    01386                                 PreviousState->Groups[(*ChangeCount)].Sid =
    01387                                     NextSid;
    01388
    01389                                 RtlCopySid( SidLength, NextSid, CurrentGroup.Sid );
    01390
    01391                                 NextSid = (PSID)((ULONG_PTR)NextSid + SidLength);
    01392                             }
    01393
    01394                             SepTokenGroupAttributes(Token,OldIndex) &=
    01395                                 ~(SepTokenGroupAttributes(Token,OldIndex)
    01396                                   & SE_GROUP_ENABLED);
    01397                             SepTokenGroupAttributes(Token,OldIndex) |=
    01398                                  (SepArrayGroupAttributes(NewState,NewIndex)
    01399                                   & SE_GROUP_ENABLED);
    01400
    01401
    01402
    01403                         } //endif make changes
    01404
    01405                         //
    01406                         // increment the number of changes
    01407                         //
    01408
    01409                         (*ChangeCount) += 1;
    01410
    01411
    01412                     } // endif change needed
    01413
    01414                 } // endif found
    01415
    01416                 NewIndex += 1;
    01417
    01418             } // endwhile searching NewState
    01419
    01420         } // endelse
    01421
    01422         OldIndex += 1;
    01423
    01424     } // endwhile more groups in token
    01425
    01426     //
    01427     // Set completion status appropriately if some not assigned
    01428     //
    01429
    01430     if (!ResetToDefault) {
    01431
    01432         if (MatchCount < GroupCount) {
    01433             CompletionStatus = STATUS_NOT_ALL_ASSIGNED;
    01434         }
    01435     }
    01436
    01437     //
    01438     //  Indicate whether changes were made
    01439     //
    01440
    01441     if ((*ChangeCount) > 0  &&  MakeChanges) {
    01442         (*ChangesMade) = TRUE;
    01443     } else {
    01444         (*ChangesMade) = FALSE;
    01445     }
    01446
    01447     //
    01448     // Calculate the space needed to return previous state information
    01449     // (The SID lengths have already been added up in LocalReturnLength).
    01450     //
    01451
    01452     if (ARGUMENT_PRESENT(PreviousState)) {
    01453
    01454         (*ReturnLength) = LocalReturnLength +
    01455                           (ULONG)sizeof(TOKEN_GROUPS) +
    01456                           ((*ChangeCount) *  (ULONG)sizeof(SID_AND_ATTRIBUTES)) -
    01457                           (ANYSIZE_ARRAY * (ULONG)sizeof(SID_AND_ATTRIBUTES));
    01458     }
    01459
    01460    return CompletionStatus;
    01461 }