다음을 통해 공유


IRP_MJ_QUERY_SECURITY 및 IRP_MJ_SET_SECURITY

다행히 파일 시스템의 경우 보안 설명자의 실제 스토리지 및 검색은 상대적으로 불투명합니다. 이는 파일 시스템에서 설명자를 이해할 필요가 없는 자체 상대 형식의 보안 설명자의 특성 때문입니다. 따라서 쿼리 작업을 처리하는 것은 일반적으로 매우 간단한 연습입니다. 파일 시스템 구현의 예는 다음과 같습니다.

NTSTATUS FsdCommonQuerySecurity( PIRP_CONTEXT IrpContext)
{
    NTSTATUS status = STATUS_SUCCESS;
    PSECURITY_DESCRIPTOR LocalPointer;

    // Need to add code to lock the FCB here

    status = FsdLoadSecurityDescriptor(IrpContext, IrpContext->Fcb);
 
    if (NT_SUCCESS(status) ) {
 
        //
        // copy the SecurityDescriptor into the callers buffer
        // note that this copy can throw an exception that must be handled
        // (code to handle the exception was omitted here for brevity)
        //
        LocalPointer = IrpContext->Fcb->SecurityDescriptor;

        status = SeQuerySecurityDescriptorInfo(
     &IrpContext->IrpSp->Parameters.QuerySecurity.SecurityInformation,
            (PSECURITY_DESCRIPTOR)IrpContext->Irp->UserBuffer,
            &IrpContext->IrpSp->Parameters.QuerySecurity.Length,
            &LocalPointer );
 
        //
        // CACLS utility expects OVERFLOW
        //
        if (status == STATUS_BUFFER_TOO_SMALL ) {
            status = STATUS_BUFFER_OVERFLOW;
        }
    }
 
    // Need to add code to unlock the FCB here

    return status;
}

이 루틴은 외부 함수를 사용하여 영구 스토리지에서 실제 보안 설명자를 로드합니다(이 구현에서는 이전에 로드되지 않은 경우에만 해당 루틴이 보안 설명자를 로드함). 보안 설명자는 파일 시스템에 불투명하므로 보안 참조 모니터를 사용하여 설명자를 사용자의 버퍼에 복사해야 합니다. 이 코드 샘플과 관련하여 다음 두 가지 사항에 유의합니다.

  1. 일부 Windows 보안 도구에 대한 올바른 동작을 제공하려면 오류 코드 STATUS_BUFFER_TOO_SMALL 경고 코드 STATUS_BUFFER_OVERFLOW 변환해야 합니다.

  2. 쿼리 및 설정 보안 작업은 일반적으로 사용자 버퍼를 직접 사용하여 수행되므로 사용자 버퍼를 처리하는 동안 오류가 발생할 수 있습니다. 파일 시스템에서 만든 DEVICE_OBJECT Flags 멤버에 의해 제어됩니다. 이 코드를 기반으로 하는 파일 시스템 구현에서 호출 함수는 잘못된 사용자 버퍼로부터 보호하기 위해 __try 블록을 사용해야 합니다.

파일 시스템이 스토리지에서 보안 설명자를 로드하는 방법의 세부 정보(이 예제의 FsdLoadSecurityDescriptor 함수)는 전적으로 파일 시스템의 보안 설명자 스토리지 구현에 따라 달라집니다.

보안 설명자를 저장하는 것이 좀 더 복잡합니다. 파일 시스템에서 보안 설명자 공유를 지원하는 경우 파일 시스템에서 보안 설명자가 기존 보안 설명자와 일치하는지 여부를 확인해야 할 수 있습니다. 일치하지 않는 보안 설명자의 경우 파일 시스템에서 이 새 보안 설명자에 대한 새 스토리지를 할당해야 할 수 있습니다. 다음은 파일의 보안 설명자를 바꾸기 위한 샘플 루틴입니다.

NTSTATUS FsdCommonSetSecurity(PIRP_CONTEXT IrpContext)
{
    NTSTATUS status = STATUS_SUCCESS;
    PSECURITY_DESCRIPTOR SavedDescriptorPtr = 
        IrpContext->Fcb->SecurityDescriptor;
    ULONG SavedDescriptorLength = 
        IrpContext->Fcb->SecurityDescriptorLength;
    PSECURITY_DESCRIPTOR newSD = NULL;
    POW_FCB Fcb = IrpContext->Fcb;
    ULONG Information = IrpContext->Irp->IoStatus.Information;

    //
    // make sure that the FCB security descriptor is up to date
    //
    status = FsdLoadSecurityDescriptor(IrpContext, Fcb);

    if (!NT_SUCCESS(status)) {
      //
      // Something is seriously wrong 
      //
      IrpContext->Irp->IoStatus.Status = status;
      IrpContext->Irp->IoStatus.Information = 0;
      return status;
    }        
 
    status = SeSetSecurityDescriptorInfo(
       NULL,
       &IrpContext->IrpSp->Parameters.SetSecurity.SecurityInformation,
       IrpContext->IrpSp->Parameters.SetSecurity.SecurityDescriptor,
       &Fcb->SecurityDescriptor,
       PagedPool,
       IoGetFileObjectGenericMapping()
       );

    if (!NT_SUCCESS(status)) {

        //
        // restore things  and return
        //
        Fcb->SecurityDescriptorLength = SavedDescriptorLength;
        Fcb->SecurityDescriptor = SavedDescriptorPtr;
        IrpContext->Irp->IoStatus.Status = status;
        IrpContext->Irp->IoStatus.Information = 0;

        return status;
    }

    //
    // get the new length
    //
    Fcb->SecurityDescriptorLength = 
        RtlLengthSecurityDescriptor(Fcb->SecurityDescriptor);

    //
    // allocate our own private SD to replace the one from
    // SeSetSecurityDescriptorInfo so we can track our memory usage
    //
    newSD = ExAllocatePoolWithTag(PagedPool, 
        Fcb->SecurityDescriptorLength, 'DSyM');

    if (!newSD) {
 
      //
      // paged pool is empty
      //
      SeDeassignSecurity(&Fcb->SecurityDescriptor);
      status = STATUS_NO_MEMORY;
      Fcb->SecurityDescriptorLength = SavedDescriptorLength;
      Fcb->SecurityDescriptor = SavedDescriptorPtr;
 
      //
      // make sure FCB security is in a valid state
      //
      IrpContext->Irp->IoStatus.Status = status;
      IrpContext->Irp->IoStatus.Information = 0;
 
      return status;
 
    } 
 
    //
    // store the new security on disk
    //
    status = FsdStoreSecurityDescriptor(IrpContext, Fcb);

    if (!NT_SUCCESS(status)) {
      //
      // great- modified the in-core SD but couldn't get it out
      // to disk. undo everything. 
      //
      ExFreePool(newSD);
      SeDeassignSecurity(&Fcb->SecurityDescriptor);
      status = STATUS_NO_MEMORY;
      Fcb->SecurityDescriptorLength = SavedDescriptorLength;
      Fcb->SecurityDescriptor = SavedDescriptorPtr;
      IrpContext->Irp->IoStatus.Status = status;
      IrpContext->Irp->IoStatus.Information = 0;
 
      return status;
    }
 
    //
    // if we get here everything worked! 
    //
    RtlCopyMemory(newSD, Fcb->SecurityDescriptor, 
        Fcb->SecurityDescriptorLength);
 
    //
    // deallocate the security descriptor
    //
    SeDeassignSecurity(&Fcb->SecurityDescriptor);
 
    //
    // this either is the new private SD or NULL if 
    // memory allocation failed
    //
    Fcb->SecurityDescriptor = newSD;

    //
    // free the memory from the previous descriptor
    //
    if (SavedDescriptorPtr) {
      //
      // this  must always be from private allocation
      //
      ExFreePool(SavedDescriptorPtr);
 
    }        
 
    IrpContext->Irp.IoStatus = status;
    IrpContext->Irp.Information = Information;

    return status;
}

이 영역은 구현이 파일 시스템에서 파일 시스템에 따라 크게 달라지는 영역입니다. 예를 들어 보안 설명자 공유를 지원하는 파일 시스템은 일치하는 보안 설명자를 찾기 위해 명시적 논리를 추가해야 합니다. 이 샘플은 구현자에게 지침을 제공하기 위한 시도일 뿐입니다.