Skywing [MVP]" said:
I assume that you are really failing at a call to LogonUser. On Windows
2000 (and below), LogonUser requires SeTcbPrivilege.
Is there a way to grant SeTcbPrivlege (Act as part of the operating system)
to a domain account without granting SeTcbPrivlege to the domain account?
Obviously i'm not going to grant every user in the global enterprise the
ability to act as part of the operating system.
On Windows XP or later, it can be used by a plain user account with no
privileges.
On Windows XP, the call to LogonUser succeeds, but the call to
CreateProcessAsUser fails with code 1314 (A required privilege is not held
by the client).
On Windows 2000, you may be able to use CreateProcessWithLogonW, which
takes no special privileges. This is essentially how runas (secondary
logon) on Windows 2000 works.
This does seem to work with my most likely incorrect code, but here's the
code anyway:
function ExecuteFileAsUser(
const Username, Domain, Password: WideString;
const FileName: WideString;
const Params: WideString='';
const DefaultDir: WideString ='';
const ShowCmd: Integer=SW_SHOWNORMAL): Boolean;
var
LocallyModifiableParams: WideString;
startupInfo: TStartupInfo;
processInformation: PROCESS_INFORMATION;
const
LOGON_WITH_PROFILE = $00000001;
begin
{
Sample Usage:
ExecuteFileAsUser(
'forest', //user name
'goldshire', //domain name
'gump', //password
'c:\windows\system32\notepad.exe', //filename
'c:\20070608.log', //params
'c:\develop' //default dir
);
}
LocallyModifiableParams := Filename+' '+Params;
{A command line contains the executable name, e.g.
notepad.exe c:\somefile.txt
}
{From the Platform SDK:
The function can modify the contents of this string.
Therefore, this parameter cannot be a pointer to read-only memory
(such as a const variable or a literal string).
If this parameter is a constant string, the function may cause an
access violation.
ed: A function that tries to cause access violations. Nice.}
//An empty structure that the function wants
ZeroMemory(@startupInfo, SizeOf(startupInfo));
startupInfo.cb :=SizeOf(startupInfo);
//An empty structure that the function wants
ZeroMemory(@processInformation, SizeOf(processInformation));
Result := CreateProcessWithLogonW(
PWideChar(Username),
PWideChar(Domain),
PWideChar(Password),
LOGON_WITH_PROFILE, //dwLogonFlags: DWORD
PWideChar(Filename),
PWideChar(LocallyModifiableParams),
0, //dwCreationFlags: DWORD
nil, //lpEnvironment: Pointer
PWideChar(DefaultDir), //lpCurrentDirectory: PWideChar;
startupInfo,
processInformation);
if Result then
begin
{From the Platform SDK:
Handles in PROCESS_INFORMATION must be closed with the
CloseHandle
function when they are not needed.}
//We don't need either of the handles in ProcessInformation.
//Hopefully Microsoft won't add any more to the structure in
the future
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
end;
end;