Annotation of wikisrc/guide/pam.mdwn, revision 1.2

1.1       jdf         1: # Pluggable Authentication Modules (PAM)
                      2: 
                      3: ## About
                      4: 
                      5: This article describes the underlying principles and mechanisms of the 
                      6: *Pluggable Authentication Modules (PAM)* library, and explains how to configure 
                      7: PAM, how to integrate PAM into applications, and how to write PAM modules.
                      8: 
1.2     ! jdf         9: See on the bottom of the page for the license of this text.
1.1       jdf        10: 
                     11: ## Introduction
                     12: 
                     13: The Pluggable Authentication Modules (PAM) library is a generalized API for 
                     14: authentication-related services which allows a system administrator to add new 
                     15: authentication methods simply by installing new PAM modules, and to modify 
                     16: authentication policies by editing configuration files.
                     17: 
                     18: PAM was defined and developed in 1995 by Vipin Samar and Charlie Lai of Sun 
                     19: Microsystems, and has not changed much since. In 1997, the Open Group published 
                     20: the X/Open Single Sign-on (XSSO) preliminary specification, which standardized 
                     21: the PAM API and added extensions for single (or rather integrated) sign-on. At 
                     22: the time of this writing, this specification has not yet been adopted as a 
                     23: standard.
                     24: 
                     25: Although this article focuses primarily on FreeBSD 5.x and NetBSD 3.x, which 
                     26: both use OpenPAM, it should be equally applicable to FreeBSD 4.x, which uses 
                     27: Linux-PAM, and other operating systems such as Linux and Solaris.
                     28: 
                     29: ## Terms and conventions
                     30: 
                     31: ### Definitions
                     32: 
                     33: The terminology surrounding PAM is rather confused. Neither Samar and Lai's 
                     34: original paper nor the XSSO specification made any attempt at formally defining 
                     35: terms for the various actors and entities involved in PAM, and the terms that 
                     36: they do use (but do not define) are sometimes misleading and ambiguous. The 
                     37: first attempt at establishing a consistent and unambiguous terminology was a 
                     38: whitepaper written by Andrew G. Morgan (author of Linux-PAM) in 1999. While 
                     39: Morgan's choice of terminology was a huge leap forward, it is in this author's 
                     40: opinion by no means perfect. What follows is an attempt, heavily inspired by 
                     41: Morgan, to define precise and unambiguous terms for all actors and entities 
                     42: involved in PAM.
                     43: 
                     44:  * *account* -- The set of credentials the applicant is requesting from the 
                     45:    arbitrator.
                     46: 
                     47:  * *applicant* -- The user or entity requesting authentication.
                     48: 
                     49:  * *arbitrator* -- The user or entity who has the privileges necessary to verify 
                     50:    the applicant's credentials and the authority to grant or deny the request.
                     51: 
                     52:  * *chain* -- A sequence of modules that will be invoked in response to a PAM 
                     53:    request. The chain includes information about the order in which to invoke 
                     54:    the modules, what arguments to pass to them, and how to interpret the 
                     55:    results.
                     56: 
                     57:  * *client* -- The application responsible for initiating an authentication 
                     58:    request on behalf of the applicant and for obtaining the necessary 
                     59:    authentication information from him.
                     60: 
                     61:  * *facility* -- One of the four basic groups of functionality provided by PAM: 
                     62:    authentication, account management, session management and authentication 
                     63:    token update.
                     64: 
                     65:  * *module* -- A collection of one or more related functions implementing a 
                     66:    particular authentication facility, gathered into a single (normally 
                     67:    dynamically loadable) binary file and identified by a single name.
                     68: 
                     69:  * *policy* -- The complete set of configuration statements describing how to 
                     70:    handle PAM requests for a particular service. A policy normally consists of 
                     71:    four chains, one for each facility, though some services do not use all four 
                     72:    facilities.
                     73: 
                     74:  * *server* -- The application acting on behalf of the arbitrator to converse 
                     75:    with the client, retrieve authentication information, verify the applicant's 
                     76:    credentials and grant or deny requests.
                     77: 
                     78:  * *service* -- A class of servers providing similar or related functionality 
                     79:    and requiring similar authentication. PAM policies are defined on a 
                     80:    per-service basis, so all servers that claim the same service name will be 
                     81:    subject to the same policy.
                     82: 
                     83:  * *session* -- The context within which service is rendered to the applicant by 
                     84:    the server. One of PAM's four facilities, session management, is concerned 
                     85:    exclusively with setting up and tearing down this context.
                     86: 
                     87:  * *token* -- A chunk of information associated with the account, such as a 
                     88:    password or passphrase, which the applicant must provide to prove his 
                     89:    identity.
                     90: 
                     91:  * *transaction* -- A sequence of requests from the same applicant to the same 
                     92:    instance of the same server, beginning with authentication and session set-up 
                     93:    and ending with session tear-down.
                     94: 
                     95: ### Usage examples
                     96: 
                     97: This section aims to illustrate the meanings of some of the terms defined above by way of a handful of simple examples.
                     98: 
                     99: #### Client and server are one
                    100: 
                    101: This simple example shows `alice` [su(1)](http://netbsd.gw.com/cgi-bin/man-cgi?su+1+NetBSD-5.0.1+i386)'ing to `root`.
                    102: 
                    103:     $ whoami
                    104:     alice
                    105:     $ ls -l `which su`
                    106:     -r-sr-xr-x  1 root  wheel  10744 Dec  6 19:06 /usr/bin/su
                    107:     $ su -
                    108:     Password: xi3kiune
                    109:     # whoami
                    110:     root
                    111: 
                    112:  * The applicant is `alice`.
                    113:  * The account is `root`.
                    114:  * The [su(1)](http://netbsd.gw.com/cgi-bin/man-cgi?su+1+NetBSD-5.0.1+i386) process is both client and server.
                    115:  * The authentication token is `xi3kiune`.
                    116:  * The arbitrator is `root`, which is why [su(1)](http://netbsd.gw.com/cgi-bin/man-cgi?su+1+NetBSD-5.0.1+i386) is setuid `root`.
                    117: 
                    118: #### Client and server are separate
                    119: 
                    120: The example below shows `eve` try to initiate an 
                    121: [ssh(1)](http://netbsd.gw.com/cgi-bin/man-cgi?ssh+1+NetBSD-5.0.1+i386) 
                    122: connection to `login.example.com`, ask to log in as `bob`, and succeed. Bob 
                    123: should have chosen a better password!
                    124: 
                    125:     $ whoami
                    126:     eve
                    127:     $ ssh bob@login.example.com
                    128:     bob@login.example.com's password: god
                    129:     Last login: Thu Oct 11 09:52:57 2001 from 192.168.0.1
                    130:     NetBSD 3.0 (LOGIN) #1: Thu Mar 10 18:22:36 WET 2005
                    131:     
                    132:     Welcome to NetBSD!
                    133:     $
                    134: 
                    135:  * The applicant is `eve`.
                    136:  * The client is Eve's [ssh(1)](http://netbsd.gw.com/cgi-bin/man-cgi?ssh+1+NetBSD-5.0.1+i386) process.
                    137:  * The server is the [sshd(8)](http://netbsd.gw.com/cgi-bin/man-cgi?sshd+8+NetBSD-5.0.1+i386) process on `login.example.com`
                    138:  * The account is `bob`.
                    139:  * The authentication token is `god`.
                    140:  * Although this is not shown in this example, the arbitrator is `root`.
                    141: 
                    142: #### Sample policy
                    143: 
                    144: The following is FreeBSD's default policy for `sshd`:
                    145: 
                    146:     sshd    auth        required    pam_nologin.so  no_warn
                    147:     sshd    auth        required    pam_unix.so no_warn try_first_pass
                    148:     sshd    account     required    pam_login_access.so
                    149:     sshd    account     required    pam_unix.so
                    150:     sshd    session     required    pam_lastlog.so  no_fail
                    151:     sshd    password    required    pam_permit.so
                    152: 
                    153:  * This policy applies to the `sshd` service (which is not necessarily 
                    154:    restricted to the 
                    155:    [sshd(8)](http://netbsd.gw.com/cgi-bin/man-cgi?sshd+8+NetBSD-5.0.1+i386) 
                    156:    server.)
                    157: 
                    158:  * `auth`, `account`, `session` and `password` are facilities.
                    159: 
                    160:  * `pam_nologin.so`, `pam_unix.so`, `pam_login_access.so`, `pam_lastlog.so` and 
                    161:    `pam_permit.so` are modules. It is clear from this example that `pam_unix.so` 
                    162:    provides at least two facilities (authentication and account management.)
                    163: 
                    164: There are some differences between FreeBSD and NetBSD PAM policies:
                    165: 
                    166:  * By default, every configuration is done under `/etc/pam.d`.
                    167: 
                    168:  * If configuration is non-existent, you will not have access to the system, in 
                    169:    contrast with FreeBSD that has a default policy of allowing authentication.
                    170: 
                    171:  * For authentication, NetBSD forces at least one `required`, `requisite` or 
                    172:    `binding` module to be present.
                    173: 
                    174: ## PAM Essentials
                    175: 
                    176: ### Facilities and primitives
                    177: 
                    178: The PAM API offers six different authentication primitives grouped in four 
                    179: facilities, which are described below.
                    180: 
                    181:  * `auth` -- *Authentication.* This facility concerns itself with authenticating 
                    182:    the applicant and establishing the account credentials. It provides two 
                    183:    primitives:
                    184: 
                    185:        * [pam\_authenticate(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_authenticate+3+NetBSD-5.0.1+i386) 
                    186:          authenticates the applicant, usually by requesting an authentication token 
                    187:          and comparing it with a value stored in a database or obtained from an 
                    188:          authentication server.
                    189: 
                    190:        * [pam\_setcred(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_setcred+3+NetBSD-5.0.1+i386) 
                    191:          establishes account credentials such as user ID, group membership and 
                    192:          resource limits.
                    193: 
                    194:  * `account` -- *Account management.* This facility handles 
                    195:    non-authentication-related issues of account availability, such as access 
                    196:    restrictions based on the time of day or the server's work load. It provides 
                    197:    a single primitive:
                    198: 
                    199:        * [pam\_acct\_mgmt(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_acct_mgmt+3+NetBSD-5.0.1+i386) 
                    200:          verifies that the requested account is available.
                    201: 
                    202:  * `session` -- *Session management.* This facility handles tasks associated 
                    203:    with session set-up and tear-down, such as login accounting. It provides two 
                    204:    primitives:
                    205: 
                    206:        * [pam\_open\_session(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_open_session+3+NetBSD-5.0.1+i386) 
                    207:          performs tasks associated with session set-up: add an entry in the `utmp` 
                    208:          and `wtmp` databases, start an SSH agent, etc.
                    209: 
                    210:        * [pam\_close\_session(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_close_session+3+NetBSD-5.0.1+i386) 
                    211:          performs tasks associated with session tear-down: add an entry in the 
                    212:          `utmp` and `wtmp` databases, stop the SSH agent, etc.
                    213: 
                    214:  * `password` -- *Password management.* This facility is used to change the 
                    215:    authentication token associated with an account, either because it has 
                    216:    expired or because the user wishes to change it. It provides a single 
                    217:    primitive:
                    218: 
                    219:        * [pam\_chauthtok(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_chauthtok+3+NetBSD-5.0.1+i386) 
                    220:          changes the authentication token, optionally verifying that it is 
                    221:          sufficiently hard to guess, has not been used previously, etc.
                    222: 
                    223: ### Modules
                    224: 
                    225: Modules are a very central concept in PAM; after all, they are the *M* in *PAM*. 
                    226: A PAM module is a self-contained piece of program code that implements the 
                    227: primitives in one or more facilities for one particular mechanism; possible 
                    228: mechanisms for the authentication facility, for instance, include the UNIX® 
                    229: password database, NIS, LDAP and Radius.
                    230: 
                    231: #### Module Naming
                    232: 
                    233: FreeBSD and NetBSD implement each mechanism in a single module, named 
                    234: `pam_mechanism`.so (for instance, `pam_unix.so` for the UNIX mechanism.) Other 
                    235: implementations sometimes have separate modules for separate facilities, and 
                    236: include the facility name as well as the mechanism name in the module name. To 
                    237: name one example, Solaris has a `pam_dial_auth.so.1` module which is commonly 
                    238: used to authenticate dialup users. Also, almost every module has a man page with 
                    239: the same name, i.e.: 
                    240: [pam\_unix(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_unix+8+NetBSD-5.0.1+i386) 
                    241: explains how the `pam_unix.so` module works.
                    242: 
                    243: #### Module Versioning
                    244: 
                    245: FreeBSD's original PAM implementation, based on Linux-PAM, did not use version 
                    246: numbers for PAM modules. This would commonly cause problems with legacy 
                    247: applications, which might be linked against older versions of the system 
                    248: libraries, as there was no way to load a matching version of the required 
                    249: modules.
                    250: 
                    251: OpenPAM, on the other hand, looks for modules that have the same version number 
                    252: as the PAM library (currently 2 in FreeBSD and 0 in NetBSD), and only falls back 
                    253: to an unversioned module if no versioned module could be loaded. Thus legacy 
                    254: modules can be provided for legacy applications, while allowing new (or newly 
                    255: built) applications to take advantage of the most recent modules.
                    256: 
                    257: Although Solaris PAM modules commonly have a version number, they're not truly 
                    258: versioned, because the number is a part of the module name and must be included 
                    259: in the configuration.
                    260: 
                    261: #### Module Path
                    262: 
                    263: There isn't a common directory for storing PAM modules. Under FreeBSD, they are 
                    264: located at `/usr/lib` and, under NetBSD, you can find them in 
                    265: `/usr/lib/security`.
                    266: 
                    267: ### Chains and policies
                    268: 
                    269: When a server initiates a PAM transaction, the PAM library tries to load a 
                    270: policy for the service specified in the 
                    271: [pam\_start(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_start+3+NetBSD-5.0.1+i386) 
                    272: call. The policy specifies how authentication requests should be processed, and 
                    273: is defined in a configuration file. This is the other central concept in PAM: 
                    274: the possibility for the admin to tune the system security policy (in the wider 
                    275: sense of the word) simply by editing a text file.
                    276: 
                    277: A policy consists of four chains, one for each of the four PAM facilities. Each 
                    278: chain is a sequence of configuration statements, each specifying a module to 
                    279: invoke, some (optional) parameters to pass to the module, and a control flag 
                    280: that describes how to interpret the return code from the module.
                    281: 
                    282: Understanding the control flags is essential to understanding PAM configuration 
                    283: files. There are a number of different control flags:
                    284: 
                    285:  * `binding` -- If the module succeeds and no earlier module in the chain has 
                    286:    failed, the chain is immediately terminated and the request is granted. If 
                    287:    the module fails, the rest of the chain is executed, but the request is 
                    288:    ultimately denied.
                    289: 
                    290:    This control flag was introduced by Sun in Solaris 9 (SunOS 5.9), and is also supported by OpenPAM.
                    291: 
                    292:  * `required` -- If the module succeeds, the rest of the chain is executed, and 
                    293:    the request is granted unless some other module fails. If the module fails, 
                    294:    the rest of the chain is also executed, but the request is ultimately denied.
                    295: 
                    296:  * `requisite` -- If the module succeeds, the rest of the chain is executed, and 
                    297:    the request is granted unless some other module fails. If the module fails, 
                    298:    the chain is immediately terminated and the request is denied.
                    299: 
                    300:  * `sufficient` -- If the module succeeds and no earlier module in the chain has 
                    301:    failed, the chain is immediately terminated and the request is granted. If 
                    302:    the module fails, the module is ignored and the rest of the chain is 
                    303:    executed.
                    304: 
                    305:    As the semantics of this flag may be somewhat confusing, especially when it is used for the last module in a chain, it is recommended that the `binding` control flag be used instead if the implementation supports it.
                    306: 
                    307:  * `optional` -- The module is executed, but its result is ignored. If all 
                    308:    modules in a chain are marked `optional`, all requests will always be 
                    309:    granted.
                    310: 
                    311: When a server invokes one of the six PAM primitives, PAM retrieves the chain for 
                    312: the facility the primitive belongs to, and invokes each of the modules listed in 
                    313: the chain, in the order they are listed, until it reaches the end, or determines 
                    314: that no further processing is necessary (either because a `binding` or 
                    315: `sufficient` module succeeded, or because a `requisite` module failed.) The 
                    316: request is granted if and only if at least one module was invoked, and all 
                    317: non-optional modules succeeded.
                    318: 
                    319: Note that it is possible, though not very common, to have the same module listed 
                    320: several times in the same chain. For instance, a module that looks up user names 
                    321: and passwords in a directory server could be invoked multiple times with 
                    322: different parameters specifying different directory servers to contact. PAM 
                    323: treat different occurrences of the same module in the same chain as different, 
                    324: unrelated modules.
                    325: 
                    326: ### Transactions
                    327: 
                    328: The lifecycle of a typical PAM transaction is described below. Note that if any 
                    329: of these steps fails, the server should report a suitable error message to the 
                    330: client and abort the transaction.
                    331: 
                    332:  1. If necessary, the server obtains arbitrator credentials through a mechanism 
                    333:     independent of PAM -- most commonly by virtue of having been started by `root`, 
                    334:     or of being setuid `root`.
                    335: 
                    336:  2. The server calls 
                    337:     [pam\_start(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_start+3+NetBSD-5.0.1+i386) 
                    338:     to initialize the PAM library and specify its service name and the target 
                    339:     account, and register a suitable conversation function.
                    340: 
                    341:  3. The server obtains various information relating to the transaction (such as 
                    342:     the applicant's user name and the name of the host the client runs on) and 
                    343:     submits it to PAM using 
                    344:     [pam\_set\_item(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_set_item+3+NetBSD-5.0.1+i386).
                    345: 
                    346:  4. The server calls 
                    347:     [pam\_authenticate(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_authenticate+3+NetBSD-5.0.1+i386) 
                    348:     to authenticate the applicant.
                    349: 
                    350:  5. The server calls 
                    351:     [pam\_acct\_mgmt(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_acct_mgmt+3+NetBSD-5.0.1+i386) 
                    352:     to verify that the requested account is available and valid. If the password is 
                    353:     correct but has expired, 
                    354:     [pam\_acct\_mgmt(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_acct_mgmt+3+NetBSD-5.0.1+i386) 
                    355:     will return `PAM_NEW_AUTHTOK_REQD` instead of `PAM_SUCCESS`.
                    356: 
                    357:  6. If the previous step returned `PAM_NEW_AUTHTOK_REQD`, the server now calls 
                    358:     [pam\_chauthtok(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_chauthtok+3+NetBSD-5.0.1+i386) 
                    359:     to force the client to change the authentication token for the requested 
                    360:     account.
                    361: 
                    362:  7. Now that the applicant has been properly authenticated, the server calls 
                    363:     [pam\_setcred(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_setcred+3+NetBSD-5.0.1+i386) 
                    364:     to establish the credentials of the requested account. It is able to do this 
                    365:     because it acts on behalf of the arbitrator, and holds the arbitrator's 
                    366:     credentials.
                    367: 
                    368:  8. Once the correct credentials have been established, the server calls 
                    369:     [pam\_open\_session(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_open_session+3+NetBSD-5.0.1+i386) 
                    370:     to set up the session.
                    371: 
                    372:  9. The server now performs whatever service the client requested -- for 
                    373:     instance, provide the applicant with a shell.
                    374: 
                    375: 10. Once the server is done serving the client, it calls 
                    376:     [pam\_close\_session(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_close_session+3+NetBSD-5.0.1+i386) 
                    377:     to tear down the session.
                    378: 
                    379: 11. Finally, the server calls 
                    380:     [pam\_end(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_end+3+NetBSD-5.0.1+i386) 
                    381:     to notify the PAM library that it is done and that it can release whatever 
                    382:     resources it has allocated in the course of the transaction.
                    383: 
                    384: ## PAM Configuration
                    385: 
                    386: ### PAM policy files
                    387: 
                    388: #### The `/etc/pam.conf` file
                    389: 
                    390: The traditional PAM policy file is `/etc/pam.conf`. This file contains all the 
                    391: PAM policies for your system. Each line of the file describes one step in a 
                    392: chain, as shown below:
                    393: 
                    394:     login   auth    required        pam_nologin.so  no_warn
                    395: 
                    396: The fields are, in order: service name, facility name, control flag, module 
                    397: name, and module arguments. Any additional fields are interpreted as additional 
                    398: module arguments.
                    399: 
                    400: A separate chain is constructed for each service / facility pair, so while the 
                    401: order in which lines for the same service and facility appear is significant, 
                    402: the order in which the individual services and facilities are listed is not. The 
                    403: examples in the original PAM paper grouped configuration lines by facility, and 
                    404: the Solaris stock `pam.conf` still does that, but FreeBSD's stock configuration 
                    405: groups configuration lines by service. Either way is fine; either way makes 
                    406: equal sense.
                    407: 
                    408: #### The `/etc/pam.d` directory
                    409: 
                    410: OpenPAM and Linux-PAM support an alternate configuration mechanism, which is the 
                    411: preferred mechanism in FreeBSD and NetBSD. In this scheme, each policy is 
                    412: contained in a separate file bearing the name of the service it applies to. 
                    413: These files are stored in `/etc/pam.d/`.
                    414: 
                    415: These per-service policy files have only four fields instead of `pam.conf`'s 
                    416: five: the service name field is omitted. Thus, instead of the sample `pam.conf` 
                    417: line from the previous section, one would have the following line in 
                    418: `/etc/pam.d/login`:
                    419: 
                    420:     auth    required        pam_nologin.so  no_warn
                    421: 
                    422: As a consequence of this simplified syntax, it is possible to use the same 
                    423: policy for multiple services by linking each service name to a same policy file. 
                    424: For instance, to use the same policy for the `su` and `sudo` services, one could 
                    425: do as follows:
                    426: 
                    427:     # cd /etc/pam.d
                    428:     # ln -s su sudo
                    429: 
                    430: This works because the service name is determined from the file name rather than 
                    431: specified in the policy file, so the same file can be used for multiple 
                    432: differently-named services.
                    433: 
                    434: Since each service's policy is stored in a separate file, the `pam.d` mechanism 
                    435: also makes it very easy to install additional policies for third-party software 
                    436: packages.
                    437: 
                    438: #### The policy search order
                    439: 
                    440: As we have seen above, PAM policies can be found in a number of places. If no 
                    441: configuration file is found for a particular service, the `/etc/pam.d/other` is 
                    442: used instead. If that file does not exist, `/etc/pam.conf` is searched for 
                    443: entries matching he specified service or, failing that, the "other" service.
                    444: 
                    445: It is essential to understand that PAM's configuration system is centered on 
                    446: chains.
                    447: 
                    448: ### Breakdown of a configuration line
                    449: 
                    450: As explained in the [PAM policy files](chap-pam.html#pam-config-file "18.5.1. 
                    451: PAM policy files") section, each line in `/etc/pam.conf` consists of four or 
                    452: more fields: the service name, the facility name, the control flag, the module 
                    453: name, and zero or more module arguments.
                    454: 
                    455: The service name is generally (though not always) the name of the application 
                    456: the statement applies to. If you are unsure, refer to the individual 
                    457: application's documentation to determine what service name it uses.
                    458: 
                    459: Note that if you use `/etc/pam.d/` instead of `/etc/pam.conf`, the service name 
                    460: is specified by the name of the policy file, and omitted from the actual 
                    461: configuration lines, which then start with the facility name.
                    462: 
                    463: The facility is one of the four facility keywords described in the
                    464: [[Facilities and primitives|guide/pam#facilities-primitives]]] section.
                    465: 
                    466: Likewise, the control flag is one of the four keywords described in the [[Chains 
                    467: and policies|guide/pam#chains-policies]] section, describing how to interpret 
                    468: the return code from the module. Linux-PAM supports an alternate syntax that 
                    469: lets you specify the action to associate with each possible return code, but 
                    470: this should be avoided as it is non-standard and closely tied in with the way 
                    471: Linux-PAM dispatches service calls (which differs greatly from the way Solaris 
                    472: and OpenPAM do it.) Unsurprisingly, OpenPAM does not support this syntax.
                    473: 
                    474: ### Policies
                    475: 
                    476: To configure PAM correctly, it is essential to understand how policies are 
                    477: interpreted.
                    478: 
                    479: When an application calls 
                    480: [pam\_start(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_start+3+NetBSD-5.0.1+i386), 
                    481: the PAM library loads the policy for the specified service and constructs four 
                    482: module chains (one for each facility.) If one or more of these chains are empty, 
                    483: the corresponding chains from the policy for the `other` service are 
                    484: substituted.
                    485: 
                    486: When the application later calls one of the six PAM primitives, the PAM library 
                    487: retrieves the chain for the corresponding facility and calls the appropriate 
                    488: service function in each module listed in the chain, in the order in which they 
                    489: were listed in the configuration. After each call to a service function, the 
                    490: module type and the error code returned by the service function are used to 
                    491: determine what happens next. With a few exceptions, which we discuss below, the 
                    492: following table applies:
                    493: 
                    494: [[!table data="""
                    495:            |   `PAM_SUCCESS`   | `PAM_IGNORE` |       `other`
                    496: binding    | if (!fail) break; |      -       |     fail = true;
                    497: required   |         -         |      -       |     fail = true;
                    498: requisite  |         -         |      -       | fail = true; break;
                    499: sufficient | if (!fail) break; |      -       |          -
                    500: optional   |         -         |      -       |          -
                    501: """]]
                    502: 
                    503: If `fail` is true at the end of a chain, or when a `break` is reached, the 
                    504: dispatcher returns the error code returned by the first module that failed. 
                    505: Otherwise, it returns `PAM_SUCCESS`.
                    506: 
                    507: The first exception of note is that the error code `PAM_NEW_AUTHTOK_REQD` is 
                    508: treated like a success, except that if no module failed, and at least one module 
                    509: returned `PAM_NEW_AUTHTOK_REQD`, the dispatcher will return 
                    510: `PAM_NEW_AUTHTOK_REQD`.
                    511: 
                    512: The second exception is that 
                    513: [pam\_setcred(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_setcred+3+NetBSD-5.0.1+i386) 
                    514: treats `binding` and `sufficient` modules as if they were `required`.
                    515: 
                    516: The third and final exception is that 
                    517: [pam\_chauthtok(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_chauthtok+3+NetBSD-5.0.1+i386) 
                    518: runs the entire chain twice (once for preliminary checks and once to actually 
                    519: set the password), and in the preliminary phase it treats `binding` and 
                    520: `sufficient` modules as if they were `required`.
                    521: 
                    522: ## PAM modules
                    523: 
                    524: ### Common Modules
                    525: 
                    526: #### pam\_deny(8)
                    527: 
                    528: The 
                    529: [pam\_deny(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_deny+8+NetBSD-5.0.1+i386) 
                    530: module is one of the simplest modules available; it responds to any request with 
                    531: `PAM_AUTH_ERR`. It is useful for quickly disabling a service (add it to the top 
                    532: of every chain), or for terminating chains of `sufficient` modules.
                    533: 
                    534: #### pam\_echo(8)
                    535: 
                    536: The 
                    537: [pam\_echo(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_echo+8+NetBSD-5.0.1+i386) 
                    538: module simply passes its arguments to the conversation function as a 
                    539: `PAM_TEXT_INFO` message. It is mostly useful for debugging, but can also serve 
                    540: to display messages such as `Unauthorized access will be prosecuted` before 
                    541: starting the authentication procedure.
                    542: 
                    543: #### pam\_exec(8)
                    544: 
                    545: The 
                    546: [pam\_exec(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_exec+8+NetBSD-5.0.1+i386) 
                    547: module takes its first argument to be the name of a program to execute, and the 
                    548: remaining arguments are passed to that program as command-line arguments. One 
                    549: possible application is to use it to run a program at login time which mounts 
                    550: the user's home directory.
                    551: 
                    552: #### pam\_ftpusers(8)
                    553: 
                    554: The 
                    555: [pam\_ftpusers(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_ftpusers+8+NetBSD-5.0.1+i386) 
                    556: module successes if and only if the user is listed in `/etc/ftpusers`. 
                    557: Currently, in NetBSD, this module doesn't understand the extended syntax of 
                    558: [ftpd(8)](http://netbsd.gw.com/cgi-bin/man-cgi?ftpd+8+NetBSD-5.0.1+i386), but 
                    559: this will be fixed in the future.
                    560: 
                    561: #### pam\_group(8)
                    562: 
                    563: The 
                    564: [pam\_group(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_group+8+NetBSD-5.0.1+i386) 
                    565: module accepts or rejects applicants on the basis of their membership in a 
                    566: particular file group (normally `wheel` for 
                    567: [su(1)](http://netbsd.gw.com/cgi-bin/man-cgi?su+1+NetBSD-5.0.1+i386)). It is 
                    568: primarily intended for maintaining the traditional behaviour of BSD 
                    569: [su(1)](http://netbsd.gw.com/cgi-bin/man-cgi?su+1+NetBSD-5.0.1+i386), but has 
                    570: many other uses, such as excluding certain groups of users from a particular 
                    571: service.
                    572: 
                    573: In NetBSD, there is an argument called `authenticate` in which the user is asked 
                    574: to authenticate using his own password.
                    575: 
                    576: #### pam\_guest(8)
                    577: 
                    578: The 
                    579: [pam\_guest(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_guest+8+NetBSD-5.0.1+i386) 
                    580: module allows guest logins using fixed login names. Various requirements can be 
                    581: placed on the password, but the default behaviour is to allow any password as 
                    582: long as the login name is that of a guest account. The 
                    583: [pam\_guest(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_guest+8+NetBSD-5.0.1+i386) 
                    584: module can easily be used to implement anonymous FTP logins.
                    585: 
                    586: #### pam\_krb5(8)
                    587: 
                    588: The 
                    589: [pam\_krb5(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_krb5+8+NetBSD-5.0.1+i386) 
                    590: module provides functions to verify the identity of a user and to set user 
                    591: specific credentials using Kerberos 5. It prompts the user for a password and 
                    592: obtains a new Kerberos TGT for the principal. The TGT is verified by obtaining a 
                    593: service ticket for the local host. The newly acquired credentials are stored in 
                    594: a credential cache and the environment variable KRB5CCNAME is set appropriately. 
                    595: The credentials cache should be destroyed by the user at logout with 
                    596: [kdestroy(1)](http://netbsd.gw.com/cgi-bin/man-cgi?kdestroy+1+NetBSD-5.0.1+i386).
                    597: 
                    598: #### pam\_ksu(8)
                    599: 
                    600: The 
                    601: [pam\_ksu(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_ksu+8+NetBSD-5.0.1+i386) 
                    602: module provides only authentication services for Kerberos 5 to determine whether 
                    603: or not the applicant is authorized to obtain the privileges of the target 
                    604: account.
                    605: 
                    606: #### pam\_lastlog(8)
                    607: 
                    608: The 
                    609: [pam\_lastlog(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_lastlog+8+NetBSD-5.0.1+i386) 
                    610: module provides only session management services. It records the session in 
                    611: [utmp(5)](http://netbsd.gw.com/cgi-bin/man-cgi?utmp+5+NetBSD-5.0.1+i386), 
                    612: [utmpx(5)](http://netbsd.gw.com/cgi-bin/man-cgi?utmpx+5+NetBSD-5.0.1+i386), 
                    613: [wtmp(5)](http://netbsd.gw.com/cgi-bin/man-cgi?wtmp+5+NetBSD-5.0.1+i386), 
                    614: [wtmpx(5)](http://netbsd.gw.com/cgi-bin/man-cgi?wtmpx+5+NetBSD-5.0.1+i386), 
                    615: [lastlog(5)](http://netbsd.gw.com/cgi-bin/man-cgi?lastlog+5+NetBSD-5.0.1+i386) 
                    616: and 
                    617: [lastlogx(5)](http://netbsd.gw.com/cgi-bin/man-cgi?lastlogx+5+NetBSD-5.0.1+i386) 
                    618: databases.
                    619: 
                    620: #### pam\_login\_access(8)
                    621: 
                    622: The 
                    623: [pam\_login\_access(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_login_access+8+NetBSD-5.0.1+i386) 
                    624: module provides an implementation of the account management primitive which 
                    625: enforces the login restrictions specified in the 
                    626: [login.access(5)](http://netbsd.gw.com/cgi-bin/man-cgi?login.access+5+NetBSD-5.0.1+i386) 
                    627: table.
                    628: 
                    629: #### pam\_nologin(8)
                    630: 
                    631: The 
                    632: [pam\_nologin(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_nologin+8+NetBSD-5.0.1+i386) 
                    633: module refuses non-root logins when `/var/run/nologin` exists. This file is 
                    634: normally created by 
                    635: [shutdown(8)](http://netbsd.gw.com/cgi-bin/man-cgi?shutdown+8+NetBSD-5.0.1+i386) 
                    636: when less than five minutes remain until the scheduled shutdown time.
                    637: 
                    638: #### pam\_permit(8)
                    639: 
                    640: The 
                    641: [pam\_permit(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_permit+8+NetBSD-5.0.1+i386) 
                    642: module is one of the simplest modules available; it responds to any request with 
                    643: `PAM_SUCCESS`. It is useful as a placeholder for services where one or more 
                    644: chains would otherwise be empty.
                    645: 
                    646: #### pam\_radius(8)
                    647: 
                    648: The 
                    649: [pam\_radius(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_radius+8+NetBSD-5.0.1+i386) 
                    650: module provides authentication services based upon the RADIUS (Remote 
                    651: Authentication Dial In User Service) protocol.
                    652: 
                    653: #### pam\_rhosts(8)
                    654: 
                    655: The 
                    656: [pam\_rhosts(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_rhosts+8+NetBSD-5.0.1+i386) 
                    657: module provides only authentication services. It reports success if and only if 
                    658: the target user's ID is not 0 and the remote host and user are listed in 
                    659: `/etc/hosts.equiv` or in the target user's `~/.rhosts`.
                    660: 
                    661: #### pam\_rootok(8)
                    662: 
                    663: The 
                    664: [pam\_rootok(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_rootok+8+NetBSD-5.0.1+i386) 
                    665: module reports success if and only if the real user id of the process calling it 
                    666: (which is assumed to be run by the applicant) is 0. This is useful for 
                    667: non-networked services such as 
                    668: [su(1)](http://netbsd.gw.com/cgi-bin/man-cgi?su+1+NetBSD-5.0.1+i386) or 
                    669: [passwd(1)](http://netbsd.gw.com/cgi-bin/man-cgi?passwd+1+NetBSD-5.0.1+i386), to 
                    670: which the `root` should have automatic access.
                    671: 
                    672: #### pam\_securetty(8)
                    673: 
                    674: The 
                    675: [pam\_securetty(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_securetty+8+NetBSD-5.0.1+i386) 
                    676: module provides only account services. It is used when the applicant is 
                    677: attempting to authenticate as superuser, and the process is attached to an 
                    678: insecure TTY.
                    679: 
                    680: #### pam\_self(8)
                    681: 
                    682: The 
                    683: [pam\_self(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_self+8+NetBSD-5.0.1+i386) 
                    684: module reports success if and only if the names of the applicant matches that of 
                    685: the target account. It is most useful for non-networked services such as 
                    686: [su(1)](http://netbsd.gw.com/cgi-bin/man-cgi?su+1+NetBSD-5.0.1+i386), where the 
                    687: identity of the applicant can be easily verified.
                    688: 
                    689: #### pam\_ssh(8)
                    690: 
                    691: The 
                    692: [pam\_ssh(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_ssh+8+NetBSD-5.0.1+i386) 
                    693: module provides both authentication and session services. The authentication 
                    694: service allows users who have passphrase-protected SSH secret keys in their 
                    695: `~/.ssh` directory to authenticate themselves by typing their passphrase. The 
                    696: session service starts 
                    697: [ssh-agent(1)](http://netbsd.gw.com/cgi-bin/man-cgi?ssh-agent+1+NetBSD-5.0.1+i386) 
                    698: and preloads it with the keys that were decrypted in the authentication phase. 
                    699: This feature is particularly useful for local logins, whether in X (using 
                    700: [xdm(1)](http://netbsd.gw.com/cgi-bin/man-cgi?xdm+1+NetBSD-5.0.1+i386) or 
                    701: another PAM-aware X login manager) or at the console.
                    702: 
                    703: This module implements what is fundamentally a password authentication scheme. 
                    704: Care should be taken to only use this module over a secure session (secure TTY, 
                    705: encrypted session, etc.), otherwise the user's SSH passphrase could be 
                    706: compromised.
                    707: 
                    708: Additional consideration should be given to the use of 
                    709: [pam\_ssh(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_ssh+8+NetBSD-5.0.1+i386). 
                    710: Users often assume that file permissions are sufficient to protect their SSH 
                    711: keys, and thus use weak or no passphrases. Since the system administrator has no 
                    712: effective means of enforcing SSH passphrase quality, this has the potential to 
                    713: expose the system to security risks.
                    714: 
                    715: #### pam\_unix(8)
                    716: 
                    717: The 
                    718: [pam\_unix(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_unix+8+NetBSD-5.0.1+i386) 
                    719: module implements traditional UNIX® password authentication, using 
                    720: [getpwnam(3)](http://netbsd.gw.com/cgi-bin/man-cgi?getpwnam+3+NetBSD-5.0.1+i386) 
                    721: under FreeBSD or 
                    722: [getpwnam\_r(3)](http://netbsd.gw.com/cgi-bin/man-cgi?getpwnam_r+3+NetBSD-5.0.1+i386) 
                    723: under NetBSD to obtain the target account's password and compare it with the one 
                    724: provided by the applicant. It also provides account management services 
                    725: (enforcing account and password expiration times) and password-changing 
                    726: services. This is probably the single most useful module, as the great majority 
                    727: of admins will want to maintain historical behaviour for at least some services.
                    728: 
                    729: ### NetBSD-specific PAM Modules
                    730: 
                    731: #### pam\_skey(8)
                    732: 
                    733: The 
                    734: [pam\_skey(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_skey+8+NetBSD-5.0.1+i386) 
                    735: module implements S/Key One Time Password (OTP) authentication methods, using 
                    736: the `/etc/skeykeys` database.
                    737: 
                    738: ## PAM Application Programming
                    739: 
                    740: This section has not yet been written.
                    741: 
                    742: ## PAM Module Programming
                    743: 
                    744: This section has not yet been written.
                    745: 
                    746: ## Sample PAM Application
                    747: 
                    748: The following is a minimal implementation of 
                    749: [su(1)](http://netbsd.gw.com/cgi-bin/man-cgi?su+1+NetBSD-5.0.1+i386) using PAM. 
                    750: Note that it uses the OpenPAM-specific 
                    751: [openpam\_ttyconv(3)](http://netbsd.gw.com/cgi-bin/man-cgi?openpam_ttyconv+3+NetBSD-5.0.1+i386) 
                    752: conversation function, which is prototyped in `security/openpam.h`. If you wish 
                    753: build this application on a system with a different PAM library, you will have 
                    754: to provide your own conversation function. A robust conversation function is 
                    755: surprisingly difficult to implement; the one presented in the [Sample PAM 
                    756: Conversation Function](chap-pam.html#pam-sample-conv "18.11. Sample PAM 
                    757: Conversation Function") sub-chapter is a good starting point, but should not be 
                    758: used in real-world applications.
                    759: 
                    760:     #include <sys/param.h>
                    761:     #include <sys/wait.h>
                    762:     
                    763:     #include <err.h>
                    764:     #include <pwd.h>
                    765:     #include <stdio.h>
                    766:     #include <stdlib.h>
                    767:     #include <string.h>
                    768:     #include <syslog.h>
                    769:     #include <unistd.h>
                    770:     
                    771:     #include <security/pam_appl.h>
                    772:     #include <security/openpam.h> /* for openpam_ttyconv() */
                    773:     
                    774:     extern char **environ;
                    775:     
                    776:     static pam_handle_t *pamh;
                    777:     static struct pam_conv pamc;
                    778:     
                    779:     static void
                    780:     usage(void)
                    781:     {
                    782:     
                    783:         fprintf(stderr, "Usage: su [login [args]]\n");
                    784:         exit(1);
                    785:     }
                    786:     
                    787:     int
                    788:     main(int argc, char *argv[])
                    789:     {
                    790:         char hostname[MAXHOSTNAMELEN];
                    791:         const char *user, *tty;
                    792:         char **args, **pam_envlist, **pam_env;
                    793:         struct passwd *pwd;
                    794:         int o, pam_err, status;
                    795:         pid_t pid;
                    796:     
                    797:         while ((o = getopt(argc, argv, "h")) != -1)
                    798:             switch (o) {
                    799:             case 'h':
                    800:             default:
                    801:                 usage();
                    802:             }
                    803:     
                    804:         argc -= optind;
                    805:         argv += optind;
                    806:     
                    807:         if (argc > 0) {
                    808:             user = *argv;
                    809:             --argc;
                    810:             ++argv;
                    811:         } else {
                    812:             user = "root";
                    813:         }
                    814:     
                    815:         /* initialize PAM */
                    816:         pamc.conv = &openpam_ttyconv;
                    817:         pam_start("su", user, &pamc, &pamh);
                    818:     
                    819:         /* set some items */
                    820:         gethostname(hostname, sizeof(hostname));
                    821:         if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
                    822:             goto pamerr;
                    823:         user = getlogin();
                    824:         if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
                    825:             goto pamerr;
                    826:         tty = ttyname(STDERR_FILENO);
                    827:         if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
                    828:             goto pamerr;
                    829:     
                    830:         /* authenticate the applicant */
                    831:         if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
                    832:             goto pamerr;
                    833:         if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
                    834:             pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
                    835:         if (pam_err != PAM_SUCCESS)
                    836:             goto pamerr;
                    837:     
                    838:         /* establish the requested credentials */
                    839:         if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
                    840:             goto pamerr;
                    841:     
                    842:         /* authentication succeeded; open a session */
                    843:         if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
                    844:             goto pamerr;
                    845:     
                    846:         /* get mapped user name; PAM may have changed it */
                    847:         pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
                    848:         if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
                    849:             goto pamerr;
                    850:     
                    851:         /* export PAM environment */
                    852:         if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
                    853:             for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
                    854:                 putenv(*pam_env);
                    855:                 free(*pam_env);
                    856:             }
                    857:             free(pam_envlist);
                    858:         }
                    859:     
                    860:         /* build argument list */
                    861:         if ((args = calloc(argc + 2, sizeof *args)) == NULL) {
                    862:             warn("calloc()");
                    863:             goto err;
                    864:         }
                    865:         *args = pwd->pw_shell;
                    866:         memcpy(args + 1, argv, argc * sizeof *args);
                    867:     
                    868:         /* fork and exec */
                    869:         switch ((pid = fork())) {
                    870:         case -1:
                    871:             warn("fork()");
                    872:             goto err;
                    873:         case 0:
                    874:             /* child: give up privs and start a shell */
                    875:     
                    876:             /* set uid and groups */
                    877:             if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
                    878:                 warn("initgroups()");
                    879:                 _exit(1);
                    880:             }
                    881:             if (setgid(pwd->pw_gid) == -1) {
                    882:                 warn("setgid()");
                    883:                 _exit(1);
                    884:             }
                    885:             if (setuid(pwd->pw_uid) == -1) {
                    886:                 warn("setuid()");
                    887:                 _exit(1);
                    888:             }
                    889:             execve(*args, args, environ);
                    890:             warn("execve()");
                    891:             _exit(1);
                    892:         default:
                    893:             /* parent: wait for child to exit */
                    894:             waitpid(pid, &status, 0);
                    895:     
                    896:             /* close the session and release PAM resources */
                    897:             pam_err = pam_close_session(pamh, 0);
                    898:             pam_end(pamh, pam_err);
                    899:     
                    900:             exit(WEXITSTATUS(status));
                    901:         }
                    902:     
                    903:     pamerr:
                    904:         fprintf(stderr, "Sorry\n");
                    905:     err:
                    906:         pam_end(pamh, pam_err);
                    907:         exit(1);
                    908:     }
                    909: 
                    910: ## Sample PAM Module
                    911: 
                    912: The following is a minimal implementation of 
                    913: [pam\_unix(8)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_unix+8+NetBSD-5.0.1+i386), 
                    914: offering only authentication services. It should build and run with most PAM 
                    915: implementations, but takes advantage of OpenPAM extensions if available: note 
                    916: the use of 
                    917: [pam\_get\_authtok(3)](http://netbsd.gw.com/cgi-bin/man-cgi?pam_get_authtok+3+NetBSD-5.0.1+i386), 
                    918: which enormously simplifies prompting the user for a password.
                    919: 
                    920:     #include <sys/param.h>
                    921:     
                    922:     #include <pwd.h>
                    923:     #include <stdlib.h>
                    924:     #include <stdio.h>
                    925:     #include <string.h>
                    926:     #include <unistd.h>
                    927:     
                    928:     #include <security/pam_modules.h>
                    929:     #include <security/pam_appl.h>
                    930:     
                    931:     #ifndef _OPENPAM
                    932:     static char password_prompt[] = "Password:";
                    933:     #endif
                    934:     
                    935:     #ifndef PAM_EXTERN
                    936:     #define PAM_EXTERN
                    937:     #endif
                    938:     
                    939:     PAM_EXTERN int
                    940:     pam_sm_authenticate(pam_handle_t *pamh, int flags,
                    941:         int argc, const char *argv[])
                    942:     {
                    943:     #ifndef _OPENPAM
                    944:         const void *ptr;
                    945:         const struct pam_conv *conv;
                    946:         struct pam_message msg;
                    947:         const struct pam_message *msgp;
                    948:         struct pam_response *resp;
                    949:     #endif
                    950:         struct passwd *pwd;
                    951:         const char *user;
                    952:         char *crypt_password, *password;
                    953:         int pam_err, retry;
                    954:     
                    955:         /* identify user */
                    956:         if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
                    957:             return (pam_err);
                    958:         if ((pwd = getpwnam(user)) == NULL)
                    959:             return (PAM_USER_UNKNOWN);
                    960:     
                    961:         /* get password */
                    962:     #ifndef _OPENPAM
                    963:         pam_err = pam_get_item(pamh, PAM_CONV, &ptr);
                    964:         if (pam_err != PAM_SUCCESS)
                    965:             return (PAM_SYSTEM_ERR);
                    966:         conv = ptr;
                    967:         msg.msg_style = PAM_PROMPT_ECHO_OFF;
                    968:         msg.msg = password_prompt;
                    969:         msgp = &msg;
                    970:     #endif
                    971:         password = NULL;
                    972:         for (retry = 0; retry < 3; ++retry) {
                    973:     #ifdef _OPENPAM
                    974:             pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
                    975:                 (const char **)&password, NULL);
                    976:     #else
                    977:             resp = NULL;
                    978:             pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
                    979:             if (resp != NULL) {
                    980:                 if (pam_err == PAM_SUCCESS)
                    981:                     password = resp->resp;
                    982:                 else
                    983:                     free(resp->resp);
                    984:                 free(resp);
                    985:             }
                    986:     #endif
                    987:             if (pam_err == PAM_SUCCESS)
                    988:                 break;
                    989:         }
                    990:         if (pam_err == PAM_CONV_ERR)
                    991:             return (pam_err);
                    992:         if (pam_err != PAM_SUCCESS)
                    993:             return (PAM_AUTH_ERR);
                    994:     
                    995:         /* compare passwords */
                    996:         if ((!pwd->pw_passwd[0] && (flags & PAM_DISALLOW_NULL_AUTHTOK)) ||
                    997:             (crypt_password = crypt(password, pwd->pw_passwd)) == NULL ||
                    998:             strcmp(crypt_password, pwd->pw_passwd) != 0)
                    999:             pam_err = PAM_AUTH_ERR;
                   1000:         else
                   1001:             pam_err = PAM_SUCCESS;
                   1002:     #ifndef _OPENPAM
                   1003:         free(password);
                   1004:     #endif
                   1005:         return (pam_err);
                   1006:     }
                   1007:     
                   1008:     PAM_EXTERN int
                   1009:     pam_sm_setcred(pam_handle_t *pamh, int flags,
                   1010:         int argc, const char *argv[])
                   1011:     {
                   1012:     
                   1013:         return (PAM_SUCCESS);
                   1014:     }
                   1015:     
                   1016:     PAM_EXTERN int
                   1017:     pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
                   1018:         int argc, const char *argv[])
                   1019:     {
                   1020:     
                   1021:         return (PAM_SUCCESS);
                   1022:     }
                   1023:     
                   1024:     PAM_EXTERN int
                   1025:     pam_sm_open_session(pam_handle_t *pamh, int flags,
                   1026:         int argc, const char *argv[])
                   1027:     {
                   1028:     
                   1029:         return (PAM_SUCCESS);
                   1030:     }
                   1031:     
                   1032:     PAM_EXTERN int
                   1033:     pam_sm_close_session(pam_handle_t *pamh, int flags,
                   1034:         int argc, const char *argv[])
                   1035:     {
                   1036:     
                   1037:         return (PAM_SUCCESS);
                   1038:     }
                   1039:     
                   1040:     PAM_EXTERN int
                   1041:     pam_sm_chauthtok(pam_handle_t *pamh, int flags,
                   1042:         int argc, const char *argv[])
                   1043:     {
                   1044:     
                   1045:         return (PAM_SERVICE_ERR);
                   1046:     }
                   1047:     
                   1048:     #ifdef PAM_MODULE_ENTRY
                   1049:     PAM_MODULE_ENTRY("pam_unix");
                   1050:     #endif
                   1051: 
                   1052: ## Sample PAM Conversation Function
                   1053: 
                   1054: The conversation function presented below is a greatly simplified version of 
                   1055: OpenPAM's 
                   1056: [openpam\_ttyconv(3)](http://netbsd.gw.com/cgi-bin/man-cgi?openpam_ttyconv+3+NetBSD-5.0.1+i386). 
                   1057: It is fully functional, and should give the reader a good idea of how a 
                   1058: conversation function should behave, but it is far too simple for real-world 
                   1059: use. Even if you're not using OpenPAM, feel free to download the source code and 
                   1060: adapt 
                   1061: [openpam\_ttyconv(3)](http://netbsd.gw.com/cgi-bin/man-cgi?openpam_ttyconv+3+NetBSD-5.0.1+i386) 
                   1062: to your uses; we believe it to be as robust as a tty-oriented conversation 
                   1063: function can reasonably get.
                   1064: 
                   1065:     #include <stdio.h>
                   1066:     #include <stdlib.h>
                   1067:     #include <string.h>
                   1068:     #include <unistd.h>
                   1069:     
                   1070:     #include <security/pam_appl.h>
                   1071:     
                   1072:     int
                   1073:     converse(int n, const struct pam_message **msg,
                   1074:         struct pam_response **resp, void *data)
                   1075:     {
                   1076:         struct pam_response *aresp;
                   1077:         char buf[PAM_MAX_RESP_SIZE];
                   1078:         int i;
                   1079:     
                   1080:         data = data;
                   1081:         if (n <= 0 || n > PAM_MAX_NUM_MSG)
                   1082:             return (PAM_CONV_ERR);
                   1083:         if ((aresp = calloc(n, sizeof *aresp)) == NULL)
                   1084:             return (PAM_BUF_ERR);
                   1085:         for (i = 0; i < n; ++i) {
                   1086:             aresp[i].resp_retcode = 0;
                   1087:             aresp[i].resp = NULL;
                   1088:             switch (msg[i]->msg_style) {
                   1089:             case PAM_PROMPT_ECHO_OFF:
                   1090:                 aresp[i].resp = strdup(getpass(msg[i]->msg));
                   1091:                 if (aresp[i].resp == NULL)
                   1092:                     goto fail;
                   1093:                 break;
                   1094:             case PAM_PROMPT_ECHO_ON:
                   1095:                 fputs(msg[i]->msg, stderr);
                   1096:                 if (fgets(buf, sizeof buf, stdin) == NULL)
                   1097:                     goto fail;
                   1098:                 aresp[i].resp = strdup(buf);
                   1099:                 if (aresp[i].resp == NULL)
                   1100:                     goto fail;
                   1101:                 break;
                   1102:             case PAM_ERROR_MSG:
                   1103:                 fputs(msg[i]->msg, stderr);
                   1104:                 if (strlen(msg[i]->msg) > 0 &&
                   1105:                     msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                   1106:                     fputc('\n', stderr);
                   1107:                 break;
                   1108:             case PAM_TEXT_INFO:
                   1109:                 fputs(msg[i]->msg, stdout);
                   1110:                 if (strlen(msg[i]->msg) > 0 &&
                   1111:                     msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                   1112:                     fputc('\n', stdout);
                   1113:                 break;
                   1114:             default:
                   1115:                 goto fail;
                   1116:             }
                   1117:         }
                   1118:         *resp = aresp;
                   1119:         return (PAM_SUCCESS);
                   1120:      fail:
                   1121:             for (i = 0; i < n; ++i) {
                   1122:                     if (aresp[i].resp != NULL) {
                   1123:                             memset(aresp[i].resp, 0, strlen(aresp[i].resp));
                   1124:                             free(aresp[i].resp);
                   1125:                     }
                   1126:             }
                   1127:             memset(aresp, 0, n * sizeof *aresp);
                   1128:         *resp = NULL;
                   1129:         return (PAM_CONV_ERR);
                   1130:     }
                   1131: 
                   1132: ## Further Reading
                   1133: 
                   1134: ### Papers
                   1135: 
                   1136:  * *[sun-pam]: [Making Login Services Independent of Authentication Technologies](http://www.sun.com/software/solaris/pam/pam.external.pdf)*. Vipin Samar and Charlie Lai. Sun Microsystems.
                   1137:  * *[opengroup-singlesignon]: [X/Open Single Sign-on Preliminary Specification](http://www.opengroup.org/pubs/catalog/p702.htm)*. The Open Group. 1-85912-144-6. June 1997.
                   1138:  * *[kernelorg-pamdraft]: [Pluggable Authentication Modules](http://www.kernel.org/pub/linux/libs/pam/pre/doc/current-draft.txt)*. Andrew G. Morgan. October 6, 1999.
                   1139: 
                   1140: ### User Manuals
                   1141: 
                   1142:  * *[sun-pamadmin]: [PAM Administration](http://www.sun.com/software/solaris/pam/pam.admin.pdf)*. Sun Microsystems.
                   1143: 
                   1144: ### Related Web pages
                   1145: 
                   1146:  * *[openpam-website]: [OpenPAM homepage](http://openpam.sourceforge.net/)*. Dag-Erling Smørgrav. ThinkSec AS.
                   1147:  * *[linuxpam-website]: [Linux-PAM homepage](http://www.kernel.org/pub/linux/libs/pam/)*. Andrew G. Morgan.
                   1148:  * *[solarispam-website]: [Solaris PAM homepage](http://www.sun.com/software/solaris/pam/)*. Sun Microsystems.
                   1149: 
1.2     ! jdf      1150: ### Networks Associates Technology's license on the PAM article
        !          1151: 
        !          1152: Copyright (c) 2001-2003 Networks Associates Technology, Inc.  
        !          1153: All rights reserved.  
        !          1154: This software was developed for the FreeBSD Project by ThinkSec AS and  
        !          1155: Network Associates Laboratories, the Security Research Division of  
        !          1156: Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035  
        !          1157: ("CBOSS"), as part of the DARPA CHATS research program.  
        !          1158: Redistribution and use in source and binary forms, with or without  
        !          1159: modification, are permitted provided that the following conditions  
        !          1160: are met:  
        !          1161: 1. Redistributions of source code must retain the above copyright  
        !          1162:    notice, this list of conditions and the following disclaimer.  
        !          1163: 2. Redistributions in binary form must reproduce the above copyright  
        !          1164:    notice, this list of conditions and the following disclaimer in the  
        !          1165:    documentation and/or other materials provided with the distribution.  
        !          1166: 3. The name of the author may not be used to endorse or promote  
        !          1167:    products derived from this software without specific prior written  
        !          1168:    permission.  
        !          1169: THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND  
        !          1170: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
        !          1171: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
        !          1172: ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE  
        !          1173: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
        !          1174: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  
        !          1175: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  
        !          1176: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  
        !          1177: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  
        !          1178: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  
        !          1179: SUCH DAMAGE.

CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb