Best way to retrieve user name in combined kernel/user mode system?

One of the features of a minifilter->user mode server system I’m helping build requires us to log user access attempts to certain files. There are a number of ways to get user IDs in both KM and UM but I was just wondering if there’s a “best practices” way of doing so, ensuring the user ID I log belongs to the Windows account that actually tried to open the file, and not a system/admin/etc. account running the minifilter and server?

Advice appreciated, especially for a UM solution as I’d prefer not to monkey with our driver code! :slight_smile:

If you’re in Pre/Post IRP_MJ_CREATE you can retrieve the SID of the requestor using the following:

_Use_decl_annotations_
VOID
FsUtilGetRequestorSid(
    PFLT_CALLBACK_DATA Data,
    PSE_SID SeSid)
{
    SID_IDENTIFIER_AUTHORITY  nullAuthority = SECURITY_NULL_SID_AUTHORITY;
    PACCESS_STATE             accessState;
    PACCESS_TOKEN             requestorToken;
    PTOKEN_USER               tokenUserInfo = NULL;
    NTSTATUS                  status;
    PSECURITY_SUBJECT_CONTEXT requestorSubjectContext;

    //
    // This routine returns a NULL SID if we fail to query
    //
    RtlInitializeSid(&SeSid->Sid,
                     &nullAuthority, 
                     1);

    accessState = Data->Iopb->Parameters.Create.SecurityContext->AccessState;

    requestorSubjectContext = &accessState->SubjectSecurityContext;

    SeLockSubjectContext(requestorSubjectContext);
    
    // 
    // SeQuerySubjectContextToken does the right thing and returns us either the
    // impersonation token or the process token of the requestor
    // 
    requestorToken = SeQuerySubjectContextToken(requestorSubjectContext);

    // 
    // This doesn't fail, there is always one or the other
    // 
    ASSERT(requestorToken);

    // 
    // Query the token to retrieve the user SID
    //  
    status = SeQueryInformationToken(requestorToken,
                                     TokenUser,
                                     (PVOID *)&tokenUserInfo);

    if (!NT_SUCCESS(status)) {

        goto Exit;

    }

    RtlCopyMemory(&SeSid->Sid,
                  tokenUserInfo->User.Sid,
                  RtlLengthSid(tokenUserInfo->User.Sid));

Exit:

    SeUnlockSubjectContext(requestorSubjectContext);
    
    if (tokenUserInfo != NULL) {

        ExFreePool(tokenUserInfo);

    }

    return;

}

User mode can then easily translate the SID to a user name (e.g. LookupAccountSid).

if you are going to log, log the invariant SID - the user name can change, but this can’t. Then in a tool that views the log, perform the conversion based on the then current name etc. for that SID. This often comes up when people change their names after marriage etc.