Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How do I obtain the current username in a TService?

46 views
Skip to first unread message

Charcoal

unread,
Jun 15, 2001, 11:53:53 PM6/15/01
to
Hi,

I am trying to obtain the name of the current interactive user. However,
since I am running the code in a TService, it is always returning "SYSTEM"
as the name of the current user (it makes sense, but it doesnt help!).
Anyway, I want to obtain the name of the current interactive user. An
example would be great!

Someone told me that the following would do it, but I have idea how to write
the code for this:
1. obtain a handle to windowstation "winsta0"
2. get security info about it by calling GetUserObjectSecurity; this
should provide you with an SID
3. close the handle to the windowstation
3. get the associated account with LookUpAccountName


Thanks,

Charcoal


Charcoal

unread,
Jun 16, 2001, 4:30:03 AM6/16/01
to

Marcel van Brakel

unread,
Jun 17, 2001, 2:58:46 PM6/17/01
to
> Anyway, I want to obtain the name of the current interactive user. An
> example would be great!

See below.



> Someone told me that the following would do it, but I have idea how to write
> the code for this:
> 1. obtain a handle to windowstation "winsta0"
> 2. get security info about it by calling GetUserObjectSecurity; this
> should provide you with an SID
> 3. close the handle to the windowstation
> 3. get the associated account with LookUpAccountName

Don't bother writing it because it won't work; there's nothing in the
security descriptor for the WinSta0 window station that identifies the
interactive user. Well, that's not entirely true. The interactive user
has access to WinSta0 and as such will have an entry in the dacl for
both the user's account as well as the user's logon session. However, it
would be difficult at best to use that information to extract which of
the ACE's represent the interactive user.

The solution is to use another object called an access token. As you
might know (or not), the interactive user is represented on the system
by a logon session. The visible part of this logon session, that is the
part you can see and manipulate as a developer, is the access token. The
access token, amongst other things, uniquely represents the user. The
only problem is how to obtain this access token. Well, when a user
interactively logs on, Windows creates a logon session for the user (and
thus an access token) and then launches the shell process as specified
in the registry. The shell is executed using the security context of
this logon session and as such gets a copy of the access token (which
represents the interactive user). Thus the solution is as follows:

1) read the registry to find out what the shell process is
2) use ToolHelp32 (or another API) to get the PID of this process
3) use OpenProcess to get a handle to this process
4) use OpenProcessToken to get the access token for the process
5) use QueryTokenInformation to get the SID stored in the token
6) use LookupAccountSid to get the name of the user as a string

This solution is coded below. Note that I've only done a minimum of
error checking. You'll have to add that yourself (check the result of
all API calls, handle the situation where no user is interactively
logged on and so forth). Also note that this code uses my Win32Api
conversion available from http://members.chello.nl/m.vanbrakel2 or
http://delphi-jedi.org (you'll probably have to rename WinSvc.pas from
that package to avoid compiler errors).

best regards,
Marcel van Brakel

Project JEDI: http://delphi-jedi.org

Do not send me private e-mail unless explicitly requested otherwise.
If you do anyway please include a billing address...

----- The Code Example -----

uses
Windows, WinNT, WinType, WinBase, Registry, TlHelp32, SysUtils;

function GetShellProcessName: string;
var
Reg: TRegistry;
begin
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
Reg.OpenKeyReadOnly('Software\Microsoft\Windows NT\CurrentVersion
\WinLogon');
Result := Reg.ReadString('Shell');
finally
Reg.Free;
end;
end;

function GetShellProcessPid(const Name: string): Longword;
var
Snapshot: THandle;
Process: TProcessEntry32;
B: Boolean;
begin
Snapshot := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if Snapshot <> INVALID_HANDLE_VALUE then
try
FillChar(Process, SizeOf(Process), 0);
Process.dwSize := SizeOf(Process);
B := Process32First(Snapshot, Process);
while B do
begin
if CompareText(Process.szExeFile, Name) = 0 then
begin
Result := Process.th32ProcessID;
Break;
end;
B := Process32Next(Snapshot, Process);
end;
finally
CloseHandle(Snapshot);
end;
end;

function GetShellHandle: THandle;
var
Pid: Longword;
begin
Pid := GetShellProcessPid(GetShellProcessName);
Result := OpenProcess(PROCESS_ALL_ACCESS, False, Pid);
end;

procedure QueryTokenInformation(Token: THandle; InformationClass:
TTokenInformationClass; var Buffer: Pointer);
var
B: BOOL;
Length: DWORD;
begin
Buffer := nil;
Length := 0;
B := GetTokenInformation(Token, InformationClass, Buffer, Length,
Length);
while (not B) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) do
begin
ReallocMem(Buffer, Length);
B := GetTokenInformation(Token, InformationClass, Buffer, Length,
Length);
end;
if not B then
begin
FreeMem(Buffer);
raise Exception.Create('...');
end;
end;

function LookupAccountBySid(Sid: PSID): string;
var
Name, RefDomain: string;
NameSize, RefDomainSize: DWORD;
Use: TSidNameUse;
begin
NameSize := 0;
RefDomainSize := 0;
LookupAccountSid(nil, Sid, nil, NameSize, nil, RefDomainSize, Use);
SetLength(Name, NameSize);
SetLength(RefDomain, RefDomainSize);
LookupAccountSid(nil, Sid, PChar(Name), NameSize, PChar(RefDomain),
RefDomainSize, Use);
Result := PChar(RefDomain) + '/' + PChar(Name);
end;

function GetInteractiveUserName: string;
var
Handle: THandle;
Token: THandle;
User: PTokenUser;
begin
Handle := GetShellHandle;
try
Win32Check(OpenProcessToken(Handle, TOKEN_QUERY, Token));
QueryTokenInformation(Token, TokenUser, Pointer(User));
try
Result := LookupAccountBySid(User.User.Sid);
finally
FreeMem(User);
end;
finally
CloseHandle(Handle);
end;
end;


Charcoal

unread,
Jun 18, 2001, 12:35:20 AM6/18/01
to
Yep it works. Thanks a million!

Charcoal


"Marcel van Brakel" <brakelm...@chello.nl> wrote in message
news:MPG.15971c52b...@newsgroups.borland.com...

0 new messages