Get the name of the user accessing a file

Hello All,

I am writing a minifilter driver to run on XP. At Precreate time I am trying
to get the SID using the method that Tony Mason recommends (code is below).
And then using the SID in the call to LookupAccountSid (executed in user
space). The code seems to work (in the sense that I don’t get any errors)
except the only user names I ever get are either NULL because the
LookupAccountSid returns an error 1332 or SYSTEM. When LookupAccountSid
returns 1332, the SID is all zeros.

The test scenario is as follows:
The account that I am logged onto has admin privileges and the user name is
Jim. When I try to access a particular file using explorer, notepad, and
wordpad the SID is always all zeros.

What does it mean when the SID contains all zeros. Does anyone have any idea
why the function is behaving this way? By the way the files are being
accessed locally.

TIA,
Jim

Code sample:

BOOLEAN
PSGetUserName (
__in PFLT_CALLBACK_DATA pCallbackData,
__in PFLT_FILTER pFilter,
OUT PUNICODE_STRING pUniUserName)
{
BOOLEAN success;
NTSTATUS status;
PTOKEN_USER pTokenUser;
SID sid;
ULONG retLength;

// First, try to open the security token of the thread
HANDLE hToken;
status = ZwOpenThreadTokenEx(NtCurrentThread(),
TOKEN_READ,
TRUE,
OBJ_KERNEL_HANDLE,
&hToken);
if (!NT_SUCCESS(status))
{
// The thread may not have a token – try to get the security token
// for the process
status = ZwOpenProcessTokenEx(NtCurrentProcess(),
TOKEN_READ,
OBJ_KERNEL_HANDLE,
&hToken);

if (!NT_SUCCESS(status))
{
DBGPRINT(5, (“PSGetUserName: Failed to open the process token. Status:
%x\n”,
status));
return FALSE;
}
}

// We have the token – now try to get the SID
//
// First, make the query to get the required length of the buffer
status = ZwQueryInformationToken(hToken,
TokenUser,
NULL,
0,
&retLength);

if (status != STATUS_BUFFER_TOO_SMALL)
{
DBGPRINT(5, (“PSGetUserName: Failed to get the length of the token
information. Status: %x\n”,
status));

ZwClose(hToken);
return FALSE;
}

// Allocate the appropriate buffer
pTokenUser = (PTOKEN_USER)ExAllocatePoolWithTag(NonPagedPool,
retLength,
UTIL_TAG);
if (pTokenUser == NULL)
{
DBGPRINT(5, (“PSGetUserName: Failed to allocate memory for the token
information.\n”));

ZwClose(hToken);
return FALSE;
}

// Now make the query with the appropriate length
status = ZwQueryInformationToken(hToken,
TokenUser,
pTokenUser,
retLength,
&retLength);

// Close the handle to the token – we don’t need it any longer
ZwClose(hToken);

// Copy the SID
RtlCopyMemory(&sid, pTokenUser->User.Sid, sizeof(SID));

// Free the buffer
ExFreePoolWithTag(pTokenUser, UTIL_TAG);

if (!NT_SUCCESS(status))
{
DBGPRINT(5, (“PSGetUserName: Failed to query token information. Status:
%x\n”,
status));
return FALSE;
}

// sEND MESSAGE TO USER SPACE

return TRUE;
}

I would use the user names in the UI only, and not in any internal
policy-making or policy-executing code. These parts of the product should use
SIDs.

So:

  • call LookupAccountSid only before displaying a SID in the UI control.
  • call LookupAccountName only in the UI path which is invoked when the user
    have chosen the user or group in the UI.

The rest of the system uses SIDs.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

“jjjames1” wrote in message news:xxxxx@ntfsd…
> Hello All,
>
> I am writing a minifilter driver to run on XP. At Precreate time I am trying
> to get the SID using the method that Tony Mason recommends (code is below).
> And then using the SID in the call to LookupAccountSid (executed in user
> space). The code seems to work (in the sense that I don’t get any errors)
> except the only user names I ever get are either NULL because the
> LookupAccountSid returns an error 1332 or SYSTEM. When LookupAccountSid
> returns 1332, the SID is all zeros.
>
> The test scenario is as follows:
> The account that I am logged onto has admin privileges and the user name is
> Jim. When I try to access a particular file using explorer, notepad, and
> wordpad the SID is always all zeros.
>
> What does it mean when the SID contains all zeros. Does anyone have any idea
> why the function is behaving this way? By the way the files are being
> accessed locally.
>
> TIA,
> Jim
>
> Code sample:
>
> BOOLEAN
> PSGetUserName (
> in PFLT_CALLBACK_DATA pCallbackData,
>
in PFLT_FILTER pFilter,
> OUT PUNICODE_STRING pUniUserName)
> {
> BOOLEAN success;
> NTSTATUS status;
> PTOKEN_USER pTokenUser;
> SID sid;
> ULONG retLength;
>
> // First, try to open the security token of the thread
> HANDLE hToken;
> status = ZwOpenThreadTokenEx(NtCurrentThread(),
> TOKEN_READ,
> TRUE,
> OBJ_KERNEL_HANDLE,
> &hToken);
> if (!NT_SUCCESS(status))
> {
> // The thread may not have a token – try to get the security token
> // for the process
> status = ZwOpenProcessTokenEx(NtCurrentProcess(),
> TOKEN_READ,
> OBJ_KERNEL_HANDLE,
> &hToken);
>
> if (!NT_SUCCESS(status))
> {
> DBGPRINT(5, (“PSGetUserName: Failed to open the process token. Status:
> %x\n”,
> status));
> return FALSE;
> }
> }
>
> // We have the token – now try to get the SID
> //
> // First, make the query to get the required length of the buffer
> status = ZwQueryInformationToken(hToken,
> TokenUser,
> NULL,
> 0,
> &retLength);
>
> if (status != STATUS_BUFFER_TOO_SMALL)
> {
> DBGPRINT(5, (“PSGetUserName: Failed to get the length of the token
> information. Status: %x\n”,
> status));
>
> ZwClose(hToken);
> return FALSE;
> }
>
> // Allocate the appropriate buffer
> pTokenUser = (PTOKEN_USER)ExAllocatePoolWithTag(NonPagedPool,
> retLength,
> UTIL_TAG);
> if (pTokenUser == NULL)
> {
> DBGPRINT(5, (“PSGetUserName: Failed to allocate memory for the token
> information.\n”));
>
> ZwClose(hToken);
> return FALSE;
> }
>
> // Now make the query with the appropriate length
> status = ZwQueryInformationToken(hToken,
> TokenUser,
> pTokenUser,
> retLength,
> &retLength);
>
> // Close the handle to the token – we don’t need it any longer
> ZwClose(hToken);
>
> // Copy the SID
> RtlCopyMemory(&sid, pTokenUser->User.Sid, sizeof(SID));
>
> // Free the buffer
> ExFreePoolWithTag(pTokenUser, UTIL_TAG);
>
> if (!NT_SUCCESS(status))
> {
> DBGPRINT(5, (“PSGetUserName: Failed to query token information. Status:
> %x\n”,
> status));
> return FALSE;
> }
>
> // sEND MESSAGE TO USER SPACE
>
> return TRUE;
> }
>
>
>

Sorry I don’t think you understood the question. There is no UI and there is
no policy code. The driver is simply trying to get the user name for the
current create via the SID. In looking at posts from the past I see that
other developers have do this using a method recommended by Tony Mason. My
version of that implemenation is below. Something is not working. Does any
one have any clues? What does it mean when the SID is all zeros?

Regards,.
Jim

“Maxim S. Shatskih” wrote in message
news:xxxxx@ntfsd…
> I would use the user names in the UI only, and not in any internal
> policy-making or policy-executing code. These parts of the product should
> use
> SIDs.
>
> So:
> - call LookupAccountSid only before displaying a SID in the UI control.
> - call LookupAccountName only in the UI path which is invoked when the
> user
> have chosen the user or group in the UI.
>
> The rest of the system uses SIDs.
>
> –
> Maxim Shatskih, Windows DDK MVP
> StorageCraft Corporation
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
> “jjjames1” wrote in message news:xxxxx@ntfsd…
>> Hello All,
>>
>> I am writing a minifilter driver to run on XP. At Precreate time I am
>> trying
>> to get the SID using the method that Tony Mason recommends (code is
>> below).
>> And then using the SID in the call to LookupAccountSid (executed in user
>> space). The code seems to work (in the sense that I don’t get any
>> errors)
>> except the only user names I ever get are either NULL because the
>> LookupAccountSid returns an error 1332 or SYSTEM. When LookupAccountSid
>> returns 1332, the SID is all zeros.
>>
>> The test scenario is as follows:
>> The account that I am logged onto has admin privileges and the user name
>> is
>> Jim. When I try to access a particular file using explorer, notepad, and
>> wordpad the SID is always all zeros.
>>
>> What does it mean when the SID contains all zeros. Does anyone have any
>> idea
>> why the function is behaving this way? By the way the files are being
>> accessed locally.
>>
>> TIA,
>> Jim
>>
>> Code sample:
>>
>> BOOLEAN
>> PSGetUserName (
>> in PFLT_CALLBACK_DATA pCallbackData,
>>
in PFLT_FILTER pFilter,
>> OUT PUNICODE_STRING pUniUserName)
>> {
>> BOOLEAN success;
>> NTSTATUS status;
>> PTOKEN_USER pTokenUser;
>> SID sid;
>> ULONG retLength;
>>
>> // First, try to open the security token of the thread
>> HANDLE hToken;
>> status = ZwOpenThreadTokenEx(NtCurrentThread(),
>> TOKEN_READ,
>> TRUE,
>> OBJ_KERNEL_HANDLE,
>> &hToken);
>> if (!NT_SUCCESS(status))
>> {
>> // The thread may not have a token – try to get the security token
>> // for the process
>> status = ZwOpenProcessTokenEx(NtCurrentProcess(),
>> TOKEN_READ,
>> OBJ_KERNEL_HANDLE,
>> &hToken);
>>
>> if (!NT_SUCCESS(status))
>> {
>> DBGPRINT(5, (“PSGetUserName: Failed to open the process token.
>> Status:
>> %x\n”,
>> status));
>> return FALSE;
>> }
>> }
>>
>> // We have the token – now try to get the SID
>> //
>> // First, make the query to get the required length of the buffer
>> status = ZwQueryInformationToken(hToken,
>> TokenUser,
>> NULL,
>> 0,
>> &retLength);
>>
>> if (status != STATUS_BUFFER_TOO_SMALL)
>> {
>> DBGPRINT(5, (“PSGetUserName: Failed to get the length of the token
>> information. Status: %x\n”,
>> status));
>>
>> ZwClose(hToken);
>> return FALSE;
>> }
>>
>> // Allocate the appropriate buffer
>> pTokenUser = (PTOKEN_USER)ExAllocatePoolWithTag(NonPagedPool,
>> retLength,
>> UTIL_TAG);
>> if (pTokenUser == NULL)
>> {
>> DBGPRINT(5, (“PSGetUserName: Failed to allocate memory for the token
>> information.\n”));
>>
>> ZwClose(hToken);
>> return FALSE;
>> }
>>
>> // Now make the query with the appropriate length
>> status = ZwQueryInformationToken(hToken,
>> TokenUser,
>> pTokenUser,
>> retLength,
>> &retLength);
>>
>> // Close the handle to the token – we don’t need it any longer
>> ZwClose(hToken);
>>
>> // Copy the SID
>> RtlCopyMemory(&sid, pTokenUser->User.Sid, sizeof(SID));
>>
>> // Free the buffer
>> ExFreePoolWithTag(pTokenUser, UTIL_TAG);
>>
>> if (!NT_SUCCESS(status))
>> {
>> DBGPRINT(5, (“PSGetUserName: Failed to query token information. Status:
>> %x\n”,
>> status));
>> return FALSE;
>> }
>>
>> // sEND MESSAGE TO USER SPACE
>>
>> return TRUE;
>> }
>>
>>
>>
>
>

> Sorry I don’t think you understood the question. There is no UI and there is

no policy code.

Then why you need the user name?

Usually, the user identity is needed to the product only to make some logging
(which contains user identity) or some access checks based on it.

If yes - then why don’t use the SID itself for this and not user name?

The driver is simply trying to get the user name for the
current create via the SID.

If you have no UI and no policy - then what is the need in all of this?

In looking at posts from the past I see that
other developers have do this using a method recommended by Tony Mason.
My
version of that implemenation is below. Something is not working. Does any
one have any clues? What does it mean when the SID is all zeros?

LookupAccountName/SID in an Active Directory (or even old NT4) domain requires
an RPC query to the domain controller. If this fails - then LookupXxx also
fails.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

> // Copy the SID

RtlCopyMemory(&sid, pTokenUser->User.Sid, sizeof(SID));

The SID has variable length. Use RtlCopySid() or RtlLengthSid().

-bg

but you can already do that from user mode, i don’t get it, SID structures are opaque, and should be accesed only via certain routines in kernel mode. what Maxim says seems the solution

>but you can already do that from user mode, i don’t get it, SID structures are

opaque, and should be accessed only via certain routines in kernel mode. what
Maxim says seems the solution

I am sorry, I don’t understand. Read carefully the original posting. He needs to send SID to user mode. He uses LookupAccountSid() in user mode, so discussion above seems to me pointless. I didn’t react to Maxim replays, but to original posting. I just pointed out that he cannot use sizeof(SID), but API for determining of SID length, to send SID (opaque blob) to user mode.

-bg

Yes, please disregard Max’s post – he obviously missed the point.

BG: Thanks so much for your help. I total missed the fact that the SID was
variable length. Things are working! Thanks again.

Kind regards,
JJ

wrote in message news:xxxxx@ntfsd…
> >but you can already do that from user mode, i don’t get it, SID
> >structures are
>>opaque, and should be accessed only via certain routines in kernel mode.
>>what
>>Maxim says seems the solution
>
> I am sorry, I don’t understand. Read carefully the original posting. He
> needs to send SID to user mode. He uses LookupAccountSid() in user mode,
> so discussion above seems to me pointless. I didn’t react to Maxim
> replays, but to original posting. I just pointed out that he cannot use
> sizeof(SID), but API for determining of SID length, to send SID (opaque
> blob) to user mode.
>
> -bg
>
>