Laboratorium 3 i 4: pam, sudo

strict warning: Only variables should be passed by reference in /usr/share/drupal6/modules/book/book.module on line 559.

Plugawe Autoryzacji Moduły: modularne systemy autoryzacji w Linuksie

Cel: umożliwienie elastycznej kontroli dostępu do systemu i programów przez wprowadzenie możliwości definiowania własnych modułów dostępu.

Rozwiązanie: ładowalne moduły autoryzacji (Pluggable Authorization Modules, PAM), popularnie zwane wtyczkami, zawierające specjalizowane metody identyfikacji (np. RIPEMD-160, SHA, linie papilarne). Oprócz autoryzacji mają dodatkowe możliwości, takie jak nakładanie dodatkowych ograniczeń (np. na liczbę jednoczesnych loginów).

Dla danej aplikacji administrator ustala (plikiem konfiguracyjnym), które z nich mają być użyte.


3 poziomy:

1. Programista aplikacji:

umieszcza w programie (np. /bin/login) odpowiednie wywołania funkcji dla ładowalnych modułów autoryzacji (no i linkuje program z odpowiednią biblioteką).

2. Programista modułów:

pisze ładowalne moduły autoryzacji zawierające specjalizowane metody identyfikacji (np. RIPEMD-160, SHA, linie papilarne), które będą używane w aplikacjach.

3. Administrator:

instaluje i modyfikuje pliki konfiguracyjne dla aplikacji i modułów autoryzacji (i zapewne także instaluje moduły w systemie).

Na co dzień najbardziej istotny jest poziom 3.


Struktura systemu PAM dzieli się na 4 w miarę niezależne grupy zarządzania (zwane też typami):

- auth: zarządzanie autoryzacją i identyfikacją,

- account: zarządzanie kontami. Określanie, czy użytkownik ma prawo dostępu do danej usługi itp.

- session: zarządzanie sesjami (np. limity),

- password: zarządzanie aktualizacją żetonów identyfikujących (np. haseł).

Niektóre programy, np. login, potrzebują usług z wszystkich czterech grup. Inne, takie jak passwd, mogą korzystać tylko z wybranych grup.


Każda aplikacja chcąca używać PAM ma plik konfiguracyjny zawierający listę modułów dla procesu uwierzytelniania. Nazwa pliku nie musi być zgodna z nazwą aplikacji, często na początek używa się ,,cudzych'' sprawdzonych plików.

Pliki te znajdują się w katalogu /etc/pam.d (w starych wersjach mógł być jeden wspólny plik /etc/pam.conf, obecnie jest on używany tylko gdy brak katalogu /etc/pam.d), na przykład dla /bin/login login plikiem tym będzie /etc/pam.d/login.

Plik konfiguracyjny o nazwie other zawiera wartości domyślne (zwykle zabrania wszystkiego). Są w nim tylko odwołania do modułu pam_deny, ewentualnie poprzedzone przez odwołaniami do pam_warn. Tego pliku używa się (również jako początkowego szablonu) dla services bez własnych plików konfiguracyjnych (oczywiście gdy używają PAM).

Moduł pam_deny po prostu odmawia dostępu (zawsze zwraca niepowodzenie).
Moduł pam_warn rejestruje w syslogu informacje o wykonywanej operacji.

Inny popularny plik używany powszechnie to login.

Wpisy mają postać:

<grupa>  <kategoria>  <moduł> [<argumenty>]

np.

auth     required     pam_securetty.so
auth     required     pam_unix.so

gdzie <kategoria> to jedna z wartości:

- requisite niepowodzenie natychmiast wraca do aplikacji z błędem,
- required każdy taki moduł musi zwrócić sukces,
- sufficient sukces takiego modułu i wszystkich jego poprzedników, powoduje zwrócenie sukcesu do aplikacji (niepowodzenie jest ignorowane),
- optional ,,ozdobnik'' bez wpływu na sukces lub niepowodzenie.

albo ,,pseudokategoria'':

- include,
- substack.

Uwaga: dawniej zamiast pseudokategorii był moduł pam_stack.so --- powodował
dołączenie list z innego podanego pliku (zwykle system-auth). Można natknąć
się na takie przykłady w Internecie.

Ostatnio w PAM wprowadzono kategorie złożone, zapisywane w nawiasach
kwadratowych. Pozwalają uzależnić wybór akcji od konkretnej wartości
zwróconej przez moduł (a nie tylko sukces/porażka). Nie będziemy ich
używać, ale mogą wystąpić w plikach, które będziecie podglądali.

Poszczególne moduły ładowane są kolejno, wiele z nich ma pliki konfiguracyjne zawarte w katalogu /etc/security.


Modułów PAM jest wiele, są one typu open-source, więc można je samodzielnie modyfikować. Można też pisać własne. Technicznie moduł to biblioteka ładowalna dynamicznie przez nazwę (wywołaniem dlopen()).

Trzyma się je standardowo w jakimś katalogu security, np.

/lib/security
/lib64/security
/usr/lib/security
/usr/lib64/security

Zwykle nazwa modułu to pam_cośtam.so, najczęściej działa

man pam_cośtam

Przykłady:

Moduł pam_access zarządza klasycznym logowaniem do systemu lub aplikacji. W celu uaktywnienia modułu pam_access dla aplikacji login należy do jej pliku konfiguracyjnego dodać na końcu grupy account wiersz:

account  required  pam_access.so

Moduł pam_access ma plik sterujący /etc/security/access.conf. Każdy wiersz w nim ma postać

<uprawnienie> : <użytkownicy> : <miejsca>

Uprawnienie to jeden ze znaków + lub -. Nazwy użytkowników można oddzielać spacjami. Miejsce to nazwa komputera, LOCAL oznacza dostęp lokalny.

Do nakładania limitów służy moduł pam_limits:

session  required  pam_limits.so

z plikiem konfiguracyjnym limits.conf. Składnia wierszy:

<dziedzina>  <typ>  <ograniczenie>  <wartość>

gdzie <dziedzina> określa użytkowników lub grupy, <typ> to hard lub soft, zaś <ograniczenie> to np. fsize lub nproc. Aby pozwolić użytkownikowi guest tylko na jednokrotne logowanie, należy tam wpisać

guest  hard  maxlogins  1

Moduł pam_securetty ogranicza do konsoli możliwość logowania się na konto root.

Nie ma ,,kompletnej'' listy modułów. W dokumentacji administratora
wymienione są te, które w danym momencie przychodzą z pakietem.
Ta lista się zmienia :-(żółw się rusza).

Poniżej częściowy wykaz:

pam_access: zobacz wyżej.

pam_cracklib: sprawdza jakość hasła ze słownikiem.

pam_debug: tylko do testowania.

pam_deny: zobacz wyżej.

pam_echo: wypisuje zawartośc pliku.

pam_env: ustawia zmienne środowiska.

pam_exec: wywołuje zewnętrzne polecenie.

pam_lastlog: odnotowuje czas ostatniego logowania w pliku /var/log/lastlog.

pam_ldap: autoryzacja w oparciu o LDAP server (niestandardowy).

pam_limits: nakłada ograniczenia na zasoby, plik /etc/security/limits.conf.

pam_listfile: alternatywna wersja pam_access.

pam_mail: sprawdza, czy użytkownik ma nową pocztę.

pam_motd: wypisuje "message of the day", zwykle z /etc/motd.

pam_nologin: jeśli istnieje plik /etc/nologin lub /var/run/nologin, to zwraca niepowodzenie, przy okazji wypisując zawartość tego pliku. Dla root'a zawsze OK.

pam_permit: zawsze zwraca sukces.

pam_pwhistory: sprawdza nowe hasło z ostatnio używanymi.

pam_rootok: tylko root, zwykle umieszcany w /etc/pam.d/su jako "sufficient" test, żeby root mógł stawać się zwykłym użytkownikiem bez podawania hasła.

pam_securetty: sprawdza, czy ten użytkownik ma prawo się logować z tego urządzenia. Zagląda do pliku /etc/securetty file --- jest to wyjątek, bo większość plików pomocniczych jest w /etc/security.

pam_shells: wpuszcza tylko, gdy shell użytkownika jest legalny (tz. wymieniony w pliku /etc/shells).

pam_succeed_if: pozwala sprawdzać różne warunki.

pam_tally: prowadzi licznik prób dostępu, odmawia gdy było za dużo.

pam_time: ograniczenie dostępu według reguł z pliku /etc/security/time.conf.

pam_unix: klasyczna autoryzacja UNIXowa (/etc/passwd, /etc/shadow).

pam_warn: zobacz wyżej.

pam_wheel: uprawnienia roota tylko dla członków grupy wheel.

Przykład pliku konfiguracyjnego /etc/pam.d/su dla programu su

auth		sufficient	pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth		sufficient	pam_wheel.so trust use_uid
# Uncomment the following line to require a user to be in the "wheel" group.
#auth		required	pam_wheel.so use_uid
auth		substack	system-auth
auth		include		postlogin
account		sufficient	pam_succeed_if.so uid = 0 use_uid quiet
account		include		system-auth
password	include		system-auth
session		include		system-auth
session		include		postlogin
session		optional	pam_xauth.so

PAM można używać również we własnych aplikacjach. Popatrzmy na przykład

#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
 
static struct pam_conv login_conv = {
  misc_conv,               /* przykładowa funkcja konwersacji z libpam_misc */
  NULL                        /* ewentualne dane aplikacji (,,domknięcie'') */
};
 
void main () {
  pam_handle_t* pamh = NULL;
  int retval;
  char *username = NULL;
 
  retval = pam_start("login", username, &login_conv, &pamh);
  if (pamh == NULL || retval != PAM_SUCCESS) {
    fprintf(stderr, "Error when starting: %d\n", retval);
    exit(1);
  }
 
  retval = pam_authenticate(pamh, 0);  /* próba autoryzacji */
  if (retval != PAM_SUCCESS) {
    fprintf(stderr, "Chyba się nie udało!\n");
    exit(2);
  }
  else
    fprintf(stderr, "Świetnie Ci poszło.\n");
 
  printf("OK\n");  /* rzekomy kod aplikacji */
 
  pam_end(pamh, PAM_SUCCESS);
  exit(0);
}

Po wywołaniu pam_start zmienna pam będzie zawierać dowiązanie do obiektu PAM, który będzie argumentem wszystkich kolejnych wywołań funkcji PAM.

Zmienna pam_conv to struktura zawierająca informacje o funkcji do konwersacji z użytkownikiem -- tu użyliśmy najprostszej bibliotecznej funkcji
misc_conv, można jednak użyć własnej.

Pierwszy argument funkcji pam_start to nazwa aplikacji, potrzebna do
odnalezienia pliku konfiguracyjnego. Żeby nie trzeba było go pisać i instalować (wymaga uprawnień roota) można użyć nazwy innej już skonfigurowanej aplikacji (tutaj login) -- będziemy mieć takie same reguły. Lepiej jednak mieć własną nazwę (np. "moje"), wtedy w katalogu /etc/pam.d powinien istnieć plik o tej nazwie (np. kopia pliku "login"). Pozwoli to używać nazwy tej aplikacji w plikach konfiguracyjnych w /etc/security.

Funkcja pam_authenticate uruchamia ,,motor'' sprawdzania PAM -- usługę auth. Dla pozostałych usług/grup istnieją analogiczne funkcje, szczegóły w podręczniku. Funkcja pam_end po prostu kończy sesję.

Przy kompilacji i linkowaniu należy pamiętać o bibliotekach libpam i
libpam_misc, np.

gcc -o tescik tescik.c -lpam -lpam_misc

Podstawowa biblioteka libpam zawsze jest zainstalowana (w /lib lub /usr/lib), nawet nie warto sprawdzać. Trzeba zapewne doładować ,,development''. Na RedHatopodobnych systemach to pakiet pam-devel, w Debianie (czyli w laboratorium) to libpam0g-dev. Można też załadować libpam-doc jeśli nie ma. W naszej pracowni

apt-get install libpam0g-dev

Trzy podstawowe procedury autentykacji w PAM to:

1. pam_start(): funkcja PAM która powinna być wywołana na początku. Inicjalizuje bibliotekę PAM, czyta plik konfiguracyjny i ładuje potrzebne moduły autentykacji w kolejności podanej w pliku konfiguracyjnym. Zwraca referencję do biblioteki PAM, której należy używać w następnych wywołaniach.

2. pam_end(): ostatnia funkcja PAM, którą powinna wołać aplikacja. Po jej zakończeniu jesteśmy odłączeni od PAM, a cała pamięć PAM zwolniona.

3. pam_authenticate(): interfejs do mechanizmu autoryzacji załadowanych modułów. Wołana przez aplikację najczęśćiej na początku, żeby zidentyfikować użytkownika.

Inne pożyteczne procedury PAM to:

- pam_acct_mgmt(): sprawdza czy konto bieżącego użytkownika jest aktywne.

- pam_open_session(): rozpoczyna sesję.

- pam_close_session(): zamyka bieżącą sesję.

- pam_setcred(): zarządza tokenami uwierzytelniającymi.

- pam_chauthtok(): zmienia żeton identyfikacji (zapewne hasło).

- pam_set_item(): modyfikuje wpis w strukturze stanu PAM.

- pam_get_item(): pobiera podany element stanu PAM.

- pam_strerror(): zwraca komunikat dla błędu.

Nagłówki tych procedur są w security/pam_appl.h.

Funkcja konwersacji obsługuje współpracę modułu z aplikacją, dotarczając
modułowi metody odpytywania uż←tkownika o nazwę, hasło itp.
Jej sygnatura to:

int conv_func (int, const struct pam_message**,
               struct pam_response**, void*);

Zwykle używa się bibliotecznej funkcji misc_conv.


Materiały:

Główne strona projektu to http://www.linux-pam.org/. Zawiera dokumentację i link do repozytorium kodu, m.in. A.G. Morgan, T. Kukuk ,,The Linux-PAM System Administrators' Guide''

Andrew G. Morgan ,,Pluggable Authentication Modules for Linux'' Linux Journal #44 (12/1997), http://www.linuxjournal.com/article/2120. Artykuł twórcy implementacji dla Linuksa, zawiera m.in. przykład programu używającego PAM.

Stara strona dystrybucyjna wszystkich materiałów dla Linuksa (http://www.kernel.org/pub/linux/libs/pam/) ma obecnie znaczenie historyczne. Ogólnie na sieci jest nieco materiałów przestarzałych, np. z roku 2001. Zostaliście ostrzeżeni!

Można też zajrzeć do http://wazniak.mimuw.edu.pl

A poza tym u nas na stronie SO:
tekst Pani Barbary Domagały

Rozszerzanie i zawężanie uprawnień zwykłych użytkowników w Linuksie

Cele:
- nakładanie ograniczeń na zasoby wykorzystywane przez użytkownika,
- rozszerzanie uprawnień użytkowników, aby mogli wykonywać uprzywilejowane akcje bez znajomości hasła administratora.


1. Nakładanie ograniczeń

Ograniczenia na wykorzystanie zasobów przez użytkowników ustawia administrator. Najlepiej, jeśli robimy to używając PAM (daje on możliwość ustawienia większego repertuaru ograniczeń).

Ustawianiem ograniczeń zajmuje się moduł pam_limits.so --- zwykle jest on wstępnie skonfigurowany i wystarczy do pliku /etc/security/limits.conf wpisać odpowiednie ograniczenia. Wiersze w tym pliku mają postać

<zakres>  <typ>  <zasób>  <wartość>

Zakres podaje, kogo dotyczy ograniczenie, może to być:

- nazwa użytkownika,
- nazwa grupy poprzedzona znakiem @,
- skrót notacyjny * oznaczający wszystkich (poza rootem).

Typ określa, czy ograniczenie jest łagodne (soft), czy surowe (hard). Użytkownicy mogą poleceniem ulimit podwyższać ograniczenia łagodne.

Zasób podaje nazwę ograniczenia, np. fsize to rozmiar pliku, nofiles to liczba otwartych plików, maxlogins to liczba jednoczesnych zalogowań, a nproc to liczba procesów.

Przykład: aby ograniczyć liczbę procesów użytkownika guest, w pliku konfiguracyjnym umieszczamy

guest  soft  nproc  40
guest  hard  nproc  80

Do oglądania i modyfikowania ograniczeń przez użytkowników służy polecenie wewnętrzne shella ulimit, dlatego nie należy czytać

man ulimit

(bo on bywa czasem dziwaczny), lecz poszukać w tym, co daje

man bash

(albo nasz inny ulubiony shell). Na pewno warto użyć

ulimit -a

żeby zobaczyć wszystkie swoje ograniczenia i opcje przestawiające je.


2. Chwilowe rozszerzanie uprawnień użytkowników

Pewne operacje wymagają uprawnień posiadanych tylko przez niektórych użytkowników (np. tylko przez administratora). Jeśli chcemy pozwolić innym na ich wykonywanie (np. sterowanie podsystemem drukowania), to mamy dwie możliwości:

a) Rozdać im hasło roota, aby mogli się nań zalogować (na innego użytkownika można się chwilowo zalogować pisząc

su root

lub

su - root

Ta możliwość wydaje się jednak (przynajmniej większości administratorów) mało atrakcyjna. Można użyć modułu pam_wheel w pliku su i ograniczyć użycie polecenia su tylko do grupy wheel.

b) Na szczęście istnieje polecenie sudo. Nie wymaga ono znajomości hasła roota, lecz jedynie własnego, użytkownik musi jednak być sudoersem.

Informacje o sudoersach znajdują się w pliku konfiguracyjnym /etc/sudoers. Nie powinno się go edytować bezpośrednio, lecz użyć polecenia visudo.

Na początku pliku można umieścić aliasy, zawsze jest dostępny alias ALL. Wiersze w zasadniczej części pliku mają postać

<użytkownik>  <komputer>=(<efektywny-użytkownik>)  <programy>

na przykład

dobo  ALL=(ALL)  ALL

powoduje, że użytkownik dobo ma na wszystkich objętych tym plikiem komputerach wszelkie prawa (ale nie zna hasła roota). Aby ograniczyć to do lokalnego komputera i uprawnień root można napisać

dobo  localhost=  ALL

Można ograniczyć działanie sudo tylko do niektórych poleceń, sudoer może poznać swoje możliwości przez

sudo -l

3. Mechanizm SUID i SGID

Niektóre aplikacje (np. passwd) wymagają uprzywilejowanego dostępu do chronionych zasobów, takich jak pliki. Oczywiście nie ma sensu czynić wszystkich sudoersami. Dlatego plik wykonywalny (czyli program) może mieć ustawiony specjalny bit powodujący, że wykonuje się on z prawami
swojego właściciela lub grupy, a nie tego, kto go uruchomił.

Pliki takie nazywa się SUID (od Set UID) bądź SGID (Set GID). Generalnie mechanizm ten jest niebezpieczny, bo nie jest dostępna zbiorcza informacja o takich programach w naszym systemie (ale polecenie find ,,poleca się łaskawym klientom'').

Ustawianie takiego bitu w programach mających możliwość wykonania dowolnego innego programu (shelle, programy w C wywołujące system(...)) świadczy o dużej wrodzonej życzliwości właściciela programu --- należy go trzymać z dala od administrowania systemem.


Materiały:

man sudo
man sudoers

http://wazniak.mimuw.edu.pl/index.php?title=Bezpiecze%C5%84stwo_system%C...

Zadania ćwiczebne na tempo i dykcję

1. Załóż użytkownika burak.

2. Zabroń mu logowania się kiedyś tam.

3. Pozwól użytkownikowi guest na zdalne logowanie się tylko z sąsiedniego komputera.

4. Ustaw temu użytkownikowi maksymalny rozmiar pliku na <n> kilobajtów.