Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi WinAPI Problem mit Rechten setzen in der Registry (https://www.delphipraxis.net/82884-winapi-problem-mit-rechten-setzen-der-registry.html)

RWarnecke 21. Dez 2006 10:10


WinAPI Problem mit Rechten setzen in der Registry
 
Hallo,

ich habe mir diesen Beitrag genommen. Das funktioniert auch sehr gut. Nun möchte ich aber keinen Registry-Key erstellen sondern einen vorhandenen öffnen und dort einen Wert löschen. Mit dem User, womit ich das Programm ausführe, hat nur Lese-Rechte auf den Schlüssel.

Der Code ist folgender :
Delphi-Quellcode:
type
  TAccessMode = (
    NOT_USED_ACCESS,
    GRANT_ACCESS,
    SET_ACCESS,
    DENY_ACCESS,
    REVOKE_ACCESS,
    SET_AUDIT_SUCCESS,
    SET_AUDIT_FAILURE
  );

type
  PObjectsAndSid = ^TObjectsAndSid;
  TObjectsAndSid = record
    ObjectsPresent: DWORD;
    ObjectTypeGuid: TGUID;
    InheritedObjectTypeGuid: TGUID;
    pSid: PSID;
  end;

type

  TSeObjectType = (
    SE_UNKNOWN_OBJECT_TYPE,
    SE_FILE_OBJECT,
    SE_SERVICE,
    SE_PRINTER,
    SE_REGISTRY_KEY,
    SE_LMSHARE,
    SE_KERNEL_OBJECT,
    SE_WINDOW_OBJECT,
    SE_DS_OBJECT,
    SE_DS_OBJECT_ALL,
    SE_PROVIDER_DEFINED_OBJECT,
    SE_WMIGUID_OBJECT
  );
  PObjectsAndNameA = ^TObjectsAndNameA;
  TObjectsAndNameA = record
    ObjectsPresent: DWORD;
    ObjectType: TSeObjectType;
    ObjectTypeName: PAnsiChar;
    InheritedObjectTypeName: PAnsiChar;
    ptstrName: PAnsiChar;
  end;

  PObjectsAndNameW = ^TObjectsAndNameW;
  TObjectsAndNameW = record
    ObjectsPresent: DWORD;
    ObjectType: TSeObjectType;
    ObjectTypeName: PWideChar;
    InheritedObjectTypeName: PWideChar;
    ptstrName: PWideChar;
  end;
  PObjectsAndName = ^TObjectsAndName;
  TObjectsAndName = TObjectsAndNameA;

type
  TMultipleTrusteeOperation = (
    NO_MULTIPLE_TRUSTEE,
    TRUSTEE_IS_IMPERSONATE
  );

  TTrusteeForm = (
    TRUSTEE_IS_SID,
    TRUSTEE_IS_NAME,
    TRUSTEE_BAD_FORM,
    TRUSTEE_IS_OBJECTS_AND_SID,
    TRUSTEE_IS_OBJECTS_AND_NAME
  );

  TTrusteeType = (
    TRUSTEE_IS_UNKNOWN,
    TRUSTEE_IS_USER,
    TRUSTEE_IS_GROUP,
    TRUSTEE_IS_DOMAIN,
    TRUSTEE_IS_ALIAS,
    TRUSTEE_IS_WELL_KNOWN_GROUP,
    TRUSTEE_IS_DELETED,
    TRUSTEE_IS_INVALID,
    TRUSTEE_IS_COMPUTER
  );
  PTrusteeA = ^TTrusteeA;
  TTrusteeA = packed record
    pMultipleTrustee: PTrusteeA;
    MultipleTrusteeOperation: TMultipleTrusteeOperation;
    TrusteeForm: TTrusteeForm;
    TrusteeType: TTrusteeType;
    case TTrusteeForm of
      TRUSTEE_IS_SID: (
        pSid: PSID);
      TRUSTEE_IS_OBJECTS_AND_SID: (
        pObjectsAndSid: PObjectsAndSid);
      TRUSTEE_IS_OBJECTS_AND_NAME: (
        pObjectsAndName: PObjectsAndNameA);
   { else }
      TRUSTEE_IS_NAME, TRUSTEE_BAD_FORM: (
        ptstrName: PAnsiChar);
   { end; }
  end;
  PTrusteeW = ^TTrusteeW;
  TTrusteeW = packed record
    pMultipleTrustee: PTrusteeW;
    MultipleTrusteeOperation: TMultipleTrusteeOperation;
    TrusteeForm: TTrusteeForm;
    TrusteeType: TTrusteeType;
    case TTrusteeForm of
      TRUSTEE_IS_SID: (
        pSid: PSID);
      TRUSTEE_IS_OBJECTS_AND_SID: (
        pObjectsAndSid: PObjectsAndSid);
      TRUSTEE_IS_OBJECTS_AND_NAME: (
        pObjectsAndName: PObjectsAndNameW);
   { else }
      TRUSTEE_IS_NAME, TRUSTEE_BAD_FORM: (
        ptstrName: PWideChar);
   { end; }
  end;
  PTrustee = ^TTrustee;
  TTrustee = TTrusteeA;

type
  PExplicitAccessA = ^TExplicitAccessA;
  TExplicitAccessA = packed record
    grfAccessPermissions: DWORD;
    grfAccessMode: TAccessMode;
    grfInheritance: DWORD;
    Trustee: TTrusteeA;
  end;

  PExplicitAccessW = ^TExplicitAccessW;
  TExplicitAccessW = packed record
    grfAccessPermissions: DWORD;
    grfAccessMode: TAccessMode;
    grfInheritance: DWORD;
    Trustee: TTrusteeW;
  end;
  PExplicitAccess = ^TExplicitAccess;
  TExplicitAccess = TExplicitAccessA;

function SetEntriesInAclA(cCountOfExplicitEntries: ULONG; pListOfExplicitEntries: PExplicitAccessA;
         OldAcl: PACL; var NewAcl: ACL): DWORD; stdcall; {use localfree to release NewAcl}
  external advapi32 name 'SetEntriesInAclA';
function SetEntriesInAclW(cCountOfExplicitEntries: ULONG; pListOfExplicitEntries: PExplicitAccessW;
         OldAcl: PACL; var NewAcl: ACL): DWORD; stdcall; {use localfree to release NewAcl}
  external advapi32 name 'SetEntriesInAclW';
function SetEntriesInAcl(cCountOfExplicitEntries: ULONG; pListOfExplicitEntries: PExplicitAccess;
         OldAcl: PACL; var NewAcl: ACL): DWORD; stdcall; {use localfree to release NewAcl}
  external advapi32 name 'SetEntriesInAclA';
{------------------------------------------------------------------------------}
const
  SECURITY_WORLD_SID_AUTHORITY: TSIDIdentifierAuthority = (
    Value: (0, 0, 0, 0, 0, 1);
  );

  SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority = (
    Value: (0, 0, 0, 0, 0, 5);
  );

  SECURITY_WORLD_RID = $00000000;
  SECURITY_BUILTIN_DOMAIN_RID = $00000020;
  DOMAIN_ALIAS_RID_ADMINS = $00000220;
  DOMAIN_ALIAS_RID_POWER_USERS = $00000223;
  NO_INHERITANCE = $0;

function RegKeyWithFullAccess(Key: HKEY; SubKey: PChar): LongBool; stdcall;
var
  EveryoneSID: PSID;
  AdminSID: PSID;
  PowerUserSID: PSID;
  ExplicitAccesses: array [0..2] of TExplicitAccess;
  Acl: PACL;
  SecurityDescriptor: PSecurityDescriptor;
  SecurityAttributes: TSecurityAttributes;
  Disposition: DWORD;
  KeyHandle: HKEY;
begin
  Result := False;
  EveryoneSID := nil;
  AdminSID := nil;
  PowerUserSID := nil;
  ACL := nil;
  SecurityDescriptor := nil;
  KeyHandle := 0;
  {  Bekannte SID fr die "Jeder"-Gruppe erzeugen. }
  if AllocateAndInitializeSid(SECURITY_WORLD_SID_AUTHORITY, 1,
    SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, EveryoneSID) then
  begin
    { Der ACE wird "Jeder" Vollzugriff erlauben. }
    FillChar(ExplicitAccesses, 2 * SizeOf(TExplicitAccess), 0);
    ExplicitAccesses[0].grfAccessPermissions := KEY_ALL_ACCESS;
    ExplicitAccesses[0].grfAccessMode := SET_ACCESS;
    ExplicitAccesses[0].grfInheritance := NO_INHERITANCE;
    ExplicitAccesses[0].Trustee.TrusteeForm := TRUSTEE_IS_SID;
    ExplicitAccesses[0].Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;
    ExplicitAccesses[0].Trustee.pSid := EveryoneSID;
  end;
  {  Bekannte SID für die "Administratoren"-Gruppe erzeugen. }
  if AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
    SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
    AdminSID) then
  begin
    { Der ACE wird "Administratoren" Vollzugriff erlauben. }
    ExplicitAccesses[1].grfAccessPermissions := KEY_ALL_ACCESS;
    ExplicitAccesses[1].grfAccessMode := SET_ACCESS;
    ExplicitAccesses[1].grfInheritance := NO_INHERITANCE;
    ExplicitAccesses[1].Trustee.TrusteeForm := TRUSTEE_IS_SID;
    ExplicitAccesses[1].Trustee.TrusteeType := TRUSTEE_IS_GROUP;
    ExplicitAccesses[1].Trustee.pSid := AdminSID;
  end;
  {  Bekannte SID für die "Hauptbenutzer"-Gruppe erzeugen. }
  if AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
    SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0,
    PowerUserSID) then
  begin
    { Der ACE wird "Hauptbenutzern" Vollzugriff erlauben. }
    ExplicitAccesses[2].grfAccessPermissions := KEY_ALL_ACCESS;
    ExplicitAccesses[2].grfAccessMode := SET_ACCESS;
    ExplicitAccesses[2].grfInheritance := NO_INHERITANCE;
    ExplicitAccesses[2].Trustee.TrusteeForm := TRUSTEE_IS_SID;
    ExplicitAccesses[2].Trustee.TrusteeType := TRUSTEE_IS_GROUP;
    ExplicitAccesses[2].Trustee.pSid := PowerUserSID;
  end;
  try
    { Neue ACL erzeugen, die den neuen ACE enthlt. }
    if SetEntriesInAcl(3, @ExplicitAccesses, nil, PACL(@Acl)^) = ERROR_SUCCESS then
    begin
      { Security Descriptor initialisieren. }
      SecurityDescriptor := PSecurityDescriptor(LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
      if Assigned(SecurityDescriptor) then
        if InitializeSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) then
          { Die ACL zum Security Descriptor hinzufgen. }
          if SetSecurityDescriptorDacl(SecurityDescriptor, True, ACL, False) then
          begin
            { Eine Sicherheits-Attribute-Struktur initialisieren. }
            SecurityAttributes.nLength := SizeOf(TSecurityAttributes);
            SecurityAttributes.lpSecurityDescriptor := SecurityDescriptor;
            SecurityAttributes.bInheritHandle := False;
            { Die Sicherheits-Attribute benutzen um den Schlssel anzulegen. }
//            RegCreateKeyEx(Key, SubKey, 0, '', 0, KEY_READ or KEY_WRITE or WRITE_DAC, @SecurityAttributes, KeyHandle, @Disposition);
            RegOpenKeyEx(Key, SubKey, 0, KEY_READ or KEY_WRITE or WRITE_DAC, KeyHandle);
            if RegSetKeySecurity(KeyHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor) = ERROR_SUCCESS then
              if RegSetValue(key, SubKey, REG_SZ, 'Test', 0 ) = ERROR_SUCCESS then
              begin
                RegDeleteValue(Key, 'Test');
                RegCloseKey(Key);
              end;
            if KeyHandle <> 0 then
              Result := RegSetKeySecurity(KeyHandle, DACL_SECURITY_INFORMATION, SecurityDescriptor) = ERROR_SUCCESS;
          end;
    end;
  finally
    if Assigned(EveryoneSID) then
      FreeSid(EveryoneSID);
    if Assigned(AdminSID) then
      FreeSid(AdminSID);
    if Assigned(PowerUserSID) then
      FreeSid(PowerUserSID);
    if Assigned(Acl) then
      LocalFree(HLOCAL(Acl));
    if Assigned(SecurityDescriptor) then
      LocalFree(HLOCAL(SecurityDescriptor));
    if KeyHandle <> 0 then
      RegCloseKey(KeyHandle);
  end;
end;
Was ist jetzt falsch an dem Code ? Ich möchte ja lediglich nur einen Registrykey öffnen um dort einen Schlüssel oder Key zu erstellen oder zu ändern mit ganz normalen Hauptbenutzerrechten. Es kann auch sein, dass ich das ganze bis jetzt falsch verstanden habe. Wenn dieses der Fall ist, da bitte ich um eine Erklärung.

Luckie 21. Dez 2006 10:18

Re: WinAPI Problem
 
Wenn ein Benutzer nur Leserechte hat wird er den Schlüssel eben nicht löschen können. Er hat ja wohl nicht umsonst nur Leserechte in dem Schlüssel. Und wenn er sich selbst (als nicht Admin) dort auch Schreibrechte verschaffen könnte per Programmcode, wäre wohl die gesamte Benutzerverwaltung von Windows für den Pop.

SirThornberry 21. Dez 2006 10:27

Re: WinAPI Problem
 
Könntest du bitte deinem Beitrag einen aussagekräftigen Titel geben? :-D

RWarnecke 21. Dez 2006 10:29

Re: WinAPI Problem
 
Zitat:

Zitat von Luckie
Wenn ein Benutzer nur Leserechte hat wird er den Schlüssel eben nicht löschen können.

Das ist mir auch klar.
Zitat:

Zitat von Luckie
Er hat ja wohl nicht umsonst nur Leserechte in dem Schlüssel. Und wenn er sich selbst (als nicht Admin) dort auch Schreibrechte verschaffen könnte per Programmcode, wäre wohl die gesamte Benutzerverwaltung von Windows für den Pop.

Ich habe mich vielleicht etwas dumm ausgedrückt. Ich brauch das ganze als Zusatzprogramm für eine Softwareverteilung, da in der Softwareverteilung manchmal manche Registryschlüssel nicht erstellt werden. Wenn dieses der Fall ist, möchte ich halt vorher als Programm laufen lassen und die dazugehörigen Rechte setzen.

Edit :
Zitat:

Zitat von SirThornberry
Könntest du bitte deinem Beitrag einen aussagekräftigen Titel geben? :-D

Dein Wunsch war mir Befehl.

Christian Seehase 21. Dez 2006 10:50

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Moin Rolf,

die Softwareverteilungen, die ich kenne, lösen das Problem dadurch, dass sie mit einem Dienst arbeiten.
Dieser wird mit einem speziell berechtigten Installationsaccount, oder dem Local System Account gestartet, der dann mit den notwendigen Berechtigungen für Installationen ausgestattet ist.

RWarnecke 21. Dez 2006 10:57

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Ja, so ist das auch. Ich benutze hier in der Firma Novell Zenworks for Desktop. Nur leider gibt es immer wieder die Situation, das im HKLM\System verschiedenste Werte nicht geändert werden können, trotz das diese Werte im Paket der Softwareverteilung stehen.

Roland Wind 3. Mai 2007 11:04

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Hi Leute

Ich habe mal den Code ausprobiert unter Vista und bekomme nach Ausführen der Funktion
SetEntriesInACL den Rückgabewert 87 (INVALID_PARAMETER).
Weiss jemand einen Rat ??

Dezipaitor 3. Mai 2007 11:15

Re: WinAPI Problem mit Rechten setzen in der Registry
 
wo genau?

Roland Wind 3. Mai 2007 11:22

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Hi

Der Rückgabewert der Funktion

Delphi-Quellcode:
   
    { Neue ACL erzeugen, die den neuen ACE enthlt. }
    if SetEntriesInAcl(3, @ExplicitAccesses, nil, PACL(@Acl)^) = ERROR_SUCCESS then
    begin
ist nicht ERROR_SUCCESS, sondern ERROR_INVALID_PARAMETER

Dezipaitor 3. Mai 2007 20:38

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Ja das kommt davon, wenn die Leute nur abkupfern und nicht die Hintergründe zum Thema dazulesen. Stimmts RWarnecke? ;-)

Die ganze Geschichte oben funktioniert nur, wenn die Aufzählungstypen eine bestimmte Größe haben.
Das muss man setzen mit :

Delphi-Quellcode:
{$MINENUMSIZE 4}




Hier ein Beispiel mit den WinNT Apis von Assarbad und Co.

Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

uses
  //jwa... download from [url]http://jedi-apilib.sourceforge.net[/url]
  jwaACLApi,
  jwaAccCtrl,

  jwaWinBase,
  jwaWindows,
  jwaNative,
  SysUtils;

var AdminSID: PSID;
    ExplicitAccesses: TExplicitAccess;
    Acl: PACL;
    dwRes : DWORD;
begin
  { TODO -oUser -cConsole Main : Hier Code einfügen }

  if AllocateAndInitializeSid(@SECURITY_NT_AUTHORITY, 2,
    SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
    AdminSID) then
  begin
    FillChar(ExplicitAccesses,sizeof(ExplicitAccesses),0);
    ExplicitAccesses.grfAccessPermissions := KEY_READ;//KEY_ALL_ACCESS;
    ExplicitAccesses.grfAccessMode := SET_ACCESS;
    ExplicitAccesses.grfInheritance := NO_INHERITANCE;
    ExplicitAccesses.Trustee.TrusteeForm := TRUSTEE_IS_SID;
    ExplicitAccesses.Trustee.TrusteeType := TRUSTEE_IS_GROUP;
   ExplicitAccesses.Trustee.ptstrName := PAnsiChar(AdminSID);
  end;

  dwRes := SetEntriesInAcl(1, @ExplicitAccesses, 0, ACL);
  if (dwRes = 0) then
  begin
    LocalFree(ACL);
  end;


end.

Roland Wind 4. Mai 2007 09:07

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Hi Leute

Danke für den Tip. Das SetEntriesInACL funktioniert nun. Leider habe ich nun ein weiteres Problem.
Ich habe versucht, mit RegOpenKeyEx den Schlüssel "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib" zu öffnen. Leider hat die Funktion immer ACCESS_DENIED zurückgegeben.

Grund all meiner Versuche ist die Abfrage der aktuellen CPU Auslastung und die Anzahl der Prozessoren unter Windows Vista. Unter allen anderen OS funkts einwandfrei. Aber unter VISTA wurde der Zugriff auf
HKEY_PERFORMANCE_DATA eingeschränkt. Habe nun in der KnowledgeBase folgenden Artikel gefunden:

Code:
/*
 This sample illustrates how to regulate access to the performance data
 provided by the registry key HKEY_PERFORMANCE_DATA.

 The security on the following registry key dictates which users or groups
 can gain access to the performance data:

 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib

 This sample opens the registry key for WRITE_DAC access, which allows
 for a new Dacl to be applied to the registry key.

 A Dacl is then built, which grants the following users access:

 Administrators are granted full control to allow for future updates to the
 security on the key and to allow for querying performance data.

 Interactively logged on users, through the well-known Interactive Sid,
 are granted KEY_READ access, which allows for querying performance
 data.

 The new Dacl is then applied to the registry key using the
 RegSetKeySecurity() Win32 API.

 This sample relies on the import library Advapi32.lib.
 Note that not all errors will cause an information message to be
 displayed.

 */ 

#include <windows.h>
#include <stdio.h>

#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13

int
__cdecl
main(
    void
    )
{
    SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
    PSID pInteractiveSid = NULL;
    PSID pAdministratorsSid = NULL;
    SECURITY_DESCRIPTOR sd;
    PACL pDacl = NULL;
    DWORD dwAclSize;
    HKEY hKey;
    LONG lRetCode;
    BOOL bSuccess = FALSE; // assume this function fails

    // 
    // open the performance key for WRITE_DAC access
    // 
    lRetCode = RegOpenKeyEx(
        HKEY_LOCAL_MACHINE,
       TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"),
        0,
        WRITE_DAC,
        &hKey
        );

    if(lRetCode != ERROR_SUCCESS) {
        fprintf(stderr, "RegOpenKeyEx error! (rc=%lu)\n", lRetCode);
        return RTN_ERROR;
    }

    // 
    // prepare a Sid representing any Interactively logged-on user
    // 
    if(!AllocateAndInitializeSid(
        &sia,
        1,
        SECURITY_INTERACTIVE_RID,
        0, 0, 0, 0, 0, 0, 0,
        &pInteractiveSid
        )) goto cleanup;

    // 
    // prepare a Sid representing the well-known admin group
    // 
    if(!AllocateAndInitializeSid(
        &sia,
        2,
        SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_ADMINS,
        0, 0, 0, 0, 0, 0,
        &pAdministratorsSid
        )) goto cleanup;

    // 
    // compute size of new acl
    // 
    dwAclSize = sizeof(ACL) +
        2 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
        GetLengthSid(pInteractiveSid) +
        GetLengthSid(pAdministratorsSid) ;

    // 
    // allocate storage for Acl
    // 
    pDacl = (PACL)HeapAlloc(GetProcessHeap(), 0, dwAclSize);
    if(pDacl == NULL) goto cleanup;

    if(!InitializeAcl(pDacl, dwAclSize, ACL_REVISION))
        goto cleanup;

    // 
    // grant the Interactive Sid KEY_READ access to the perf key
    // 
    if(!AddAccessAllowedAce(
        pDacl,
        ACL_REVISION,
        KEY_READ,
        pInteractiveSid
        )) goto cleanup;

    // 
    // grant the Administrators Sid GENERIC_ALL access to the perf key
    // 
    if(!AddAccessAllowedAce(
        pDacl,
        ACL_REVISION,
        KEY_ALL_ACCESS,
        pAdministratorsSid
        )) goto cleanup;

    if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
        goto cleanup;

    if(!SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE)) {
        fprintf(stderr, "SetSecurityDescriptorDacl error! (rc=%lu)\n",
            GetLastError());
        goto cleanup;
    }

    // 
    // apply the security descriptor to the registry key
    // 
    lRetCode = RegSetKeySecurity(
        hKey,
        (SECURITY_INFORMATION)DACL_SECURITY_INFORMATION,
        &sd
        );

    if(lRetCode != ERROR_SUCCESS) {
        fprintf(stderr, "RegSetKeySecurity error! (rc=%lu)\n",
            lRetCode);
        goto cleanup;
    }

    bSuccess = TRUE; // indicate success

cleanup:

    RegCloseKey(hKey);
    RegCloseKey(HKEY_LOCAL_MACHINE);

    // 
    // free allocated resources
    // 
    if(pDacl != NULL)
        HeapFree(GetProcessHeap(), 0, pDacl);

    if(pInteractiveSid != NULL)
        FreeSid(pInteractiveSid);

    if(pAdministratorsSid != NULL)
        FreeSid(pAdministratorsSid);

    if(!bSuccess) return RTN_ERROR;

    return RTN_OK;
}
Den habe ich nun versucht in Delphi zu übersetzen und damit den Zugriff auch für Hauptbenutzer wieder freizugeben. Leider habe ich dabei ein paar Problemchen. Oder gibt es noch eine andere Möglichkeit (mglw. mit Manifest ??).

Kann mir einer beim Übersetzen helfen ??

Dezipaitor 4. Mai 2007 11:43

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Wenn du die Rechte ändern willst, brauchst du natürlich das Rechte das Recht zu ändern.
Also z.B. Admin- oder Besitzerrechte.

D.h. der Benutzer muss dein Programm zumindest mit Adminrechten gestartet haben.

Wenn der Administrator selbst nicht in der ACL (Access Control List)vorkommt, oder sogar den Zugriff verwehrt bekommt,
dann muss er ersteinmal der Besitzer werden, und die ACL korrigieren.

gore 26. Feb 2009 11:24

Re: WinAPI Problem mit Rechten setzen in der Registry
 
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)

Dezipaitor 26. Feb 2009 13:45

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Zitat:

Problem: Ich erhalte bei Registry oder Dateizugriff ERROR_ACCESS_DENIED obwohl ich Owner oder Admin bin
Besitzer zu sein bedeutet, dass man immer das Recht WRITE_DAC hat, auch wenn dies die DACL verweigert. Dann kann man sie anpassen und sich selbst alle Rechte geben.


Beispiel für File Security

Beispiel für Registry Key Security.
Delphi-Quellcode:
program RegKeySecurity;

{.$APPTYPE CONSOLE}

uses
  SysUtils,
  Registry,
  JwaWindows,
  JwsclToken,
  JwsclSecureObjects,
  JwsclPrivileges,
  JwsclAcl,
  JwsclDescriptor,
  JwsclTypes,
  JwsclConstants,
  JwsclKnownSid,
  JwsclUtils,
  JwsclStrings;

procedure SetRegKeySecurity(KeyRoot : HKEY; KeyName : String);
var
  Privs : IJwPrivilegeScope;
  Key : HKEY;
  KeySec : TJwSecureRegistryKey;
  DACL : TJwDAccessControlList;
begin
  JwInitWellKnownSIDs; //inits JwSecurityProcessUserSID

  if RegOpenKeyEx(KeyRoot, PChar(KeyName), 0, KEY_ALL_ACCESS, Key) = ERROR_ACCESS_DENIED then
  begin
    //not necessary since KeySec.TakeOwnerShip(); does it on its own
    //But just show the power of interfaces
    //The privilege will be restored to inactive state when the procedure exists
    Privs := JwGetPrivilegeScope([SE_TAKE_OWNERSHIP_NAME], pst_Enable);

    //First open key for write owner
    if RegOpenKeyEx(KeyRoot, PChar(KeyName), 0, WRITE_OWNER, Key) <> 0 then
      RaiseLastOSError;

    try
      //take ownership - can fail with exception
      TJwSecureRegistryKey.TakeOwnerShip(Key);

      //we need to reopen the handle for further access
      if RegOpenKeyEx(KeyRoot, PChar(KeyName), 0, WRITE_DAC, Key) <> 0 then
        RaiseLastOSError;

      //because access is granted on handle creation we need to
      //recreate the object

      KeySec := TJwSecureRegistryKey.Create(Key);
      try
        DACL := KeySec.DACL; //returns a cached DACL so we must not free it!

        //add process user with full access
        //and also set inheritance
        DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil, [afContainerInheritAce], KEY_ALL_ACCESS, JwSecurityProcessUserSID));
        //set DACL - may fail with exception
        KeySec.SetDACL(DACL);
      finally
        KeySec.Free;
      end;
    finally
      RegCloseKey(Key)
    end;
  end;
end;

begin
  SetRegKeySecurity(HKEY_CURRENT_USER, 'test');
end.

gore 27. Feb 2009 08:36

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Hi Dezipaitor,

Danke für Deine elegante Lösung (auch wenn ich ein Fan vom reinen Win32API bin). Danke besonders für den Link zum genialen JWSCL Blog!

Noch ein Nachtrag/Frage:
Am 04.05.2007 schriebst Du:
Zitat:

Wenn du die Rechte ändern willst, brauchst du natürlich das Rechte das Recht zu ändern.
Also z.B. Admin- oder Besitzerrechte.
D.h. der Benutzer muss dein Programm zumindest mit Adminrechten gestartet haben.
Richtig wäre doch:
D.h. der Benutzer muss dein Programm zumindest mit Adminrechten gestartet haben oder der Benutzer ist Besitzer des Objektes.
(Genauer gesagt: das Programm läuft im Account des Owners des Objektes; Objekt ist hier der Registry-Key oder die Datei).

Das hast Du ja auch gestern geschrieben:
Zitat:

Besitzer zu sein bedeutet, dass man immer das Recht WRITE_DAC hat, auch wenn dies die DACL verweigert. Dann kann man sie anpassen und sich selbst alle Rechte geben.
Ben

Dezipaitor 27. Feb 2009 12:37

Re: WinAPI Problem mit Rechten setzen in der Registry
 
Ich habe mich ungeschickt ausgedrückt.

Wenn der Benutzer nicht der Besitzer ist, dann muss er Admin sein, um der Besitzer werden zu können. Das gilt jedoch nicht, wenn die DACL ihm WRITE_OWNER gewährt.
Wenn er jedoch Besitzer schon ist, kann er mit dem Objekt machen was er will, auch wenn er erstmal noch die DACL anpassen muss.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:01 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz