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

Delphi 'RunAs'

545 views
Skip to first unread message

Alan Greenwood

unread,
Sep 8, 2007, 4:53:57 AM9/8/07
to
Our organisation has an application launcher for commonly used
programs. I would like to make it run some of these programs at a
higher level of privilege than the user's normal privileges. (Some of
our older applications throw up errors when they try to write
temporary files and are forbidden to do so). We have a mixture of 2000
and XP machines (plus a few NT 4) on a Novell network (changing to
Microsoft over the next 12 months).

I looked at LogonUser but this didn't work because ordinary users do
not have the SE_TCB_NAME privilege. (This was on Windows 2000 - I
believe the situation is different on XP but we have a mixture of
machines and this must work everywhere).

I also found Colin Wilson's TImpersonator but this appears to be a
service which impersonates the currently logged-in user. Preferably I
would like to skip installing any services and, in effect, use RunAs.

RunAs does not allow a password on the command line but I have found
LSRunAs, which does. If push came to shove I could use LSRunAs and
pass in a password automatically from a command line inside my
launcher. All in all, though, I would prefer to achieve my aims
programatically.

There is a further wrinkle, in that I would like any impersonated
applications to use the profile of the logged-in user instead of that
of the impersonated user. I knocked up a quick test program which I
ran under both RunAs and LSRunAs, and HKCU entries ended up in the
.DEFAULT part of the HKEY_USERS registry, not that of the current
user. If any of the applications I run need to persist some settings
into the registry, I need them to go to the right part of the
registry.

I would be grateful for any help anyone could give. I have not been
able to find much in the way of resources on impersonation, and would
really appreciate any URLs of articles that people may have found. I
have a large number of snippets but find it hard to make sense of
them. If I could find a single cogent approach to the problem I could
move forwards. MSDN has information on individual calls but I can't
find anything about the _sequence_ of calls that would be required to
produce the result I need.

Thanks a lot in advance to anyone who can help.

-------------------------------------------------------
Please do NOT use the email address in the headers - it
is a spam-trap. Please respond to the newsgroup only.
-------------------------------------------------------

Yorai Aminov (TeamB)

unread,
Sep 8, 2007, 12:29:22 PM9/8/07
to
On 08/09/2007 11:53:57, Alan Greenwood wrote:

> I looked at LogonUser but this didn't work because ordinary users do
> not have the SE_TCB_NAME privilege.

That's right. The Local Service account, however, does have the
required permissions. In fact, that's one of the reasons RunAs is a
service.

> All in all, though, I would prefer to achieve my aims
> programatically.

You can call the CreateProcessWithLogonW function, which essentially
uses the RunAs service. However, it's only available in Windows 2000
and higher.

> There is a further wrinkle, in that I would like any impersonated
> applications to use the profile of the logged-in user instead of
> that of the impersonated user. I knocked up a quick test program
> which I ran under both RunAs and LSRunAs, and HKCU entries ended up
> in the .DEFAULT part of the HKEY_USERS registry, not that of the
> current user.

That's because by default, CreateProcessWithLogonW doesn't load the
user's profile. You can load the user's hive before calling
CreateProcessWithLogonW using the LoadUserProfile function.
CreateProcessWithLogonW can also load the hive for you if you specify
the LOGON_WITH_PROFILE flag.

I haven't tried it, but you might be able to load the logged-on
user's profile by callong LoadUserProfile and passing a token for
that user. If that doesn't work, you can try loading the registry
hive directly (there used to be sample code in Micrsoft's KB Q168877
that would also work on NT 4.0, but the article no longer seems to
exist).

--
Yorai Aminov (TeamB)
(TeamB cannot answer questions received via email.)
Shorter Path - http://www.shorterpath.com
Yorai's Page - http://www.yoraispage.com

Alan Greenwood

unread,
Sep 9, 2007, 3:50:10 AM9/9/07
to
P.S. I should have added that I'm using D7, so .NET solutions won't
work for me. Thanks in advance.

Alan Greenwood

unread,
Sep 11, 2007, 2:26:05 AM9/11/07
to
Yorai

This is exactly the kind of help I needed - thanks very much.

Alan
--

Nigel Tavendale

unread,
Jan 15, 2008, 11:27:44 AM1/15/08
to
Try this:

function CreateProcessWithLogon(lpUsername: PWideChar;
lpDomain: PWideChar;
lpPassword: PWideChar;
dwLogonFlags: DWORD;
lpApplicationName: PWideChar;
lpCommandLine: PWideChar;
dwCreationFlags: DWORD;
lpEnvironment: Pointer;
lpCurrentDirectory: PWideChar;
var lpStartupInfo: TStartupInfo;
var lpProcessInfo: TProcessInformation):
BOOL; stdcall;
external 'advapi32' name
'CreateProcessWithLogonW';

function CreateEnvironmentBlock(var lpEnvironment: Pointer;
hToken: THandle;
bInherit: BOOL): BOOL; stdcall; external
'userenv';

function DestroyEnvironmentBlock(pEnvironment: Pointer): BOOL; stdcall;
external 'userenv';

const
LOGON_WITH_PROFILE = $00000001;

{------------
Emulate the RunAs function
--------------}

function RunAs(User, Password, Command: String): Integer;
var dwSize: DWORD;
hToken: THandle;
lpvEnv: Pointer;
pi: TProcessInformation;
si: TStartupInfo;
szPath: Array [0..MAX_PATH] of WideChar;
begin

ZeroMemory(@szPath, SizeOf(szPath));
ZeroMemory(@pi, SizeOf(pi));
ZeroMemory(@si, SizeOf(si));
si.cb:=SizeOf(TStartupInfo);

if LogonUser(PChar(User), nil, PChar(Password), LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, hToken) then
begin
if CreateEnvironmentBlock(lpvEnv, hToken, True) then
begin
dwSize:=SizeOf(szPath) div SizeOf(WCHAR);
if (GetCurrentDirectoryW(dwSize, @szPath) > 0) then
begin
if (CreateProcessWithLogon(PWideChar(WideString(User)), nil,
PWideChar(WideString(Password)),
LOGON_WITH_PROFILE, nil, PWideChar(WideString(Command)),
CREATE_UNICODE_ENVIRONMENT,
lpvEnv, szPath, si, pi)) then
begin
result:=ERROR_SUCCESS;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
end
else
result:=GetLastError;
end
else
result:=GetLastError;
DestroyEnvironmentBlock(lpvEnv);
end
else
result:=GetLastError;
CloseHandle(hToken);
end
else
result:=GetLastError;

end;

"Alan Greenwood" <fake...@fake.address> wrote in message
news:neo4e3t2egnbv204l...@4ax.com...

0 new messages