Einzelnen Beitrag anzeigen

gore

Registriert seit: 9. Jun 2006
Ort: Magdeburg
29 Beiträge
 
Delphi 7 Professional
 
#13

Re: WinAPI Problem mit Rechten setzen in der Registry

  Alt 26. Feb 2009, 11: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)
  Mit Zitat antworten Zitat