Naturalnym sposobem rozszerzenia tradycyjnego modelu uprawnień uniksowych jest uzupełnienie go o dodatkowe klasy (oprócz właściciela, grupy i innych) oraz umożliwienie nadawania uprawnień tym klasom. To podejście, zwane Listami Kontroli Dostępu (ACL - Access Control Lists) wymyślono już dość dawno, a nawet próbowano włączyć do standardu POSIX (Portable Operating System Interface), ale odpowiednie propozycje standardu (POSIX 1003.1e i POSIX 1003.2c) zostały odrzucone. Bazuje jednak na nich większość implementacji w popularnych systemach uniksowych i dlatego czasami nazywa się je POSIX ACLami.
Podczas projektowania ACLi przyjęto założenie, że muszą one być przeźroczyste dla starszych programów (które nie wiedzą o ich istnieniu). Dlatego zdefiniowano możliwość przekształceń (w obie strony) - zwanych mapowaniem - pomiędzy standardowymi uprawnieniami a ACLami.
ACL to lista składająca się z wpisów.
Każdy wpis zawiera klasę oraz uprawnienia nadane użytkownikom kwalifikującym się do tej klasy.
Uprawnienia są identyczne ze standardowymi (rwx
), jest natomiast więcej klas.
Typ wpisu ACL | Zapis typu |
---|---|
Minimalny ACL | |
właściciel | user::rwx |
grupa właściciela | group::rwx |
inni | other::rwx |
Rozszerzony ACL | |
użytkownik nazwany | user:nazwa:rwx |
grupa nazwana | group:nazwa:rwx |
maska | mask::rwx |
Każdy plik posiada minimalny ACL (jest on identyczny z tradycyjnymi uprawnieniami stąd jego przekształcenie na tradycyjny system i z powrotem jest trywialne). Problem pojawia się, gdy jakiś plik posiada również (dodatkowo) wpis dla jakiegoś nazwanego użytkownika lub grupy (czyli gdy mamy do czynienia z rozszerzonym ACLem). Wtedy musi również posiadać wpis maski i właśnie ten wpis jest mapowany na klasę grupy w tradycyjnym modelu uprawnień. Można powiedzieć, że wpis maski jest górnym limitem ustawień rozszerzonego ACLa (prawa wpisów rozszerzonego ACLa oraz grupy właściciela mają znaczenie tylko wtedy, gdy odpowiednie prawa są ustawione również w masce; w przeciwnym przypadku są ignorowane). Pozostałe uprawnienia (właściciela i innych) mapowane są tak jak w przypadku minimalnego ACLa. Zostały również zdefiniowane algorytmy umożliwiające (dzięki masce) współdzielenie (z minimalnymi problemami) plików przez programy rozumiejące i nierozumiejące ACLi (dodawanie uprawnień dla grupy zgodnie z tradycyjnym modelem powoduje ustawienie odpowiednich bitów w masce, odebranie uprawnień powoduje wyzerowanie tych bitów zarówno w masce jak i we wpisie grupy właściciela).
Wprowadzono także pojęcie domyślnego ACLa (dla katalogów).
Jeżeli katalog posiada takiego ACLa, to tworzony w nim plik otrzymuje te wpisy (modulo umask
i parametr mode
w wywołaniu systemowym tworzącym plik).
Tworzony w nim podkatalog dodatkowo ustawia te wpisy jako własny domyślny ACL.
Oto krótki przykład odczytywania i ustawiania ACLa:
$ ls -al razem 27 drwxr-xr-x 2 kangur users 1024 sty 17 02:50 . drwxr-xr-x 128 kangur users 25600 sty 17 02:47 .. $ touch test $ ls -al razem 27 drwxr-xr-x 2 kangur users 1024 sty 17 02:50 . drwxr-xr-x 128 kangur users 25600 sty 17 02:47 .. -rw-r--r-- 1 kangur users 0 sty 17 02:50 test $ getfacl test # file: test # owner: kangur # group: users user::rw- group::r-- other::r-- $ setfacl -m group:wheel:rwx test $ ls -al razem 28 drwxr-xr-x 2 kangur users 1024 sty 17 02:47 . drwxr-xr-x 128 kangur users 25600 sty 17 02:47 .. -rw-rwxr--+ 1 kangur users 0 sty 17 02:47 test $ getfacl test # file: test # owner: kangur # group: users user::rw- group::r-- group:wheel:rwx mask::rwx other::r--
W czasie kontroli dostępu wpisy ACL sprawdzane są w następującej kolejności: właściciel, nazwany użytkownik, grupa, nazwana grupa, inni (uprawnienia klas rozszerzonego ACLa i grupy są oczywiście najpierw mnożone logicznie z maską). Przywileje nie akumulują się. Wystarczy, że proces pasuje chociaż do jednego wpisu dającego mu dostęp. Jeżeli nie istnieje żaden wpis pasujący do procesu i dający mu żądany dostęp kontrola nie powiedzie się.
Dość ciekawy jest także sposób implementacji ACLi w konkretnych systemach plików.
Ogólnie ACLe są przechowywane w Rozszerzonych Atrybutach (EA - Extended Attributes) ale szczególy są bardzo różne.
Omówię je pokrótce na przykładzie kilku linuksowych systemów plików (w jądrze 2.6 - wcześniejsze nia miały ACLi
domyślnie i trzeba było stosować łatki).
W systemach plików Ext2 i Ext3 ACLe trzymane są w osobnym bloku wskazywanym przez pole w i-węźle.
Jeżeli kilka i-węzłów ma dokładnie te same atrybuty to mogą wskazywać na ten sam blok.
Gdy atrybuty jednego z i-węzłów są zmieniane, to używany jest mechanizm COW (Copy On Write - kopiowanie przy zapisie)
chyba, że uda się znależć inny, istniejący już blok, który pasuje do nowych atrybutów.
Identyczne bloki szukane są z wykorzystaniem funkcji skrótu.
Wszystkie atrybuty rozszerzone danego i-węzła mogą zajmować najwyżej jeden blok.
Ostatnio na LKML pojawiły się łatki powiekszające i-węzeł i pozwalające trzymać w nim część atrybutów, co znacznie
poprawia wydajność testów typu dbench
udających operacje eksperymentalnej wersji demona Samby,
który używa ACLi do trzymania uprawnień serwowanych plików systemu Windows.
Z kolei JFS trzyma rozszerzone atrybuty w i-węźle i następujących po nim blokach (zwanych ekstentem).
Niestety JFS nie umożliwia dzielenia atrybutów pomiędzy i-węzłami.
Najbardziej skomplikowane podejście zastosowano w przypadku XFSa.
Istnieje tam trzystopniowy system przechowywania atrybutów: najpierw w i-węźle, większe w liściach B+drzewa,
a największe w pełnym B+drzewie.
Jest to bardzo podobne do sposobu przechowywania katalogów, chociaż rzadko zdarza się by pojedynczy i-węzeł
miał aż tak dużo atrybutów.
Niestety XFS również nie umożliwia dzielenia atrybutów.
Zupełnie inne rozwiązanie zostało zastosowane w ReiserFSie.
Hans Reiser nie jest zadowolony z grzebania w stabilnej wersji swojego systemu plików a do tego był zajęty
zaawansowanymi pracami nad Reiser4.
Jednak presja ze strony (przede wszystkim) SUSE (które oferuje ReiserFS jako domyślny system plików) była tak duża,
że implementację EA i ACLi dodali właśnie deweloperzy kernela pracujący dla SUSE (głównie Chris Mason i Jeff Mahoney).
Zrobili to jednak w bardzo ciekawy sposób.
Dodali oni (domyślnie ukryty) katalog, w którym dla każdego i-węzła tworzony jest podkatalog z plikami o nazwie
takiej jak nazwa atrybutu i zawartości równej treści tego atrybutu.
Jest to efektywne ponieważ ReiserFS umożliwia łączenie małych plików w jeden blok dyskowy (kosztem nieznacznie
większego użycia procesora) - opcja notail
.
Przy tym podejściu potencjalnie łatwo można zaimplementować dzielenie na poziomie poszczególnych atrybutów a nie na
poziomie bloków, jednak nie zostało to dotychczas zrobione.
ACLe niewątpliwie uzupełniają braki w tradycyjnym modelu uprawnień. Pozwalają wreszcie w sposób prosty i przyjazny, nawet dla początkującego użytkownika, zarządzać uprawnieniami dostępu do plików. Umożliwiają również integrację z innymi systemami operacyjnymi (na przykład poprzez Sambę z Windowsami z serii NT, które ACLe - niestety według innego modelu - miały już od dłuższego czasu). Pozwalają uprawnienia opisywać dokładniej - dzięki temu nie trzeba nadawać za dużych uprawnień, co może podnieść bezpieczeństwo systemu. Są one także dość przenośne - większość systemów operacyjnych posiada jakąś implementację ACLi.
Niestety mają również poważne wady.
Po pierwsze wymagają poprawnienia niektórych istniejących aplikacji.
Przyładem mogą być edytory.
Zapisując plik pod inną nazwą edytor zgubiłby ACLe co skutkowałoby pozostawieniem trochę większych niż normalnie
uprawnień do pliku (ponieważ wpis maski mapowany na pole uprawnień grupy to górny limit uprawnień rozszerzonych
ACLi i grupy właściciela).
Niestety, dobre edytory zapisując plik tworzą najpierw plik tymczasowy a dopiero po powodzeniu operacji
zapisu zamieniają te pliki, stąd całkiem prawdopodobne, że edytor zgubiłby ACLe również dla aktualizowanych plików.
ACLe mogą także powodować bardzo dziwne i trudne do wykrycia błędy ponieważ część skryptów usiłuje parsować
wyjście komendy ls
i gubi się na dodanym znaku +
świadczącym o obecności rozszerzonych
ACLi dla danego pliku.
Także wiele aplikacji systemowych ma wciąż problemy z ACLami.
Wprawdzie nowe wersje coreutils (czyli programy typu cp
, mv
i podobne) posiadają już
wsparcie dla ACLi, ale wciąż nie zostało ono dodane chociażby do programów archiwizujących.
Jedynie star
pozwala zachowywać część rozszerzonych atrybutów, ale już na przykład do tak popularnego
i powszechnie stosowanego tar
a wsparcie to nie może być dodane ponieważ format plików tar
jest zdefiniowany w standardach (na przykład POSIX) i nie może być łatwo zmieniony.
Są również kłopoty z ACLami i NFSem - nawet w najnowszym, eksperymentalnym NFS4, który definiuje wreszcie ACLe,
ale według modelu bardziej podobnego do Windowsów niż Uniksów (a przekształcenia są w tym przypadku problematyczne).
Do tego ACLe (głównie z powodu prób zachowania zgodności z tradycyjnymi uprawnieniami) komplikują niepotrzebnie
tak prosty i naturalny tradycyjny model uprawnień.
Jest to częsta odpowiedź administratorów na pytanie dlaczego w danym systemie nie umożliwią korzystania z ACLi.