Wie nutzt man ACLs (Access Control Lists) richtig?

(Oder: „Warum zum Geier geht der sch**** nicht!?!??!?!“)

Einleitung

ACLs (Access Control Listen) sind eine Erweiterung fuer die ueblichen Unix-Zugriffsrechte von Dateien und Verzeichnisse. Waehrend die ueblichen Zugriffsrechte, die mittels chmod, chgrp und umask gesetzt werden, nur 3 Gruppen kennen (User, Group, Global), sind ACLs eigene Listen, die unabhaengig von Unix-Gruppen Benutzern verschiedene Rechte fuer Dateien und Verzeichnisse zuweisen koennen.

ACLs eignen sich hervoragend dazu, Dateien und Verzeichnisse auf Webservern zu schuetzen, die zwar vom WWW-User (also der User unter dem der Webserver laeuft) und dem Owner gelesen werden koennen sollen, aber sonst von niemanden anderem. (Und auch nicht von den CGI- und PHP-Skripten der anderen User auf dem System).
Ein typisches Problem auf Nicht-Dedizierten Servern mit mehreren Domains ist nämlich das folgende: Zwar kann ein User A seine Verzeichnisse und Dateien mittels HTACCESS gegen Webzugriffe schuetzen, doch was nutzt dies, wenn der User B ueber das Filesystem direkt die Datei lesen kann? Oder noch schlimmer: Wenn der User B ein CGI- oder PHP-Skript im Einsatz hat, welches es -bei genuegend dummer Serverkonfiguration- erlaubt, dass man beliebige Files im ganzen Dateisystem lesen kann, unabhaengig von der eigenen DocumentRoot.

Der herkoemmliche Schutz ueber CHMOD ist somit oft nicht ausreichend. Man koennte zwar auf die Idee kommen, dass der WWW-User und der jeweilige User jeweils in einer eigenen Unix-Gruppe gesetzt werden, aber dies ist auf Dauer nicht praktikabel: Fuer jeden neuen User muesste eine eigene Gruppe angelegt werden. Und der Webserver muss in diese rein. Dumm nur, dass es nicht moeglich ist, Mitglied in beliebig vielen Gruppen zu sein…

ACLs sind die Alternative und die Loesung zu dieser Situation. (Will man nicht auf eine Architektur aus dedizierten Servern umschwenken.) setfacl erlaubt das Setzen von zusaetzlichen Zugriffsrechten auf Dateien und Verzeichnissen.
Mittels getfacl kann man sich die aktuelle ACL einer Datei oder eines Verzeichnisses anzeigen lassen.

Beispiele

  1. ACL fuer eine Datei oder ein Verzeichnis (ohne Vererbung!) vergeben

    Vorheriger Status:

    -rw-r-----   1 xwolf   sbadmin           0 Jan 29 16:58 blafasel

    Benutzer xbaer soll nun ebenfalls schreiben koennen:

    > setfacl -m user:xbaer:rw-,mask:rw- blafasel

    Neue ‚ls -la‘ -Anzeige:

    rw-r-----+  1 xwolf   sbadmin           0 Jan 29 16:58 blafasel

    Wir wollen es genauer wissen:

    > getfacl blafasel
    
    # file: blafasel
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:xbaer:rw-         	#effective:rw-
    group::r--              #effective:r--
    mask:rw-
    other:---

    Der Benutzer hat nun das Recht erhalten, die Datei zu edieren. Ausserdem wurde eine Maske gesetzt, die festlegt, wieviel Rechte maximal ueberhaupt vergeben werden koennen: mask:rw-
    Setzt man nun fuer einen Dritten User folgendes:

          > setfacl -m user:www:rwx blafasel

    verhindert die Maske rw-, dass das ‚x‘-Flag aktiv wirken kann. Dies wird auch bei der getfacl-Anzeige sichtbar:

    # file: blafasel
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:www:rwx            #effective:rw-
    user:xbaer:rw-         	#effective:rw-
    group::r--              #effective:r--
    mask:rw-
    other:---

    Man beachte den Kommentar: #effective:rw-
    Man kann mit also Hilfe der Maske, ohne das man eine moegliche Liste an usern aendert, quasi wie ein Schalter alle rechte einschraenken:

    > setfacl -m mask:r-- blafasel
    > getfacl blafasel
    
    # file: blafasel
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:www:rwx            #effective:r--
    user:xbaer:rw-         	#effective:r--
    group::r--              #effective:r--
    mask:r--
    other:---
  2. Mit Hilfe der Option -d kann man einzelne User wieder aus der Liste entfernen:

    > setfacl -d user:www blafasel
    > getfacl blafasel
    
    # file: blafasel
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:xbaer:rw-         	#effective:r--
    group::r--              #effective:r--
    mask:r--
    other:---
  3. Vererbbare ACLs fuer Verzeichnisse setzen

    Wenn man, wie oben beschrieben ein ACL auf ein Verzeichnis setzt, werden die ACLs nur fuer das Verzeichnis als solches wirksam. Nicht jedoch auf neue Dateien, die spaeter im Verzeichnis angelegt werden.
    Im Unterschied zum bekannten s-Bit wurde betreff ACLs etwas neues eingefuehrt: Default-ACLs.
    Die Default-ACLs koennen nur auf Verzeichnisse vergeben werden. Sie definieren, welche ACLs automatisch auf neue Unterverzeichnisse oder Dateien gesetzt werden. (Uebrigens ist die Standard-Manual an dieser Stelle etwas unzureichend. Deswegen gibt es auch hier die meisten Verwirrungen und Probleme.)
    Setzen einer vererbbaren ACL auf ein Verzeichnis:

    > ls -la
    ...
    drwxr-x---   2 xwolf   sbadmin         512 Jan 29 17:16 blub
    ...
    
    > setfacl -s user::rwx,group::r-x,mask:rwx,other:---, default:user::rwx,default:group::r-x,
    default:mask:rwx,default:other:--- blub

    Zur Erklaerung:
    Im ersten Teil ‚user::rwx,group::r-x,mask:rwx,other:—‚ werden die normalen ACLs fuer das Verzeichnis gesetzt. Hier also: der normale User darf alles (rwx), die Group nur lesen (r-x), alle anderen nichts (—). Und die Maske ist so, dass zusaetzliche Eintraege spaeter alle Rechte bekommen koennen (rwx).
    Man beachte hierbei: Wenn bei der Syntax User, Group oder Other keine UID oder GUID angegeben ist, wird der Benutzer und die Group genommen, die bereits vorliegen. Also im obigen Fall User ‚xwolf‘ und Group ’sbadmin‘.
    Im zweiten Teil werden die Default-ACLs definiert, die fuer neue Dateien und Verzeichnisse im blub-Verzeichniss gelten: default:user::rwx,default:group::r-x,default:mask:rwx,default:other:---
    Die Syntax sollte recht selbsterklaerend sein.
    Was ist zu beachten:

    • Beim Setzen der Default-ACLs muss das ACL mit der Option -s neu gesetzt werden.
    • Die Reihenfolge und Vollstaendigkeit der Definition ist wichtig! Vergisst man z.B. die Default-Group ‚others‘, kriegt man folgende Fehlermeldung:
       > setfacl -s user::rwx,group::r-x,mask:rwx,other:---, default:user::rwx,default:user:www:r-x,
      default:user:xbaer:rwx,default:group::r-x,default:mask:rwx blub
      Missing user/group owner, other, mask entry
      aclcnt 9, file blub

      (Das kann extrem nervig werden, wenn man nicht aufpasst. An dieser Stelle sollten die Systemprogrammierer etwas merh Usability in der Fehlerausgabe machen…)

    • Beim setzen zusaetzlicher Default-Eintraege sollte man sich an die Reihenfolge halten! Auch muss man hier wieder mit der Option ‚-s‘ arbeiten. Die Modify-Option ‚-m‘ ist wie gesagt nicht ausreichend.

    Wenn ich nun will, dass bei der Default-ACL weitere Angaben stehen, muss ich die gesamte ACL explizit neu setzen.
    Beispelsweise moechte ich den User xbaer und www im Default haben:

    > setfacl -s user::rwx,group::r-x,mask:rwx,other:---,
    default:user::rwx,default:user:xbaer:rwx,default:user:www:r-x,
    default:group::r-x,default:mask:rwx,default:other:--- blub
    > getfacl blub
    
    # file: blub
    # owner: xwolf
    # group: sbadmin
    user::rwx
    group::r-x              #effective:r-x
    mask:rwx
    other:---
    default:user::rwx
    default:user:www:r-x
    default:user:xbaer:rwx
    default:group::r-x
    default:mask:rwx
    default:other:---

    Hier ein Beleg dafuer, dass obige Aussage mit der Vererbbarkeit stimmt:

    > cd blub
    > touch platsch
    > getfacl platsch
    
    # file: platsch
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:www:r-x            #effective:r--
    user:xbaer:rwx         #effective:rw-
    group::r--              #effective:r--
    mask:rw-
    other:---

    Das gilt auch fuer Verzeichnisse:

    > mkdir wasser
    > getfacl wasser
    
    # file: wasser
    # owner: xwolf
    # group: sbadmin
    user::rwx
    user:www:r-x            #effective:r-x
    user:xbaer:rwx         #effective:rwx
    group::r-x              #effective:r-x
    mask:rwx
    other:---
    default:user::rwx
    default:user:www:r-x
    default:user:xbaer:rwx
    default:group::r-x
    default:mask:rwx
    default:other:---

    Wie man sieht, funktioniert die Vererbbarkeit eigentlich sehr schoen. Wenn man dann mal nur aufpasst mit der Syntax des Befehls! Aber dazu gibt es eine Hilfe, wie das folgende Beispiel zeigt.

  4. Einfacheres Setzen von ACLs über ACL-Dateien

    Wie oben bemerkt ist das Setzen von ACLs, inbesondere wenn sie sich wiederholen und gleichzeitig lang ist, eine nervige und muehsame Sache. Insbesondere fuer die Finger, die nach dem Dritten fehlgeschlagenen Versuch den aufsteigenden Aerger an der Tastatur auslassen.
    (Aber vielleicht ist das Strategie von Sun. Neue Tastaturen bringen Geld…)
    Die Option -f erlaubt es, ACLs aus einer Datei zu lesen und dann zu setzen. Angenommen, ich will ein weiteres Verzeichnis mit ACls versehen, neben ‚blub‘:

    >  ls -la
    drwxr-x---+  3 xwolf   sbadmin         512 Jan 29 17:30 blub
    drwxr-x---   2 xwolf   sbadmin         512 Jan 29 17:37 dumdidum

    dumdidum soll dieselben Rechte bekommen wie blub.

    1. Erste Lösung (fast schon gut):
      > getfacl blub > blub.acls
      > setfacl -f blub.acls dumdidum
      > getfacl dumdidum
      
      # file: dumdidum
      # owner: xwolf
      # group: sbadmin
      user::rwx
      group::r-x              #effective:r-x
      mask:rwx
      other:---
      default:user::rwx
      default:user:www:r-x
      default:user:xbaer:rwx
      default:group::r-x
      default:mask:rwx
      default:other:---

      Klappt, wackelt und hat Luft! Man koennte zufrieden sein. Es geht aber besser.

    2. Ohne Umweg ueber eine Datei sondern über STDIN:
      > getfacl blub | setfacl -f - dumdidum
      > getfacl dumdidum
      
      # file: dumdidum
      # owner: xwolf
      # group: sbadmin
      user::rwx
      group::r-x              #effective:r-x
      mask:rwx
      other:---
      default:user::rwx
      default:user:www:r-x
      default:user:xbaer:rwx
      default:group::r-x
      default:mask:rwx
      default:other:---

    Und auch diesmal hat es geklappt!

  5. ACLs entfernen

    Manch einer kommt mit ACLs nicht zurecht und will sie loswerden. Und das stellt sich dann als schwierig raus (insbesondere bei Verzeichnissen mit Default-ACLs), wenn man eh schon Probleme mit ACLs hat.
    Folgender Aufruf erweist sich jedoch als zuverlässig:

    > setfacl -s u::rwx,g::r--,mask:rw-,other:---

    Hierfuer lohnt es sich uebrigens ein Alias zu setzen.
    Man muss unterscheiden, ob es sich um ein Verzeichnis, eine ausführbare Datei, oder einen normale Datei handelt und sollte gegebenenfalls die x Rechte im Falle eines Verzeichnisses bei group und mask nicht zurücksetzen bzw. falls es eine normale Datei ist, bei user nicht setzen.
    Insbesondere gilt dies, wenn man mit dem Kommando ‚find‘ die ACL’s eines ganzen Verzeichnisbaumes aendert. Das entfernen der ACLs für einen ganzen Teilbaum kann dann nach diesem Rezept erfolgen:

    1. Man nehme ein schönes Verzeichnis ohne ACLs oder mit den ACLs, die man für seinen Teilbaum haben will:
      getfacl good_dir > /tmp/gooddir.acls
    2. Man startet ein find auf dem Teilbaum:
      find /mein/verwurschtelter/Teilbaum -type d -exec setfacl -f /tmp/gooddir.acls {} \;

    Um ganz auf Nummer sicher zu gehen, kann man sich den Baum vorher mit tar sichern, wichtig dabei ist aber auch beim Erzeugen des tar Archivs die option -p anzugeben, da sonst die ACL´s verloren gehen.Weitere Beispiele: http://www.cs.indiana.edu/Facilities/software/ACL.html

    Was muss man bei CHMOD beachten?

    ACLs und CHMOD arbeiten eigentlich ganz gut zusammen. Man muss nur eines beachten: Die Mask einer ACL haengt an den Gruppenrechten, die man mittels CHMOD setzt.
    Beispiel:

    > getfacl blafasel
    
    # file: blafasel
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:xbaer:rw-         	#effective:r--
    group::r--              #effective:r--
    mask:r--
    other:---

    Die Maske ist auf ‚r‘. Ist nicht so schön fuer den User. Mit ‚ls -la‘ sieht dieselbe Datei so aus:

    -rw-r-----+  1 xwolf   sbadmin           0 Jan 29 16:58 blafasel

    Und nun spielen wir mal etwas mit CHMOD:

    > chmod 664  blafasel
    > ls -la
    -rw-rw-r--+  1 xwolf   sbadmin           0 Jan 29 16:58 blafasel
    > getfacl blafasel
    
    # file: blafasel
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:xbaer:rw-         	#effective:rw-
    group::rw-              #effective:rw-
    mask:rw-
    other:r--

    Wie man sieht, hat das CHMOD dafuer gesorgt, das auch die Mask ein Write-Recht bekommen hat. Dies hat dann entsprechende Wirkung auf die User-Einträge. Dies zeigt es noch besser:

    > chmod g-rw blafasel
    > getfacl blafasel
    
    # file: blafasel
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:xbaer:rw-         	#effective:---
    group::---              #effective:---
    mask:---
    other:r--

    Das Setzen von Rechten auf Global und User hat dagegen keine Auswirkung auf die Mask:

    > chmod o+rw blafasel
    > getfacl blafasel
    
    # file: blafasel
    # owner: xwolf
    # group: sbadmin
    user::rw-
    user:xbaer:rw-         #effective:---
    group::---              #effective:---
    mask:---
    other:rw-

    Backup

    Einige System-Backups kennen ACLs nicht. In Folge dessen können ACls verloren gehen, wenn eine Datei recoverd wird. Um damit nicht ebenfalls alle ACLs zu verlieren, ist es unter Umständen sinnvoll, die ACL-Konfiguration der wichtigsten Files oder Verzeichnisse zu speichern.

    getfacl [datei|verzeichnis] > ACL_File

    ist hierzu die Lösung.

    Linux (SuSe)

    SuSe-Linux unterstützt seit Version 8.1. ACLs. Sowohl auf der Filesystem-Ebene, als auch innerhalb seines Samba- und NFS-Daemons.
    Vgl: http://sdb.suse.de/de/sdb/html/81_acl.html