Answer the question
In order to leave comments, you need to log in
How to force the service to add an entry to the database on behalf of another user?
Hello! I will try to describe in detail the whole essence of the problem:
Under Win8 there are two users, user1 (administrator) and user2 (ordinary user). There is a service running from user1. What she does? It receives some data via sockets and launches another program (proga.exe) on behalf of user2 with parameters received from sockets. Next, proga.exe creates a file with the SHELL script in a certain directory and runs it. What the script does: creates some txt files (this succeeds) and adds some data to the Access DB via odbc (this fails).
Moreover, entries in the database are not written only if proga.exe is launched from the service. If the finished script is run from under user2, then the data is written.
From the service I launch proga.exe with the RunAs procedure, the description is below
procedure StrResetLength(var S: AnsiString);
begin
SetLength(S, StrLen(PChar(S)));
end;
function GetUserObjectName(hUserObject: THandle): string;
var
Count: DWORD;
begin
// have the the API function determine the required string length
GetUserObjectInformation(hUserObject, UOI_NAME, PChar(Result), 0, Count);
SetLength(Result, Count + 1);
if GetUserObjectInformation(hUserObject, UOI_NAME, PChar(Result), Count, Count) then
StrResetLength(Result)
else
Result := '';
end;
function SetUserObjectFullAccess(hUserObject: THandle): Boolean;
var
Sd: PSecurity_Descriptor;
Si: Security_Information;
begin
Sd := PSecurity_Descriptor(LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
InitializeSecurityDescriptor(Sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(Sd, True, nil, False);
Si := DACL_SECURITY_INFORMATION;
Result := SetUserObjectSecurity(hUserObject, Si, Sd);
LocalFree(HLOCAL(Sd));
end;
procedure RunAs(var UserDomain, UserName, Password, CommandLine: string);
const
Environment: PChar=nil;
// default values for window stations and desktops
CreateProcDEFWINSTATION = 'WinSta0';
CreateProcDEFDESKTOP = 'Default';
CreateProcDOMUSERSEP = '\';
var
ConsoleTitle: string;
Help: string;
WinStaName: string;
DesktopName: string;
hUserToken: THandle;
hWindowStation: HWINSTA;
hDesktop: HDESK;
StartUpInfo: TStartUpInfo;
ProcInfo: TProcessInformation;
Runned: boolean;
begin
// Step 2: logon as the specified user
if not LogonUser(PChar(UserName), PChar(UserDomain), PChar(Password),
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hUserToken) then
log('ERROR LogonUser');
// Step 3: give the new user access to the current WindowStation and Desktop
hWindowStation:= GetProcessWindowStation;
WinStaName := GetUserObjectName(hWindowStation);
if WinStaName = '' then
WinStaName := CreateProcDEFWINSTATION;
if not SetUserObjectFullAccess(hWindowStation) then begin
CloseHandle(hUserToken);
// raise EJclCreateProcessError.CreateResRecFmt(@RsCreateProcSetStationSecurityError, [WinStaName]);
log('ERROR SetUserObjectFullAccess(hWindowStation');
end;
hDesktop := GetThreadDesktop(GetCurrentThreadId);
DesktopName := GetUserObjectName(hDesktop);
if DesktopName = '' then
DesktopName := CreateProcDEFDESKTOP;
if not SetUserObjectFullAccess(hDesktop) then begin
CloseHandle(hUserToken);
// raise EJclCreateProcessError.CreateResRecFmt(@RsCreateProcSetDesktopSecurityError, [DesktopName]);
log('ERROR SetUserObjectFullAccess(hDesktop)');
end;
// Step 4: set the startup info for the new process
ConsoleTitle := UserDomain + UserName;
FillChar(StartUpInfo, SizeOf(StartUpInfo), #0);
with StartUpInfo do begin
cb:= SizeOf(StartUpInfo);
lpTitle:= PChar(ConsoleTitle);
Help := WinStaName + '\' + DeskTopName;
lpDesktop:= PChar(Help);
end;
// Step 5: create the child process
Runned := CreateProcessAsUser(hUserToken, nil, PChar(CommandLine),
nil, nil, False, CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP,
Environment, nil, StartUpInfo, ProcInfo);
if(not(Runned)) then begin
case GetLastError of
ERROR_PRIVILEGE_NOT_HELD:
{raise EJclCreateProcessError.CreateResRecFmt(@RsCreateProcPrivilegesMissing,
[GetPrivilegeDisplayName(SE_ASSIGNPRIMARYTOKEN_NAME), SE_ASSIGNPRIMARYTOKEN_NAME,
GetPrivilegeDisplayName(SE_INCREASE_QUOTA_NAME), SE_INCREASE_QUOTA_NAME]); }
log('ERROR_PRIVILEGE_NOT_HELD :: ' + IntToStr(GetLastError));
ERROR_FILE_NOT_FOUND:
//raise EJclCreateProcessError.CreateResRecFmt(@RsCreateProcCommandNotFound, [CommandLine]);
log('ERROR_FILE_NOT_FOUND :: ' + IntToStr(GetLastError));
else
//raise EJclCreateProcessError.CreateResRec(@RsCreateProcFailed);
log('ERROR NUM :: ' + IntToStr(GetLastError));
end;
end;
// clean up
CloseWindowStation(hWindowStation);
CloseDesktop(hDesktop);
CloseHandle(hUserToken);
if Runned then begin
WaitForSingleObject(ProcInfo.hProcess, INFINITE);
{ Free the Handles }
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
end;
end;
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question