![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Запуск приложений из сервиса с правами не LocalService [D7, WinXP]
Шуршик © (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 необходимого пользователя.