예제 #1
0
BOOLEAN
AFSIsInGroup(PSID Sid)
{
    SECURITY_SUBJECT_CONTEXT subjectContext;
    PTOKEN_GROUPS groups;
    PACCESS_TOKEN token;
    BOOLEAN retVal = FALSE;

    SeCaptureSubjectContext( &subjectContext );
    SeLockSubjectContext( &subjectContext );

    token = SeQuerySubjectContextToken( &subjectContext );

    if (NT_SUCCESS(SeQueryInformationToken(token, TokenGroups, (PVOID*) &groups)))
    {
        ULONG i;
        for (i = 0; !retVal && i < groups->GroupCount; i++)
        {
            retVal = RtlEqualSid(Sid, groups->Groups[i].Sid);
        }

        ExFreePool( groups );
    }
    SeUnlockSubjectContext( &subjectContext );
    SeReleaseSubjectContext( &subjectContext );
    return retVal;
}
예제 #2
0
파일: audit.c 프로젝트: reactos/reactos
VOID
NTAPI
SePrivilegedServiceAuditAlarm(
    _In_opt_ PUNICODE_STRING ServiceName,
    _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
    _In_ PPRIVILEGE_SET PrivilegeSet,
    _In_ BOOLEAN AccessGranted)
{
    PTOKEN EffectiveToken;
    PSID UserSid;
    PAGED_CODE();

    /* Get the effective token */
    if (SubjectContext->ClientToken != NULL)
        EffectiveToken = SubjectContext->ClientToken;
    else
        EffectiveToken = SubjectContext->PrimaryToken;

    /* Get the user SID */
    UserSid = EffectiveToken->UserAndGroups->Sid;

    /* Check if this is the local system SID */
    if (RtlEqualSid(UserSid, SeLocalSystemSid))
    {
        /* Nothing to do */
        return;
    }

    /* Check if this is the network service or local service SID */
    if (RtlEqualSid(UserSid, SeExports->SeNetworkServiceSid) ||
            RtlEqualSid(UserSid, SeExports->SeLocalServiceSid))
    {
        // FIXME: should continue for a certain set of privileges
        return;
    }

    /* Call the worker function */
    SepAdtPrivilegedServiceAuditAlarm(SubjectContext,
                                      &SeSubsystemName,
                                      ServiceName,
                                      SubjectContext->ClientToken,
                                      SubjectContext->PrimaryToken,
                                      PrivilegeSet,
                                      AccessGranted);

}
예제 #3
0
파일: uipers.c 프로젝트: conioh/os-design
BOOLEAN
SidTranslation(
    PSID Sid,
    PSTRING AccountName
    )
// AccountName is expected to have a large maximum length

{
    if (RtlEqualSid(Sid, WorldSid)) {
        RtlInitString( AccountName, "WORLD");
        return(TRUE);
    }

    if (RtlEqualSid(Sid, LocalSid)) {
        RtlInitString( AccountName, "LOCAL");

        return(TRUE);
    }

    if (RtlEqualSid(Sid, NetworkSid)) {
        RtlInitString( AccountName, "NETWORK");

        return(TRUE);
    }

    if (RtlEqualSid(Sid, BatchSid)) {
        RtlInitString( AccountName, "BATCH");

        return(TRUE);
    }

    if (RtlEqualSid(Sid, InteractiveSid)) {
        RtlInitString( AccountName, "INTERACTIVE");
        return(TRUE);
    }

    if (RtlEqualSid(Sid, LocalSystemSid)) {
        RtlInitString( AccountName, "SYSTEM");
        return(TRUE);
    }

    if (RtlEqualSid(Sid, LocalManagerSid)) {
        RtlInitString( AccountName, "LOCAL MANAGER");
        return(TRUE);
    }

    if (RtlEqualSid(Sid, LocalAdminSid)) {
        RtlInitString( AccountName, "LOCAL ADMIN");
        return(TRUE);
    }

    return(FALSE);

}
예제 #4
0
BOOLEAN
RtlIsSidMemberOfToken(
    IN PACCESS_TOKEN AccessToken,
    IN PSID Sid
    )
{
    BOOLEAN isMember = FALSE;
    BOOLEAN isLocked = FALSE;
    ULONG i = 0;

    SHARED_LOCK_RWLOCK(&AccessToken->RwLock, isLocked);

    if (RtlEqualSid(Sid, AccessToken->User.Sid))
    {
        isMember = TRUE;
        GOTO_CLEANUP();
    }

    for (i = 0; i < AccessToken->GroupCount; i++)
    {
        PSID_AND_ATTRIBUTES sidInfo = &AccessToken->Groups[i];
        if (IsSetFlag(sidInfo->Attributes, SE_GROUP_ENABLED) &&
            RtlEqualSid(Sid, sidInfo->Sid))
        {
            isMember = TRUE;
            GOTO_CLEANUP();
        }
    }

    isMember = FALSE;

cleanup:
    UNLOCK_RWLOCK(&AccessToken->RwLock, isLocked);

    return isMember;
}
예제 #5
0
파일: netshare.c 프로젝트: twistround/pbis
static
DWORD
MapBuiltinSidToName(
    PWSTR *ppwszName,
    PSID pSid
    )
{
    DWORD dwError = 0;
    union
    {
        SID sid;
        BYTE buffer[SID_MAX_SIZE];
    } Sid;
    ULONG SidSize = sizeof(Sid.buffer);
    PWSTR pwszEveryone = NULL;

    dwError = LwNtStatusToWin32Error(
        RtlCreateWellKnownSid(
            WinWorldSid,
            NULL,
            &Sid.sid,
            &SidSize));
    BAIL_ON_LTNET_ERROR(dwError);

    if (RtlEqualSid(&Sid.sid, pSid))
    {
        dwError = LwNtStatusToWin32Error(
            RtlWC16StringAllocateFromCString(
                &pwszEveryone,
                "Everyone"));
        BAIL_ON_LTNET_ERROR(dwError);

    }

    *ppwszName = pwszEveryone;

cleanup:

    return dwError;

error:
    LwNetWC16StringFree(pwszEveryone);

    goto cleanup;
}
예제 #6
0
PWELL_KNOWN_SID
LsapLookupWellKnownSid(PSID Sid)
{
    PLIST_ENTRY ListEntry;
    PWELL_KNOWN_SID Ptr;

    ListEntry = WellKnownSidListHead.Flink;
    while (ListEntry != &WellKnownSidListHead)
    {
        Ptr = CONTAINING_RECORD(ListEntry,
                                WELL_KNOWN_SID,
                                ListEntry);
        if (RtlEqualSid(Sid, Ptr->Sid))
        {
            return Ptr;
        }

        ListEntry = ListEntry->Flink;
    }

    return NULL;
}
예제 #7
0
BOOLEAN
AFSIsUser( IN PSID Sid)
{
    SECURITY_SUBJECT_CONTEXT subjectContext;
    PTOKEN_USER user;
    PACCESS_TOKEN token;
    BOOLEAN retVal = FALSE;

    SeCaptureSubjectContext( &subjectContext);
    SeLockSubjectContext( &subjectContext);

    token = SeQuerySubjectContextToken( &subjectContext);

    if (NT_SUCCESS (SeQueryInformationToken( token, TokenUser, (PVOID*) &user)))
    {

        retVal = RtlEqualSid( user->User.Sid, Sid);

        ExFreePool( user );
    }
    SeUnlockSubjectContext( &subjectContext);
    SeReleaseSubjectContext( &subjectContext);
    return retVal;
}
예제 #8
0
파일: connect.c 프로젝트: GYGit/reactos
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtSecureConnectPort(OUT PHANDLE PortHandle,
                    IN PUNICODE_STRING PortName,
                    IN PSECURITY_QUALITY_OF_SERVICE Qos,
                    IN OUT PPORT_VIEW ClientView OPTIONAL,
                    IN PSID ServerSid OPTIONAL,
                    IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
                    OUT PULONG MaxMessageLength OPTIONAL,
                    IN OUT PVOID ConnectionInformation OPTIONAL,
                    IN OUT PULONG ConnectionInformationLength OPTIONAL)
{
    ULONG ConnectionInfoLength = 0;
    PLPCP_PORT_OBJECT Port, ClientPort;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    NTSTATUS Status = STATUS_SUCCESS;
    HANDLE Handle;
    PVOID SectionToMap;
    PLPCP_MESSAGE Message;
    PLPCP_CONNECTION_MESSAGE ConnectMessage;
    PETHREAD Thread = PsGetCurrentThread();
    ULONG PortMessageLength;
    LARGE_INTEGER SectionOffset;
    PTOKEN Token;
    PTOKEN_USER TokenUserInfo;
    PAGED_CODE();
    LPCTRACE(LPC_CONNECT_DEBUG,
             "Name: %wZ. Qos: %p. Views: %p/%p. Sid: %p\n",
             PortName,
             Qos,
             ClientView,
             ServerView,
             ServerSid);

    /* Validate client view */
    if ((ClientView) && (ClientView->Length != sizeof(PORT_VIEW)))
    {
        /* Fail */
        return STATUS_INVALID_PARAMETER;
    }

    /* Validate server view */
    if ((ServerView) && (ServerView->Length != sizeof(REMOTE_PORT_VIEW)))
    {
        /* Fail */
        return STATUS_INVALID_PARAMETER;
    }

    /* Check if caller sent connection information length */
    if (ConnectionInformationLength)
    {
        /* Retrieve the input length */
        ConnectionInfoLength = *ConnectionInformationLength;
    }

    /* Get the port */
    Status = ObReferenceObjectByName(PortName,
                                     0,
                                     NULL,
                                     PORT_CONNECT,
                                     LpcPortObjectType,
                                     PreviousMode,
                                     NULL,
                                     (PVOID *)&Port);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("Failed to reference port '%wZ': 0x%lx\n", PortName, Status);
        return Status;
    }

    /* This has to be a connection port */
    if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
    {
        /* It isn't, so fail */
        ObDereferenceObject(Port);
        return STATUS_INVALID_PORT_HANDLE;
    }

    /* Check if we have a SID */
    if (ServerSid)
    {
        /* Make sure that we have a server */
        if (Port->ServerProcess)
        {
            /* Get its token and query user information */
            Token = PsReferencePrimaryToken(Port->ServerProcess);
            //Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo);
            // FIXME: Need SeQueryInformationToken
            Status = STATUS_SUCCESS;
            TokenUserInfo = ExAllocatePoolWithTag(PagedPool, sizeof(TOKEN_USER), TAG_SE);
            TokenUserInfo->User.Sid = ServerSid;
            PsDereferencePrimaryToken(Token);

            /* Check for success */
            if (NT_SUCCESS(Status))
            {
                /* Compare the SIDs */
                if (!RtlEqualSid(ServerSid, TokenUserInfo->User.Sid))
                {
                    /* Fail */
                    Status = STATUS_SERVER_SID_MISMATCH;
                }

                /* Free token information */
                ExFreePoolWithTag(TokenUserInfo, TAG_SE);
            }
        }
        else
        {
            /* Invalid SID */
            Status = STATUS_SERVER_SID_MISMATCH;
        }

        /* Check if SID failed */
        if (!NT_SUCCESS(Status))
        {
            /* Quit */
            ObDereferenceObject(Port);
            return Status;
        }
    }

    /* Create the client port */
    Status = ObCreateObject(PreviousMode,
                            LpcPortObjectType,
                            NULL,
                            PreviousMode,
                            NULL,
                            sizeof(LPCP_PORT_OBJECT),
                            0,
                            0,
                            (PVOID *)&ClientPort);
    if (!NT_SUCCESS(Status))
    {
        /* Failed, dereference the server port and return */
        ObDereferenceObject(Port);
        return Status;
    }

    /* Setup the client port */
    RtlZeroMemory(ClientPort, sizeof(LPCP_PORT_OBJECT));
    ClientPort->Flags = LPCP_CLIENT_PORT;
    ClientPort->ConnectionPort = Port;
    ClientPort->MaxMessageLength = Port->MaxMessageLength;
    ClientPort->SecurityQos = *Qos;
    InitializeListHead(&ClientPort->LpcReplyChainHead);
    InitializeListHead(&ClientPort->LpcDataInfoChainHead);

    /* Check if we have dynamic security */
    if (Qos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)
    {
        /* Remember that */
        ClientPort->Flags |= LPCP_SECURITY_DYNAMIC;
    }
    else
    {
        /* Create our own client security */
        Status = SeCreateClientSecurity(Thread,
                                        Qos,
                                        FALSE,
                                        &ClientPort->StaticSecurity);
        if (!NT_SUCCESS(Status))
        {
            /* Security failed, dereference and return */
            ObDereferenceObject(ClientPort);
            return Status;
        }
    }

    /* Initialize the port queue */
    Status = LpcpInitializePortQueue(ClientPort);
    if (!NT_SUCCESS(Status))
    {
        /* Failed */
        ObDereferenceObject(ClientPort);
        return Status;
    }

    /* Check if we have a client view */
    if (ClientView)
    {
        /* Get the section handle */
        Status = ObReferenceObjectByHandle(ClientView->SectionHandle,
                                           SECTION_MAP_READ |
                                           SECTION_MAP_WRITE,
                                           MmSectionObjectType,
                                           PreviousMode,
                                           (PVOID*)&SectionToMap,
                                           NULL);
        if (!NT_SUCCESS(Status))
        {
            /* Fail */
            ObDereferenceObject(Port);
            return Status;
        }

        /* Set the section offset */
        SectionOffset.QuadPart = ClientView->SectionOffset;

        /* Map it */
        Status = MmMapViewOfSection(SectionToMap,
                                    PsGetCurrentProcess(),
                                    &ClientPort->ClientSectionBase,
                                    0,
                                    0,
                                    &SectionOffset,
                                    &ClientView->ViewSize,
                                    ViewUnmap,
                                    0,
                                    PAGE_READWRITE);

        /* Update the offset */
        ClientView->SectionOffset = SectionOffset.LowPart;

        /* Check for failure */
        if (!NT_SUCCESS(Status))
        {
            /* Fail */
            ObDereferenceObject(SectionToMap);
            ObDereferenceObject(Port);
            return Status;
        }

        /* Update the base */
        ClientView->ViewBase = ClientPort->ClientSectionBase;

        /* Reference and remember the process */
        ClientPort->MappingProcess = PsGetCurrentProcess();
        ObReferenceObject(ClientPort->MappingProcess);
    }
    else
    {
        /* No section */
        SectionToMap = NULL;
    }

    /* Normalize connection information */
    if (ConnectionInfoLength > Port->MaxConnectionInfoLength)
    {
        /* Use the port's maximum allowed value */
        ConnectionInfoLength = Port->MaxConnectionInfoLength;
    }

    /* Allocate a message from the port zone */
    Message = LpcpAllocateFromPortZone();
    if (!Message)
    {
        /* Fail if we couldn't allocate a message */
        if (SectionToMap) ObDereferenceObject(SectionToMap);
        ObDereferenceObject(ClientPort);
        return STATUS_NO_MEMORY;
    }

    /* Set pointer to the connection message and fill in the CID */
    ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
    Message->Request.ClientId = Thread->Cid;

    /* Check if we have a client view */
    if (ClientView)
    {
        /* Set the view size */
        Message->Request.ClientViewSize = ClientView->ViewSize;

        /* Copy the client view and clear the server view */
        RtlCopyMemory(&ConnectMessage->ClientView,
                      ClientView,
                      sizeof(PORT_VIEW));
        RtlZeroMemory(&ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW));
    }
    else
    {
        /* Set the size to 0 and clear the connect message */
        Message->Request.ClientViewSize = 0;
        RtlZeroMemory(ConnectMessage, sizeof(LPCP_CONNECTION_MESSAGE));
    }

    /* Set the section and client port. Port is NULL for now */
    ConnectMessage->ClientPort = NULL;
    ConnectMessage->SectionToMap = SectionToMap;

    /* Set the data for the connection request message */
    Message->Request.u1.s1.DataLength = (CSHORT)ConnectionInfoLength +
                                         sizeof(LPCP_CONNECTION_MESSAGE);
    Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
                                         Message->Request.u1.s1.DataLength;
    Message->Request.u2.s2.Type = LPC_CONNECTION_REQUEST;

    /* Check if we have connection information */
    if (ConnectionInformation)
    {
        /* Copy it in */
        RtlCopyMemory(ConnectMessage + 1,
                      ConnectionInformation,
                      ConnectionInfoLength);
    }

    /* Acquire the port lock */
    KeAcquireGuardedMutex(&LpcpLock);

    /* Check if someone already deleted the port name */
    if (Port->Flags & LPCP_NAME_DELETED)
    {
        /* Fail the request */
        Status = STATUS_OBJECT_NAME_NOT_FOUND;
    }
    else
    {
        /* Associate no thread yet */
        Message->RepliedToThread = NULL;

        /* Generate the Message ID and set it */
        Message->Request.MessageId =  LpcpNextMessageId++;
        if (!LpcpNextMessageId) LpcpNextMessageId = 1;
        Thread->LpcReplyMessageId = Message->Request.MessageId;

        /* Insert the message into the queue and thread chain */
        InsertTailList(&Port->MsgQueue.ReceiveHead, &Message->Entry);
        InsertTailList(&Port->LpcReplyChainHead, &Thread->LpcReplyChain);
        Thread->LpcReplyMessage = Message;

        /* Now we can finally reference the client port and link it*/
        ObReferenceObject(ClientPort);
        ConnectMessage->ClientPort = ClientPort;

        /* Enter a critical region */
        KeEnterCriticalRegion();
    }

    /* Add another reference to the port */
    ObReferenceObject(Port);

    /* Release the lock */
    KeReleaseGuardedMutex(&LpcpLock);

    /* Check for success */
    if (NT_SUCCESS(Status))
    {
        LPCTRACE(LPC_CONNECT_DEBUG,
                 "Messages: %p/%p. Ports: %p/%p. Status: %lx\n",
                 Message,
                 ConnectMessage,
                 Port,
                 ClientPort,
                 Status);

        /* If this is a waitable port, set the event */
        if (Port->Flags & LPCP_WAITABLE_PORT) KeSetEvent(&Port->WaitEvent,
                                                         1,
                                                         FALSE);

        /* Release the queue semaphore and leave the critical region */
        LpcpCompleteWait(Port->MsgQueue.Semaphore);
        KeLeaveCriticalRegion();

        /* Now wait for a reply */
        LpcpConnectWait(&Thread->LpcReplySemaphore, PreviousMode);
    }

    /* Check for failure */
    if (!NT_SUCCESS(Status)) goto Cleanup;

    /* Free the connection message */
    SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);

    /* Check if we got a message back */
    if (Message)
    {
        /* Check for new return length */
        if ((Message->Request.u1.s1.DataLength -
             sizeof(LPCP_CONNECTION_MESSAGE)) < ConnectionInfoLength)
        {
            /* Set new normalized connection length */
            ConnectionInfoLength = Message->Request.u1.s1.DataLength -
                                   sizeof(LPCP_CONNECTION_MESSAGE);
        }

        /* Check if we had connection information */
        if (ConnectionInformation)
        {
            /* Check if we had a length pointer */
            if (ConnectionInformationLength)
            {
                /* Return the length */
                *ConnectionInformationLength = ConnectionInfoLength;
            }

            /* Return the connection information */
            RtlCopyMemory(ConnectionInformation,
                          ConnectMessage + 1,
                          ConnectionInfoLength );
        }

        /* Make sure we had a connected port */
        if (ClientPort->ConnectedPort)
        {
            /* Get the message length before the port might get killed */
            PortMessageLength = Port->MaxMessageLength;

            /* Insert the client port */
            Status = ObInsertObject(ClientPort,
                                    NULL,
                                    PORT_ALL_ACCESS,
                                    0,
                                    (PVOID *)NULL,
                                    &Handle);
            if (NT_SUCCESS(Status))
            {
                /* Return the handle */
                *PortHandle = Handle;
                LPCTRACE(LPC_CONNECT_DEBUG,
                         "Handle: %p. Length: %lx\n",
                         Handle,
                         PortMessageLength);

                /* Check if maximum length was requested */
                if (MaxMessageLength) *MaxMessageLength = PortMessageLength;

                /* Check if we had a client view */
                if (ClientView)
                {
                    /* Copy it back */
                    RtlCopyMemory(ClientView,
                                  &ConnectMessage->ClientView,
                                  sizeof(PORT_VIEW));
                }

                /* Check if we had a server view */
                if (ServerView)
                {
                    /* Copy it back */
                    RtlCopyMemory(ServerView,
                                  &ConnectMessage->ServerView,
                                  sizeof(REMOTE_PORT_VIEW));
                }
            }
        }
        else
        {
            /* No connection port, we failed */
            if (SectionToMap) ObDereferenceObject(SectionToMap);

            /* Acquire the lock */
            KeAcquireGuardedMutex(&LpcpLock);

            /* Check if it's because the name got deleted */
            if (!(ClientPort->ConnectionPort) ||
                (Port->Flags & LPCP_NAME_DELETED))
            {
                /* Set the correct status */
                Status = STATUS_OBJECT_NAME_NOT_FOUND;
            }
            else
            {
                /* Otherwise, the caller refused us */
                Status = STATUS_PORT_CONNECTION_REFUSED;
            }

            /* Release the lock */
            KeReleaseGuardedMutex(&LpcpLock);

            /* Kill the port */
            ObDereferenceObject(ClientPort);
        }

        /* Free the message */
        LpcpFreeToPortZone(Message, 0);
    }
    else
    {
        /* No reply message, fail */
        if (SectionToMap) ObDereferenceObject(SectionToMap);
        ObDereferenceObject(ClientPort);
        Status = STATUS_PORT_CONNECTION_REFUSED;
    }

    /* Return status */
    ObDereferenceObject(Port);
    return Status;

Cleanup:
    /* We failed, free the message */
    SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);

    /* Check if the semaphore got signaled */
    if (KeReadStateSemaphore(&Thread->LpcReplySemaphore))
    {
        /* Wait on it */
        KeWaitForSingleObject(&Thread->LpcReplySemaphore,
                              WrExecutive,
                              KernelMode,
                              FALSE,
                              NULL);
    }

    /* Check if we had a message and free it */
    if (Message) LpcpFreeToPortZone(Message, 0);

    /* Dereference other objects */
    if (SectionToMap) ObDereferenceObject(SectionToMap);
    ObDereferenceObject(ClientPort);

    /* Return status */
    ObDereferenceObject(Port);
    return Status;
}
예제 #9
0
static
NTSTATUS
LsaDisableMachineAccount(
    IN PCWSTR pwszDCName,
    IN LW_PIO_CREDS pCreds,
    IN PCWSTR pwszMachineAccountName
    )
{
    const DWORD dwConnAccess = SAMR_ACCESS_OPEN_DOMAIN |
                               SAMR_ACCESS_ENUM_DOMAINS;

    const DWORD dwDomainAccess = DOMAIN_ACCESS_ENUM_ACCOUNTS |
                                 DOMAIN_ACCESS_OPEN_ACCOUNT |
                                 DOMAIN_ACCESS_LOOKUP_INFO_2;

    const DWORD dwUserAccess = USER_ACCESS_GET_ATTRIBUTES |
                               USER_ACCESS_SET_ATTRIBUTES |
                               USER_ACCESS_SET_PASSWORD;

    NTSTATUS ntStatus = STATUS_SUCCESS;
    SAMR_BINDING hSamrBinding = NULL;
    CONNECT_HANDLE hConnect = NULL;
    PSID pBuiltinSid = NULL;
    DWORD dwResume = 0;
    DWORD dwSize = 256;
    PWSTR *ppwszDomainNames = NULL;
    DWORD i = 0;
    DWORD dwNumEntries = 0;
    PSID pSid = NULL;
    PSID pDomainSid = NULL;
    DOMAIN_HANDLE hDomain = NULL;
    PDWORD pdwRids = NULL;
    PDWORD pdwTypes = NULL;
    ACCOUNT_HANDLE hUser = NULL;
    DWORD dwLevel = 0;
    UserInfo *pInfo = NULL;
    DWORD dwFlagsDisable = 0;
    UserInfo Info;

    memset(&Info, 0, sizeof(Info));

    ntStatus = SamrInitBindingDefault(&hSamrBinding,
                                      pwszDCName,
                                      pCreds);
    BAIL_ON_NT_STATUS(ntStatus);
    
    ntStatus = SamrConnect2(hSamrBinding,
                            pwszDCName,
                            dwConnAccess,
                            &hConnect);
    BAIL_ON_NT_STATUS(ntStatus);    

    ntStatus = RtlAllocateWellKnownSid(
                    WinBuiltinDomainSid,
                    NULL,
                    &pBuiltinSid);
    BAIL_ON_NT_STATUS(ntStatus);

    do
    {
        ntStatus = SamrEnumDomains(hSamrBinding,
                                   hConnect,
                                   &dwResume,
                                   dwSize,
                                   &ppwszDomainNames,
                                   &dwNumEntries);
        BAIL_ON_NT_STATUS(ntStatus);

        if (ntStatus != STATUS_SUCCESS &&
            ntStatus != STATUS_MORE_ENTRIES)
        {
            BAIL_ON_NT_STATUS(ntStatus);
        }

        for (i = 0; pDomainSid == NULL && i < dwNumEntries; i++)
        {
            ntStatus = SamrLookupDomain(hSamrBinding,
                                        hConnect,
                                        ppwszDomainNames[i],
                                        &pSid);
            BAIL_ON_NT_STATUS(ntStatus);

            if (!RtlEqualSid(pSid, pBuiltinSid))
            {
                ntStatus = RtlDuplicateSid(&pDomainSid, pSid);
                BAIL_ON_NT_STATUS(ntStatus);
            }

            SamrFreeMemory(pSid);
            pSid = NULL;
        }

        if (ppwszDomainNames)
        {
            SamrFreeMemory(ppwszDomainNames);
            ppwszDomainNames = NULL;
        }
    }
    while (ntStatus == STATUS_MORE_ENTRIES);

    ntStatus = SamrOpenDomain(hSamrBinding,
                              hConnect,
                              dwDomainAccess,
                              pDomainSid,
                              &hDomain);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SamrLookupNames(hSamrBinding,
                               hDomain,
                               1,
                               (PWSTR*)&pwszMachineAccountName,
                               &pdwRids,
                               &pdwTypes,
                               NULL);
    if (ntStatus == STATUS_NONE_MAPPED)
    {
        BAIL_ON_LSA_ERROR(NERR_SetupAlreadyJoined);
    }

    ntStatus = SamrOpenUser(hSamrBinding,
                            hDomain,
                            dwUserAccess,
                            pdwRids[0],
                            &hUser);
    BAIL_ON_NT_STATUS(ntStatus);

    dwLevel = 16;

    ntStatus = SamrQueryUserInfo(hSamrBinding,
                                 hUser,
                                 dwLevel,
                                 &pInfo);
    BAIL_ON_NT_STATUS(ntStatus);

    dwFlagsDisable = pInfo->info16.account_flags | ACB_DISABLED;

    Info.info16.account_flags = dwFlagsDisable;
    ntStatus = SamrSetUserInfo2(hSamrBinding,
                                hUser,
                                dwLevel,
                                &Info);
    BAIL_ON_NT_STATUS(ntStatus);

cleanup:
    if (hSamrBinding && hUser)
    {
        SamrClose(hSamrBinding, hUser);
    }

    if (hSamrBinding && hDomain)
    {
        SamrClose(hSamrBinding, hDomain);
    }

    if (hSamrBinding && hConnect)
    {
        SamrClose(hSamrBinding, hConnect);
    }

    if (hSamrBinding)
    {
        SamrFreeBinding(&hSamrBinding);
    }

    if (pInfo)
    {
        SamrFreeMemory(pInfo);
    }

    if (pdwRids)
    {
        SamrFreeMemory(pdwRids);
    }

    if (pdwTypes)
    {
        SamrFreeMemory(pdwTypes);
    }

    if (ppwszDomainNames)
    {
        SamrFreeMemory(ppwszDomainNames);
    }

    RTL_FREE(&pBuiltinSid);
    RTL_FREE(&pDomainSid);

    return ntStatus;

error:
    goto cleanup;
}
예제 #10
0
/******************************************************************************
 * EqualSid [ADVAPI32.@]
 *
 * PARAMS
 *   pSid1 []
 *   pSid2 []
 */
BOOL WINAPI
EqualSid( PSID pSid1, PSID pSid2 )
{
    return RtlEqualSid( pSid1, pSid2 );
}
예제 #11
0
파일: bootdata.c 프로젝트: RPG-7/reactos
static NTSTATUS
RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle,
                                IN PISECURITY_DESCRIPTOR SecurityDescriptor)
{
    PSECURITY_DESCRIPTOR RelSD = NULL;
    PSECURITY_DESCRIPTOR NewRelSD = NULL;
    PSECURITY_DESCRIPTOR AbsSD = NULL;
#ifdef _WIN64
    BOOLEAN AbsSDAllocated = FALSE;
#endif
    PSID AdminSid = NULL;
    PSID LocalSystemSid = NULL;
    ULONG DescriptorSize;
    ULONG AbsSDSize, RelSDSize = 0;
    PACL Dacl;
    BOOLEAN DaclPresent, DaclDefaulted;
    PSID OwnerSid;
    BOOLEAN OwnerDefaulted;
    ULONG AceIndex;
    PACE Ace = NULL;
    NTSTATUS Status;

    /* find out how much memory we need to allocate for the self-relative
       descriptor we're querying */
    Status = ZwQuerySecurityObject(DirectoryHandle,
                                   OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
                                   NULL,
                                   0,
                                   &DescriptorSize);
    if (Status != STATUS_BUFFER_TOO_SMALL)
    {
        /* looks like the FS doesn't support security... return success */
        Status = STATUS_SUCCESS;
        goto Cleanup;
    }

    /* allocate enough memory for the security descriptor */
    RelSD = RtlpAllocateMemory(DescriptorSize,
                               'dSeS');
    if (RelSD == NULL)
    {
        Status = STATUS_NO_MEMORY;
        goto Cleanup;
    }

    /* query the self-relative security descriptor */
    Status = ZwQuerySecurityObject(DirectoryHandle,
                                   OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
                                   RelSD,
                                   DescriptorSize,
                                   &DescriptorSize);
    if (!NT_SUCCESS(Status))
    {
        /* FIXME - handle the case where someone else modified the owner and/or
                   DACL while we allocated memory. But that should be *very*
                   unlikely.... */
        goto Cleanup;
    }

    /* query the owner and DACL from the descriptor */
    Status = RtlGetOwnerSecurityDescriptor(RelSD,
                                           &OwnerSid,
                                           &OwnerDefaulted);
    if (!NT_SUCCESS(Status))
    {
        goto Cleanup;
    }

    Status = RtlGetDaclSecurityDescriptor(RelSD,
                                          &DaclPresent,
                                          &Dacl,
                                          &DaclDefaulted);
    if (!NT_SUCCESS(Status))
    {
        goto Cleanup;
    }

    /* create the Administrators SID */
    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
                                         2,
                                         SECURITY_BUILTIN_DOMAIN_RID,
                                         DOMAIN_ALIAS_RID_ADMINS,
                                         0,
                                         0,
                                         0,
                                         0,
                                         0,
                                         0,
                                         &AdminSid);
    if (!NT_SUCCESS(Status))
    {
        goto Cleanup;
    }

    /* create the local SYSTEM SID */
    Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
                                         1,
                                         SECURITY_LOCAL_SYSTEM_RID,
                                         0,
                                         0,
                                         0,
                                         0,
                                         0,
                                         0,
                                         0,
                                         &LocalSystemSid);
    if (!NT_SUCCESS(Status))
    {
        goto Cleanup;
    }

    /* check if the Administrators are the owner and at least a not-NULL DACL
       is present */
    if (OwnerSid != NULL &&
        RtlEqualSid(OwnerSid,
                    AdminSid) &&
        DaclPresent && Dacl != NULL)
    {
        /* check the DACL for an Allowed ACE for the SYSTEM account */
        AceIndex = 0;
        do
        {
            Status = RtlGetAce(Dacl,
                               AceIndex++,
                               (PVOID*)&Ace);
            if (!NT_SUCCESS(Status))
            {
                Ace = NULL;
            }
            else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
            {
                /* check if the the ACE is a set of allowed permissions for the
                   local SYSTEM account */
                if (RtlEqualSid((PSID)(Ace + 1),
                                LocalSystemSid))
                {
                    /* check if the ACE is inherited by noncontainer and
                       container objects, if not attempt to change that */
                    if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) ||
                        !(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE))
                    {
                        Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
                        Status = ZwSetSecurityObject(DirectoryHandle,
                                                     DACL_SECURITY_INFORMATION,
                                                     RelSD);
                    }
                    else
                    {
                        /* all done, we have access */
                        Status = STATUS_SUCCESS;
                    }

                    goto Cleanup;
                }
            }
        } while (Ace != NULL);
    }

    AbsSDSize = DescriptorSize;

    /* because we need to change any existing data we need to convert it to
       an absolute security descriptor first */
    Status = RtlSelfRelativeToAbsoluteSD2(RelSD,
                                          &AbsSDSize);
#ifdef _WIN64
    if (Status == STATUS_BUFFER_TOO_SMALL)
    {
        /* this error code can only be returned on 64 bit builds because
           the size of an absolute security descriptor is greater than the
           size of a self-relative security descriptor */
        ASSERT(AbsSDSize > DescriptorSize);

        AbsSD = RtlpAllocateMemory(DescriptorSize,
                                   'dSeS');
        if (AbsSD == NULL)
        {
            Status = STATUS_NO_MEMORY;
            goto Cleanup;
        }

        AbsSDAllocated = TRUE;

        /* make a raw copy of the self-relative descriptor */
        RtlCopyMemory(AbsSD,
                      RelSD,
                      DescriptorSize);

        /* finally convert it */
        Status = RtlSelfRelativeToAbsoluteSD2(AbsSD,
                                              &AbsSDSize);
    }
    else
#endif
    {
        AbsSD = RelSD;
    }

    if (!NT_SUCCESS(Status))
    {
        goto Cleanup;
    }

    /* set the owner SID */
    Status = RtlSetOwnerSecurityDescriptor(AbsSD,
                                           AdminSid,
                                           FALSE);
    if (!NT_SUCCESS(Status))
    {
        goto Cleanup;
    }

    /* set the DACL in the security descriptor */
    Status = RtlSetDaclSecurityDescriptor(AbsSD,
                                          TRUE,
                                          SecurityDescriptor->Dacl,
                                          FALSE);
    if (!NT_SUCCESS(Status))
    {
        goto Cleanup;
    }

    /* convert it back to a self-relative descriptor, find out how much
       memory we need */
    Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
                                         NULL,
                                         &RelSDSize);
    if (Status != STATUS_BUFFER_TOO_SMALL)
    {
        goto Cleanup;
    }

    /* allocate enough memory for the new self-relative descriptor */
    NewRelSD = RtlpAllocateMemory(RelSDSize,
                                  'dSeS');
    if (NewRelSD == NULL)
    {
        Status = STATUS_NO_MEMORY;
        goto Cleanup;
    }

    /* convert the security descriptor to self-relative format */
    Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
                                         NewRelSD,
                                         &RelSDSize);
    if (Status == STATUS_BUFFER_TOO_SMALL)
    {
        goto Cleanup;
    }

    /* finally attempt to change the security information */
    Status = ZwSetSecurityObject(DirectoryHandle,
                                 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
                                 NewRelSD);

Cleanup:
    if (AdminSid != NULL)
    {
        RtlFreeSid(AdminSid);
    }

    if (LocalSystemSid != NULL)
    {
        RtlFreeSid(LocalSystemSid);
    }

    if (RelSD != NULL)
    {
        RtlpFreeMemory(RelSD,
                       'dSeS');
    }

    if (NewRelSD != NULL)
    {
        RtlpFreeMemory(NewRelSD,
                       'dSeS');
    }

#ifdef _WIN64
    if (AbsSDAllocated)
    {
        RtlpFreeMemory(AbsSD,
                       'dSeS');
    }
#endif

    return Status;
}
예제 #12
0
NTSTATUS
NtSetInformationToken (
    IN HANDLE TokenHandle,
    IN TOKEN_INFORMATION_CLASS TokenInformationClass,
    IN PVOID TokenInformation,
    IN ULONG TokenInformationLength
    )

/*++


Routine Description:

    Modify information in a specified token.

Arguments:

    TokenHandle - Provides a handle to the token to operate on.

    TokenInformationClass - The token information class being set.

    TokenInformation - The buffer containing the new values for the
        specified class of information.  The buffer must be aligned
        on at least a longword boundary.  The actual structures
        provided are dependent upon the information class specified,
        as defined in the TokenInformationClass parameter
        description.

        TokenInformation Format By Information Class:

           TokenUser => This value is not a valid value for this API.
           The User ID may not be replaced.

           TokenGroups => This value is not a valid value for this
           API.  The Group IDs may not be replaced.  However, groups
           may be enabled and disabled using NtAdjustGroupsToken().

           TokenPrivileges => This value is not a valid value for
           this API.  Privilege information may not be replaced.
           However, privileges may be explicitly enabled and disabled
           using the NtAdjustPrivilegesToken API.

           TokenOwner => TOKEN_OWNER data structure.
           TOKEN_ADJUST_DEFAULT access is needed to replace this
           information in a token.  The owner values that may be
           specified are restricted to the user and group IDs with an
           attribute indicating they may be assigned as the owner of
           objects.

           TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
           TOKEN_ADJUST_DEFAULT access is needed to replace this
           information in a token.  The primary group values that may
           be specified are restricted to be one of the group IDs
           already in the token.

           TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
           TOKEN_ADJUST_DEFAULT access is needed to replace this
           information in a token.  The ACL provided as a new default
           discretionary ACL is not validated for structural
           correctness or consistency.

           TokenSource => This value is not a valid value for this
           API.  The source name and context handle  may not be
           replaced.

           TokenStatistics => This value is not a valid value for this
           API.  The statistics of a token are read-only.

    TokenInformationLength - Indicates the length, in bytes, of the
        TokenInformation buffer.  This is only the length of the primary
        buffer.  All extensions of the primary buffer are self describing.

Return Value:

    STATUS_SUCCESS - The operation was successful.

    STATUS_INVALID_OWNER - The ID specified to be an owner (or
        default owner) is not one the caller may assign as the owner
        of an object.

    STATUS_INVALID_INFO_CLASS - The specified information class is
        not one that may be specified in this API.

    STATUS_ALLOTTED_SPACE_EXCEEDED - The space allotted for storage
        of the default discretionary access control and the primary
        group ID is not large enough to accept the new value of one
        of these fields.

--*/
{

    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;

    PTOKEN Token;

    ULONG Index;
    BOOLEAN Found;
    BOOLEAN TokenModified = FALSE;

    ULONG NewLength;
    ULONG CurrentLength;

    PSID CapturedOwner;
    PSID CapturedPrimaryGroup;
    PACL CapturedDefaultDacl;

    PAGED_CODE();

    //
    // Get previous processor mode and probe input buffer if necessary.
    //

    PreviousMode = KeGetPreviousMode();
    if (PreviousMode != KernelMode) {
        try {

            //
            // This just probes the main part of the information buffer.
            // Any information class-specific data hung off the primary
            // buffer are self describing and must be probed separately
            // below.
            //

            ProbeForRead(
                TokenInformation,
                TokenInformationLength,
                sizeof(ULONG)
                );

        } except(EXCEPTION_EXECUTE_HANDLER) {
            return GetExceptionCode();
        }
    }

    //
    // Return error if not legal class
    //
    if ( (TokenInformationClass != TokenOwner)  &&
         (TokenInformationClass != TokenPrimaryGroup) &&
         (TokenInformationClass != TokenDefaultDacl) ) {

        return STATUS_INVALID_INFO_CLASS;

    }

    //
    // Check access rights and reference token
    //

    Status = ObReferenceObjectByHandle(
             TokenHandle,           // Handle
             TOKEN_ADJUST_DEFAULT,  // DesiredAccess
             SepTokenObjectType,    // ObjectType
             PreviousMode,          // AccessMode
             (PVOID *)&Token,       // Object
             NULL                   // GrantedAccess
             );

    if ( !NT_SUCCESS(Status) ) {
        return Status;
    }


    //
    // Case on information class.
    //

    switch ( TokenInformationClass ) {

    case TokenOwner:

        //
        //  Make sure the buffer is large enough to hold the
        //  necessary information class data structure.
        //

        if (TokenInformationLength < (ULONG)sizeof(TOKEN_OWNER)) {

            ObDereferenceObject( Token );
            return STATUS_INFO_LENGTH_MISMATCH;
        }

        //
        //  Capture and copy

        try {

            //
            //  Capture Owner SID
            //

            CapturedOwner = ((PTOKEN_OWNER)TokenInformation)->Owner;
            Status = SeCaptureSid(
                         CapturedOwner,
                         PreviousMode,
                         NULL, 0,
                         PagedPool,
                         TRUE,
                         &CapturedOwner
                         );

        } except(EXCEPTION_EXECUTE_HANDLER) {

            ObDereferenceObject( Token );
            return GetExceptionCode();
        }

        if (!NT_SUCCESS(Status)) {
            ObDereferenceObject( Token );
            return Status;
        }

        //
        //  Gain write access to the token.
        //

        SepAcquireTokenWriteLock( Token );

        //
        //  Walk through the list of user and group IDs looking
        //  for a match to the specified SID.  If one is found,
        //  make sure it may be assigned as an owner.  If it can,
        //  then set the index in the token's OwnerIndex field.
        //  Otherwise, return invalid owner error.
        //

        Index = 0;
        while (Index < Token->UserAndGroupCount) {

            try {

                Found = RtlEqualSid(
                            CapturedOwner,
                            Token->UserAndGroups[Index].Sid
                            );

                if ( Found ) {

                    if ( SepIdAssignableAsOwner(Token,Index) ){

                        Token->DefaultOwnerIndex = Index;
                        TokenModified = TRUE;
                        Status = STATUS_SUCCESS;

                    } else {

                        Status = STATUS_INVALID_OWNER;

                    } //endif assignable

                    SepReleaseTokenWriteLock( Token, TokenModified );
                    ObDereferenceObject( Token );
                    SeReleaseSid( CapturedOwner, PreviousMode, TRUE);
                    return Status;

                }  //endif Found

            } except(EXCEPTION_EXECUTE_HANDLER) {

                SepReleaseTokenWriteLock( Token, TokenModified );
                ObDereferenceObject( Token );
                SeReleaseSid( CapturedOwner, PreviousMode, TRUE);
                return GetExceptionCode();

            }  //endtry

            Index += 1;

        } //endwhile

        SepReleaseTokenWriteLock( Token, TokenModified );
        ObDereferenceObject( Token );
        SeReleaseSid( CapturedOwner, PreviousMode, TRUE);
        return STATUS_INVALID_OWNER;

    case TokenPrimaryGroup:

        //
        // Assuming everything works out, the strategy is to move everything
        // in the Dynamic part of the token (exept the primary group) to
        // the beginning of the dynamic part, freeing up the entire end of
        // the dynamic part for the new primary group.
        //

        //
        //  Make sure the buffer is large enough to hold the
        //  necessary information class data structure.
        //

        if (TokenInformationLength < (ULONG)sizeof(TOKEN_PRIMARY_GROUP)) {

            ObDereferenceObject( Token );
            return STATUS_INFO_LENGTH_MISMATCH;
        }

        //
        // Capture And Validate TOKEN_PRIMARY_GROUP and corresponding SID.
        //

        try {

            CapturedPrimaryGroup =
                ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup;

            Status = SeCaptureSid(
                         CapturedPrimaryGroup,
                         PreviousMode,
                         NULL, 0,
                         PagedPool,
                         TRUE,
                         &CapturedPrimaryGroup
                         );

        } except(EXCEPTION_EXECUTE_HANDLER) {

            ObDereferenceObject( Token );
            return GetExceptionCode();
        }

        if (!NT_SUCCESS(Status)) {
            ObDereferenceObject( Token );
            return Status;
        }

        //
        //  Gain write access to the token.
        //

        SepAcquireTokenWriteLock( Token );

        //
        // See if there is enough room in the dynamic part of the token
        // to replace the current Primary Group with the one specified.
        //

        NewLength = SeLengthSid( CapturedPrimaryGroup );
        CurrentLength = SeLengthSid( Token->PrimaryGroup );

        if (NewLength > (CurrentLength + Token->DynamicAvailable) ) {

            SepReleaseTokenWriteLock( Token, TokenModified );
            ObDereferenceObject( Token );
            SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE);
            return STATUS_ALLOTTED_SPACE_EXCEEDED;
        }

        //
        // Free up the existing primary group
        //

        SepFreePrimaryGroup( Token );

        //
        // And put the new SID in its place
        //

        SepAppendPrimaryGroup( Token, CapturedPrimaryGroup );

        TokenModified = TRUE;

        //
        // All done.
        //

        SepReleaseTokenWriteLock( Token, TokenModified );
        ObDereferenceObject( Token );
        SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE);
        return STATUS_SUCCESS;


    case TokenDefaultDacl:

        //
        // Assuming everything works out, the strategy is to move everything
        // in the Dynamic part of the token (exept the default Dacl) to
        // the beginning of the dynamic part, freeing up the entire end of
        // the dynamic part for the new default Dacl.
        //

        //
        //  Make sure the buffer is large enough to hold the
        //  necessary information class data structure.
        //

        if (TokenInformationLength < (ULONG)sizeof(TOKEN_DEFAULT_DACL)) {

            ObDereferenceObject( Token );
            return STATUS_INFO_LENGTH_MISMATCH;
        }

        //
        // Capture And Validate TOKEN_DEFAULT_DACL and corresponding ACL.
        //

        try {

            CapturedDefaultDacl =
                ((PTOKEN_DEFAULT_DACL)TokenInformation)->DefaultDacl;

            if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
                Status = SeCaptureAcl(
                             CapturedDefaultDacl,
                             PreviousMode,
                             NULL, 0,
                             PagedPool,
                             TRUE,
                             &CapturedDefaultDacl,
                             &NewLength
                             );

            } else {
                NewLength = 0;
                Status = STATUS_SUCCESS;
            }

        } except(EXCEPTION_EXECUTE_HANDLER) {

            ObDereferenceObject( Token );
            return GetExceptionCode();
        }

        if (!NT_SUCCESS(Status)) {
            ObDereferenceObject( Token );
            return Status;
        }

        //
        //  Gain write access to the token.
        //

        SepAcquireTokenWriteLock( Token );

        //
        // See if there is enough room in the dynamic part of the token
        // to replace the current Default Dacl with the one specified.
        //

        if (ARGUMENT_PRESENT(Token->DefaultDacl)) {
            CurrentLength = Token->DefaultDacl->AclSize;
        } else {
            CurrentLength = 0;
        }

        if (NewLength > (CurrentLength + Token->DynamicAvailable) ) {

            SepReleaseTokenWriteLock( Token, TokenModified );
            ObDereferenceObject( Token );
            if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
                SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE);
            }
            return STATUS_ALLOTTED_SPACE_EXCEEDED;
        }

        //
        // Free up the existing Default Dacl
        //

        SepFreeDefaultDacl( Token );

        //
        // And put the new ACL in its place
        //

        if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
            SepAppendDefaultDacl( Token, CapturedDefaultDacl );
        }

        TokenModified = TRUE;

        //
        // All done.
        //

        SepReleaseTokenWriteLock( Token, TokenModified );
        ObDereferenceObject( Token );
        if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
            SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE);
        }
        return STATUS_SUCCESS;

    } //endswitch

    ASSERT( TRUE == FALSE );  // Should never reach here.

}
예제 #13
0
파일: chworker.c 프로젝트: mingpen/OpenNT
NTSTATUS
NlAddGlobalGroupsToList(
    PLIST_ENTRY GroupList,
    ULONG LocalGroupID
    )
/*++

Routine Description:

    This procedure adds the global groups that are member of the given
    alias.

Arguments:

    GroupList : List to munch.

    LocalGroupId : Rid of the local group.

Return Value:

    Return NT Status code.

--*/
{
    NTSTATUS Status;
    SAMPR_HANDLE AliasHandle = NULL;

    SAMPR_PSID_ARRAY Members = {0, NULL};
    PULONG RidArray = NULL;
    DWORD RidArrayLength = 0;
    SAMPR_RETURNED_USTRING_ARRAY Names = {0, NULL};
    SAMPR_ULONG_ARRAY Use = {0, NULL};
    DWORD i;

    //
    // Open Local Group
    //

    Status = SamrOpenAlias(
                NlGlobalChWorkerBuiltinDBHandle,
                0,              // No desired access
                LocalGroupID,
                &AliasHandle );

    if (!NT_SUCCESS(Status)) {
        AliasHandle = NULL;
        goto Cleanup;
    }

    //
    // Enumerate members in this local group.
    //

    Status = SamrGetMembersInAlias(
                AliasHandle,
                &Members );

    if (!NT_SUCCESS(Status)) {
        Members.Sids = NULL;
        goto Cleanup;
    }

    //
    // Determine the SIDs that belong to the Account Domain and get the
    // RIDs of them.
    //

    if( Members.Count == 0) {

        Status = STATUS_SUCCESS;
        goto Cleanup;
    }

    //
    // Allocate the maximum size RID array required.
    //

    RidArray = (PULONG)NetpMemoryAllocate( Members.Count * sizeof(ULONG) );

    if( RidArray == NULL ) {
        Status = STATUS_NO_MEMORY;
        goto Cleanup;
    }

    for( i = 0; i < Members.Count; i++) {

        PUCHAR SubAuthorityCount;
        BOOLEAN EqualSid;

        SubAuthorityCount =
            RtlSubAuthorityCountSid(Members.Sids[i].SidPointer);

        (*SubAuthorityCount)--;
        EqualSid = RtlEqualSid( NlGlobalChWorkerSamDomainSid,
                                    Members.Sids[i].SidPointer );
        (*SubAuthorityCount)++;

        if( EqualSid ) {

            RidArray[RidArrayLength] =
                *RtlSubAuthoritySid( Members.Sids[i].SidPointer,
                                        (*SubAuthorityCount) -1 );
            RidArrayLength++;
        }
    }

    if( RidArrayLength == 0) {

        Status = STATUS_SUCCESS;
        goto Cleanup;
    }

    //
    // Get Group RIDs and add them to list.
    //

    Status = SamrLookupIdsInDomain( NlGlobalChWorkerSamDBHandle,
                                        RidArrayLength,
                                        RidArray,
                                        &Names,
                                        &Use );

    if ( !NT_SUCCESS(Status) ) {

        Names.Element = NULL;
        Use.Element = NULL;

        if( Status == STATUS_NONE_MAPPED ) {

            //
            // if no SID is mapped, we can't do much here.
            //

            NlPrint((NL_CRITICAL,
                "NlAddGlobalGroupsToList could not map any SID from "
                "local group, RID = %lx \n", LocalGroupID ));

            Status = STATUS_SUCCESS;
        }

        goto Cleanup;
    }

    NlAssert( Names.Count == RidArrayLength );
    NlAssert( Names.Element != NULL );
    NlAssert( Use.Count == RidArrayLength );
    NlAssert( Use.Element != NULL );

    //
    // Find groups and add them to list.
    //

    for( i = 0; i < RidArrayLength; i++ ) {

        if( Use.Element[i] == SidTypeGroup ) {

            //
            // we found a group, add it to the list if it is not there
            // already.
            //

            if( NlGetGroupEntry( GroupList, RidArray[i] ) != NULL ) {

                //
                // entry already in the list.
                //

                continue;
            }

            //
            // add an entry to the list.
            //

            Status = NlAddGroupEntry( GroupList, RidArray[i] );

            if ( !NT_SUCCESS(Status) ) {
                goto Cleanup;
            }
        }
    }

Cleanup:

    if( Names.Element != NULL ) {
        SamIFree_SAMPR_RETURNED_USTRING_ARRAY( &Names );
    }

    if( Use.Element != NULL ) {
        SamIFree_SAMPR_ULONG_ARRAY( &Use );
    }

    if( RidArray != NULL ) {
        NetpMemoryFree( RidArray );
    }

    if ( Members.Sids != NULL ) {
        SamIFree_SAMPR_PSID_ARRAY( (PSAMPR_PSID_ARRAY)&Members );
    }

    if( AliasHandle != NULL ) {
        SamrCloseHandle( &AliasHandle );
    }

    if ( !NT_SUCCESS(Status) ) {

        NlPrint((NL_CRITICAL, "NlAddGlobalGroupsToList failed %lx\n",
                    Status ));
    }

    return( Status );
}
예제 #14
0
BOOLEAN
SepValidOwnerSubjectContext(
    IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
    IN PSID Owner,
    IN BOOLEAN ServerObject
)
/*++

Routine Description:

    This routine checks to see whether the provided SID is one the subject
    is authorized to assign as the owner of objects.  It will also check to
    see if the caller has SeRestorePrivilege, if so, the request is granted.

Arguments:

    SubjectContext - Points to the subject's security context.

    Owner - Points to the SID to be checked.



Return Value:

    none.

--*/

{

    ULONG Index;
    BOOLEAN Found;
    PTOKEN EffectiveToken;
    BOOLEAN Rc = FALSE;

    PAGED_CODE();

    //
    // It is invalid to assign a NULL owner, regardless of
    // whether you have SeRestorePrivilege or not.
    //

    if (Owner == NULL) {
        return( FALSE );
    }

    //
    // Allowable owners come from the primary if it's a server object.
    //

    if (!ServerObject && ARGUMENT_PRESENT(SubjectContext->ClientToken)) {
        EffectiveToken = (PTOKEN)SubjectContext->ClientToken;
    } else {
        EffectiveToken = (PTOKEN)SubjectContext->PrimaryToken;
    }


    //
    // If we're impersonating, make sure we're at TokenImpersonation
    // or above.  This prevents someone from setting the owner of an
    // object when impersonating at less Identify or Anonymous.
    //

    if (EffectiveToken->TokenType == TokenImpersonation) {

        if (EffectiveToken->ImpersonationLevel < SecurityImpersonation) {

            return( FALSE );

        }
    }

    Index = 0;

    SepAcquireTokenReadLock( EffectiveToken );

    //
    //  Walk through the list of user and group IDs looking
    //  for a match to the specified SID.  If one is found,
    //  make sure it may be assigned as an owner.
    //
    //  This code is similar to that performed to set the default
    //  owner of a token (NtSetInformationToken).
    //

    while (Index < EffectiveToken->UserAndGroupCount) {


        Found = RtlEqualSid(
                    Owner,
                    EffectiveToken->UserAndGroups[Index].Sid
                );

        if ( Found ) {

            //
            // We may return success if the Sid is one that may be assigned
            // as an owner, or if the caller has SeRestorePrivilege
            //

            if ( SepIdAssignableAsOwner(EffectiveToken,Index) ) {

                SepReleaseTokenReadLock( EffectiveToken );
                Rc = TRUE;
                goto exit;

            } else {

                //
                // Rc is already set to FALSE, just exit.
                //

                SepReleaseTokenReadLock( EffectiveToken );
                goto exit;

            } //endif assignable


        }  //endif Found


        Index += 1;

    } //endwhile


    SepReleaseTokenReadLock( EffectiveToken );

exit:

    //
    // If we are going to fail this call, check for Restore privilege,
    // and succeed if he has it.
    //

    //
    // We should really have gotten PreviousMode from the caller, but we
    // didn't, so hard wire it to be user-mode here.
    //

    if ( Rc == FALSE ) {
        Rc = SeSinglePrivilegeCheck( SeRestorePrivilege, UserMode );
    }

    return Rc;
}
예제 #15
0
BOOLEAN
SepIdAssignableAsGroup(
    IN PACCESS_TOKEN AToken,
    IN PSID Group
)
/*++

Routine Description:

    This routine checks to see whether the provided SID is one that
    may be assigned to be the default primary group in a token.

    The current criteria is that the passed SID be a group in the
    token, with no other restrictions.

Arguments:

    Token - Points to the token to be examined.

    Group - Points to the SID to be checked.

Return Value:

    TRUE - SID passed by be assigned as the default primary group in a token.

    FALSE - Passed SID may not be so assigned.

--*/

{
    ULONG Index;
    BOOLEAN Found = FALSE;
    PTOKEN Token;

    PAGED_CODE();

    Token = (PTOKEN)AToken;

    //
    // Let's make it invalid to assign a NULL primary group,
    // but we may need to revisit this.
    //

    if (Group == NULL) {
        return( FALSE );
    }
    Index = 0;

    SepAcquireTokenReadLock( Token );

    //
    //  Walk through the list of user and group IDs looking
    //  for a match to the specified SID.
    //

    while (Index < Token->UserAndGroupCount) {

        Found = RtlEqualSid(
                    Group,
                    Token->UserAndGroups[Index].Sid
                );

        if ( Found ) {
            break;
        }

        Index += 1;
    }

    SepReleaseTokenReadLock( Token );

    return Found;
}
예제 #16
0
파일: changelg.c 프로젝트: shuowen/OpenNT
NTSTATUS
I_NetNotifyDelta (
    IN SECURITY_DB_TYPE DbType,
    IN LARGE_INTEGER SerialNumber,
    IN SECURITY_DB_DELTA_TYPE DeltaType,
    IN SECURITY_DB_OBJECT_TYPE ObjectType,
    IN ULONG ObjectRid,
    IN PSID ObjectSid,
    IN PUNICODE_STRING ObjectName,
    IN DWORD ReplicateImmediately,
    IN PSAM_DELTA_DATA MemberId
)
/*++

Routine Description:

    This function is called by the SAM and LSA services after each
    change is made to the SAM and LSA databases.  The services describe
    the type of object that is modified, the type of modification made
    on the object, the serial number of this modification etc.  This
    information is stored for later retrieval when a BDC or member
    server wants a copy of this change.  See the description of
    I_NetSamDeltas for a description of how the change log is used.

    Add a change log entry to circular change log maintained in cache as
    well as on the disk and update the head and tail pointers

    It is assumed that Tail points to a block where this new change log
    entry may be stored.

Arguments:

    DbType - Type of the database that has been modified.

    SerialNumber - The value of the DomainModifiedCount field for the
        domain following the modification.

    DeltaType - The type of modification that has been made on the object.

    ObjectType - The type of object that has been modified.

    ObjectRid - The relative ID of the object that has been modified.
        This parameter is valid only when the object type specified is
        either SecurityDbObjectSamUser, SecurityDbObjectSamGroup or
        SecurityDbObjectSamAlias otherwise this parameter is set to zero.

    ObjectSid - The SID of the object that has been modified.  If the object
        modified is in a SAM database, ObjectSid is the DomainId of the Domain
        containing the object.

    ObjectName - The name of the secret object when the object type
        specified is SecurityDbObjectLsaSecret or the old name of the object
        when the object type specified is either SecurityDbObjectSamUser,
        SecurityDbObjectSamGroup or SecurityDbObjectSamAlias and the delta
        type is SecurityDbRename otherwise this parameter is set to NULL.

    ReplicateImmediately - TRUE if the change should be immediately
        replicated to all BDCs.  A password change should set the flag
        TRUE.

    MemberId - This parameter is specified when group/alias membership
        is modified. This structure will then point to the member's ID that
        has been updated.

Return Value:

    STATUS_SUCCESS - The Service completed successfully.

--*/
{
    NTSTATUS Status;
    CHANGELOG_ENTRY ChangeLogEntry;
    NETLOGON_DELTA_TYPE NetlogonDeltaType;
    USHORT Flags = 0;
    BOOL LanmanReplicateImmediately = FALSE;

    //
    // Ensure the role is right.  Otherwise, all the globals used below
    //  aren't initialized.
    //

    if ( NlGlobalChangeLogRole != ChangeLogPrimary ) {
        return STATUS_INVALID_DOMAIN_ROLE;
    }

    //
    // Also make sure that the change log cache is available.
    //

    if ( NlGlobalChangeLogDesc.Buffer == NULL ) {
        return STATUS_INVALID_DOMAIN_ROLE;
    }


    //
    // Determine the database index.
    //

    if( DbType == SecurityDbLsa ) {

        ChangeLogEntry.DBIndex = LSA_DB;

    } else if( DbType == SecurityDbSam ) {

        if ( RtlEqualSid( ObjectSid, NlGlobalChWorkerBuiltinDomainSid )) {

            ChangeLogEntry.DBIndex = BUILTIN_DB;

        } else {

            ChangeLogEntry.DBIndex = SAM_DB;

        }

        //
        // For the SAM database, we no longer need the ObjectSid.
        // Null out the pointer to prevent us from storing it in the
        // changelog.
        //

        ObjectSid = NULL;

    } else {

        //
        // unknown database, do nothing.
        //

        return STATUS_SUCCESS;
    }



    //
    // Map object type and delta type to NetlogonDeltaType
    //

    switch( ObjectType ) {
    case SecurityDbObjectLsaPolicy:

        switch (DeltaType) {
        case SecurityDbNew:
        case SecurityDbChange:
            NetlogonDeltaType = AddOrChangeLsaPolicy;
            break;

        // unknown delta type
        default:
            return STATUS_SUCCESS;
        }
        break;


    case SecurityDbObjectLsaTDomain:

        switch (DeltaType) {
        case SecurityDbNew:
        case SecurityDbChange:
            NetlogonDeltaType = AddOrChangeLsaTDomain;

            //
            //  Tell the netlogon service to update its in-memory list now.
            //
            (VOID) NlSendChangeLogNotification( ChangeLogTrustAdded,
                                                NULL,
                                                ObjectSid,
                                                0 );
            break;

        case SecurityDbDelete:
            NetlogonDeltaType = DeleteLsaTDomain;

            //
            //  Tell the netlogon service to update its in-memory list now.
            //
            (VOID) NlSendChangeLogNotification( ChangeLogTrustDeleted,
                                                NULL,
                                                ObjectSid,
                                                0 );
            break;

        // unknown delta type
        default:
            return STATUS_SUCCESS;
        }
        break;


    case SecurityDbObjectLsaAccount:

        switch (DeltaType) {
        case SecurityDbNew:
        case SecurityDbChange:
            NetlogonDeltaType = AddOrChangeLsaAccount;
            break;

        case SecurityDbDelete:
            NetlogonDeltaType = DeleteLsaAccount;
            break;

        // unknown delta type
        default:
            return STATUS_SUCCESS;
        }
        break;


    case SecurityDbObjectLsaSecret:

        switch (DeltaType) {
        case SecurityDbNew:
        case SecurityDbChange:
            NetlogonDeltaType = AddOrChangeLsaSecret;
            break;

        case SecurityDbDelete:
            NetlogonDeltaType = DeleteLsaSecret;
            break;

        // unknown delta type
        default:
            return STATUS_SUCCESS;
        }
        break;


    case SecurityDbObjectSamDomain:

        switch (DeltaType) {
        case SecurityDbNew:
        case SecurityDbChange:
            NetlogonDeltaType = AddOrChangeDomain;
            break;

        // unknown delta type
        default:
            return STATUS_SUCCESS;
        }
        break;

    case SecurityDbObjectSamUser:

        switch (DeltaType) {
        case SecurityDbChangePassword:
            Flags |= CHANGELOG_PASSWORD_CHANGE;
            LanmanReplicateImmediately = TRUE;
            NetlogonDeltaType = AddOrChangeUser;
            break;

        case SecurityDbNew:

            //
            // For down-level system, a newly added user needs to
            // have it's membership in "Domain Users" updated, too.
            // The following worker entry will add the additional
            // delta entry and increment the serial number
            // accordingly.
            //

            LOCK_CHANGELOG();
            if( IsChangeLogWorkerRunning() ) {
                (VOID) NlAddWorkerQueueEntry( ChangeLogAddUser, ObjectRid );
            }
            UNLOCK_CHANGELOG();

            NetlogonDeltaType = AddOrChangeUser;
            break;

        case SecurityDbChange:
            NetlogonDeltaType = AddOrChangeUser;
            break;

        //
        // This is a dummy delta sent by chworker to indicate that "Domain Users"
        // was added as a member of this user.
        //
        case SecurityDbChangeMemberAdd:
            Flags |= CHANGELOG_DOMAINUSERS_CHANGED;
            NetlogonDeltaType = AddOrChangeUser;
            break;

        case SecurityDbDelete:

            //
            // This might be a Lanman BDC so check to be sure.
            //

            NlLmBdcListDel( ObjectRid );

            NetlogonDeltaType = DeleteUser;
            break;


        case SecurityDbRename:
            NetlogonDeltaType = RenameUser;

            //
            // For down-level system, Rename user is handled as two
            // deltas, viz. 1) Delete old user and 2) Add new user.
            // The following worker entry will add the additional
            // delta entry and increment the serial number
            // accordingly.
            //

            LOCK_CHANGELOG();

            if( IsChangeLogWorkerRunning() ) {
                (VOID) NlAddWorkerQueueEntry( ChangeLogRenameUser, ObjectRid );
            }

            UNLOCK_CHANGELOG();

            break;

        //
        // unknown delta type
        //

        default:
            return STATUS_SUCCESS;
        }

        break;

    case SecurityDbObjectSamGroup:

        switch ( DeltaType ) {
        case SecurityDbNew:
        case SecurityDbChange:
            NetlogonDeltaType = AddOrChangeGroup;
            break;

        case SecurityDbDelete:
            NetlogonDeltaType = DeleteGroup;

            //
            // when a global group is deleted, we also delete it
            // from the special group list, if it is included
            // in the list.
            //

            LOCK_CHANGELOG();

            if( IsChangeLogWorkerRunning() ) {

                PGLOBAL_GROUP_ENTRY GroupEntry;

                GroupEntry = NlGetGroupEntry (
                                 &NlGlobalSpecialServerGroupList,
                                 ObjectRid );

                if( GroupEntry != NULL ) {

                    RemoveEntryList( &GroupEntry->Next );
                    NetpMemoryFree( GroupEntry );
                }

            }

            UNLOCK_CHANGELOG();
            break;

        case SecurityDbRename:
            NetlogonDeltaType = RenameGroup;

            //
            // For down-level system, Rename group is handled as
            // three deltas, viz. 1) Delete old group, 2) Add new
            // group and 3. Changemembership of new group. The
            // following worker entry will add the additional
            // two delta entries and increment the serial number
            // accordingly.
            //

            LOCK_CHANGELOG();

            if( IsChangeLogWorkerRunning() ) {
                (VOID) NlAddWorkerQueueEntry( ChangeLogRenameGroup, ObjectRid );

            }

            UNLOCK_CHANGELOG();

            break;

        case SecurityDbChangeMemberAdd:
        case SecurityDbChangeMemberSet:
        case SecurityDbChangeMemberDel: {

            UNICODE_STRING ServersGroup;

            NetlogonDeltaType = ChangeGroupMembership;

            //
            // without object name we can't do much here.
            //
            if( ObjectName == NULL ) {
                break;
            }

            //
            // do something for down level
            //

            RtlInitUnicodeString( &ServersGroup, SSI_SERVER_GROUP_W );

            LOCK_CHANGELOG();

            if( RtlEqualUnicodeString(
                        &ServersGroup, ObjectName, (BOOLEAN)TRUE ) ) {

                //
                // Handle a new LM BDC.
                //

                if( DeltaType == SecurityDbChangeMemberAdd ) {

                    NlLmBdcListAdd( MemberId->GroupMemberId.MemberRid );


                    //
                    // Handle an LM BDC being deleted.
                    //

                } else if( DeltaType == SecurityDbChangeMemberDel ) {

                    NlLmBdcListDel( MemberId->GroupMemberId.MemberRid );
                }

            } else {

                if( IsChangeLogWorkerRunning() ) {

                    //
                    // Change log work is running. If the global groups
                    // list watched is empty, add this delta in the
                    // queue anyway, otherwise add this delta to entry
                    // only if this group is monitored.
                    //

                    if( IsListEmpty( &NlGlobalSpecialServerGroupList ) ||

                            ( NlGetGroupEntry(
                                  &NlGlobalSpecialServerGroupList,
                                  ObjectRid ) != NULL ) ) {


                        (VOID) NlAddWorkerQueueEntry(
                            ChangeLogGroupMembership,
                            MemberId->GroupMemberId.MemberRid );

                    }
                }
            }

            UNLOCK_CHANGELOG();

            break;
        }

        //
        // unknown delta type
        //
        default:
            return STATUS_SUCCESS;
        }
        break;

    case SecurityDbObjectSamAlias:

        switch (DeltaType) {
        case SecurityDbNew:
        case SecurityDbChange:
            NetlogonDeltaType = AddOrChangeAlias;
            break;

        case SecurityDbDelete:
            NetlogonDeltaType = DeleteAlias;
            break;

        case SecurityDbRename:
            NetlogonDeltaType = RenameAlias;
            break;

        case SecurityDbChangeMemberAdd:
        case SecurityDbChangeMemberSet:
        case SecurityDbChangeMemberDel:

            NetlogonDeltaType = ChangeAliasMembership;

            LOCK_CHANGELOG();

            //
            // if this delta is BUILTIN domain delta and the group
            // modified is special group then add this delta to
            // workers queue if it is running.
            //

            if ( (ChangeLogEntry.DBIndex == BUILTIN_DB) &&
                    ( IsChangeLogWorkerRunning() ) &&
                    ( IsSpecialLocalGroup( ObjectRid ) ) ) {

                ULONG Rid;
                PUCHAR SubAuthorityCount;
                BOOLEAN EqualSid;

                //
                // if the member modified belongs to the local SAM
                // database.
                //

                SubAuthorityCount =
                    RtlSubAuthorityCountSid(
                        MemberId->AliasMemberId.MemberSid);

                (*SubAuthorityCount)--;

                if( NlGlobalChWorkerSamDomainSid != NULL ) {

                    EqualSid = RtlEqualSid(
                                   NlGlobalChWorkerSamDomainSid,
                                   MemberId->AliasMemberId.MemberSid);
                } else {
                    EqualSid = FALSE;
                }

                (*SubAuthorityCount)++;

                if( EqualSid ) {

                    Rid = *RtlSubAuthoritySid(
                              MemberId->AliasMemberId.MemberSid,
                              (*SubAuthorityCount) -1 );

                    (VOID) NlAddWorkerQueueEntry(
                        ChangeLogAliasMembership,
                        Rid );


                    //
                    // add this member in the global group list,
                    // since this member may be a global group and we
                    // don't want to miss any delta made on this group.
                    // Worker thread will adjust the list and remove
                    // unwanted user entries from the list.
                    //

                    Status = NlAddGroupEntry(
                                 &NlGlobalSpecialServerGroupList,
                                 Rid );

                    if ( !NT_SUCCESS(Status) ) {

                        NlPrint((NL_CRITICAL,
                                 "NlAddGroupEntry failed %lx\n",
                                 Status ) );
                    }
                }
            }

            UNLOCK_CHANGELOG();

            break;

        // unknown delta type
        default:
            return STATUS_SUCCESS;
        }
        break;

    default:

        // unknown object type
        return STATUS_SUCCESS;

    }


    //
    // Build the changelog entry and write it to the changelog
    //

    ChangeLogEntry.DeltaType = NetlogonDeltaType;
    ChangeLogEntry.SerialNumber = SerialNumber;
    ChangeLogEntry.ObjectRid = ObjectRid;
    ChangeLogEntry.Flags = ReplicateImmediately ? CHANGELOG_REPLICATE_IMMEDIATELY : 0;
    ChangeLogEntry.Flags |= Flags;

    (VOID) NlWriteChangeLogEntry( &NlGlobalChangeLogDesc, &ChangeLogEntry, ObjectSid, ObjectName, TRUE );


    //
    // If this change requires immediate replication, do so
    //

    if( ReplicateImmediately ) {

        LOCK_CHANGELOG();
        NlGlobalChangeLogReplicateImmediately = TRUE;
        UNLOCK_CHANGELOG();

        if ( !SetEvent( NlGlobalChangeLogEvent ) ) {
            NlPrint((NL_CRITICAL,
                     "Cannot set ChangeLog event: %lu\n",
                     GetLastError() ));
        }


        //
        // If this change requires immediate replication to Lanman BDCs, do so
        //

    } else if( LanmanReplicateImmediately ) {

        LOCK_CHANGELOG();
        NlGlobalChangeLogLanmanReplicateImmediately = TRUE;
        UNLOCK_CHANGELOG();

        if ( !SetEvent( NlGlobalChangeLogEvent ) ) {
            NlPrint((NL_CRITICAL,
                     "Cannot set ChangeLog event: %lu\n",
                     GetLastError() ));
        }

    }

    return STATUS_SUCCESS;
}
예제 #17
0
파일: upgrade.c 프로젝트: mingpen/OpenNT
NTSTATUS
SampFixBug18471 (
    IN ULONG Revision
    )
/*++

Routine Description:

    This routine fixes bug 18471, that SAM does not adjust the protection
    on groups that are members of administrative aliases in the builtin
    domain. It fixes this by opening a fixed set of known aliases
    (Administrators, Account Operators, Backup Operators, Print Operators,
    and Server Operators), and enumerating their members.  To fix this,
    we will remove all the members of these aliases (except the
    Administrator user account) and re-add them.

Arguments:

    Revision - Revision of the Sam server.

Return Value:


    Note:


--*/
{
    NTSTATUS            Status;
    ULONG               Index, Index2;
    PSID                BuiltinDomainSid = NULL;
    SID_IDENTIFIER_AUTHORITY BuiltinAuthority = SECURITY_NT_AUTHORITY;
    PSID                AccountDomainSid;
    ULONG               AccountDomainIndex = 0xffffffff;
    ULONG               BuiltinDomainIndex = 0xffffffff;
    SAMPR_PSID_ARRAY    AliasMembership;
    ULONG               MemberRid;
    ULONG               SdRevision;
    PSECURITY_DESCRIPTOR OldDescriptor;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    ULONG               SecurityDescriptorLength;
    SAMP_OBJECT_TYPE    MemberType;
    PSAMP_OBJECT        MemberContext;
    PSAMP_OBJECT        AliasContext;
    SAMP_V1_0A_FIXED_LENGTH_GROUP GroupV1Fixed;
    SAMP_V1_0A_FIXED_LENGTH_USER UserV1Fixed;

    //
    // Check the revision on the server to see if this upgrade has
    // already been performed.
    //


    if (Revision >= SAMP_SERVER_REVISION) {

        //
        // This upgrade has already been performed.
        //

        goto Cleanup;
    }


    //
    // Build a the BuiltIn domain SID.
    //

    BuiltinDomainSid  = RtlAllocateHeap(RtlProcessHeap(), 0,RtlLengthRequiredSid( 1 ));

    if ( BuiltinDomainSid == NULL ) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto Cleanup;
    }

    RtlInitializeSid( BuiltinDomainSid,   &BuiltinAuthority, 1 );
    *(RtlSubAuthoritySid( BuiltinDomainSid,  0 )) = SECURITY_BUILTIN_DOMAIN_RID;


    //
    // Lookup the index of the account domain
    //

    for (Index = 0;
         Index < SampDefinedDomainsCount ;
         Index++ ) {

        if (RtlEqualSid( BuiltinDomainSid, SampDefinedDomains[Index].Sid)) {
            BuiltinDomainIndex = Index;
        } else {
            AccountDomainIndex = Index;
        }
    }

    ASSERT(AccountDomainIndex < SampDefinedDomainsCount);
    ASSERT(BuiltinDomainIndex < SampDefinedDomainsCount);

    AccountDomainSid = SampDefinedDomains[AccountDomainIndex].Sid;

    //
    // Create out transaction log
    //

    Status = SampCreate18471Key();
    if (!NT_SUCCESS(Status)) {
        goto Cleanup;
    }




    //
    // Now loop through and open the aliases we are intersted in
    //

    for (Index = 0;
         Index < ADMINISTRATIVE_ALIAS_COUNT ;
         Index++ )
    {

        SampSetTransactionDomain( BuiltinDomainIndex );

        SampAcquireReadLock();

        Status = SampCreateAccountContext(
                    SampAliasObjectType,
                    AdministrativeRids[Index],
                    TRUE,                       // Trusted client
                    TRUE,                       // Account exists
                    &AliasContext
                    );

        if ( !NT_SUCCESS(Status) ) {

            SampReleaseReadLock();
            if (Status == STATUS_NO_SUCH_ALIAS) {
                Status = STATUS_SUCCESS;
                continue;
            } else {

                goto Cleanup;
            }
        }


        //
        // Get the members in the alias so we can remove and re-add them
        //

        Status = SampRetrieveAliasMembers(
                    AliasContext,
                    &(AliasMembership.Count),
                    (PSID **)&(AliasMembership.Sids)
                    );

        SampDeleteContext(AliasContext);
        SampReleaseReadLock();
        if (!NT_SUCCESS(Status)) {
            break;
        }

        //
        // Write that we are opening this alias to the log.  We don't need
        // to do this for administrators, since for them we the update is
        // idempotent.
        //

        if (AdministrativeRids[Index] != DOMAIN_ALIAS_RID_ADMINS) {
            Status = SampAddAliasTo18471Key(
                        AdministrativeRids[Index]
                        );
            if (!NT_SUCCESS(Status)) {
                break;
            }
        }


        //
        // Loop through the members and split each sid.  For every
        // member in the account domain , remove it and re-add it from
        // this alias.
        //




        for (Index2 = 0; Index2 < AliasMembership.Count ; Index2++ )
        {
            //
            // Check to see if this account is in the account domain
            //

            if ( SampMatchDomainPrefix(
                    (PSID) AliasMembership.Sids[Index2].SidPointer,
                    AccountDomainSid
                    ) )
            {

                //
                // Get the RID for this member
                //

                MemberRid = *RtlSubAuthoritySid(
                                AliasMembership.Sids[Index2].SidPointer,
                                *RtlSubAuthorityCountSid(
                                    AliasMembership.Sids[Index2].SidPointer
                                ) - 1
                                );

                //
                // Now remove and re-add the administratie nature of this
                // membership
                //

                if (AdministrativeRids[Index] == DOMAIN_ALIAS_RID_ADMINS) {

                    Status = SampAcquireWriteLock();
                    if (!NT_SUCCESS(Status)) {
                        break;
                    }

                    SampSetTransactionDomain( AccountDomainIndex );

                    //
                    // Try to create a context for the account as a group.
                    //

                    Status = SampCreateAccountContext(
                                     SampGroupObjectType,
                                     MemberRid,
                                     TRUE, // Trusted client
                                     TRUE, // Account exists
                                     &MemberContext
                                     );

                    if (!NT_SUCCESS( Status ) ) {

                        //
                        // If this ID does not exist as a group, that's fine -
                        // it might be a user or might have been deleted.
                        //

                        SampReleaseWriteLock( FALSE );
                        if (Status == STATUS_NO_SUCH_GROUP) {
                            Status = STATUS_SUCCESS;
                            continue;
                        }
                        break;
                    }

                    //
                    // Now set a flag in the group itself,
                    // so that when users are added and removed
                    // in the future it is known whether this
                    // group is in an ADMIN alias or not.
                    //

                    Status = SampRetrieveGroupV1Fixed(
                                   MemberContext,
                                   &GroupV1Fixed
                                   );

                    if ( NT_SUCCESS(Status)) {

                        GroupV1Fixed.AdminCount = 1;

                        Status = SampReplaceGroupV1Fixed(
                                    MemberContext,
                                    &GroupV1Fixed
                                    );
                        //
                        // Modify the security descriptor to
                        // prevent account operators from adding
                        // anybody to this group
                        //

                        if ( NT_SUCCESS( Status ) ) {

                            Status = SampGetAccessAttribute(
                                        MemberContext,
                                        SAMP_GROUP_SECURITY_DESCRIPTOR,
                                        FALSE, // don't make copy
                                        &SdRevision,
                                        &OldDescriptor
                                        );

                            if (NT_SUCCESS(Status)) {

                                Status = SampModifyAccountSecurity(
                                            SampGroupObjectType,
                                            TRUE, // this is an admin
                                            OldDescriptor,
                                            &SecurityDescriptor,
                                            &SecurityDescriptorLength
                                            );
                            }

                            if ( NT_SUCCESS( Status ) ) {

                                //
                                // Write the new security descriptor into the object
                                //

                                Status = SampSetAccessAttribute(
                                               MemberContext,
                                               SAMP_USER_SECURITY_DESCRIPTOR,
                                               SecurityDescriptor,
                                               SecurityDescriptorLength
                                               );

                                MIDL_user_free( SecurityDescriptor );
                            }



                        }
                        if (NT_SUCCESS(Status)) {

                            //
                            // Add the modified group to the current transaction
                            // Don't use the open key handle since we'll be deleting the context.
                            //

                            Status = SampStoreObjectAttributes(MemberContext, FALSE);

                        }

                    }

                    //
                    // Clean up the group context
                    //

                    SampDeleteContext(MemberContext);

                    //
                    // we don't want the modified count to change
                    //

                    SampTransactionWithinDomain = FALSE;

                    if (NT_SUCCESS(Status)) {
                        Status = SampReleaseWriteLock( TRUE );
                    } else {
                        (VOID) SampReleaseWriteLock( FALSE );
                    }

                }
                else
                {


                    //
                    // Check to see if we've already upgraded this member
                    //

                    Status = SampCheckMemberUpgradedFor18471(
                                AdministrativeRids[Index],
                                MemberRid);

                    if (NT_SUCCESS(Status)) {

                        //
                        // This member already was upgraded.
                        //

                        continue;
                    } else {

                        //
                        // We continue on with the upgrade
                        //

                        Status = STATUS_SUCCESS;
                    }

                    //
                    // Change the operator account for the other
                    // aliases.
                    //

                    if (NT_SUCCESS(Status)) {

                        Status = SampAcquireWriteLock();
                        if (!NT_SUCCESS(Status)) {
                            break;
                        }

                        SampSetTransactionDomain( AccountDomainIndex );

                        Status = SampChangeAccountOperatorAccessToMember(
                                    AliasMembership.Sids[Index2].SidPointer,
                                    NoChange,
                                    AddToAdmin
                                    );

                        //
                        // If that succeeded, add this member to the log
                        // as one that was upgraded.
                        //

                        if (NT_SUCCESS(Status)) {
                            Status = SampAddMemberRidTo18471Key(
                                        AdministrativeRids[Index],
                                        MemberRid
                                        );

                        }

                        //
                        // We don't want the modified count to be updated so
                        // make this not a domain transaction
                        //

                        SampTransactionWithinDomain = FALSE;
                                                if (NT_SUCCESS(Status)) {
                            Status = SampReleaseWriteLock( TRUE );
                        } else {
                            (VOID) SampReleaseWriteLock( FALSE );
                        }

                    }

                    if (!NT_SUCCESS(Status)) {
                        break;
                    }

                }
            }
        }

        SamIFree_SAMPR_PSID_ARRAY(
            &AliasMembership
            );
        AliasMembership.Sids = NULL;


        //
        // If something up above failed or the upgrade was already done,
        // exit now.
        //

        if (!NT_SUCCESS(Status)) {
            break;
        }
    }

Cleanup:

    if (BuiltinDomainSid != NULL) {
        RtlFreeHeap(
            RtlProcessHeap(),
            0,
            BuiltinDomainSid
            );
    }

    if (NT_SUCCESS(Status)) {
        Status = SampCleanup18471();
    }
    return(Status);
}
예제 #18
0
/*
 * @implemented
 */
BOOLEAN
NTAPI
SeFastTraverseCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
                    IN PACCESS_STATE AccessState,
                    IN ACCESS_MASK DesiredAccess,
                    IN KPROCESSOR_MODE AccessMode)
{
    PACL Dacl;
    ULONG AceIndex;
    PKNOWN_ACE Ace;

    PAGED_CODE();

    NT_ASSERT(AccessMode != KernelMode);

    if (SecurityDescriptor == NULL)
        return FALSE;

    /* Get DACL */
    Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
    /* If no DACL, grant access */
    if (Dacl == NULL)
        return TRUE;

    /* No ACE -> Deny */
    if (!Dacl->AceCount)
        return FALSE;

    /* Can't perform the check on restricted token */
    if (AccessState->Flags & TOKEN_IS_RESTRICTED)
        return FALSE;

    /* Browse the ACEs */
    for (AceIndex = 0, Ace = (PKNOWN_ACE)((ULONG_PTR)Dacl + sizeof(ACL));
         AceIndex < Dacl->AceCount;
         AceIndex++, Ace = (PKNOWN_ACE)((ULONG_PTR)Ace + Ace->Header.AceSize))
    {
        if (Ace->Header.AceFlags & INHERIT_ONLY_ACE)
            continue;

        /* If access-allowed ACE */
        if (Ace->Header.AceType & ACCESS_ALLOWED_ACE_TYPE)
        {
            /* Check if all accesses are granted */
            if (!(Ace->Mask & DesiredAccess))
                continue;

            /* Check SID and grant access if matching */
            if (RtlEqualSid(SeWorldSid, &(Ace->SidStart)))
                return TRUE;
        }
        /* If access-denied ACE */
        else if (Ace->Header.AceType & ACCESS_DENIED_ACE_TYPE)
        {
            /* Here, only check if it denies all the access wanted and deny if so */
            if (Ace->Mask & DesiredAccess)
                return FALSE;
        }
    }

    /* Faulty, deny */
    return FALSE;
}
예제 #19
0
파일: SECSYS.C 프로젝트: caidongyun/libs
//----------------------------------------------------------------------
//
// NTIRemoveWorldAce
// 
// Scans the passed security descriptor's DACL, looking for
// the World SID's ACE (its first because the of the way device object
// security descriptors are created) and removes it.
//
// If successful, the original security descriptor is deallocated
// and a new one is returned.
//
//----------------------------------------------------------------------
NTSTATUS NTIRemoveWorldAce( PSECURITY_DESCRIPTOR SecurityDescriptor,
			    PSECURITY_DESCRIPTOR *NewSecurityDescriptor )
{
   PSECURITY_DESCRIPTOR	     absSecurityDescriptor;
   PSECURITY_DESCRIPTOR	     relSecurityDescriptor;
   PACE_HEADER               aceHeader;
   NTSTATUS		     status;
   PACL			     Dacl;
   BOOLEAN		     DaclPresent, DaclDefaulted;
   USHORT                    aceIndex;
   ULONG                     worldSidLength;
   SID_IDENTIFIER_AUTHORITY  worldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
   PULONG                    worldSidSubAuthority;
   ULONG                     relLength;
   PSID                      worldSid;
   PSID                      aceSid;

   //
   // First, get an absolute version of the self-relative descriptor
   //
   relLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
   status = NTIMakeAbsoluteSD( SecurityDescriptor, 
			       &absSecurityDescriptor );
   if( !NT_SUCCESS( status )) {
	  
     return status;
   }

   //
   // Pull the DACL out so that we can scan it
   //
   status = RtlGetDaclSecurityDescriptor( absSecurityDescriptor,
					  &DaclPresent,
					  &Dacl,
					  &DaclDefaulted );
   if( !NT_SUCCESS( status ) || !DaclPresent ) {

     DbgPrint(("Secsys: strange - couldn't get DACL from our absolute SD: %x\n", 
	       status ));
     ExFreePool( absSecurityDescriptor );
     return status;
   }

   //
   // Initialize a SID that identifies the world-authority so
   // that we can recognize it in the ACL
   //
   worldSidLength = RtlLengthRequiredSid( 1 );
   worldSid = (PSID) ExAllocatePool( PagedPool, worldSidLength );
   RtlInitializeSid( worldSid, &worldSidAuthority, 1 );
   worldSidSubAuthority = RtlSubAuthoritySid( worldSid, 0 );
   *worldSidSubAuthority = SECURITY_WORLD_RID;

   //
   // Now march through the ACEs looking for the World ace. We could 
   // do one of two things: 
   //
   //	- remove the ACE
   //	- convert it into a grant-nothing ACE
   //
   // For demonstration purposes I'll remove the ACE. In addition,
   // this requires that I implement kernel-mode GetAce and DeleteAce functions,
   // since they are not implemented by the NT kernel.
   //
   DbgPrint(("Secsys: %d ACEs in DACL\n", Dacl->AceCount ));

   for( aceIndex = 0; aceIndex < Dacl->AceCount; aceIndex++ ) {

     aceHeader = NTIGetAce( Dacl, aceIndex );
     
     DbgPrint(("  ACE: type: %s mask: %x\n", 
	       (aceHeader->AceType & ACCESS_DENIED_ACE_TYPE ? "Deny" : "Allow"),
	       *(PULONG) ((PUCHAR) aceHeader + sizeof(ACE_HEADER))));

     //
     // Get the SID in this ACE and see if its the WORLD (Everyone) SID
     //
     aceSid    = (PSID) ((PUCHAR) aceHeader + sizeof(ACE_HEADER) + sizeof(ULONG));
     if( RtlEqualSid( worldSid, aceSid )) {

       //
       // We found it: remove it.
       //
       DbgPrint(("Secsys: Deleting ace %d\n", aceIndex ));
       NTIDeleteAce( Dacl, aceIndex );
       break;
     }
   }

   // 
   // Write new DACL back to security descriptor
   //
   status = RtlSetDaclSecurityDescriptor( absSecurityDescriptor,
					  TRUE,
					  Dacl,
					  FALSE );
   if( !NT_SUCCESS( status )) {

      DbgPrint(("Secsys: Could not update SD Dacl: %x\n", status ));
      goto cleanup;
   }

   // 
   // Make sure its valid
   //
   if( !RtlValidSecurityDescriptor( absSecurityDescriptor )) {

      DbgPrint(("Secsys: SD after remove is invalid!\n"));
      status = STATUS_UNSUCCESSFUL;
      goto cleanup;
   }

   //
   // Now convert the security descriptor back to 
   // self-relative
   //
   relSecurityDescriptor = ExAllocatePool( PagedPool, relLength );
   status = RtlAbsoluteToSelfRelativeSD( absSecurityDescriptor,
					 relSecurityDescriptor, &relLength );
   if( !NT_SUCCESS( status )) {

     DbgPrint(("Could not convert absolute SD to relative: %x\n", status ));
   }

   //
   // Final step, free the original security descriptor and return the new one
   //
   ExFreePool( SecurityDescriptor );
   *NewSecurityDescriptor = relSecurityDescriptor;

cleanup:
   ExFreePool( worldSid );
   ExFreePool( absSecurityDescriptor );
   return status;
}
예제 #20
0
NTSTATUS
PvfsSetSecurityDescriptorFile(
    IN PPVFS_CCB pCcb,
    IN SECURITY_INFORMATION SecInfo,
    IN PSECURITY_DESCRIPTOR_RELATIVE pSecDesc,
    IN ULONG SecDescLength
    )
{
    NTSTATUS ntError = STATUS_ACCESS_DENIED;
    PSECURITY_DESCRIPTOR_RELATIVE pFinalSecDesc = NULL;
    ULONG ulFinalSecDescLength = 0;
    SECURITY_INFORMATION SecInfoAll = (OWNER_SECURITY_INFORMATION |
                                       GROUP_SECURITY_INFORMATION |
                                       DACL_SECURITY_INFORMATION |
                                       SACL_SECURITY_INFORMATION);
    BYTE pCurrentSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE];
    ULONG ulCurrentSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE;
    BYTE pNewSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE];
    ULONG ulNewSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE;
    PSECURITY_DESCRIPTOR_ABSOLUTE pIncAbsSecDesc = NULL;
    union {
        TOKEN_OWNER TokenOwnerInfo;
        BYTE Buffer[SID_MAX_SIZE];
    } TokenOwnerBuffer;
    PTOKEN_OWNER pTokenOwnerInformation = (PTOKEN_OWNER)&TokenOwnerBuffer;
    ULONG ulTokenOwnerLength = 0;
    union {
        SID Sid;
        BYTE Buffer[SID_MAX_SIZE];
    } LocalSystemSidBuffer;
    PSID pLocalSystemSid = (PSID)&LocalSystemSidBuffer;
    ULONG ulLocalSystemSidLength = sizeof(LocalSystemSidBuffer);

    memset(pCurrentSecDescBuffer, 0, SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE);
    memset(pNewSecDescBuffer, 0, SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE);
    memset(TokenOwnerBuffer.Buffer, 0, SID_MAX_SIZE);

    /* Sanity checks */

    if (SecInfo == 0)
    {
        ntError = STATUS_INVALID_PARAMETER;
        BAIL_ON_NT_STATUS(ntError);
    }

    /* If the new Security Descriptor contains owner or group SID
       information, berify that the user's ACCESS_TOKEN contains the
       SID as a member */

    if (SecInfo & (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION))
    {
        PSID pOwner = NULL;
        PSID pGroup = NULL;
        BOOLEAN bDefaulted = FALSE;

        ntError = PvfsSecurityAclSelfRelativeToAbsoluteSD(
                      &pIncAbsSecDesc,
                      pSecDesc);
        BAIL_ON_NT_STATUS(ntError);

        ntError = RtlQueryAccessTokenInformation(
                      pCcb->pUserToken,
                      TokenOwner,
                      (PVOID)pTokenOwnerInformation,
                      sizeof(TokenOwnerBuffer),
                      &ulTokenOwnerLength);
        BAIL_ON_NT_STATUS(ntError);

        ntError = RtlCreateWellKnownSid(
                      WinLocalSystemSid,
                      NULL,
                      pLocalSystemSid,
                      &ulLocalSystemSidLength);
        BAIL_ON_NT_STATUS(ntError);

        if (SecInfo & OWNER_SECURITY_INFORMATION)
        {
            ntError = RtlGetOwnerSecurityDescriptor(
                          pIncAbsSecDesc,
                          &pOwner,
                          &bDefaulted);
            BAIL_ON_NT_STATUS(ntError);

            if (!RtlIsSidMemberOfToken(pCcb->pUserToken, pOwner) &&
                !RtlEqualSid(pLocalSystemSid, pTokenOwnerInformation->Owner))
            {
                ntError = STATUS_ACCESS_DENIED;
                BAIL_ON_NT_STATUS(ntError);
            }
        }

        if (SecInfo & GROUP_SECURITY_INFORMATION)
        {
            ntError = RtlGetGroupSecurityDescriptor(
                          pIncAbsSecDesc,
                          &pGroup,
                          &bDefaulted);
            BAIL_ON_NT_STATUS(ntError);

            if (!RtlIsSidMemberOfToken(pCcb->pUserToken, pGroup) &&
                !RtlEqualSid(pLocalSystemSid, pTokenOwnerInformation->Owner))
            {
                ntError = STATUS_ACCESS_DENIED;
                BAIL_ON_NT_STATUS(ntError);
            }
        }
    }


    if (SecInfo == SecInfoAll)
    {
        /* We already have a fully formed Security Descriptor */

        pFinalSecDesc = pSecDesc;
        ulFinalSecDescLength = SecDescLength;
    }
    else
    {
        /* Retrieve the existing SD and merge with the incoming one */

        ntError = PvfsGetSecurityDescriptorFile(
                      pCcb,
                      SecInfoAll,
                      (PSECURITY_DESCRIPTOR_RELATIVE)pCurrentSecDescBuffer,
                      &ulCurrentSecDescLength);
        BAIL_ON_NT_STATUS(ntError);

        /* Assume that the new SD is <= the combined size of the current
           SD and the incoming one */

        ntError = RtlSetSecurityDescriptorInfo(
                      SecInfo,
                      pSecDesc,
                      (PSECURITY_DESCRIPTOR_RELATIVE)pCurrentSecDescBuffer,
                      (PSECURITY_DESCRIPTOR_RELATIVE)pNewSecDescBuffer,
                      &ulNewSecDescLength,
                      &gPvfsFileGenericMapping);
        BAIL_ON_NT_STATUS(ntError);

        pFinalSecDesc = (PSECURITY_DESCRIPTOR_RELATIVE)pNewSecDescBuffer;
        ulFinalSecDescLength = ulNewSecDescLength;

    }


    /* Save the combined SD */

#ifdef HAVE_EA_SUPPORT
    ntError = PvfsSetSecurityDescriptorFileXattr(
                  pCcb,
                  pFinalSecDesc,
                  ulFinalSecDescLength);
#else
    ntError = PvfsSetSecurityDescriptorPosix(
                  pCcb,
                  pFinalSecDesc,
                  ulFinalSecDescLength);
#endif

    BAIL_ON_NT_STATUS(ntError);

    PvfsNotifyScheduleFullReport(
        pCcb->pFcb,
        FILE_NOTIFY_CHANGE_SECURITY,
        FILE_ACTION_MODIFIED,
        pCcb->pszFilename);


cleanup:
    if (pIncAbsSecDesc)
    {
        PvfsFreeAbsoluteSecurityDescriptor(&pIncAbsSecDesc);
    }

    return ntError;

error:
    goto cleanup;
}