Registriert seit: 9. Jun 2006
Ort: Magdeburg
29 Beiträge
Delphi 7 Professional
|
Re: WinAPI Problem mit Rechten setzen in der Registry
26. Feb 2009, 12:24
Hallo,
ich hatte ein ähnliches Problem (alle Rechte eines Registry Schlüssels bzw. Datei wurden gelöscht, wie setze ich die Rechte) und dieser Thread hat mir sehr geholfen. Die Antwort von Dezipaitor sollte man sich zweimal durchlesen. Für alle die ein ähnliches Problem haben und auf diesen Thread stoßen, will ich hier meinen Source posten.
Problem: Ich erhalte bei Registry oder Dateizugriff ERROR_ACCESS_DENIED obwohl ich Owner oder Admin bin (siehe auch http://support.microsoft.com/kb/111546).
Delphi-Quellcode:
if RegOpenKeyEx(HKEY_LOCAL_MACHINE, '...', 0, KEY_READ, Key)=ERROR_ACCESS_DENIED then begin
SetRegPermission(HKEY_LOCAL_MACHINE,'...', OldResetAccess);
RegOpenKeyExW(HKEY_LOCAL_MACHINE, '...', 0, KEY_READ, Key);
end;
SetRegPermission setzt die Zugriffsrechte des aktuellen Benutzers (bzw. Account meines Delphiprogramms).
Delphi-Quellcode:
function SetRegPermission(Key:HKey; SubKeyName:WideString; var ResetAccess: string):boolean;
const SDDL_REVISION_1 = 1;
SECURITY_DESCRIPTOR_REVISION = 1;
var dwSize,RegResult:DWORD;
pNewSD,pSD:Windows.PSECURITY_DESCRIPTOR;
pSdStr:PChar;
SvcKey:HKey;
dwLength: DWORD;
Token:THandle;
pTokenUser:PTOKEN_USER;
sNewSD: string;
begin
result:=false;
sErr:=' ';
//*** Start Set Owner **** (see [url]http://support.microsoft.com/kb/111546[/url])
SetPrivilege(' SeTakeOwnershipPrivilege', True); // SE_TAKE_OWNERSHIP_NAME
try
RegResult:=RegOpenKeyExW(Key, PWideChar(SubKeyName), 0, WRITE_OWNER, SvcKey); //TODO reset Owner?
if RegResult=ERROR_SUCCESS then begin
dwLength:=0;
pTokenUser := nil;
OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token);
if not GetTokenInformation(Token, TokenUser, pTokenUser, 0, dwLength) then begin
if GetLastError=ERROR_INSUFFICIENT_BUFFER then begin
pTokenUser:=HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwLength);
if pTokenUser<> nil then begin
if GetTokenInformation(Token, TokenUser, pTokenUser, dwLength, dwLength) then begin
GetMem(pSD,SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(pSD, True, Nil, False); // No ACL - all access granted
SetSecurityDescriptorOwner(pSD, pTokenUser^.User.Sid, FALSE);
SysErrorMessage( RegSetKeySecurity(SvcKey,OWNER_SECURITY_INFORMATION, pSD) );
FreeMem(pSD);
end;
HeapFree(GetProcessHeap, 0, pTokenUser);
end;
end;
end;
CloseHandle(Token);
RegCloseKey(SvcKey);
end;
finally
SetPrivilege(' SeTakeOwnershipPrivilege', false);
end;
//*** End Set Owner ****
RegResult:=RegOpenKeyExW(Key, PWideChar(SubKeyName), 0, READ_CONTROL or WRITE_DAC, SvcKey);
if RegResult<>ERROR_SUCCESS then raise Exception.Create(SysErrorMessage(RegResult));
try
pSD:=nil;
dwSize:=0;
RegResult:=RegGetKeySecurity(SvcKey,DACL_SECURITY_INFORMATION, pSD, dwSize);
if RegResult<>ERROR_SUCCESS then raise Exception.Create(SysErrorMessage(RegResult));
GetMem(pSD,dwSize);
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
RegResult:=RegGetKeySecurity(SvcKey, DACL_SECURITY_INFORMATION, pSD, dwSize);
if RegResult<>ERROR_SUCCESS then raise Exception.Create(SysErrorMessage(RegResult));
if ConvertSecurityDescriptorToStringSecurityDescriptor(pSD, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, pSdStr, nil) then begin
pNewSD:=nil;
if ResetAccess<>' ' then sNewSD:=ResetAccess else sNewSD:=StrPas(pSdStr)+' (A;OICI;GA;;;'+GetCurrentUserSIDString(' BA')+' )'; //AdminAccess='(A;OICI;GA;;;BA)'; //see "Security Descriptor String Format": [url]http://msdn2.microsoft.com/en-us/library/aa379570.aspx[/url] + "SID Strings" [url]http://msdn2.microsoft.com/en-us/library/aa379602.aspx[/url] + [url]http://msdn.microsoft.com/en-us/magazine/cc982153.aspx[/url]
if ConvertStringSecurityDescriptorToSecurityDescriptor(PChar(sNewSD), SDDL_REVISION_1, pNewSD, nil) then
if IsValidSecurityDescriptor(pNewSD) then begin
RegResult:=RegSetKeySecurity(SvcKey, DACL_SECURITY_INFORMATION, pNewSD);
if RegResult=ERROR_SUCCESS then begin
ResetAccess:=StrPas(pSdStr);
result:=true;
end;
end;
if pNewSD<> nil then LocalFree(HLOCAL(pNewSD));
LocalFree(HLOCAL(pSdStr));
end;
finally
if pSD<> nil then FreeMem(pSD);
RegCloseKey(SvcKey);
end;
end;
Für Dateirechte sieht es so aus (SetNamedSecurityInfo kann man auch für Registry nutzen)
Delphi-Quellcode:
{SetFileAccessForAll: Set File Access for the current user}
procedure SetFileAccessForAll(FileName: string);
var pSD:PSECURITY_DESCRIPTOR;
Token:THandle;
pTokenUser:PTOKEN_USER;
r,dwLength: DWORD;
sErr: string;
pOldDACL,pDACL: PACL;
EA: TExplicitAccess;
begin
sErr:=' ';
SetPrivilege(' SeTakeOwnershipPrivilege', True); // SE_TAKE_OWNERSHIP_NAME
try
dwLength:=0;
pTokenUser := nil;
OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token);
if not GetTokenInformation(Token, TokenUser, pTokenUser, 0, dwLength) then begin
if GetLastError=ERROR_INSUFFICIENT_BUFFER then begin
pTokenUser:=HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwLength);
if pTokenUser<> nil then begin
if GetTokenInformation(Token, TokenUser, pTokenUser, dwLength, dwLength) then begin
SetNamedSecurityInfo(PChar(FileName), SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, pTokenUser^.User.Sid, nil, nil, nil);
// **** Start: grant all access to current User ***
pSD:=nil;
pOldDACL:=nil;
GetNamedSecurityInfo(PChar(FileName), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, @pOldDACL, nil, pSD);
ZeroMemory(@EA, SizeOf(EA));
BuildTrusteeWithSid(@EA.Trustee, pTokenUser^.User.Sid);
EA.grfAccessPermissions := GENERIC_ALL;
EA.grfAccessMode := SET_ACCESS;
EA.grfInheritance := SUB_CONTAINERS_AND_OBJECTS_INHERIT;
EA.Trustee.TrusteeForm := TRUSTEE_IS_SID;
EA.Trustee.TrusteeType := TRUSTEE_IS_USER;
r := SetEntriesInAcl(1, @EA, pOldDACL, pDACL); // Merges EA + pOldDACL = pDACL
if r = ERROR_SUCCESS then begin
SetNamedSecurityInfo(PAnsiChar(FileName), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, pDACL, nil);
if pDACL<> nil then LocalFree(Cardinal(pDACL));
end;
if pOldDACL<> nil then LocalFree(Cardinal(pOldDACL));
// **** Ende: ***
end;
HeapFree(GetProcessHeap, 0, pTokenUser);
end;
end;
CloseHandle(Token);
end;
finally
SetPrivilege(' SeTakeOwnershipPrivilege', false);
end;
end;
Hier noch die Hilfsfunktionen:
Delphi-Quellcode:
function ConvertSidToStringSid(Sid: PSID; var StringSid: LPSTR): BOOL; stdcall; external advapi32 name 'ConvertSidToStringSidA';
//function ConvertStringSidToSid(StringSid: LPCSTR; var Sid: PSID): BOOL; stdcall; external advapi32 name 'ConvertStringSidToSidA';
function GetCurrentUserSIDString(sDefault:string):string; //für SvcHostDlls
var dwLength: DWORD;
Token:THandle;
pTokenUser:PTOKEN_USER;
StringSid:PChar;
begin
result:=sDefault;
dwLength:=0;
pTokenUser := nil;
OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, Token);
if not GetTokenInformation(Token, TokenUser, pTokenUser, 0, dwLength) then begin
if GetLastError=ERROR_INSUFFICIENT_BUFFER then begin
pTokenUser:=HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwLength);
if pTokenUser<>nil then begin
if GetTokenInformation(Token, TokenUser, pTokenUser, dwLength, dwLength) then begin
ConvertSidToStringSid(pTokenUser^.User.Sid, StringSid);
result:=StrPas(StringSid);
LocalFree(HLOCAL(StringSid));
end;
HeapFree(GetProcessHeap, 0, pTokenUser);
end;
end;
end;
CloseHandle(Token);
end;
function ConvertSecurityDescriptorToStringSecurityDescriptor(
SecurityDescriptor: PSECURITY_DESCRIPTOR; RequestedStringSDRevision: DWORD;
SecurityInformation: SECURITY_INFORMATION; var StringSecurityDescriptor: LPSTR;
StringSecurityDescriptorLen: PULONG): BOOL; stdcall; external advapi32 name 'ConvertSecurityDescriptorToStringSecurityDescriptorA';
function ConvertStringSecurityDescriptorToSecurityDescriptor(StringSecurityDescriptor: LPCSTR;
StringSDRevision: DWORD; var SecurityDescriptor: Windows.PSECURITY_DESCRIPTOR;
SecurityDescriptorSize: PULONG): BOOL; stdcall; external advapi32 name 'ConvertStringSecurityDescriptorToSecurityDescriptorA';
Als Anregung auch mal hier angucken: allow non-Admin users to modify registry
(Bitte nicht meckern, dass ich einen alten Thread ausgegraben habe - für die Delphiprogrammierer die nach Hilfe googeln ist doch nur wichtig, ob sie Hilfe finden oder nicht)
|