Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Запуск приложений из сервиса с правами не LocalService [D7, WinXP]


Страницы:   1 2

Шуршик ©   (2005-03-04 03:35:00) 

Есть системный сервис, работающий под правами LOCAL SERVICE, необходимо через определённые промежутки времени запускать из него внешнюю программу.

Если запускать её как обычно (CreateProcess, все настройки по-умолчанию), то запускается дочерний к сервису процесс с пользователем LOCAL SERVICE. А мне надо бы, чтобы он запускался для пользователя, который работает в данный момент в системе. Как запустить процесс для текущего пользователя?

Я нашёл функции CreateProcessAsUser и LogonUser, но они требуют пары ИмяЮзера/Пароль. В тоже время некоторые системные сервисы умеют запускать процессы для уже залогиненых пользователей в системе. Они же не спрашивают пароля? Не могу никак найти, как же сделать так, чтобы, не спрашивая пароля для учётной записи пользователя, запустить из службы другой процесс с правами некоторого пользователя, с учётом того, что он уже вошёл в систему???


Набережных С.   (2005-03-09 14:06:00) [21]

Я тут, роясь в MSDN, наткнулся на одну штуку, должно работать в W2k, XP и выше, но нужен локальный СОМ-сервер. В 2000 проверил, а XP сейчас не доступен, вечером проверю.
Делаем COM сервер, в нем объект, реализующий следующий интерфейс(это для примера, можно любой):

 IExecutor = interface(IDispatch)
   ['{5EF8BF3A-697D-4CBA-B6FF-9D9F74D7AF21}']
   function Execute(const AppName: WideString): HResult; stdcall;
 end;

Реализация метода Execute:

function TExecutor.Execute(const AppName: WideString): HResult;
var
 H: Cardinal;
begin
 H:=ShellExecuteW(0, nil, PWideChar(AppName), nil, nil, SW_SHOWNORMAL);
 if H > 32 then Result:=S_OK else Result:=H;
end;

Хотя конечно можно CreateProcess, так для быстроты.
Ну а в сервисе вызываем вот такую функцию:

function ExecuteAsIU_XP2k(SessionID: Cardinal; const AppName: WideString;
                            out Executor: IExecutor): HResult;
var
 Bind: IBindCtx;
 Moniker: IMoniker;
 Fact: IClassFactory;
 Eater: integer;
 ws: WideString;
const
 s_Exec = '6D7760E2-165E-4D3A-850E-1F9A23A7A36B'; // Class identifier
label
 final_;
begin
 ws:=Format('Session:%d!clsid:%s', [SessionID, s_Exec]);
 CoInitialize(nil);
 try
   Result:=CreateBindCtx(0, Bind);
   if Result <> S_OK then GoTo final_;

   Result:=MkParseDisplayName(Bind, @ws[1], Eater, Moniker);
   if Result <> S_OK then GoTo final_;

   Result:=Moniker.BindToObject(Bind, nil, IClassFactory, Fact);
   if Result <> S_OK then GoTo final_;

   Result:=Fact.CreateInstance(nil, IID_IExecutor, Executor);
   if Result <> S_OK then GoTo final_;

   if AppName = '' then GoTo final_;

   Result:=Executor.Execute(AppName);

final_:
 finally
   CoUninitialize;
 end;
end;

Здесь s_Exec - GUID класса, реализующего интерфейс IExecutor, специально вынес в объявления. Да, сервер должен быть настроен на запуск под интерактивным пользователем, ну и права конечно на его запуск нужно дать.

Вызывать можно так:

var
 Exec: IExecutor;

ExecuteAsIU_XP2k(0, 'Notepad.exe', Exec);

Первый параметр - идентификатор сессии, должен быть валидным, но 0-й всегда есть.
Собственно для чего:
если есть желающие, неплохо было бы проверить под разными системами и сообщить результат.


Шуршик   (2005-03-09 01:46:00) [22]

Код сеанса у всех - 0, создавать пробовал со станциями и столом по-умолчанию (nil в оба параметра) и следующим макаром (код взят из Jedi Code Library):

hWindowStation := GetProcessWindowStation;
WinStaName := GetUserObjectName (hWindowStation);
if WinStaName = '' then
WinStaName := CreateProcDEFWINSTATION;
if not SetUserObjectFullAccess (hWindowStation) then
begin
CloseHandle(hUserToken);
raise EJclWin32Error.CreateResRecFmt (@RsCreateProcSetStationSecurityError, [WinStaName]);
end;
hDesktop := GetThreadDesktop (GetCurrentThreadId);
DesktopName := GetUserObjectName (hDesktop);
if DesktopName = '' then
DesktopName := CreateProcDEFDESKTOP;
if not SetUserObjectFullAccess (hDesktop) then
begin
CloseHandle (hUserToken);
raise EJclWin32Error.CreateResRecFmt (@RsCreateProcSetDesktopSecurityError, [DesktopName]);
end;

З.Ы. в MSDN инфы действительно море, но после самостоятельного изучения DirectX по MSDN отпадает всякое желание изучать по нему ещё хоть что-то :)  Да, справочник это незаменимый, функцию какую посмотреть или ещё что - это всегда можно. Но вот так о чём-то просто почитать - это конечно не самый лучший источник информации. Ладно, всё равно спасибо.


Набережных С.   (2005-03-08 09:04:00) [23]


> Шуршик   (08.03.05 06:10) [13]

Где запустить-то пытался? В какой сессии, в какой оконной станции, на каком столе? Суть не в том, сколько в данный момент пользователей залогинено, а в том, что сервис твой работает в одной оконной станции, а юзер в другой, да еще и в собственной сессии. Причем каждый юзер в собственной сессии с собственной оконной станцией. И все они друг от друга изолированы. Код бы лучше показал. А про сессии - MSDN, читать не перечитать:)


Шуршик   (2005-03-08 06:10:00) [24]

Я был единственным вошедшим в систему и пытался запустить процесс из сервиса для самого себя. Сейчас пытаюсь разобраться с Windows Terminal Services. В связи с этим: нет ли у кого каких-нибудь ссылочек (о5 ссылочки :) ) на что-нибудь почитать по этой теме (не на форумах).


Набережных С.   (2005-03-07 09:38:00) [25]


> Шуршик   (07.03.05 00:50) [8]

Не внимательно прочитал сразу. Принцип-то везде одинаковый - получить маркер интерактивного пользователя и создать процесс в его оконной станции на активном рабочем столе. Просто до XP это всегда была WinSta0, а в ХР локально залогинившихся может быть несколько, в этом и разница. Как в 2003 не знаю, не доходят руки до него:(


Набережных С.   (2005-03-07 07:29:00) [26]

Да ну, что ты, какие ссылки? Могу только предположить, по косвенным уликам, что это было в первой половине 2003-го.

А ты от какого пользователя и в какой станции пытаешься запустить процесс? Может эта учетка не имеет доступа к этой станции? Запускать-то надо в его оконной станции, либо дать ему доступ к целевой станции.


kami   (2005-03-07 01:14:00) [27]

например,  смотри соседнюю ветку
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1110144139&n=5

но - если верить Сергею Николаевичу (а неверить ему не вижу оснований), то енто только для XP-ей.

---
Аксиома:У программ нет глюков. Они просто содержат неизвестные тебе функции.


Шуршик   (2005-03-07 01:08:00) [28]

Гыыы... в архивах я передумал щелить, уж больно много там качать...
Дайте хотя бы ссылочки на что-нибудь по теме


Шуршик   (2005-03-07 00:50:00) [29]

Доступ брался типа "ALL ACCESS", а AccessDenied отвечала CreateProcessAsUser. У меня стоит XP, но программа реально должна работать под Win2003. Чем иначе действовать под XP? И не подойдёт ли способ от 2000?

З.Ы. а в архиве щас пощелю...


Набережных С.   (2005-03-06 06:23:00) [30]


> Шуршик   (06.03.05 00:27) [5]

Во-первых, непонятно, кто ответил отказом - OpenProcessToken или CreateProcessAsUser. Если вторая, то не тот флаг требуемого доступа выставил в первой. Во-вторых, для XP нужно действовать иначе. В ней свитчинг реализован через терминальные сессии, а у них весьма развитый API, особенно в ХР, это упрощает задачу. А для NT/2000 я приводил здесь пример года полтора-два назад, если хочешь, поищи в архивах по WinApi.


Anatoly Podgoretsky   (2005-03-06 00:31:00) [31]

Какого именно из залогинившихся?


Шуршик   (2005-03-06 00:27:00) [32]

Вообще-то я спросил, как можно получить hUserToken от (процесса ли или ещё как) уже залогиненного пользователя.
Я пробовал взять токен из OpenProcessToken для explorer.exe и пихнуть его в CreateProcessAsUser, на что она отвечала ошибкой В доступе отказано.


BiN   (2005-03-05 15:42:00) [33]

Шуршик   (04.03.05 03:35)  

Последовательность примерно такая:
function CreateProcessAsUser_(const Domain, UserName, Password, CommandLine: String):BOOL;
var
 hUserToken: DWORD;
 ...
begin
 if not LogonUser(Pchar(UserName), Pchar(Domain), Pchar(Password),
                 LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                 hUserToken)
   then RaiseLastOSError;
 Result:=CreateProcessAsUser(hUserToken, nil, Pchar(CommandLine), ....а дальше все то же, что и при обычном CreateProcess
 ...
 CloseHandle(hUserToken);
end;


Но сначала требуется знать, вообще залогинен ли кто-нибудь, и если да, то кто. Как вариант, можно попробовать найти shell-процесс (обычно это explorer.exe), и определить в контексте безопасности чьей учетной записи он работает. Также следует помнить, что в системах с сервером терминалов активных пользователей может быть несколько.


Alex_Petr   (2005-03-05 14:09:00) [34]

Шуршик   (05.03.05 0:45) [2]
ИХМО, жмем F1 на CreateService и читаем
lpServiceStartName
[in] Pointer to a null-terminated string that specifies the name of the account under which the service should run. If the service type is SERVICE_WIN32_OWN_PROCESS, use an account name in the form DomainName\UserName. The service process will be logged on as this user. If the account belongs to the built-in domain, you can specify .\UserName.
Это то, что нужно ?


Шуршик   (2005-03-05 00:45:00) [35]

Я не покажусь слишком назойливым, если спрошу, как это сделать? Дело в том, что мне самому это в голову пришло, но никак не могу найти "волшебную" последовательность вызовов функций.


Игорь Шевченко   (2005-03-04 10:46:00) [36]


>  Не могу никак найти, как же сделать так, чтобы, не спрашивая
> пароля для учётной записи пользователя, запустить из службы
> другой процесс с правами некоторого пользователя, с учётом
> того, что он уже вошёл в систему???


Эти сервисы используют CreateProcessAsUser, узнавая Token необходимого пользователя.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо