PNIAM "jak wol krowie w rowie" mam nadzieje ;-)

Grzegorz Stanislawski stangrze w open.net.pl
Pon, 1 Lut 1999, 19:31:58 CET


Witam
 Nawet mi to szybko poszlo, choc pewnie jest tu kupa bledow.
 Wlozylem to tez do CVS'a.
 Mam nadzieje, ze nie jest zbyt patetycznie ;-).

Grzegorz Stanislawski
Open-Net / PKFL

-----------------------------------------------------------------
Wprowadzenie do PNIAM (Pluggable Non Interactive Autentication Modules)
Grzegorz Stanisławski <stangrze w open.net.pl>

PNIAM jest biblioteką i zestawem dynamicznie ładowanych modułów, których
zadaniem jest najkrócej mówiąc autentykacja i autoryzacja użytkownika.
PNIAM powstało na bazie doświadczeń zdobytych podczas implementacji PAM
i głowną zadaniem tej biblioteki, jest dostarczenie podobnej a nawet
wieększej funkcjonalności oraz usunięcie wad, które zostały odkryte w
PAM'ie.
 
Definicje.

 Autentykacja - jest to procedura mająca na celu znalezienie odpowiedzi
czy użytkownik jest rzeczywiscie tym za kogo się podaje. Zwykle
autentykacja sprowadza sie do przedstawienia się użyktownika przy pomocy
unikatowej nazwy (login) oraz uwiarygodnienie się przy pomocy
odpowiedniego hasła, choć bardziej zaawansowane systemy mogą kożystać z
innych danych jak np. odcisk palca ;-)
 Autoryzacja - Odpowiedz na pytanie czy użytkownik, przeważnie już
zweryfikowany przez procedure autentykacji, może uzyskać dostęp do
aplikacji/zasobu, którego żąda oraz dostarczenie aplikacji danych o
użytkowniku.

 Po co.

Jedną z głównych wad jakie wytykano PAM'owi było nie dotykanie problemu  
autoryzacji poza kwestią dostępu do zasobów. Dane o użytkowniku zarówno
aplikacja jak i same moduły musiały znajdować sobie na własną ręke,
najczęsciej przeszukując odpowiednimi funkcjami glibc'a pliki
/etc/{passwd|shadow}. Mechanizm wbudowany w glibc umożliwiał wprawdzie
dostanie sie do tych danych również jesli były one w bazie NIS, jednak
inne bazy danych były niedostępne.
Próbą rozwiązania tego problemy było pojawienie sie biblioteki pwdb,
której zadaniem była autoryzacja i to tylko w kwestii dostarczania danych.
Pwdb jednak nigdy nie rozwinęło się poza zastąpienie funkcjonalności
oferowanej już przez glibc (nss_switch). W dodatku, konstrukcja samego
PAM'a powodowała że dane dostarczone przez pwdb modułowi pam_pwdb ginęły
po zakończeniu każdego stadium autentykacji. W efekcie plik /etc/passwd
był przeszukiwany przez moduł pam_pwdb cztery razy, nie licząc kolejnych
wykonywanych już przez samą aplikacje, która musiała jakoś te dane
uzyskać i najczęsciej robiła to przy pomocy funkcji oferowanych przez
glibc.
 Kolejną wadą PAM'a była jego interaktywność, Moduły miały prawo same
komunikować się z użytkownikiem, co w wielu przypadkach prowadziło do
problemów. Problem ten dało się w prawdzie omijać ale nie było to spójne
ani odporne na ewentualne komplikacje rozwiązanie (partrz PAM w sambie).
 Bylo tego więcej ale akurat nie pamiętam ;-)

Jak działa pniam.

 Pniam obsługuje zarówno autentykacje jak i autoryzacje.
 Całą procedure udostępniania zasobu wykonuje się przy pomocy czterech
funkcji realzujących kolejno autentykację, autoryzację, otwarcie i
zamknięcie sesji oraz jednej struktury danych, co umożliwia współprace z
bazami danych w których autoryzacja i autentykacja są realizowane podczas
jednego wywołania np. RADIUS. Odpowiednia tablica jest wypełniana danymi
potrzebnymi do autoryzacji już podczas autentykacji, dane te czekają
następnie na "swój moment".
 Komunikacja pomiędzy aplikacją a biblioteką, czy bardziej dokładnie
odpowiednim modułem, odbywaq się w następujący sposób.
 Aplikacja podaje, jakie dane o użytkowniku ją interesują. Zwykle będą to:
 UID, GID, GROUPS, GECOS, SHELL i HOME, oraz jakie dane jest w stanie sama
dostarczyc. Przeważnie USER(name) PLAIN_PASSWORD, TTY lub RHOST.
 Jesli je już zna może je do struktury wprowadzić (np, gdy jest
uruchamiana nieinteraktywnie i dane te były przekazane w wierszu
polecenia)
 Uruchamia procedure autentykacji z biblioteki, która przeglądając
plik konfiguracyjny uruchamia odpowiednie moduły. Moduly na podstawie tych
danych weryfikują użytkownika, zwracając PNIAM_OK, PNIAM_FAIL, 
PNIAM_IGNORE lub PNIAM_AGAIN odpowiednio w przypadku sukcesu, porażki,
braku możliwości podjęcia takiej decyzji (ewentualnie modułowi może byc
wszystko jedno) lub w razie jakiś dodatkowych pytań.
 W ostatnim przypadku, struktura danych PNIAM'a zawiera dodatkowe pytania,
na które aplikacja powinna udzielić odpowiedzi (struktura zawiera również
domyślny prompt którym można się zapytać użytkownika o tę daną), lub jeśli
nie jest wstanie tego zrobić (np. nieinteraktywne działanie) zaznaczyć
jako niedostępne. Kolejne wywołanie funkcji autentykującej powinno, o le
nie pojawią się nowe pytania zakończyć sukcesem bądź porażką.
Biblioteka sprawdza kody zwracane przez moduły i zwraca PNIAM_OK jeżeli
wystąpiły same PNIAM_OK lub PNIAM_IGNORE, oraz PNIAM_FAIL jesli pojawiło
się choć jedno PNIAM_FAIL bądź same PNIAM_IGNORE.
 Podobnie wygląda procedura autoryzacji z tym, że biblioteka dba aby
wszyskie dane, które "chciała" aplikacja a których nie oznaczyła
jako PNIAM_ITEM_OPTIONAL zostały dostarczone.
 
Funkcje otwarcia i zamknięcia sesji dotyczą tylko zbierania danych na
temat wykorzystania aplikacji/zasobu i jak narazie nie istnieje moduł
który by to realizował więc pozwole sobie je pominąć.

Zmiania danych w bazie.

 Pniam ma również funkcję do zmiany danych przechowywanych w bazach,
jednak nie jest ona jeszcze do końca zdefiniowana.

Struktura danych PNIAM'a.

 Pisalem powyżej o strukturze wykożysywaniej przez PNIAM. Oto ona:

typedef struct pniam_request {
        pniam_item_list_t *input;
        pniam_item_list_t *ok_replies;
        pniam_item_list_t *prompts;
    pniam_item_list_t *fail_replies;
        void  **priv_data[0];
} pniam_request_t;

Pierwszy element rekordu (input) to lista danych, które aplikacja może
dostarczyć. 
Drugi (ok_replies), zawiera listę danych o które aplikacja pyta, wtedy
wartośc pola value (patrz niżej) ma mieć wartość NULL, lub które zostały
dostarczone przez moduły, wtedy pole value zawiera odpowiednią wartość.
fail_replies zawiera te, których nie udało się modułom znaleśc w swoich
bazach danych.
Pole prompts zawiera dane które aplikacja powinna jeszcze dostarczyc.
(to w przypadku kiedy funkcja pniam_authenticte() lub pniam_authorize()
zwróciły PNIAM_AGAIN)

Dane w wyżej wymienionych polach są przechowywanie w formie "typu
słownikowego", jako dynamiczna lista (właściwie dwukierunkowa 
kolejka) następujących rekordów:

typedef struct pniam_item {
                const char *name; /* zero-terminated string*/
                unsigned char *data;
                int len; /*data length */
                unsigned int flags;
                /* Supplementary data */
                struct pniam_item *prev;
                struct pniam_item *next;
} pniam_item_t;

Odpowieni zestaw funkcji pozwala na dodawanie i usuwanie elementów tej
listy oraz jej przeszukiwanie. Przeszukiwanie odbywa się przy pomocy
nazwy danej - klucza przechowywanego w polu name.
Funkcjonalnie jest to "tablica indeksowana stringiem" czyli "typ
słownikowy"

Prototypy funkcji:
void          pniam_item_list_push(pniam_item_list_t **,pniam_item_t *);
void          pniam_item_list_pop(pniam_item_list_t **,pniam_item_t *);
pniam_item_t  *pniam_item_list_getfirst(pniam_item_list_t *);
pniam_result_t pniam_item_add2list(pniam_item_list_t **,const char *,
                                   unsigned char *, int, unsigned int);

pniam_item_t  *pniam_item_list_getnext(pniam_item_list_t *,pniam_item_t *);
/*                 return NULL if data is unavailable                   */
pniam_item_t  *pniam_item_list_find(pniam_item_list_t *,const char *key);
/* key is the name field of pniam_item struct                           */
void pniam_item_list_delitem(pniam_item_list_t **,pniam_item_t *);
/* Remove item from list and free item memory                           */

pniam_result_t pniam_start(const char *appname, struct pniam_handle **);
pniam_result_t pniam_create_request(struct pniam_handle *,pniam_request_t **);
void           pniam_destroy_request(struct pniam_handle *,pniam_request_t *,
		   unsigned int flags);
pniam_result_t pniam_end(struct pniam_handle *);
pniam_result_t pniam_authenticate(struct pniam_handle *, struct pniam_request *);
pniam_result_t pniam_authorize(struct pniam_handle *, struct pniam_request *);
pniam_result_t pniam_account_start(struct pniam_handle *, struct pniam_request *);
pniam_result_t pniam_account_end(struct pniam_handle *, struct pniam_request *);
pniam_result_t pniam_change(struct pniam_handle *, struct pniam_request *);


Skąd ściągnąć.

 Primary site:	ftp://ftp.nc.orc.ru/pub/Linux/pniam/pniam-0.02.tgz
 
 Nieoficjaly "mirror" oraz mój patch:	ftp://stardust.open.net.pl/pub/stangrze/pniam
 (moduł pniam_rootok oraz funkcja pniam_dump_request):
 
 Dokumentacja:	http://www.msu.ru/pniam/pniam.html




Więcej informacji o liście dyskusyjnej pld-devel-pl