File:  [NetBSD Developer Wiki] / wikisrc / guide / pam.mdwn
Revision 1.3: download - view: text, annotated - select for diffs
Sun Mar 10 09:58:15 2013 UTC (7 years, 7 months ago) by jdf
Branches: MAIN
CVS tags: HEAD
Remove trailing whitespaces.

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

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