Listy kontroli dostępu

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.

Budowa ACLi

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 ACLZapis typu
Minimalny ACL
właścicieluser::rwx
grupa właścicielagroup::rwx
inniother::rwx
Rozszerzony ACL
użytkownik nazwanyuser:nazwa:rwx
grupa nazwanagroup:nazwa:rwx
maskamask::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.

Przykład korzystania z ACLi

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--

Kontrola dostępu

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ę.

Implementacja ACLi

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.

Zalety i wady ACLi

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 tara 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.

Prezentacja na Systemy Operacyjne 2004/2005 - Informatyka MIMUW.
Grzegorz Kulewski (O nas)