               Podklyuchaemye Moduli Autentifikacii (PAM)

  Dag-Erling Smo/rgrav

   $FreeBSD: release/8.4.0/ru_RU.KOI8-R/articles/pam/article.xml
   39632 2012-10-01 11:56:00Z gabor $

   Copyright (c) 2001, 2002, 2003 Networks Associates Technology,
   Inc.

   $FreeBSD: release/8.4.0/ru_RU.KOI8-R/articles/pam/article.xml
   39632 2012-10-01 11:56:00Z gabor $

   `Eta stat'ya byla napisana dlya Proekta FreeBSD kompaniyami
   ThinkSec AS i Network Associates Laboratories, Security Research
   Division of Network Associates, Inc. v ramkah rabot po kontraktu
   N66001-01-C-8035 s DARPA/SPAWAR (''CBOSS''), kak chast'
   issledovatel'skoj programmy DARPA CHATS.

   FreeBSD `eto zaregistrirovannaya torgovaya marka FreeBSD
   Foundation.

   Linux `eto zaregistrirovannaya torgovaya marka Linus Torvalds.

   Motif, OSF/1 i UNIX `eto zaregistrirovannye torgovye marki, a IT
   DialTone i The Open Group `eto torgovye marki Open Group v
   Soedinennyh SHtatah i drugih stranah.

   Sun, Sun Microsystems, Java, Java Virtual Machine, JavaServer
   Pages, JDK, JRE, JSP, JVM, Netra, Solaris, StarOffice, Sun Blade,
   Sun Enterprise, Sun Fire, SunOS i Ultra `eto torgovye marki ili
   zaregistrirovannye torgovye marki Sun Microsystems, Inc. v
   Soedinennyh SHtatah i drugih stranah.

   Mnogie iz oboznachenij, ispol'zuemye proizvoditelyami i prodavcami
   dlya oboznacheniya svoih produktov, zayavlyayutsya v kachestve
   torgovyh marok. Kogda takie oboznacheniya poyavlyayutsya v `etom
   dokumente, i Proektu FreeBSD izvestno o torgovoj marke, k
   oboznacheniyu dobavlyaetsya znak ''(TM)'' ili ''(R)''.

   V `etoj stat'e opisyvayutsya principy i mehanizmy, lezhaschie v
   osnove biblioteki Podklyuchaemyh Modulej Autentifikacii (PAM -
   Pluggable Authentication Modules), i rasskazyvaetsya, kak
   nastroit' PAM, kak integrirovat' PAM v prilozheniya i kak
   sozdavat' moduli PAM.

     --------------------------------------------------------------

1. Vvedenie

   Biblioteka Pluggable Authentication Modules (PAM) yavlyaetsya
   obobschionnym API dlya sluzhb, svyazannyh s autentifikaciej,
   kotorye pozvolyayut sistemnomu administratoru dobavlyat' novye
   metody autentifikacii prostoj ustanovkoj novyh modulej PAM, i
   izmenyat' politiku autentifikacii posredstvom redaktirovaniya
   konfiguracionnyh fajlov.

   PAM opisali i razrabotali Vipin Samar i Charlie Lai iz Sun
   Microsystems v 1995 godu, s teh on sil'no ne menyalsya. V 1997
   godu Open Group opublikovala predvaritel'nye specifikacii na
   X/Open Single Sign-on (XSSO), chto standartizovalo API dlya PAM i
   dobavilo rasshireniya dlya odnorazovoj (ili dostatochno
   integrirovannoj) podpisi. Na moment napisaniya `etogo dokumenta
   `eta specifikaciya eschio ne byla prinyata za standart.

   Hotya `eta stat'ya posvyaschena v osnovnom FreeBSD 5.x, v kotoroj
   ispol'zuetsya OpenPAM, ona podojdiot dlya FreeBSD 4.x,
   ispol'zuyuschej Linux-PAM, i drugih operacionnyh sistem, takih,
   kak Linux i Solaris(TM).

     --------------------------------------------------------------

2. Terminy i soglasheniya

  2.1. Opredeleniya

   Terminologiya, ispol'zuemaya v PAM, dostatochno zaputana. Ni
   original'naya rabota Samar i Lai, ni specifikaciya XSSO ne delayut
   nikakih popytok formal'no opredelit' terminy dlya razlichnyh
   ob"ektov i uchastvuyuschih v PAM storon, a terminy, kotorye oni
   ispol'zuyut (no ne opredelyayut) inogda neverny i neodnoznachny.
   Pervoj popytkoj sozdat' nedvusmyslennuyu i soglasovannuyu
   terminologiyu byla rabota, kotoruyu napisal Andrew G. Morgan
   (avtor Linux-PAM) v 1999 godu. Hotya vybor terminologii, kotoruyu
   sdelal Morgan, byl gigantskim skachkom vpered, `eto, po mneniyu
   avtora dannoj stat'i, ne oznachaet ee pravil'nost'. Dalee
   delaetsya popytka, v znachitel'noj stepeni na osnove raboty
   Morgana, dat' tochnye i nedvusmyslennye opredeleniya terminov dlya
   vseh uchastnikov i ob"ektov PAM.

   uchiotnaya zapis' (account)

           Nabor polnomochij, kotorye applikant zaprashivaet ot
           arbitratora.

   applikant (applicant)

           Pol'zovatel' ili ob"ekt, zaprashivayuschie
           autentifikaciyu.

   arbitrator (arbitrator)

           Pol'zovatel' ili ob"ekt, imeyuschij privilegii,
           dostatochnye dlya proverki polnomochij applikanta i prava
           podtverdit' ili otklonit' zapros.

   cepochka (chain)

           Posledovatel'nost' modulej, kotorye budut vyzvany v otvet
           na zapros PAM. V cepochku vklyuchena informaciya o
           posledovatel'nosti vyzovov modulej, argumentah, kotorye
           nuzhno im peredat', i o tom, kak interpretirovat'
           rezul'taty.

   klient (client)

           Prilozhenie, otvechayuschee za iniciirovanie zaprosa na
           autentifikaciyu ot imeni applikanta i poluchayuschee ot
           nego neobhodimuyu dlya autentifikacii informaciyu.

   podsistema (facility)

           Odna iz chetyreh osnovnyh grupp funkcional'nosti, kotorye
           daet PAM: autentifikaciya, upravlenie uchetnymi zapisyami,
           upravlenie seansom i obnovlenie klyuchom autentifikacii.

   modul' (module)

           Nabor iz odnoj ili bol'shego kolichestva svyazannyh
           funkcij, realizuyuschih opredelennuyu podsistemu
           autentifikacii, sobrannyj v odin (obychno dinamicheski
           zagruzhaemyj) dvoichnyj fajl, identificiruemyj po imeni.

   politika (policy)

           Polnyj nabor konfiguracionnyh deklaracij, opisyvayuschih,
           kak obrabatyvat' zaprosy PAM k opredelennoj usluge.
           Politika obychno sostoit iz chetyreh cepochek, po odnoj
           dlya kazhdoj podsistemy, hotya nekotorye sluzhby
           ispol'zuyut ne vse chetyre podsistemy.

   server (server)

           Prilozhenie, vystupayuschee ot imeni arbitratora dlya
           obscheniya s klientom, zaprashivaniya autentifikacionnoj
           informacii, proverki polnomochij applikanta i
           podtverzhdayuschee ili otklonyayuschee zapros.

   servis (service)

           Klass serverov, predostavlyayuschih pohozhuyu ili
           svyazannuyu funkcional'nost', i trebuyuschuyu podobnuyu
           autentifikaciyu. Politiki PAM zadayutsya na osnove
           servisov, tak chto ko vsem serveram, ob"yavlyayuschim odno
           i tozhe imya servisa, budet primenyat'sya odna i ta zhe
           politika.

   seans (session)

           Kontekst, v kotorom servis okazyvaetsya applikantu
           serverom. Odna iz chetyreh podsistem PAM, upravlenie
           seansom, kasaetsya isklyuchitel'no nastrojke i ochistke
           `etogo konteksta.

   klyuch (token)

           Blok informacii, svyazannyj s uchiotnoj zapis'yu,
           naprimer, parol' ili klyuchevaya fraza, kotoruyu applikant
           dolzhen predostavit' dlya svoej identifikacii.

   tranzakciya (transaction)

           Posledovatel'nost' zaprosov ot odnogo i togo zhe
           applikanta k odnomu i tomu zhe `ekzemplyaru togo zhe
           samogo servera, nachinaya s autentifikacii i ustanovleniya
           seansa i zakanchivaya zakrytiem seansa.

     --------------------------------------------------------------

  2.2. Primery ispol'zovaniya

   `Etot razdel prednaznachen dlya illyustracii znachenij nekotoryh
   terminov, opredelennyh vyshe, pri pomoschi prostyh primerov.

     --------------------------------------------------------------

    2.2.1. Ob"edinennye klient i server

   V `etom prostom primere pokazyvaetsya pol'zovatel' alice,
   vypolnyayuschij komandu su(1) dlya togo, chtoby stat'
   pol'zovatelem root.

 % whoami
 alice
 % ls -l `which su`
 -r-sr-xr-x  1 root  wheel  10744 Dec  6 19:06 /usr/bin/su
 % su -
 Password: xi3kiune
 # whoami
 root

     * Applikantom yavlyaetsya alice.

     * Uchetnoj zapis'yu yavlyaetsya root.

     * Process su(1) yavlyaetsya kak klientom, tak i serverom.

     * Autentifikacionnym klyuchom yavlyaetsya xi3kiune.

     * Arbitratorom vystupaet root, i imenno po`etomu u komandy su(1)
       vystavlen bit vypolneniya s pravami root.

     --------------------------------------------------------------

    2.2.2. Klient i server razdeleny

   V primere nizhe rassmatrivaetsya pol'zovatel' eve, pytayuschijsya
   ustanovit' ssh(1)-soedinenie s login.example.com, i uspeshno
   vhodya kak pol'zovatel' bob. Bob dolzhen byl vybrat' parol'
   poluchshe!

 % whoami
 eve
 % ssh bob@login.example.com
 bob@login.example.com's password: god
 Last login: Thu Oct 11 09:52:57 2001 from 192.168.0.1
 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
         The Regents of the University of California.  All rights reserved.
 FreeBSD 4.4-STABLE (LOGIN) #4: Tue Nov 27 18:10:34 PST 2001

 Welcome to FreeBSD!
 %

     * Applikantom yavlyaetsya eve.

     * Klientom yavlyaetsya process ssh(1) pol'zovatelya Eve.

     * Serverom yavlyaetsya process sshd(8) na mashine
       login.example.com

     * Uchetnoj zapis'yu yavlyaetsya bob.

     * Klyuchom autentifikacii yavlyaetsya god.

     * Hotya `etogo ne vidno v primere, no arbitratorom yavlyaetsya
       root.

     --------------------------------------------------------------

    2.2.3. Primer politiki

   Sleduyuschee yavlyaetsya politikoj, ispol'zuemoj vo FreeBSD po
   umolchaniyu dlya sshd:

 sshd   auth            required        pam_nologin.so  no_warn
 sshd   auth            required        pam_unix.so     no_warn try_first_pass
 sshd   account         required        pam_login_access.so
 sshd   account         required        pam_unix.so
 sshd   session         required        pam_lastlog.so  no_fail
 sshd   password        required        pam_permit.so

     * `Eta politika primenyaetsya k sluzhbe sshd (chto ne
       obyazatel'no ogranicheno serverom sshd(8)).

     * auth, account, session i password yavlyayutsya podsistemami.

     * pam_nologin.so, pam_unix.so, pam_login_access.so,
       pam_lastlog.so i pam_permit.so yavlyayutsya modulyami. Iz
       `etogo primera vidno, chto pam_unix.so realizuet po krajnej
       mere dve podsistemy (autentifikaciyu i upravlenie uchiotnymi
       zapisyami).

     --------------------------------------------------------------

3. Osnovy PAM

  3.1. Podsistemy i primitivy

   API dlya PAM predostavlyaet shest' razlichnyh primitivov dlya
   autentifikacii, sgruppirovannyh v chetyre podsistemy, kazhdaya iz
   kotoryh opisyvaetsya nizhe.

   auth

           Autentifikaciya. `Eta podsistema, sobstvenno govorya,
           realizuet autentifikaciyu applikanta i vyyasnenie
           polnomochij uchiotnoj zapisi. Ona predostavlyaet dva
           primitiva:

              * Funkciya pam_authenticate(3) autentificiruet
                applikanta, obychno zaprashivaya autentifikacionnyj
                klyuch i sravnivaya ego so znacheniem, hranyaschimsya
                v baze dannyh ili poluchaemym ot servera
                autentifikacii.

              * Funkciya pam_setcred(3) ustanavlivaet polnomochiya
                uchiotnoj zapisi, takie, kak identifikator
                pol'zovatelya, chlenstvo v gruppah i ogranicheniya na
                ispol'zovanie resursov.

   account

           Upravlenie uchiotnoj zapis'yu. `Eta podsistema
           obrabatyvaet voprosy dostupnosti uchetnoj zapisi, ne
           svyazannye s autentifikaciej, takie, kak ogranicheniya v
           dostupe na osnove vremeni sutok ili zagruzki servera. On
           predostavlyaet edinstvennyj primitiv:

              * Funkciya pam_acct_mgmt(3) proveryaet, dostupna li
                zaprashivaemaya uchiotnaya zapis'.

   session

           Upravlenie seansom. `Eta podsistema otrabatyvaet zadachi,
           svyazannye s ustanovleniem i zakrytiem seansa, takie, kak
           uchet vhodov pol'zovatelej. Ona predostavlyaet dva
           primitiva:

              * Funkciya pam_open_session(3) vypolnyaet dejstviya,
                svyazannye s ustanovleniem seansa: dobavlenie zapisej
                v bazy dannyh utmp i wtmp, zapusk agenta SSH i tak
                dalee.

              * Funkciya pam_close_session(3) vypolnyaet dejstviya,
                svyazannye s zakrytiem seansa: dobavlenie zapisej v
                bazy dannyh utmp i wtmp, zavershenie raboty agenta
                SSH i tak dalee.

   password

           Upravlenie parolem. `Eta podsistema ispol'zuetsya dlya
           izmeneniya klyucha autentifikacii, svyazannogo s uchetnoj
           zapis'yu, po prichine istecheniya ego sroka dejstviya ili
           zhelaniya pol'zovatelya izmenit' ego. Ona predostavlyaet
           edinstvennyj primitiv:

              * Funkciya pam_chauthtok(3) izmenyaet klyuch
                autentifikacii, opcional'no proveryaya, chto on
                truden dlya podbora, ne ispol'zovalsya ranee i tak
                dalee.

     --------------------------------------------------------------

  3.2. Moduli

   Moduli yavlyayutsya central'noj koncepciej v PAM; v konce koncov,
   im sootvetstvuet bukva ''M'' v sokraschenii ''PAM''. Modul' PAM
   predstavlyaet soboj samodostatochnyj kusok programmnogo koda,
   kotoryj realizuet primitivy odnoj ili bol'shego kolichestva
   podsistem odnogo konkretnogo mehanizma; k vozmozhnym mehanizmam
   dlya podsistemy autentifikacii, k primeru, otnosyatsya bazy dannyh
   parolej UNIX(R), sistemy NIS, LDAP ili Radius.

     --------------------------------------------------------------

    3.2.1. Imenovanie modulej

   Vo FreeBSD kazhdyj mehanizm realizuetsya v otdel'nom module s
   imenem pam_mechanism.so (naprimer, pam_unix.so dlya mehanizma
   UNIX.) V drugih realizaciyah inogda otdel'nye moduli
   ispol'zuyutsya dlya raznyh podsistem, i v ih imya vklyuchaetsya,
   krome nazvaniya mehanizma, i imya podsistemy. K primeru, v Solaris
   imeetsya modul' pam_dial_auth.so.1, kotoryj chasto ispol'zuetsya
   dlya autentifikacii pol'zovatelej, rabotayuschih po kommutiruemym
   kanalam svyazi.

     --------------------------------------------------------------

    3.2.2. Versii modulej

   Iznachal'naya realizaciya PAM vo FreeBSD, kotoraya byla osnovana
   na Linux-PAM, ne ispol'zovala nomera versij dlya modulej PAM. `Eto
   budet privodit' k problemam pri rabote unasledovannyh prilozhenij,
   kotorye mogut byt' skomponovany so starymi versiyami sistemnyh
   bibliotek, tak kak sposoba podgruzit' sootvetstvuyuschuyu versiyu
   trebuemyh modulej net.

   OpenPAM, s drugoj storony, ischet moduli, kotorye imeyut tot zhe
   samyj nomer versii, chto i biblioteka PAM (na dannyj moment 2), i
   ispol'zuet modul' bez versii, tol'ko esli modul' s izvestnoj
   versiej ne byl zagruzhen. Po`etomu dlya staryh prilozhenij mogut
   predostavlyat'sya starye moduli, pri `etom novye (ili zanovo
   postroennye) prilozheniya budut ispol'zovat' vse vozmozhnosti
   poslednih versij modulej.

   Hotya moduli PAM v Solaris imeyut nomer versii, po-nastoyaschemu
   nomer versii v nih ne otslezhivaetsya, potomu chto nomer
   yavlyaetsya chast'yu imeni i dolzhen vklyuchat'sya v
   konfiguraciyu.

     --------------------------------------------------------------

  3.3. Cepochki i politiki

   Kogda server iniciiruet PAM-tranzakciyu, biblioteka PAM pytaetsya
   zagruzit' politiku dlya sluzhby, ukazannoj pri vyzove funkcii
   pam_start(3). Politika opredelyaet, kak dolzhny obrabatyvat'sya
   zaprosy na autentifikaciyu, i zadaiotsya v konfiguracionnom fajle.
   `Eto sostavlyaet druguyu osnovopolagayuschuyu koncepciyu PAM:
   vozmozhnost' administratoru nastraivat' politiku bezopasnosti
   sistemy (v samom shirokom eio ponimanii) prostym redaktirovaniem
   tekstovogo fajla.

   Politika sostoit iz chetyrioh cepochek, po odnoj na kazhdyj iz
   metodov PAM. Kazhdoe zveno predstavlyaet soboj posledovatel'nost'
   konfiguracionnyh utverzhdenij, zadayuschih vyzyvaemyj modul',
   nekotorye (neobyazatel'nye) parametry dlya peredachi v modul', i
   upravlyayuschij flag, opisyvayuschij, kak interpretirovat'
   vozvraschaemyj iz modulya kod.

   Ponimanie smysla upravlyayuschego flaga neobhodimo dlya ponimaniya
   konfiguracionnyh fajlov PAM. Suschestvuyut chetyre razlichnyh
   upravlyayuschih flaga:

   binding

           Esli modul' otrabotal uspeshno, i ni odin iz predyduschih
           modulej v cepochke ne srabotal otricatel'no, to cepochka
           preryvaetsya, a zapros podtverzhdaetsya. Esli zhe modul'
           otrabotaet neudachno, to vypolnyaetsya ostavshayasya
           chast' cepochki, odnako zapros otvergaetsya.

           `Etot upravlyayuschij flag byl dobavlen kompaniej Sun v
           Solaris 9 (SunOS(TM) 5.9), i podderzhivaetsya v OpenPAM.

   required

           Esli modul' vozvratil polozhitel'nyj otvet, vypolnyaetsya
           ostavshayasya chast' cepochki, zapros udovletvoryaetsya,
           esli nikakoj drugoj modul' ne otrabotaet otricatel'no.
           Esli zhe modul' vozvratit otricatel'nyj otvet, ostatok
           cepochki tozhe otrabatyvaetsya, no zapros otvergaetsya.

   requisite

           Esli modul' vozvraschaet polozhitel'nyj otvet,
           vypolnyaetsya ostavshayasya chast' cepochki, zapros
           udovletvoryaetsya, esli nikakoj drugoj modul' ne
           otrabotaet otricatel'no. Esli zhe modul' otrabatyvaet
           otricatel'no, to otrabotka cepochki nemedlenno
           prekraschaetsya, a zapros otvergaetsya.

   sufficient

           Esli modul' vozvratit polozhitel'nyj otvet, i ni odin iz
           predyduschih modulej v cepochke na otrabotal otricatel'no,
           to otrabotka cepochki nemedlenno prekraschaetsya, a zapros
           udovletvoryaetsya. Esli modul' otrabotal otricatel'no, to
           rezul'tat ignoriruetsya i cepochka otrabatyvaetsya
           dal'she.

           Tak kak semantika `etogo flaga mozhet okazat'sya
           zaputannoj, osobenno pri ego ispol'zovanii s poslednim
           modulem v cepochke, rekomenduetsya vmesto nego
           ispol'zovat' upravlyayuschij flag binding, esli
           realizaciya ego podderzhivaet.

   optional

           Modul' otrabatyvaetsya, no rezul'tat vypolneniya
           ignoriruetsya. Esli vse moduli v cepochke pomecheny kak
           optional, to udovletvoryat'sya budut vse zaprosy.

   Kogda server vyzyvaet odin iz shesti PAM-primitivov, PAM
   zaprashivaet cepochku podsistemy, k kotoroj prinadlezhit primitiv,
   i zapuskaet kazhdyj modul', perechislennyj v cepochke v poryadke
   ih perechisleniya, poka spisok ne budet ischerpan libo ne budet
   opredeleno, chto dal'nejshej obrabotki ne nuzhno (po prichine
   dostizhenie modulya, vernuvshego polozhitel'nyj otvet pri uslovii
   binding ili sufficient, libo otricatel'nyj s usloviem requisite).
   Zapros podtverzhdaetsya, esli tol'ko byl vyzvan po krajnej mere
   odin modul', i vse neopcional'nye moduli vernuli polozhitel'nyj
   otvet.

   Zamet'te, chto vozmozhno, hotya `eto ne rasprostraneno,
   perechislyat' odin i tot zhe modul' neskol'ko raz v odnoj
   cepochke. K primeru, modul', prosmatrivayuschij imena i paroli
   pol'zovatelya v servere kataloga mozhet byt' vyzvan neskol'ko raz
   s razlichnymi parametrami, zadayuschimi razlichnye servery
   katalogov dlya svyazi. PAM schitaet razlichnye poyavleniya odnogo
   modulya v toj zhe samoj cepochke raznymi i ne svyazannymi
   modulyami.

     --------------------------------------------------------------

  3.4. Tranzakcii

   ZHiznennyj cikl tipichnoj PAM-tranzakcii opisan nizhe. Zamet'te,
   chto v sluchae, esli lyuboj iz perechislennyh shagov
   okanchivaetsya neudachno, server dolzhen vydat' klientu
   sootvetstvuyuschee soobschenie ob oshibke i prervat' tranzakciyu.

    1. Esli `eto neobhodimo, server poluchaet polnomochiya
       arbitratora cherez nezavisimyj ot PAM mehanizm-chasche vsego
       po faktu zapuska pol'zovatelem root ili s ustanovlennym
       setuid-bitom root.

    2. Server vyzyvaet funkciyu pam_start(3) dlya inicializacii
       biblioteki PAM i zadaniya imeni servisa i celevoj uchiotnoj
       zapisi, a takzhe registracii podhodyaschego sposoba
       obscheniya.

    3. Server poluchaet razlichnuyu informaciyu, otnosyaschuyusya k
       tranzakcii (takuyu, kak imya pol'zovatelya applikanta i imya
       hosta, na kotorom zapuschen klient), i otpravlyaet eio v PAM
       pri pomoschi funkcii pam_set_item(3).

    4. Server vyzyvaet funkciyu pam_authenticate(3) dlya
       autentifikacii applikanta.

    5. Server vyzyvaet funkciyu pam_acct_mgmt(3) dlya proverki togo,
       chto zaproshennaya uchiotnaya zapis' dostupna i korrektna.
       Esli parol' veren, no ego srok istiok, pam_acct_mgmt(3)
       vozvratit rezul'tat PAM_NEW_AUTHTOK_REQD, a ne PAM_SUCCESS.

    6. Esli na predyduschem shage byl poluchen rezul'tat
       PAM_NEW_AUTHTOK_REQD, to server vyzyvaet funkciyu
       pam_chauthtok(3) dlya togo, chtoby vynudit' klienta izmenit'
       klyuch autentifikacii dlya zaproshennoj uchiotnoj zapisi.

    7. Teper', kogda applikant polnost'yu autentificirovan, server
       vyzyvaet funkciyu pam_setcred(3) dlya polucheniya polnomochij
       zaproshennoj uchiotnoj zapisi. Sdelat' `eto vozmozhno, potomu
       chto on rabotaet kak arbitrator, i ostavlyaet za soboj
       polnomochiya arbitratora.

    8. Posle polucheniya neobhodimyh polnomochij, server vyzyvaet
       funkciyu pam_open_session(3) dlya ustanovleniya seansa.

    9. Teper' server vypolnyaet tot servis, kotoryj zatreboval
       klient-naprimer, predostavlyaet applikantu obolochku.

   10. Posle togo, kak server zakonchil obsluzhivanie klienta, on
       vyzyvaet funkciyu pam_close_session(3) dlya zakrytiya seansa.

   11. Nakonec, server vyzyvaet funkciyu pam_end(3) dlya
       opovescheniya biblioteki PAM o tom, chto rabota s nej
       zavershena i kakie-libo vydelennye v techenie seansa resursy
       mozhno osvobodit'.

     --------------------------------------------------------------

4. Nastrojka PAM

  4.1. Fajly politik PAM

    4.1.1. Fajl /etc/pam.conf

   Tradicionno fajlom politik PAM yavlyaetsya /etc/pam.conf. On
   soderzhit vse politiki PAM dlya vashej sistemy. Kazhdaya stroka
   fajla opisyvaet odin shag v cepochke, kak pokazano nizhe:

 login   auth    required        pam_nologin.so  no_warn

   Polya sleduyut v takom poryadke: imya sluzhby, imya podsistemy,
   upravlyayuschij flag, imya modulya i parametry modulya. Lyubye
   dopolnitel'nye polya interpretiruyutsya kak dopolnitel'nye
   parametry modulya.

   Dlya kazhdoj pary servis/podsistema sostavlyaetsya otdel'naya
   cepochka, i togda poluchaetsya, chto, hotya poryadok sledovaniya
   strok dlya odnoj i toj zhe uslugi i podsistemy yavlyaetsya
   znachimym, poryadok perechisleniya otdel'nyh servisov ne znachim.
   V primerah iz original'noj raboty po PAM stroki konfiguracii
   sgruppirovany po podsistemam, v postavlyaemom s Solaris fajle
   pam.conf imenno tak i sdelano, no v standartnom konfiguracionnom
   fajle iz postavki FreeBSD stroki nastroek sgruppirovany po
   servisam. Podhodit lyuboj iz `etih sposobov; oni imeyut odin i tot
   zhe smysl.

     --------------------------------------------------------------

    4.1.2. Katalog /etc/pam.d

   OpenPAM i Linux-PAM podderzhivayut al'ternativnyj mehanizm
   nastrojki, kotoryj dlya FreeBSD yavlyaetsya predpochtitel'nym. V
   `etoj sheme kazhdaya politika soderzhitsya v otdel'nom fajle s
   imenem, sootvetstvuyuschem servisu, k kotoromu ona primenyaetsya.
   `Eti fajly razmeschayutsya v kataloge /etc/pam.d/.

   Takie fajly politik, orientirovannye na servisy, imeyut tol'ko
   chetyre polya, vmesto pyati polej v fajle pam.conf: pole imeni
   servisa opuscheno. Takim obrazom, vmesto primera stroki fajla
   pam.conf iz predyduschego razdela poluchitsya sleduyuschaya stroka
   v fajle /etc/pam.d/login:

 auth    required        pam_nologin.so  no_warn

   Kak sledstvie takogo uproschionnogo sintaksisa, vozmozhno
   ispol'zovanie odnih i teh zhe politik dlya neskol'kih servisov,
   svyazyvaya kazhdoe imya servisa s tem zhe samym fajlom politik. K
   primeru, dlya ispol'zovaniya toj zhe samoj politiki dlya servisov
   su i sudo, mozhno sdelat' sleduyuschee:

 # cd /etc/pam.d
 # ln -s su sudo

   `Eto rabotaet, potomu chto imya servisa opredelyaetsya imenem
   fajla, a ne ego ukazaniem v fajle politiki, tak chto odin i tot
   zhe fajl mozhet ispol'zovat'sya dlya neskol'kih servisov s raznymi
   nazvaniyami.

   Tak kak politika kazhdogo servisa hranitsya v otdel'nom fajle, to
   mehanizm pam.d delaet ustanovku dopolnitel'nyh politik dlya
   programmnyh paketov storonnih razrabotchikov ochen' liogkoj
   zadachej.

     --------------------------------------------------------------

    4.1.3. Poryadok poiska politik

   Kak vy videli vyshe, politiki PAM mogut nahodit'sya v neskol'kih
   mestah. CHto budet, esli politiki dlya odnogo i togo zhe servisa
   imeyutsya v raznyh mestah?

   Neobhodimo osoznat', chto sistema konfiguracii PAM orientirovana
   na cepochki.

     --------------------------------------------------------------

  4.2. Struktura stroki nastrojki

   Kak `eto ob"yasneno v razdele Fajly politik PAM, kazhdaya stroka
   fajla /etc/pam.conf sostoit iz chetyrioh ili bol'shego kolichestva
   polej: imeni servisa, imeni podsistemy, upravlyayuschego flaga,
   imeni modulya i dopolnitel'nyh parametrov modulya, kotorye mogut
   otsutstvovat'.

   Imya servisa obychno (hotya ne vsegda) yavlyaetsya imenem
   prilozheniya, kotoroe `etot servis obsluzhivaet. Esli vy ne
   uvereny, obratites' k dokumentacii po konkretnomu prilozheniyu
   dlya opredeleniya ispol'zuemogo imeni servisa.

   Zamet'te, chto esli vy ispol'zuete /etc/pam.d/ vmesto
   /etc/pam.conf, to imya servisa zadaetsya imenem fajla politiki, i
   opuskaetsya iz strok nastrojki, kotorye v takom sluchae
   nachinayutsya s nazvaniya podsistemy.

   Imya podsistemy predstavlyaet soboj odno iz chetyrioh klyuchevyh
   slov, opisannyh v glave Podsistemy i primitivy.

   Tochno takzhe upravlyayuschij flag yavlyaetsya odnim iz chetyrioh
   klyuchevyh slov, opisannyh v razdele Cepochki i politiki, v
   kotorom rasskazano, kak interpretirovat' vozvraschaemyj iz modulya
   kod. V Linux-PAM podderzhivaetsya al'ternativnyj sintaksis,
   kotoryj pozvolyaet ukazat' dejstvie, svyazannoj s kazhdyj
   vozmozhnym kodom vozvrata, no `etogo sleduet izbegat', tak kak on
   ne yavlyaetsya standartnym i tesno svyazan so sposobom
   dispetcherizacii vyzovov servisov v Linux-PAM (a on znachitel'no
   otlichaetsya ot sposoba vzaimodejstviya v Solaris i OpenPAM). Ne
   vyzyvaet udivleniya tot fakt, chto v OpenPAM `etot sintaksis ne
   podderzhivaetsya.

     --------------------------------------------------------------

  4.3. Politiki

   Dlya korrektnoj nastrojki PAM neobhodimo ponimat', kak proishodit
   interpretaciya politik.

   V moment, kogda prilozhenie vyzyvaet funkciyu pam_start(3),
   biblioteka PAM zagruzhaet politiku dlya ukazannogo servisa i
   vystraivaet chetyre cepochki modulej (po odnoj dlya kazhdoj
   podsistemy). Esli odna ili bol'shee kolichestvo `etih cepochek
   yavlyayutsya pustymi, to budut vypolnyat'sya podstanovki
   sootvetstvuyuschih cepochek iz politiki dlya servisa other.

   Kogda zatem prilozhenie vyzyvaet odnu iz shesti primitivov PAM,
   biblioteka PAM vydelyaet iz cepochki nuzhnuyu podsistemu i
   vyzyvaet funkciyu, sootvetstvuyuschuyu servisu, v kazhdom module,
   perechislennom v cepochke, v tom poryadke, v kakom oni
   perechisleny v konfiguracii. Posle kazhdogo obrascheniya k funkcii
   servisa, tip modulya i vozvraschionnyj iz `etoj funkcii kod
   rezul'tata vypolneniya ispol'zuyutsya dlya togo, chto delat'
   dal'she. Za nekotorymi isklyucheniyami, kotorye budut opisany
   nizhe, primenyaetsya takaya tablica:

   Tablica 1. Svodnaya tablica otrabotki cepochek PAM

   +----------------------------------------------------------------+
   |            |    PAM_SUCCESS    | PAM_IGNORE |    other     |   |
   |------------+-------------------+------------+--------------|   |
   | binding    | if (!fail) break; | -          | fail = true; |   |
   |------------+-------------------+------------+--------------|   |
   | required   | -                 | -          | fail = true; |   |
   |------------+-------------------+------------+--------------|   |
   | requisite  | -                 | -          | fail = true; |   |
   |            |                   |            | break;       |   |
   |------------+-------------------+------------+--------------+---|
   | sufficient | if (!fail) break; | -          | -            |   |
   |------------+-------------------+------------+--------------+---|
   | optional   | -                 | -          | -            |   |
   +----------------------------------------------------------------+

   Esli peremennaya fail prinimaet istinnoe znachenie v konce
   otrabotki cepochki, ili kogda dostignut ''break'', dispetcher
   vozvraschaet kod oshibki, vozvraschionnyj pervym modulem,
   otrabotavshim neudachno. V protivnom sluchae vozvraschaetsya
   PAM_SUCCESS.

   Pervym isklyucheniem yavlyaetsya to, chto kod oshibki
   PAM_NEW_AUTHTOK_REQD interpretiruetsya kak uspeshnyj rezul'tat,
   krome sluchaya, kogda modul' otrabotal uspeshno, i po krajnej mere
   odin modul' vozvratil PAM_NEW_AUTHTOK_REQD, togda dispetcher
   vozvratit rezul'tat PAM_NEW_AUTHTOK_REQD.

   Vtorym isklyucheniem yavlyaetsya to, chto pam_setcred(3) schitaet,
   chto moduli binding i sufficient yavlyayutsya ravnoznachnymi
   required.

   Tret'im i poslednim isklyucheniem yavlyaetsya to, chto funkciya
   pam_chauthtok(3) otrabatyvaet polnuyu cepochku dvazhdy (odin raz
   dlya predvaritel'nyh proverok, i eschio raz dlya real'nogo
   zadaniya parolya), i na podgotovitel'noj faze ona schitaet, chto
   moduli binding i sufficient yavlyayutsya ravnoznachnymi required.

     --------------------------------------------------------------

5. Moduli PAM vo FreeBSD

  5.1. pam_deny(8)

   Modul' pam_deny(8) yavlyaetsya odnim iz prostejshih dostupnyh
   modulej; na lyuboj zapros on vozvraschaet rezul'tat PAM_AUTH_ERR.
   On polezen dlya bystrogo otklyucheniya servisa (dobav'te ego na
   verh kazhdoj cepochki) ili zaversheniya cepochek modulej
   sufficient.

     --------------------------------------------------------------

  5.2. pam_echo(8)

   Modul' pam_echo(8) prosto peredaiot svoi parametry v funkciyu
   vzaimodejstviya kak soobschenie PAM_TEXT_INFO. V osnovnom polezna
   dlya otladki, no takzhe mozhet ispol'zovat'sya dlya vyvoda
   soobschenij, takih kak ''Unauthorized access will be prosecuted''
   do zapuska procedury autentifikacii.

     --------------------------------------------------------------

  5.3. pam_exec(8)

   Modul' pam_exec(8) vosprinimaet pervyj peredannyj emu parametr kak
   imya programmy dlya vypolneniya, a ostal'nye argumenty
   peredayutsya `etoj programme v kachestve parametrov komandnoj
   stroki. Odnim iz vozmozhnyh primenenij yavlyaetsya ego
   ispol'zovanie dlya zapuska v moment registracii v sisteme
   programmy montirovaniya domashnego kataloga pol'zovatelya.

     --------------------------------------------------------------

  5.4. pam_ftpusers(8)

   Modul' pam_ftpusers(8)

     --------------------------------------------------------------

  5.5. pam_group(8)

   Modul' pam_group(8) prinimaet ili otvergaet applikantov v
   zavisimosti ot ih chlenstva v opredelionnoj fajlovoj gruppe
   (obychno wheel dlya su(1)). V pervuyu ochered' prednaznachen dlya
   sohraneniya tradicionnogo povedeniya utility BSD su(1), hotya
   imeet i mnogo drugih primenenij, takih kak otklyuchenie
   opredelionnyh grupp pol'zovatelej ot nekotorogo servisa.

     --------------------------------------------------------------

  5.6. pam_guest(8)

   Modul' pam_guest(8) pozvolyaet osuschestvlyat' gostevye vhody s
   ispol'zovaniem fiksirovannyh imion vhoda v sistemu. Na parol'
   mogut nakladyvat'sya razlichnye ogranicheniya, odnako dejstviem po
   umolchaniyu yavlyaetsya vvod lyubogo parolya pri ispol'zovanii
   imeni, sootvetstvuyuschego gostevomu vhodu. Modul' pam_guest(8)
   mozhno legko ispol'zovat' dlya realizacii anonimnyh vhodov na FTP.

     --------------------------------------------------------------

  5.7. pam_krb5(8)

   Modul' pam_krb5(8)

     --------------------------------------------------------------

  5.8. pam_ksu(8)

   Modul' pam_ksu(8)

     --------------------------------------------------------------

  5.9. pam_lastlog(8)

   Modul' pam_lastlog(8)

     --------------------------------------------------------------

  5.10. pam_login_access(8)

   Modul' pam_login_access(8) predostavlyaet realizaciyu primitiva
   dlya upravleniya uchiotnymi zapisyami, kotoryj vvodit v dejstvie
   ogranicheniya na vhod, zadavaemye v tablice login.access(5).

     --------------------------------------------------------------

  5.11. pam_nologin(8)

   Modul' pam_nologin(8) otvergaet lyubye vhody ne pol'zovatelem
   root, esli suschestvuet fajl /var/run/nologin. Obychno `etot fajl
   sozdaiotsya utilitoj shutdown(8), kogda do zaplanirovannogo
   zaversheniya raboty sistemy ostaiotsya menee pyati minut.

     --------------------------------------------------------------

  5.12. pam_opie(8)

   Modul' pam_opie(8) realizuet metod autentifikacii opie(4). Sistema
   opie(4) yavlyaetsya mehanizmom raboty po sheme zapros-otvet, pri
   kotorom otvet na kazhdyj zapros yavlyaetsya pryamoj funkciej ot
   zaprosa i klyuchevoj frazy, tak chto otvet mozhet byt' legko i
   ''vovremya'' vychislen lyubym, znayuschim klyuchevuyu frazu, chto
   izbavlyaet ot neobhodimosti peredavat' parol'. Krome togo, tak kak
   v opie(4) nikogda povtorno ne ispol'zuetsya zapros, otvet na
   kotoryj byl korrektno poluchen, `eta shema yavlyaetsya ustojchivoj
   k atakam, osnovannym na povtore dejstvij.

     --------------------------------------------------------------

  5.13. pam_opieaccess(8)

   Modul' pam_opieaccess(8) dopolnyaet modul' pam_opie(8). Ego rabota
   zaklyuchaetsya v vypolnenii ogranichenij, zadavaemyh fajlom
   opieaccess(5), kotoryj opredelyaet usloviya, pri kotoryh
   pol'zovatel', normal'no proshedshij autentifikaciyu posredstvom
   opie(4), mozhet ispol'zovat' al'ternativnye metody. CHasche vsego
   on ispol'zuetsya dlya zapreta ispol'zovaniya autentifikacii na
   osnove parolej s neproverennyh hostov.

   Dlya `effektivnosti modul' pam_opieaccess(8) dolzhen byt'
   opredelion v cepochke auth kak requisite srazu zhe posle zapisi
   sufficient dlya pam_opie(8), no pered lyubymi drugimi modulyami.

     --------------------------------------------------------------

  5.14. pam_passwdqc(8)

   Modul' pam_passwdqc(8)

     --------------------------------------------------------------

  5.15. pam_permit(8)

   Modul' pam_permit(8) yavlyaetsya odnim iz samyh prostym iz
   imeyuschihsya; na lyuboj zapros on otvechaet PAM_SUCCESS. On
   polezen v kachestve zameny pustogo mesta dlya servisov, kogda odna
   ili bol'shee kolichestvo cepochek v protivnom sluchae ostanutsya
   pustymi.

     --------------------------------------------------------------

  5.16. pam_radius(8)

   Modul' pam_radius(8)

     --------------------------------------------------------------

  5.17. pam_rhosts(8)

   Modul' pam_rhosts(8)

     --------------------------------------------------------------

  5.18. pam_rootok(8)

   Modul' pam_rootok(8) vozvraschaet polozhitel'nyj rezul'tat v tom i
   tol'ko v tom sluchae, esli real'nyj id pol'zovatelya processa, ego
   vyzvavshego (predpolagaetsya, chto ego zapuskaet applikant) raven
   0. `Eto polezno dlya nesetevyh servisov, takih kak su(1) ili
   passwd(1), k kotorym pol'zovatel' root dolzhen imet'
   avtomaticheskij dostup.

     --------------------------------------------------------------

  5.19. pam_securetty(8)

   Modul' pam_securetty(8)

     --------------------------------------------------------------

  5.20. pam_self(8)

   Modul' pam_self(8) vozvraschaet polozhitel'nyj rezul'tat togda i
   tol'ko togda, kogda imena applikanta sootvetstvuyut celevoj
   uchiotnoj zapisi. Bol'she vsego `eto prigoditsya v nesetevyh
   servisah, takih kak su(1), v kotoryh identifikaciya applikanta
   mozhet byt' s liogkost'yu proverena.

     --------------------------------------------------------------

  5.21. pam_ssh(8)

   Modul' pam_ssh(8) predostavlyaet kak servis autentifikacii, tak i
   seansa. Servis autentifikacii pozvolyaet pol'zovatelyam,
   imeyuschim sekretnye klyuchi SSH, zaschischionnye parolyami, v
   svoih katalogah ~/.ssh, autentificirovat'sya posredstvom `etih
   parolej. Seansovyj servis zapuskaet ssh-agent(1) i zagruzhaet
   klyuchi, kotorye byli rasshifrovany na faze autentifikacii. Takaya
   vozmozhnost', v chastnosti, polezna dlya lokal'nyh vhodov v
   sistemu, kak v sistemu X (posredstvom xdm(1) ili drugogo
   X-menedzhera vhodov, umeyuschego rabotat' s PAM), tak i na
   konsol'.

     --------------------------------------------------------------

  5.22. pam_tacplus(8)

   Modul' pam_tacplus(8)

     --------------------------------------------------------------

  5.23. pam_unix(8)

   Modul' pam_unix(8) realizuet tradicionnuyu autentifikaciyu UNIX na
   osnove parolej, ispol'zuyuschuyu funkciyu getpwnam(3) dlya
   polucheniya parolya celevoj uchiotnoj zapisi i sravnivayuschuyu
   eio s tem, chto predstavil applikant. On takzhe predostavlyaet
   sredstva upravleniya uchiotnymi zapisyami (otslezhivaya vremya
   dejstviya uchiotnoj zapisi i parolya) i smeny parolej. Navernoe,
   `eto samyj poleznyj modul', tak kak podavlyayuschee bol'shinstvo
   administratorov hotyat sohranit' istoricheski slozhivsheesya
   povedenie po krajnej mere nekotoryh servisov.

     --------------------------------------------------------------

6. Programmirovanie prilozhenij s PAM

   `Etot razdel eschio ne napisan.

     --------------------------------------------------------------

7. Programmirovanie modulya PAM

   `Etot razdel eschio ne napisan.

     --------------------------------------------------------------

                       A. Primer PAM-prilozheniya

   Dalee sleduet minimal'naya realizaciya programmy su(1) s
   ispol'zovaniem PAM. Zamet'te, chto v nej ispol'zuetsya
   specifichnaya dlya OpenPAM funkciya vzaimodejstviya
   openpam_ttyconv(3), ob"yavlenie kotoroj raspolozheno v fajle
   security/openpam.h. Esli vy sobiraetes' stroit' `eto prilozhenie v
   sisteme s drugoj bibliotekoj PAM, vam neobhodimo budet sozdat'
   sobstvennuyu funkciyu vzaimodejstviya. Nadiozhnuyu funkciyu
   vzaimodejstviya neozhidanno trudno napisat'; ta, chto nahoditsya v
   prilozhenii Primer funkcii vzaimodejstviya PAM, horosha v
   kachestve otpravnoj tochki, no v real'nyh prilozheniyah
   ispol'zovat'sya ne mozhet.

 #include <sys/param.h>
 #include <sys/wait.h>

 #include <err.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
 #include <unistd.h>

 #include <security/pam_appl.h>
 #include <security/openpam.h>   /* for openpam_ttyconv() */

 extern char **environ;

 static pam_handle_t *pamh;
 static struct pam_conv pamc;

 static void
 usage(void)
 {

         fprintf(stderr, "Usage: su [login [args]]\n");
         exit(1);
 }

 int
 main(int argc, char *argv[])
 {
         char hostname[MAXHOSTNAMELEN];
         const char *user, *tty;
         char **args, **pam_envlist, **pam_env;
         struct passwd *pwd;
         int o, pam_err, status;
         pid_t pid;

         while ((o = getopt(argc, argv, "h")) != -1)
                 switch (o) {
                 case 'h':
                 default:
                         usage();
                 }

         argc -= optind;
         argv += optind;

         if (argc > 0) {
                 user = *argv;
                 --argc;
                 ++argv;
         } else {
                 user = "root";
         }

         /* initialize PAM */
         pamc.conv = &openpam_ttyconv;
         pam_start("su", user, &pamc, &pamh);

         /* set some items */
         gethostname(hostname, sizeof(hostname));
         if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
                 goto pamerr;
         user = getlogin();
         if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
                 goto pamerr;
         tty = ttyname(STDERR_FILENO);
         if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
                 goto pamerr;

         /* authenticate the applicant */
         if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
                 goto pamerr;
         if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
                 pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
         if (pam_err != PAM_SUCCESS)
                 goto pamerr;

         /* establish the requested credentials */
         if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
                 goto pamerr;

         /* authentication succeeded; open a session */
         if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
                 goto pamerr;

         /* get mapped user name; PAM may have changed it */
         pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
         if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
                 goto pamerr;

         /* export PAM environment */
         if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
                 for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
                         putenv(*pam_env);
                         free(*pam_env);
                 }
                 free(pam_envlist);
         }

         /* build argument list */
         if ((args = calloc(argc + 2, sizeof *args)) == NULL) {
                 warn("calloc()");
                 goto err;
         }
         *args = pwd->pw_shell;
         memcpy(args + 1, argv, argc * sizeof *args);

         /* fork and exec */
         switch ((pid = fork())) {
         case -1:
                 warn("fork()");
                 goto err;
         case 0:
                 /* child: give up privs and start a shell */

                 /* set uid and groups */
                 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
                         warn("initgroups()");
                         _exit(1);
                 }
                 if (setgid(pwd->pw_gid) == -1) {
                         warn("setgid()");
                         _exit(1);
                 }
                 if (setuid(pwd->pw_uid) == -1) {
                         warn("setuid()");
                         _exit(1);
                 }
                 execve(*args, args, environ);
                 warn("execve()");
                 _exit(1);
         default:
                 /* parent: wait for child to exit */
                 waitpid(pid, &status, 0);

                 /* close the session and release PAM resources */
                 pam_err = pam_close_session(pamh, 0);
                 pam_end(pamh, pam_err);

                 exit(WEXITSTATUS(status));
         }

 pamerr:
         fprintf(stderr, "Sorry\n");
 err:
         pam_end(pamh, pam_err);
         exit(1);
 }

     --------------------------------------------------------------

                         B. Primer PAM-modulya

   Dalee privedena minimal'naya realizaciya pam_unix(8),
   predostavlyayuschaya tol'ko servisy autentifikacii. Ona dolzhna
   stroit'sya i rabotat' s bol'shinstvom iz realizacij PAM, no
   ispol'zuet vozmozhnosti rasshirenij OpenPAM, esli oni
   prisutstvuyut: otmet'te ispol'zovanie funkcii pam_get_authtok(3),
   kotoraya kardinal'no uproschaet organizaciyu vvoda parolya
   pol'zovatelem.

 #include <sys/param.h>

 #include <pwd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>

 #include <security/pam_modules.h>
 #include <security/pam_appl.h>

 #ifndef _OPENPAM
 static char password_prompt[] = "Password:";
 #endif

 #ifndef PAM_EXTERN
 #define PAM_EXTERN
 #endif

 PAM_EXTERN int
 pam_sm_authenticate(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {
 #ifndef _OPENPAM
         struct pam_conv *conv;
         struct pam_message msg;
         const struct pam_message *msgp;
         struct pam_response *resp;
 #endif
         struct passwd *pwd;
         const char *user;
         char *crypt_password, *password;
         int pam_err, retry;

         /* identify user */
         if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
                 return (pam_err);
         if ((pwd = getpwnam(user)) == NULL)
                 return (PAM_USER_UNKNOWN);

         /* get password */
 #ifndef _OPENPAM
         pam_err = pam_get_item(pamh, PAM_CONV, (const void **)&conv);
         if (pam_err != PAM_SUCCESS)
                 return (PAM_SYSTEM_ERR);
         msg.msg_style = PAM_PROMPT_ECHO_OFF;
         msg.msg = password_prompt;
         msgp = &msg;
 #endif
         for (retry = 0; retry < 3; ++retry) {
 #ifdef _OPENPAM
                 pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
                     (const char **)&password, NULL);
 #else
                 resp = NULL;
                 pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
                 if (resp != NULL) {
                         if (pam_err == PAM_SUCCESS)
                                 password = resp->resp;
                         else
                                 free(resp->resp);
                         free(resp);
                 }
 #endif
                 if (pam_err == PAM_SUCCESS)
                         break;
         }
         if (pam_err == PAM_CONV_ERR)
                 return (pam_err);
         if (pam_err != PAM_SUCCESS)
                 return (PAM_AUTH_ERR);

         /* compare passwords */
         if ((!pwd->pw_passwd[0] && (flags & PAM_DISALLOW_NULL_AUTHTOK)) ||
             (crypt_password = crypt(password, pwd->pw_passwd)) == NULL ||
             strcmp(crypt_password, pwd->pw_passwd) != 0)
                 pam_err = PAM_AUTH_ERR;
         else
                 pam_err = PAM_SUCCESS;
 #ifndef _OPENPAM
         free(password);
 #endif
         return (pam_err);
 }

 PAM_EXTERN int
 pam_sm_setcred(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SUCCESS);
 }

 PAM_EXTERN int
 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SUCCESS);
 }

 PAM_EXTERN int
 pam_sm_open_session(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SUCCESS);
 }

 PAM_EXTERN int
 pam_sm_close_session(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SUCCESS);
 }

 PAM_EXTERN int
 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SERVICE_ERR);
 }

 #ifdef PAM_MODULE_ENTRY
 PAM_MODULE_ENTRY("pam_unix");
 #endif

     --------------------------------------------------------------

                 C. Primer funkcii vzaimodejstviya PAM

   Funkciya vzaimodejstviya, privodimaya nizhe, yavlyaetsya
   znachitel'no uproschionnoj versiej funkcii openpam_ttyconv(3) iz
   OpenPAM. Ona polnofunkcional'na, i dolzhna posluzhit' istochnikom
   idej o tom, kak dolzhna sebya vesti funkciya vzaimodejstviya,
   odnako ona slishkom prosta dlya real'nyh prilozhenij. Dazhe esli
   vy ne ispol'zuete OpenPAM, mozhete sgruzit' ishodnyj kod i
   ispol'zovat' openpam_ttyconv(3) v svoih celyah; my nadeemsya, chto
   ona dostatochno nadiozhna v kachestve funkcii dlya vzaimodejstviya
   s terminal'nymi ustrojstvami.

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>

 #include <security/pam_appl.h>

 int
 converse(int n, const struct pam_message **msg,
         struct pam_response **resp, void *data)
 {
         struct pam_response *aresp;
         char buf[PAM_MAX_RESP_SIZE];
         int i;

         data = data;
         if (n <= 0 || n > PAM_MAX_NUM_MSG)
                 return (PAM_CONV_ERR);
         if ((aresp = calloc(n, sizeof *aresp)) == NULL)
                 return (PAM_BUF_ERR);
         for (i = 0; i < n; ++i) {
                 aresp[i].resp_retcode = 0;
                 aresp[i].resp = NULL;
                 switch (msg[i]->msg_style) {
                 case PAM_PROMPT_ECHO_OFF:
                         aresp[i].resp = strdup(getpass(msg[i]->msg));
                         if (aresp[i].resp == NULL)
                                 goto fail;
                         break;
                 case PAM_PROMPT_ECHO_ON:
                         fputs(msg[i]->msg, stderr);
                         if (fgets(buf, sizeof buf, stdin) == NULL)
                                 goto fail;
                         aresp[i].resp = strdup(buf);
                         if (aresp[i].resp == NULL)
                                 goto fail;
                         break;
                 case PAM_ERROR_MSG:
                         fputs(msg[i]->msg, stderr);
                         if (strlen(msg[i]->msg) > 0 &&
                             msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                                 fputc('\n', stderr);
                         break;
                 case PAM_TEXT_INFO:
                         fputs(msg[i]->msg, stdout);
                         if (strlen(msg[i]->msg) > 0 &&
                             msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                                 fputc('\n', stdout);
                         break;
                 default:
                         goto fail;
                 }
         }
         *resp = aresp;
         return (PAM_SUCCESS);
  fail:
         for (i = 0; i < n; ++i) {
                 if (aresp[i].resp != NULL) {
                         memset(aresp[i].resp, 0, strlen(aresp[i].resp));
                         free(aresp[i].resp);
                 }
         }
         memset(aresp, 0, n * sizeof *aresp);
         *resp = NULL;
         return (PAM_CONV_ERR);
 }

     --------------------------------------------------------------

                       Dopolnitel'naya literatura

     `Eto spisok dokumentov, otnosyaschihsya k PAM i svyazannym
     voprosam. On, nesomnenno, ne yavlyaetsya polnym.

     --------------------------------------------------------------

Raboty

   Making Login Services Independent of Authentication Technologies,
   Vipin Samar, Charlie Lai, Sun Microsystems.

   X/Open Single Sign-on Preliminary Specification, The Open Group,
   1-85912-144-6, Iyun' 1997.

   Pluggable Authentication Modules, Andrew G. Morgan, 6 oktyabrya
   1999.

     --------------------------------------------------------------

Rukovodstva pol'zovatelya

   PAM Administration, Sun Microsystems.

     --------------------------------------------------------------

Web-stranicy po dannoj tematike

   Domashnyaya stranica OpenPAM, Dag-Erling Smo/rgrav, ThinkSec AS.

   Domashnyaya stranica Linux-PAM, Andrew G. Morgan.

   Domashnyaya stranica Solaris PAM, Sun Microsystems.

     --------------------------------------------------------------

            `Etot, i drugie dokumenty, mogut byt' skachany s
                ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

  Po voprosam, svyazannym s FreeBSD, prochitajte dokumentaciyu prezhde
                 chem pisat' v <questions@FreeBSD.org>.
         Po voprosam, svyazannym s `etoj dokumentaciej, pishite
                           <doc@FreeBSD.org>.
  Po voprosam, svyazannym s russkim perevodom dokumentacii, pishite v
                    rassylku <frdp@FreeBSD.org.ua>.
  Informaciya po podpiske na `etu rassylku nahoditsya na sajte proekta
                               perevoda.
