@vista1x

Как заставить службу добавить запись в бд от имени другого пользователя?

Здравствуйте! Постараюсь подробно описать всю суть проблема:
Под Win8 есть два пользователя, user1 (администратор) и user2(простой пользователь). Есть служба, работающая от user1. Что она делает? Она принимает через сокеты некоторые данные и запускает другую программу (proga.exe) от имени user2 с параметрами, полученными из сокетов. Далее, proga.exe создает в определенной директории файл со скриптом SHELL и запускает его. Что делает скрипт: создает несколько файлов txt (это выполняется успешно) и добавляет некоторые данные в БД Access через odbc (это не выполняется).
Причем записи в бд не пишутся только если proga.exe запущена из службы. Если готовый скрипт запустить из под user2, то данные записываются.

Из службы запускаю proga.exe процедурой RunAs, описание ниже
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;


Собственно, как сделать так, что бы запущенная из под службы proga.exe отработала нормально?
Уже много перепробовал, не понимаю, где еще искать ошибку.
Было подозрение, что у user1 не хватает каких то прав в "локальных политиках безопасности", пробовал давать ему самые различные права, ничего не помогло.
  • Вопрос задан
  • 2457 просмотров
Пригласить эксперта
Ответы на вопрос 1
@OvLab
Возможно ошибка кроется в содержимом CommandLine. Например какой-либо путь или файл недоступен пользователю SYSTEM, под которым работают службы.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы