I want to set a HKCU registry setting from my service app; I know a Windows user is logged on at that moment.
I used the sample code at http://www.delphifaq.com/faq/delphi_windows_API/f663.shtml to impersonate the logged on user.
I get error 998 "Invalid access to memory location" at the call to SetTokenInformation
I failed to contact the original author.
The original call to DuplicateTokenEx used params SecurityIdentification and TokenPrimary, I also tried SecurityImpersonation and TokenImpersonation (see code)
Testing under XP Prof
What could be going wrong?
One hint maybe: hUserToken is retrieved in WTSQueryUserToken, but never used??
Below is the code; Write2Log is my own debugging stuff (all values reported look fine); GLE=GetlastError description
Thanks in advance
Jan
function xbwImpersonateLoggedOnUser: Boolean;
var
winlogonPid,
dwSessionId: DWord;
hUserToken,
hPToken,
hProcess : THANDLE;
tp : TOKEN_PRIVILEGES;
bError : Boolean;
strClone : String;
begin
{ Start process as elevated by cloning existing process, as we're running as admin... }
Result := True;
bError := False;
if not InitProcLibs then begin
Write2Log(xbwImpersonateLoggedOnUser InitProcLibs failed');
Exit;
end;
// Get explorer.exe process ID:
strClone := 'explorer.exe';
winlogonPid := xbwGetProcessID(strClone);
Write2Log('winLogonPiD: ' + inttostr(winlogonpid));
try
// Get user token for winlogon:
dwSessionId := WTSGetActiveConsoleSessionId;
Write2Log('dwSessionId: ' + inttostr(dwSessionId));
// Get the primary access token of the logged-on user specified by the session ID
if not WTSQueryUserToken(dwSessionId, hUserToken) then
begin
Write2Log('WTSQueryUserToken error: ' + GLE);
bError := True;
end;
Write2Log('hUserToken: ' + inttostr(hUserToken));
// Open the existing local process object identified by winlogonPid
hProcess := OpenProcess(MAXIMUM_ALLOWED, FALSE, winlogonPid);
Write2Log('hProcess: ' + inttostr(hProcess));
// Open the access token associated with the process, result is put in hPToken
if (not OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY or TOKEN_DUPLICATE or
TOKEN_ASSIGN_PRIMARY or TOKEN_ADJUST_SESSIONID or TOKEN_READ or TOKEN_WRITE, hPToken)) then
begin
Write2Log('OpenProcessToken error: ' + GLE);
bError := True;
end;
// Retrieve the locally unique identifier (LUID) used on a specified system to locally represent the specified privilege name.
// Put it in the TOKEN_PRIVILEGES structure tp
if (not LookupPrivilegeValue(nil, SE_DEBUG_NAME, tp.Privileges[0].Luid)) then
begin
Write2Log('LookupPrivilegeValue error: ' + GLE);
bError := True;
end;
// Set other tp params:
tp.PrivilegeCount := 1;
tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
// Create a new access token FhUserTokenDup that duplicates the existing token hPToken
if not DuplicateTokenEx(hPToken,
MAXIMUM_ALLOWED, // Request all access rights that are valid for the caller
Nil, // Token gets a default security descriptor
// SecurityIdentification, // Value from the SECURITY_IMPERSONATION_LEVEL enumeration that indicates the impersonation level of the new token
SecurityImpersonation, // Value from the SECURITY_IMPERSONATION_LEVEL enumeration that indicates the impersonation level of the new token
// http://msdn.microsoft.com/en-us/library/aa379572(VS.85).aspx
// TokenPrimary, // Value from the TOKEN_TYPE enumeration
TokenImpersonation, // Value from the TOKEN_TYPE enumeration
FhUserTokenDup) then
begin
Write2Log('DuplicateTokenEx error: ' + GLE);
bError := True;
end;
// Overwrite information for the FhUserTokenDup token (Adjust token privilege):
if not SetTokenInformation(FhUserTokenDup,
TokenSessionId, // TOKEN_INFORMATION_CLASS enumeration type contains values that specify the type of information being assigned
// TokenSessionId = You will receive a DWORD value that indicates the Terminal Services session identifier that is associated with the token
pointer(dwSessionId),
sizeof(DWORD)) then
begin
{ ERROR 998 Invalid access to memory location. }
Write2Log('SetTokenInformation error: ' + GLE);
bError := True;
end;
// Now adjust the priviliges of the duplicated token with the settings in tp:
if (not AdjustTokenPrivileges(FhUserTokenDup, FALSE, @tp, sizeof(TOKEN_PRIVILEGES), nil, nil)) then
begin
Write2Log('AdjustTokenPrivileges error: ' + GLE);
bError := True;
end;
if (GetLastError() = ERROR_NOT_ALL_ASSIGNED) then begin
Write2Log('xbwImpersonateLoggedOnUser error ERROR_NOT_ALL_ASSIGNED');
bError := True;
end;
// Finally, do the impersonation:
if not ImpersonateLoggedOnUser(FhUserTokenDup) then
begin
Write2Log('ImpersonateLoggedOnUser error: ' + GLE);
bError := True;
end;
{ perform all the close handles tasks... }
try
CloseHandle(hProcess);
CloseHandle(hUserToken);
// CloseHandle(FhUserTokenDup); { This is closed later in xbwRevertToSelf }
CloseHandle(hPToken);
except
on E:Exception do
Write2Log('xbwImpersonateLoggedOnUser error (1): ' + E.Message);
end;
except
on E:Exception do begin
Write2Log('xbwImpersonateLoggedOnUser error (2): ' + E.Message);
bError := True;
end;
end;
Result := not bError;
end; { xbwImpersonateLoggedOnUser }