POSIX ACL

A Unix/Linux szerverek üzemeltetése wikiből
A lap korábbi változatát látod, amilyen KornAndras (vitalap | szerkesztései) 2010. október 13., 01:28-kor történt szerkesztése után volt.

Írta: Tevesz Ágnes, 2009. december.

A POSIX ACL (hozzáférés-vezérlési listák) a hagyományos unixos fájlrendszer-jogosultságrendszer kiterjesztése. Olyan jogosultság-konstrukciók is leírhatók a segítségével, amelyek a hagyományos jogosultságrendszerrel nem: pl. hogy egy adott fájlt egy csoport tagjai írhassák és olvashassák, egy másik csoport tagjai csak olvashassák, a többiek pedig se ne írhassák, se ne olvashassák.

Tartalomjegyzék

1 Bevezetés

Azok a rendszerek, amelyek támogatják/megvalósítják a POSIX-szabványokat (Portable Operating System Interface), általában egy egyszerű, de hatékony fájl-jogosultsági modellt használnak. Minden fájlhoz három jogosultsághalmaz tartozik: külön megadható, milyen jogai legyenek a fájl tulajdonosának, a fájlt birtokló csoportnak és rajtuk kívül mindenk másnak. A három jogosultsághalmaz három-három bitből áll: ezek az olvasás (r), az írás (w) és végrehajtás (x) jogát reprezentálják. Az így kapott jogokat, minden fájl illetve könyvtár esetében, kilenc biten tudjuk tárolni. Megadható ezen felül a felhasználói azonosító beállítása (set user id), a csoportazonosító beállítása (set group id) és a ragadós (sticky) bit is.

Az összetett feladatok ellátására ez a modell nem biztosított elég lehetőséget, ezért indították a POSIX 1003.1e fejlesztését és így született meg az ACL (Access Control List) szabványtervezet, amely azonban sosem vált szabvánnyá és már valószínűleg nem is fog. A jövő útja valószínűleg az NFSv4 ACL-eké, de ezeket jelen sorok írásakor a szabad unix-féleségek közül csak a FreeBSD és az OpenSolaris támogatja, míg az 1003.1e szerinti ACL-eket a Linux is; ráadásul a megvalósítás kiforrottnak tekinthető, és a felhasználói programok oldaláról is megvan a szükséges támogatás, úgyhogy még érdemes ezzel az ACL-rendszerrel foglalkozni.

2 Az ACL-ek felépítése és működése

Egy ACL bejegyzések sokaságából épül fel (ACE). Egy ACL-bejegyzés három információt tartalmaz:

  • A bejegyzés típusa. A következő típusok léteznek (zárójelben a típusok kódja -- a későbbiekben a rövidség érdekében gyakran a kóddal fogok hivatkozni a bejegyzéstípusokra):
    1. tulajdonos (ACL_USER_OBJ);
    2. egyéb konkrét felhasználó (ACL_USER);
    3. tulajdonoscsoport (ACL_GROUP_OBJ);
    4. egyéb konkrét csoport (ACL_GROUP);
    5. maszk (ACL_MASK) - ezzel a USER, a GROUP_OBJ és a GROUP típusú ACL-ek által megadott jogokból kimaszkolhatunk bizonyos biteket, l. később;
    6. mindenki más (ACL_OTHER).
  • Annak a csoportnak vagy felhasználónak a neve, amelyikre az adott bejegyzés vonatkozik; ez lehet
    • üres, vagy
    • egy konkrét felhasználó vagy csoport.
  • Az adott felhasználóhoz vagy csoporthoz rendelt jogok:
    • a szokásos r/w/x bit formájában.

A szintaxis a következő:

<acl típusa>:<név>:<jogok>

Az alábbi táblázat az egyes bejegyzéstípusok szintaxisát részletesebben is bemutatja:

Típus Kód Szöveges forma
ACL-bejegyzéstípusok
tulajdonos ACL_USER_OBJ user::rwx
konkrét felhasználó ACL_USER user:név:rwx
tulajdonoscsoport ACL_GROUP_OBJ group::rwx
konkrét csoport ACL_GROUP group:név:rwx
maszk ACL_MASK mask::rwx
egyéb ACL_OTHER other::rwx

Minden ACL kötelezően tartalmaz egy USER_OBJ, egy GROUP_OBJ és egy OTHER típusú bejegyzést. Azokat az ACL-eket, amelyek ezen a három bithármason kívül további elemeket is tartalmaznak, kiterjesztett vagy bővített ACL-eknek hívjuk. Ezek tartalmaznak egy mask bejegyzést illetve megnevezett felhasználókat és csoportokat is. Más szavakkal: ha egy ACL-ben szerepel GROUP vagy USER típusú (tehát konkrét felhasználóra vagy konkrét csoportra vonatkozó) bejegyzés, akkor kötelezően tartalmaz egy MASK típusú bejegyzést is; a MASK bejegyzés minden egyéb esetben opcionális.

A maszk a jogosultságok elbírálásakor jut szerephez. Ha egy processz megpróbál megnyitni egy olyan fájlt amelyhez bővített ACL tartozik, egy jogosultságvizsgáló algoritmus fut le, amelynek a működése a következőképpen foglalható össze:

  1. Ha a processz effektív UID-ja megegyezik a fájl tulajdonosáéval, akkor a USER_OBJ bejegyzésben megadott jogosultságbitek az érvényesek.
  2. Ha nem egyezik, és van a processz effektív UID-jára vonatkozó USER típusú ACL-bejegyzés, az ebben szereplő jogosultságbitek az irányadóak.
  3. Ha nincs ilyen bejegyzés, és a processz effektív GID-ja megegyezik a fájl tulajdonoscsoportjával, akkor a GROUP_OBJ bejegyzésben megadott jogosultságbitek az irányadóak.
  4. Ha nem egyezik meg, akkor a processz effektív GID-jára és kiegészítő csoportjaira vonatkozó ACL-bejegyzésekben megadott jogosultságokat VAGY kapcsolatba hozzuk egymással, az eredményt pedig ÉS kapcsolatba hozzuk a maszkkal. Az így kapott jogosultságbiteket tekintjük irányadónak; ha ezek lehetővé teszik a fájl megnyitását, akkor az sikerül, ha nem, akkor nem.
  5. Ha nincs ilyen ACL-bejegyzés, akkor az OTHER típusú bejegyzésben szereplő jogosultságbitek jutnak érvényre.

Vegyük észre, hogy ez azt jelenti, hogy az azonos típusú ACL-bejegyzések közül az engedélyezők "erősebbek" a tiltóknál.

Megjegyzés: az itt leírt algoritmus az, amelyet a Linux ténylegesen megvalósítani látszik; az acl(5) manpage által leírt algoritmus nem pontosan ez. Nem világos, hogy az implementáció vagy a dokumentáció hibás.

Az alábbi táblázat egy egyszerű példán kersztül szemlélteti a maszk működését:

Típus Szöveges forma Jogok
konkrét felhasználó user:név:rw- r-x
mask mask::rw- rw-
Effektív jogok r--

Ha valamilyen hagyományos, tehát ACL-eket nem támogató eszközzel kérdezzük le egy fájl jogosultságbitjeit, valahogyan meg kell bennük jeleníteni az ACL által reprezentált jogokat is; tehát szükségünk van egy leképezésre, ami az ACL tartalmát hagyományos unixos jogosultságbitekre képezi le. Egy ilyen leképezés természetesen nem lehet bijekció, hiszen az ACL-nek nagyobb a kifejezőereje, mint a jogosultságbiteknek; de egyértelmű azért lehet. A következő megoldást találták ki:

  1. A tulajdonos jogosultságbitjei megegyeznek a USER_OBJ típusú ACL-bejegyzés tartalmával.
  2. Az "egyéb" jogosultságbitjei megegyeznek az OTHER típusú ACL-bejegyzés tartalmával.
  3. A tulajdonoscsoport látszólagos jogosultságbitjei a következőképpen állnak elő:
    1. Ha van MASK típusú bejegyzés az ACL-ben, akkor a tulajdonoscsoport látszólagos jogai a maszk értékével egyeznek meg.
    2. Ha nincs MASK típusú bejegyzés az ACL-ben, akkor a tulajdonoscsoport jogai a GROUP_OBJ típusú bejegyzés értékével egyeznek meg.

Ugyanez a leképezés fordítva is működik: ha a chmod paranccsal vagy az azonos nevű rendszerhívással állítjuk a jogosultságbiteket, akkor a csoportra vonatkozó bitek a maszk típusú bejegyzésbe íródnak bele, ha van ilyen a fájlon. Erre jó odafigyelni, mert esetleg nem ezt szeretnénk. Ha ugyanis töröljük valamelyik bitet a maszkból, akkor természetesen hiába szerepel az a bit valamelyik nevesített felhasználóra vagy csoportra vonatkozó bejegyzésben, nem fog érvényre jutni.

Alapértelmezés szerint, amikor módosítjuk az ACL-t egy fájlon vagy könyvtáron, a maszk újraszámolódik és a nevesített felhasználókra és csoportokra vonatkozó jogosultságok összességének VAGY-kapcsolatával fog megegyezni; így, ha pl. egy ls -l kimenetét nézzük, képet kapunk arról, legfeljebb milyen jogokat osztottunk ki ACL-ek formájában.

Azt is jó tudni, hogy a fent leírt leképezés igazából nem a jogok kiolvasásakor, hanem a fájlrendszerben történő rögzítésükkor történik meg (hiszen az inode-ban adottak a jogosultságbitekhez tartozó mezők, ahová valamilyen értéket be kell írni). Ez azért fontos, mert előfordulhatnak (és elő is fordulnak) olyan hibák, amikor a tulajdonoscsoport jogait tartalmazó mezőbe valami miatt nem a maszk értéke kerül (vagy fordítva), és amíg nem nézzük meg közelről a teljes ACL-t, csak tanácstalanul vakarjuk a fejünket és nem értjük, miért nem működnek az ACL-lel beállított jogok. Jelen sorok írásakor pl. az xfsrestore állít be nullás maszkot úgy, hogy azt az értéket, amelynek a maszkban szerepelnie kellene, a tulajdonoscsoport jogosultságaihoz azért beírja. Így ránézésre látszólag minden rendben van, a gyakorlatban viszont nem jut érvényre az ACL, mert minden bitet kimaszkolunk belőle.

3 Hozzáférési ACL

Az eddigiekben bemutatott ACL-ek segítségével viszonylag finoman szabályozhatjuk, hogy létező fájlrendszer-objektumokhoz való hozzáféréskor mely felhasználóknak és mely csoportoknak milyen jogai legyenek. Az ilyen típusú ACL-eket hozzáférési ACL-nek hívják.

Nézzünk egy példát. Állítsuk az umaskunkat 033-ra; ezzel az újonnan létrehozott fájlok és könyvtárak jogosultságbitjeiből kimaszkoltuk a tulajdonoscsoport és az egyéb végrehajtási és írási jogát (1-es ill. 2-es bit; a 4-es az olvasás).

% umask 033
% mkdir konyvtar
% ls -dl konyvtar
drwxr--r-- [...] júzer csoport [...] konyvtar

A pontok helyén levő információk most nem fontosak. Most írassuk ki a getfacl paranccsal az ACL-t. A getfacl paranccsal megjeleníthetjük egy fájl nevét, tulajdonosát, csoportját és a hozzá tartozó ACL-t.

% getfacl konyvtar
# file: konyvtar
# owner: júzer
# group: csoport
user::rwx
group::r--
other::r--

Az utolsó három sor a szokásos unixos jogosultságbiteket reprezentáló ACL-bejegyzéseket mutatja. Nézzük meg, hogy hogyan tudnánk egy megnevezett felhasználónak, mondjuk Bobnak jogokat biztosítani. Mivel Bobot szeretjük, olvasási, írási és végrehajtási jogot is adunk neki. A -m paraméter segítségével tudjuk módosítani a jogokat.

% setfacl -m u:bob:rwx konyvtar
% getfacl konyvtar
# file: konyvtar
# owner: júzer
# group: csoport
user::rwx
user:bob:rwx
group::r--
mask::rwx
other::r--

(Vegyük észre, hogy azt, hogy user:bob:rwx rövidíthettük úgy, hogy u:bob:rwx.)

Itt megjelenik ugyebár a Bob nevű felhasználó bejegyzése és a mask típusú bejegyzés. A mask bejegyzés automatikusan létrejön, ha szükséges, és nem adtuk meg külön. Ahogy már említettem, a maszk alapértelmezés szerint a nevesített felhasználókra és csoportokra vonatkozó jogosultságok összességének VAGY-kapcsolatával fog megegyezni, így biztosan nem maszkol egyetlen jogot sem. Ha megnézzük az ls -dl konyvtar parancs kimenetét, a következőt láthatjuk:

drwxrwx---+ [...] júzer csoport [...] konyvtar

Itt a + jel azt mutatja, hogy konyvtarhoz tartozik bővített ACL. Látszik az is, hogy a mask bejegyzés tartalma jelenik meg a tulajdonoscsoport jogai helyén; ez azért hasznos, mert a mask az ACL-ek által biztosított jogok felső korlátja. Csoport jogai még mindig csak az olvasásra korlátozódnak.

Ha megpróbáljuk módosítani a tulajdonoscsoport jogait a chmod segítségével r-x-re, akkor a következő történik:

% chmod g-w konyvtar
% ls -dl konyvtar
drwxr-x---+ [...] júzer csoport [...] konyvtar
% getfacl --omit-header konyvtar
user::rwx
user:bob:rwx            #az érvényesülő jogok:r-x
group::r--
mask::r-x
other::---

Ezen a példán látható a mask hatása: maszkolja a Bob felhasználó egyes jogait. Ha a chmod-dal visszaadnánk az írási jogot, akkor csak a Bob felhasználó tudná újra írni a könyvtárat, tehát a tulajdonoscsoport jogait ez nem érintené.

4 Alapértelmezett ACL

A hozzáférési ACL-eken túlmenően ún. alapértelmezett ACL-eket is használhatunk. Ha egy könyvtárhoz tartozik alapértelmezett ACL, akkor az adott könyvtárban újonnan létrehozott valamennyi fájlrendszer-objektum hozzáférési ACL-ként ezt az alapértelmezett ACL-t örökli (az új alkönyvtárak alapértelmezett ACL-ként is).

Új fájlrendszer-objektum létrehozásakor, ha a szülőkönyvtárnak van alapértelmezett ACL-je, az alábbi történik:

  • Az új objektum hozzáférési ACL-ként megkapja a szülőkönyvtár alapértelmezett ACL-jét.
  • Ezután a maszkot kivéve az összes ACL-bejegyzésből törlődik minden olyan bit, amely az objektumot létrehozó rendszerhívásnak átadott mode paraméterben (ami a létrehozandó objektum jogosultságbitjeit tartalmazza) nincs beállítva.
  • Az umask nem jut szerephez!

Lássunk egy példát! A setfacl paranccsal kétféleképpen is beállíthatunk default ACL-t; az alábbi két parancssor ekvivalens:

 
setfacl -d -m g:csoport2:r-x konyvtar
setfacl -m d:g:csoport2:r-x konyvtar

(Linuxon az r-x helyett írhatunk csak simán rx-et is, de pl. Solarison nem: ott mindig pontosan három karakterrel kell megadnunk a jogosultságbiteket.)

A második forma előnye akkor mutatkozik meg, ha egyszerre akarunk hozzáférési és alapértelmezett ACL-t is létrehozni; a setfacl -m után ugyanis vesszővel elválasztva több ACL-elemet is felsorolhatunk, és a második szintaxis lehetővé teszi az alapértelmezett és a hozzáférési ACL-ek keverését, míg az első nem.

Nézzük meg, mit csináltunk!

getfacl konyvtar
# file: konyvtar
# owner: júzer
# group: csoport
user::rwx
user:bob:rwx
group::r-x
mask::rwx
other::---
default:user::rwx
default:group::r-x
default:group:csoport2:r-x
default:mask::r-x
default:other::---

A default ACL megjelenítésével és működésével kapcsolatban vannak különbségek az egyes implementációk között; pl. elképzelhető, hogy a default ACL-t csak akkor látjuk, ha -d kapcsolóval hívjuk meg a getfacl. Azt is vegyük észre, hogy a Linux automatikusan létrehozott a hozzáférési ACL alapján néhány alapértelmezett ACL-bejegyzést; ez sem feltétlenül történik ugyanígy minden más oprendszeren.

Hozzunk most létre egy alkönyvtárat az mkdir paranccsal! Az mkdir(1) program 0777-es mode paraméterrel hívja meg az mkdir() rendszerhívást. Lássuk, milyen ACL-t kap az uj alkönyvtár:

mkdir konyvtar/alkonyvtar
getfacl konyvtar/alkonyvtar
# file: konyvtar/alkonyvtar
# owner: júzer
# group: csoport
user::rwx
group::r-x
group:csoport2:r-x
mask::r-x
other::---
default:user::rwx
default:group::r-x
default:group:csoport2:r-x
default:mask::r-x
default:other::---

Látható, hogy az új könyvtár az ACL-t mint hozzáférési és alapértelmezett ACL-t is örökölte.

5 Alkalmazási példák

Tegyük fel, hogy van egy SSL-kulcsunk. Nem szeretnénk, hogy bárki elolvashassa, kivéve a webszervert. A webszerver a www-data nevű felhasználó jogaival fut. Ha a www-data felhasználó tulajdonába helyezzük a fájlt, akkor ő el tudja rajta állítani a jogokat is, amit nem szeretnénk; ACL-lel viszont megoldhatjuk, hogy a root tulajdonában maradjon, de a www-data is el tudja olvasni a tartalmát anélkül, hogy a jogokat elállíthatná. ACL nélküli megoldás is van: legyen saját csoportja a www-data usernek, és birtokolja ez a csoport az SSL-kulcsot. Ha csak a csoportnak van rá olvasási joga, akkor nem tudja elállítani a jogokat.

Ha víruskeresőt futtatunk a bejövő leveleken, általában különböző felhasználóként fut a levelezőszerver és a víruskereső. Azt szeretnénk, ha a levelezőszerver által létrehozott fájlok a víruskereső számára is olvashatóak lennének, de senki más számára nem lennének olvashatóak. Megtehetjük, hogy egy olyan könyvtárba tesszük ezeket a fájlokat, amelyen olyan alapértelmezett ACL van, amely a víruskeresős felhasználónak olvasási jogot biztosít. ACL nélkül megoldás: helyezzük közös csoportba ezt a két felhasználót, és az adott könyvtár legyen ennek a csoportnak a tulajdona, valamint setgid-es. Az is szükséges, hogy a levelezőszerver umaskja megfelelő legyen, tehát ne maszkolja ki a csoport olvasási jogát.

Személyes eszközök