DevTrain

Autor: Shinja Strasser

Sicherheitskennung von Ordnern ändern

Oftmals möchte man programmtechnisch die Sicherheitskennungen (read, execute, ...) ändern, um eine Aufgabe zu erledigen. Angenommen, keiner darf in einem Ordner etwas ändern oder löschen - mit ausnahme Ihres Programmes, so kann man eine VB Komponente erstellen, die kurzzeitig die Sicherheitskennungen eines Ordners ändert um z.B. etwas zu speichern. Dies erfordert aber eine Menge an API Funktionen.

Hier einmal im Überblick, welche API Funktionen notwendig sind:

GetComputerName liefert den Computernamen des aktuellen Systems.

GetUserName liefert den Benutzernamen des aktuellen Threads

Die Funktion LookupAccountName versucht, eine Sicherheitskennung für
den spezifizierten Namen zu finden, indem sie zuerst eine Liste von
bekanntem SIDs überprüft.

Die Funktion InitializeSecurityDescriptor initialisiert eine neue
Sicherheitskennung

Die Funktion GetSecurityDescriptorDacl ermittelt einen Zeiger zur
Zugriffskontrolliste (ACL).

Die Funktion GetFileSecurity holt sich Angaben über die
Sicherheit einer Datei oder eines Verzeichnisses ein.  Die eingeholten
Informationen werden durch die Auskunftsrechte und die Privilegien des
aufrufenden Programms begrenzt.

Die Funktion GetAclInformation holt Informationen über eine
Zugriffskontrolliste zurück (ACL).

Die Funktion EqualSid überprüft zwei Werte der Sicherheitskennung (SID)
auf Gleichheit.

Die Funktion GetLengthSid liefert die Länge, in Bytes, einer
gültigen SID-Struktur zurück.

Die Funktion InitializeAcl erstellt eine neue ACL-Struktur.

Mit der Funktion GetAce erhält man einen AS Zeiger in ACL Format

Die Funktion AddAce fügt einen oder mehrere ACEs einem spezifizierten ACL hinzu.

Die Funktion AddAccessAllowedAce fügt einen Zugriffsberechtigten AS einem
ACL hinzu.  Der Zugriff wird einem spezifizierten SID bewilligt.

Die Funktion AddAccessDeniedAce fügt einem verweigerten Zugriff eines AS
einem ACL hinzu.  Der Zugriff wird einem spezifizierten SID verweigert.

Die Funktion SetSecurityDescriptorDacl stellt Informationen in einer
beliebigen Zugriffskontrolliste ein (ACL).  Wenn ein beliebiger ACL
bereits im der Sicherheitskennung vorhanden ist, wird es ersetzt.

Die Funktion SetFileSecurity stellt die Sicherheit einer Datei- oder
Verzeichnisnachricht ein.

Die Funktion CopyMemory kopiert einen Block des Speichers von einem
Speicherort zu einem anderen.


Gehen wir nun weiter und sehen uns einmal die programmtechnische Umsetzung an:

Option Explicit

' Speicherkonstanten für den aufruf einiger API Funktionen
Const GMEM_MOVEABLE = &H2
Const LMEM_FIXED = &H0
Const LMEM_ZEROINIT = &H40
Const LPTR = (LMEM_FIXED + LMEM_ZEROINIT)
Const GENERIC_READ = &H80000000
Const GENERIC_ALL = &H10000000
Const GENERIC_EXECUTE = &H20000000
Const GENERIC_WRITE = &H40000000

'Datei / Sicherheits - Konstanten für API Funktonen
Const DACL_SECURITY_INFORMATION = &H4
Const SECURITY_DESCRIPTOR_REVISION = 1
Const SECURITY_DESCRIPTOR_MIN_LENGTH = 20
Const SD_SIZE = (65536 + SECURITY_DESCRIPTOR_MIN_LENGTH)
Const ACL_REVISION2 = 2
Const ACL_REVISION = 2
Const MAXDWORD = &HFFFFFFFF
Const SidTypeUser = 1
Const AclSizeInformation = 2

Const OBJECT_INHERIT_ACE = &H1
Const CONTAINER_INHERIT_ACE = &H2
Const NO_PROPAGATE_INHERIT_ACE = &H4
Const INHERIT_ONLY_ACE = &H8
Const INHERITED_ACE = &H10
Const VALID_INHERIT_FLAGS = &H1F
Const DELETE = &H10000

' Stukturen die für die API Funktionen benötigt werden
Type ACE_HEADER
   AceType As Byte
   AceFlags As Byte
   AceSize As Integer
End Type

Public Type ACCESS_DENIED_ACE
  Header As ACE_HEADER
  Mask As Long
  SidStart As Long
End Type

Type ACCESS_ALLOWED_ACE
   Header As ACE_HEADER
   Mask As Long
   SidStart As Long
End Type

Type ACL
   AclRevision As Byte
   Sbz1 As Byte
   AclSize As Integer
   AceCount As Integer
   Sbz2 As Integer
End Type

Type ACL_SIZE_INFORMATION
   AceCount As Long
   AclBytesInUse As Long
   AclBytesFree As Long
End Type

Type SECURITY_DESCRIPTOR
   Revision As Byte
   Sbz1 As Byte
   Control As Long
   Owner As Long
   Group As Long
   sACL As ACL
   Dacl As ACL
End Type

Private Declare Function GetComputerName Lib "kernel32" Alias _
   "GetComputerNameA" (ByVal lpBuffer As String, _
   nSize As Long) As Long

Private Declare Function GetUserName Lib "advapi32.dll" Alias _
   "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Private Declare Function LookupAccountName Lib "advapi32.dll" Alias _
   "LookupAccountNameA" (lpSystemName As String, _
   ByVal lpAccountName As String, sid As Any, cbSid As Long, _
   ByVal ReferencedDomainName As String, _
   cbReferencedDomainName As Long, peUse As Long) As Long

Private Declare Function InitializeSecurityDescriptor Lib "advapi32.dll" _
   (pSecurityDescriptor As SECURITY_DESCRIPTOR, _
   ByVal dwRevision As Long) As Long

Private Declare Function GetSecurityDescriptorDacl Lib "advapi32.dll" _
   (pSecurityDescriptor As Byte, lpbDaclPresent As Long, _
   pDacl As Long, lpbDaclDefaulted As Long) As Long

Private Declare Function GetFileSecurityN Lib "advapi32.dll" Alias _
   "GetFileSecurityA" (ByVal lpFileName As String, _
   ByVal RequestedInformation As Long, _
   ByVal pSecurityDescriptor As Long, ByVal nLength As Long, _
   lpnLengthNeeded As Long) As Long

Private Declare Function GetFileSecurity Lib "advapi32.dll" Alias _
   "GetFileSecurityA" (ByVal lpFileName As String, _
   ByVal RequestedInformation As Long, _
   pSecurityDescriptor As Byte, ByVal nLength As Long, _
   lpnLengthNeeded As Long) As Long

Private Declare Function GetAclInformation Lib "advapi32.dll" _
   (ByVal pAcl As Long, pAclInformation As Any, _
   ByVal nAclInformationLength As Long, _
   ByVal dwAclInformationClass As Long) As Long

Private Declare Function EqualSid Lib "advapi32.dll" (pSid1 As Byte, ByVal pSid2 As Long) As Long

Private Declare Function GetLengthSid Lib "advapi32.dll" (pSid As Any) As _
   Long

Private Declare Function InitializeAcl Lib "advapi32.dll" (pAcl As Byte, _
   ByVal nAclLength As Long, ByVal dwAclRevision As Long) As Long

Private Declare Function GetAce Lib "advapi32.dll" (ByVal pAcl As Long, _
   ByVal dwAceIndex As Long, pace As Any) As Long

Private Declare Function AddAce Lib "advapi32.dll" (ByVal pAcl As Long, _
   ByVal dwAceRevision As Long, ByVal dwStartingAceIndex As Long, _
   ByVal pAceList As Long, ByVal nAceListLength As Long) As Long

Private Declare Function AddAccessAllowedAce Lib "advapi32.dll" _
   (pAcl As Byte, ByVal dwAceRevision As Long, _
   ByVal AccessMask As Long, pSid As Byte) As Long

Private Declare Function AddAccessDeniedAce Lib "advapi32.dll" _
  (pAcl As Byte, ByVal dwAceRevision As Long, _
   ByVal AccessMask As Long, pSid As Byte) As Long

Private Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" _
   (pSecurityDescriptor As SECURITY_DESCRIPTOR, _
   ByVal bDaclPresent As Long, pDacl As Byte, _
   ByVal bDaclDefaulted As Long) As Long

Private Declare Function SetFileSecurity Lib "advapi32.dll" Alias _
   "SetFileSecurityA" (ByVal lpFileName As String, _
   ByVal SecurityInformation As Long, _
   pSecurityDescriptor As SECURITY_DESCRIPTOR) As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
   (hpvDest As Any, ByVal hpvSource As Long, ByVal cbCopy As Long)

Private mvarFErr As String

Private Sub SetAccess(sUserName As String, sFileName As String, lMask As Long)
   Dim lResult As Long             ' Resultat der verschiedenen API-Aufrufe.
   Dim I As Integer                ' Allgem. Zaehler
   Dim bUserSid(255) As Byte      ' enthält die SID.
   Dim bTempSid(255) As Byte      ' enthält die  Sid für jeden ACE in der ACL .
   Dim sSystemName As String      ' Name des Computersystems

   Dim lSystemNameLength As Long  'Länge des Strings, welcher den Computernamen enthält

   Dim lLengthUserName As Long    ' Maximale Länge des Benutzernamen
  
   Dim lUserSID As Long           ' SID des Benutzers

   Dim lTempSid As Long            'SID für jeden ACE in der ACL
   Dim lUserSIDSize As Long          ' Grösse der SID.
   Dim sDomainName As String * 255   ' DomainName
   Dim lDomainNameLength As Long     ' Länge des Domainnames

   Dim lSIDType As Long             'Typ der SID

   Dim sFileSD As SECURITY_DESCRIPTOR   ' SD der Datei

   Dim bSDBuf() As Byte          Puffer für die SD für eine Datei

   Dim lFileSDSize As Long           ' Grösse der Datei SD
   Dim lSizeNeeded As Long           ' Benötigte Grösse der Datei SD


   Dim sNewSD As SECURITY_DESCRIPTOR ' Neuer security descriptor.

   'Wird verwendet, wenn das DACL von der Datei Sd geöffnet wird.
   Dim sACL As ACL                
   Dim lDaclPresent As Long         
   Dim lDaclDefaulted As Long      

   Dim sACLInfo As ACL_SIZE_INFORMATION    'Wird verwendet, wenn das ACL von der Datei Sd geöffnet wird.

   Dim lACLSize As Long           ' Größe der ACL-Struktur

   Dim pAcl As Long               '  ACL der Datei
   Dim lNewACLSize As Long        ' Grösse der neuen ACL welche erzeugt wurde
   Dim bNewACL() As Byte          ' Puffer der neuen ACL.

   Dim sCurrentACE As ACCESS_ALLOWED_ACE    ' Aktuelle ACE.
   Dim pCurrentAce As Long              

   Dim nRecordNumber As Long

Sie erhalten die SID dieses Benutzers, indem Sie das LookupAccountName
API verwenden.  Um die SID des aktuellen Benutzerkontos zu verwenden,
rufen Sie das LookupAccountName API zweimal auf.  Das erste mal,
um die angeforderten Größen der SID und die Zeichenkette das DomainNames zu
erhalten.  Der zweite Aufruf soll die gewünschten Informationen wirklich erhalten.
   lResult = LookupAccountName(vbNullString, sUserName, _
      bUserSid(0), 255, sDomainName, lDomainNameLength, _
      lSIDType)

Stellen Sie jetzt den sDomainName - Zeichenkettepuffer auf seine korrekte
Größe ein, bevor Sie wieder die API verwenden 

sDomainName = Space(lDomainNameLength)

   lResult = LookupAccountName(vbNullString, sUserName, _
      bUserSid(0), 255, sDomainName, lDomainNameLength, _
      lSIDType)


Rückgabewert NULL bedeutet das der Aufruf LookupAccountName
entfällt,  prüfen Sie dies, bevor Sie fortfahren.

     If (lResult = 0) Then
        FErr = "Error: Unable to Lookup the Current User Account: " _
           & sUserName
        Exit Sub
     End If

Sie haben jetzt die SID für den Benutzer, der angemeldet ist.  Die
SID ist vom Interesse, da sie die Sicherheitskennung der Datei
erhält.  Das GetFileSecurity API holt die Sicherheitskennung für die Datei
zurück.  Jedoch müssen Sie diese API zweimal aufrufen um die korrekte
Größe für den Sicherheitskennung einmal zu erhalten und um die
tatsächlichen Informationen der Sicherheitskennung zul erhalten.
   lResult = GetFileSecurityN(sFileName, DACL_SECURITY_INFORMATION, _
      0, 0, lSizeNeeded)

Dimensionieren der Sicherheitskennungspuffer

ReDim bSDBuf(lSizeNeeded)

Gibt aktuellen Security Descriptor der Datei zurück
   lResult = GetFileSecurity(sFileName, DACL_SECURITY_INFORMATION, _
      bSDBuf(0), lSizeNeeded, lSizeNeeded)

Ein Rückgabewert NULL bedeutet, dass der Aufruf ausfällt;  prüfen Sie
dies, bevor Sie fortfahren.

   If (lResult = 0) Then
       FErr = "Error: Unable to Get the File Security Descriptor"
      Exit Sub
   End If

Rufen Sie InitializeSecurityDescriptor auf, um ein neues Sd für die Datei zu erhalten

   lResult = InitializeSecurityDescriptor(sNewSD, _
      SECURITY_DESCRIPTOR_REVISION)

Ein Rückgabewert NULL bedeutet, dass der Aufruf ausfällt;  prüfen Sie
dies, bevor Sie fortfahren.

   If (lResult = 0) Then
       FErr = "Error: Unable to Initialize New Security Descriptor"
      Exit Sub
   End If

Sie haben jetzt eine Sd der Datei und eine neue Sicherheitskennung,
um die aktuellen zu überschreiben.

   lResult = GetSecurityDescriptorDacl(bSDBuf(0), lDaclPresent, _
      pAcl, lDaclDefaulted)

Ein Rückgabewert NULL bedeutet, dass der Aufruf ausfällt;  prüfen Sie
dies, bevor Sie fortfahren.

   If (lResult = 0) Then
       FErr = "Error: Unable to Get DACL from File Security " _
         & "Descriptor"
      Exit Sub
   End If

Sie haben eine Sd der Datei und möchten nun von der ACL die Sd zurück
Geben Sie darauf acht dass die ACL für diese Datei existiert, bevor es die ACL-Informationen erhält.

   If (lDaclPresent = False) Then
       FErr = "Error: No ACL Information Available for this File"
      Exit Sub
   End If

 versuchen Sie, die ACL zu erhalten.
   lResult = GetAclInformation(pAcl, sACLInfo, Len(sACLInfo), 2&)

Ein Rückgabewert NULL bedeutet, dass der Aufruf ausfällt;  prüfen Sie
dies, bevor Sie fortfahren.

   If (lResult = 0) Then
       FErr = "Error: Unable to Get ACL from File Security Descriptor"
      Exit Sub
   End If

Nun da Sie die ACL-Informationen haben, berechnen Sie die neuen
ACL-Größen.

   lNewACLSize = sACLInfo.AclBytesInUse + (Len(sCurrentACE) + _
      GetLengthSid(bUserSid(0))) * 2 - 4

Bestimmen Sie den neuen ACL-Buffer 

ReDim bNewACL(lNewACLSize)

Verwenden Sie den Funktionsaufruf InitializeAcl API, um die neue ACL
zu initialisieren.

lResult = InitializeAcl(bNewACL(0), lNewACLSize, ACL_REVISION)

Ein Rückgabewert NULL bedeutet, dass der Aufruf ausfällt;  prüfen Sie
dies, bevor Sie fortfahren.

   If (lResult = 0) Then
       FErr = "Error: Unable to Initialize New ACL"
      Exit Sub
   End If

wenn ein DACL vorhanden ist, kopieren Sie es zu einem neuen DACL.

If (lDaclPresent) Then

   Kopieren Sie die ACEs von der Datei zum neuen ACL.    
If (sACLInfo.AceCount > 0) Then

 Ergreifen Sie jedes AS und fügen Sie sie in den neuen ACL ein
.         nRecordNumber = 0
         For I = 0 To (sACLInfo.AceCount - 1)
            lResult = GetAce(pAcl, I, pCurrentAce)

  Überprüfen Sie die aktuelle AS
            If (lResult = 0) Then
                FErr = "Error: Unable to Obtain ACE (" & I & ")"
               Exit Sub
            End If

Sie haben nun einen Zeiger auf die AS um die Größe zu erhalten.

CopyMemory sCurrentACE, pCurrentAce, LenB(sCurrentACE)
           
            lTempSid = pCurrentAce + 8
            If EqualSid(bUserSid(0), lTempSid) = 0 Then
                                
                lResult = AddAce(VarPtr(bNewACL(0)), ACL_REVISION, _
                  MAXDWORD, pCurrentAce, _
                  sCurrentACE.Header.AceSize)
               
                 If (lResult = 0) Then
                    FErr = "Error: Unable to Add ACE to New ACL"
                    Exit Sub
                 End If
                 nRecordNumber = nRecordNumber + 1
            End If
            
         Next I

Sie haben jetzt einen neuen ACL aufgebaut und möchten es dem eben erstellten
DACL hinzufügen

         lResult = AddAccessAllowedAce(bNewACL(0), ACL_REVISION, _
            lMask, bUserSid(0))


         If (lResult = 0) Then
             FErr = "Error: Unable to Add ACL to DACL"
            Exit Sub
         End If

         If GetAttr(sFileName) And vbDirectory Then
            
      
            lResult = GetAce(VarPtr(bNewACL(0)), nRecordNumber, pCurrentAce)
           
            If (lResult = 0) Then
                FErr = "Error: Unable to Obtain ACE (" & I & ")"
               Exit Sub
            End If

            CopyMemory sCurrentACE, pCurrentAce, LenB(sCurrentACE)
            sCurrentACE.Header.AceFlags = OBJECT_INHERIT_ACE + INHERIT_ONLY_ACE
            CopyMemory ByVal pCurrentAce, VarPtr(sCurrentACE), LenB(sCurrentACE)

hinzufügen anderer ACE
            lResult = AddAccessAllowedAce(bNewACL(0), ACL_REVISION, _
               lMask, bUserSid(0))
           
            If (lResult = 0) Then
                FErr = "Error: Unable to Add ACL to DACL"
               Exit Sub
            End If

 nächstes ACE.

            lResult = GetAce(VarPtr(bNewACL(0)), nRecordNumber + 1, pCurrentAce)
   
 
            If (lResult = 0) Then
                FErr = "Error: Unable to Obtain ACE (" & I & ")"
               Exit Sub
            End If
               
            CopyMemory sCurrentACE, pCurrentAce, LenB(sCurrentACE)
            sCurrentACE.Header.AceFlags = CONTAINER_INHERIT_ACE
            CopyMemory ByVal pCurrentAce, VarPtr(sCurrentACE), LenB(sCurrentACE)
        End If

Einen neuen Security Descriptor  für eine Datei erzeugen (neuen DACL).

         lResult = SetSecurityDescriptorDacl(sNewSD, 1, _
            bNewACL(0), 0)

         If (lResult = 0) Then
             FErr = "Error: " & _
                "Unable to Set New DACL to Security Descriptor"
            Exit Sub
         End If

  Der abschließende Schritt ist, die Sicherheitskennung wieder der Datei hinzuzufügen!

         lResult = SetFileSecurity(sFileName, _
            DACL_SECURITY_INFORMATION, sNewSD)


         If (lResult = 0) Then
             FErr = "Error: Unable to Set New Security Descriptor " _
               & " to File : " & sFileName
             FErr = Err.LastDllError
         Else
             FErr = "Updated Security Descriptor on File: " _
               & sFileName
         End If

      End If

   End If

End Sub


Public Sub Change(sFolderName As String, sUserName As String, sAccess As String)
    sUserName = Trim$(sUserName)
    sFolderName = Trim$(sFolderName)
    sAccess = UCase(sAccess)
   
    Select Case sAccess
        Case "R"
            SetAccess sUserName, sFolderName, GENERIC_READ
        Case "EX"
            SetAccess sUserName, sFolderName, GENERIC_EXECUTE
        Case "D"
            SetAccess sUserName, sFolderName, DELETE
        Case "W"
            SetAccess sUserName, sFolderName, GENERIC_WRITE
        Case "ALL"
            SetAccess sUserName, sFolderName, GENERIC_ALL
        Case Else
       
    End Select
End Sub

Private Property Let FErr(ByVal vData As String)
    mvarFErr = vData
End Property

Public Property Get FErr() As String
    FErr = mvarFErr
End Property

 

 

 


 


Erfasst am: 03.04.2001 - Artikel-URL: http://www.devtrain.de/news.aspx?artnr=412
© Copyright 2003 ppedv AG - http://www.ppedv.de