NT service: Получить SID текущего пользователя
Мучаюсь с задачкой:
Нужно написать сервис под NT/2000, который среди прочего может получить SID пользователя, залогиненного сейчас на компьютере. Как получить SID - разобрался быстро - примеров полно. Получаю S-1-5-21-1060284298-1677128483-839522115-500 для Админа и ...-1006 для Юзера. Но!
Засунул этот код в тело сервиса и получаю...
сначала S-1-5-18, а через 4-5 секунд S-1-5-24
.
По идее, причина ясна - сервисы работают с SID, присвоенным системой вне зависимости от текущего пользователя.
А как тогда вытащить ВНУТРИ сервиса SID пользователя, а не сервиса?
var
hd: HDESK;
hNewSta, hOldSta: HWINSTA;
ProcessId: DWORD;
pLogonSid: PSID;
s: PChar;
hProcess: THandle;
len: DWORD;
...
hNewSta := OpenWindowStation('Winsta0', True, STANDARD_RIGHTS_REQUIRED);
if hNewSta <> 0 then begin
GetUserObjectInformation(hNewSta, UOI_USER_SID, pLogonSid, 0, len);
GetMem(pLogonSid, len);
if GetUserObjectInformation(hNewSta, UOI_USER_SID, pLogonSid, len, len) then begin
ConvertSidToStringSidA(pLogonSid, s);
LogMessage('GetUserObjectInformation SID = ' + s);
end else LogMessage('GetUserObjectInformation error: ' + SysErrorMessage(GetLastError));
FreeMem(pLogonSid);
...
Получаю SID S-1-5-5-0-28093
А должно быть длиннее
.
procedure TThread1.Execute;
begin
while not Terminated do
Synchronize(DoExec);
end;
.
где
procedure TThread1.DoExec;
var
hd: HDESK;
hNewSta, hOldSta: HWINSTA;
ProcessId: DWORD;
pLogonSid: PSID;
s: PChar;
hProcess: THandle;
begin
FirstWin := 0;
hProcess := 0;
hNewSta := OpenWindowStation('Winsta0', True, STANDARD_RIGHTS_REQUIRED);
if hNewSta <> 0 then begin
LogMessage('OpenWindowStation good');
hOldSta := GetProcessWindowStation;
if SetProcessWindowStation(hNewSta) then begin
LogMessage('SetProcessWindowStation good');
hd := OpenDesktop('Default', 0, True, STANDARD_RIGHTS_REQUIRED);
if hd <> 0 then begin
LogMessage('OpenDesktop good');
EnumDesktopWindows(hd, @EnumDesktopWindowsProc, 0);
if FirstWin <> 0 then begin
LogMessage('Desktop window exists');
//*********************************
if FirstWin <> 0 then begin
GetWindowThreadProcessId(FirstWin, ProcessId);
if ProcessId <> 0 then begin
LogMessage('Process ID ' + IntToStr(ProcessId));
hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, ProcessId);
if hProcess <> 0 then begin
pLogonSid := GetProcessSid(hProcess);
if pLogonSid <> nil then begin
ConvertSidToStringSidA(pLogonSid, s);
LogMessage(s);
end;
end else LogMessage('Process handle error: ' + SysErrorMessage(GetLastError));
end else LogMessage('Process non-accessible, error: ' + SysErrorMessage(GetLastError));
end;//if
//*********************************
end else LogMessage('Desktop window not founded, error: ' + SysErrorMessage(GetLastError));
CloseDesktop(hd);
end else LogMessage('OpenDesktop error: ' + SysErrorMessage(GetLastError));
SetProcessWindowStation(hOldSta);
end else LogMessage('SetProcessWindowStation error: ' + SysErrorMessage(GetLastError));
CloseWindowStation(hNewSta);
end else LogMessage('OpenWindowStation error: ' + SysErrorMessage(GetLastError));
LogMessage('');
Sleep(100);
end;
.
Примечание: LogMessage пишет текст сообщения в TXT-файл
function ConvertSidToStringSidA(Sid: PSID; var StringSid: PChar): boolean; stdcall; external 'advapi32.dll';
function GetProcessSid(ProcessId: DWORD): PSID;
type
PTOKEN_USER = ^_TOKEN_USER;
_TOKEN_USER = record
User : TSidAndAttributes;
end;
TOKEN_USER = _TOKEN_USER;
var
hToken: THandle;
cbBuf: DWORD;
ptiUser: PTOKEN_USER;
szUser, szDomain: array [0..50] of Char;
chDomain: DWORD;
chUser: DWORD;
snu: DWORD;
begin
Result := nil;
chDomain := 50;
chUser := 50;
// our thread havn't special token; lets get token from entire process
if not OpenProcessToken(ProcessId, TOKEN_QUERY, hToken) then begin
LogMessage('OpenProcessToken error: ' + SysErrorMessage(GetLastError));
exit;
end;
// calc buffer size
if not GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf) then
if GetLastError() <> ERROR_INSUFFICIENT_BUFFER then begin
CloseHandle(hToken);
exit;
end;//if
// apply buffer size
if cbBuf = 0 then exit;
GetMem(ptiUser, cbBuf);
// get TOKEN_USER record in ptiUser
if GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf) then begin
// get user name and domain by SID
//if LookupAccountSid(nil, ptiUser.User.Sid, szUser, chUser, szDomain, chDomain, snu) then
Result := ptiUser.User.Sid;
end;//if
// Free resources
CloseHandle(hToken);
FreeMem(ptiUser);
end;
Приведу выдержки из лога (только SID, остальные места выкушены):
17.11.2003 2:09:31 Process ID 176
17.11.2003 2:09:31 S-1-5-18
...
17.11.2003 2:09:32 Process ID 176
17.11.2003 2:09:32 S-1-5-24
...
17.11.2003 2:09:35 Process ID 952
17.11.2003 2:09:35 S-1-5-21-1060284298-1677128483-839522115-500
...
17.11.2003 2:09:43 Process ID 952
17.11.2003 2:09:43 S-1-5-21-1060284298-1677128483-839522115-40
17.11.2003 2:09:43 Process ID 952
17.11.2003 2:09:43 S-1-5-21-1060284298-1677128483-839522115-500
.
(сервис стартовал вместе с системой, была произведена перезагрузка)
Допустим, в начале идет инициализация сервиса, отклики и прочее, потом становится виден пользователь S-1-5-21-1060284298-1677128483-839522115-500
Но КТО ТАКОЙ S-1-5-21-1060284298-1677128483-839522115-40
Что это за сороковка?
Дальше опять спокойно идет пятисотый...Изредка вклинивается сороковка...
Набрал статистику:
1) Если сервис стартует с самой системой, то сороковка появляется один-два раза за всю сессию, два раза подряд НЕ ВСТРЕЧАЕТСЯ
2) Если сервис запускать вручную через сервис-менеджер, то сороковки идут весьма густо, ЧАСТО ПОДРЯД
В чем дело, кто знает?