Catch up with the current state of -CURRENT, and discuss the differences
between OpenPAM, Linux-PAM and Solaris PAM in some more detail. Also add IDs to most sections and their titles, and an appendix listing a sample conversation function. Translators: please leave for later, there's still a lot to do. Sponsored by: DARPA, NAI Labs
This commit is contained in:
parent
70a78a3610
commit
a0e5c66ae0
Notes:
svn2git
2020-12-08 03:00:23 +00:00
svn path=/head/; revision=13327
2 changed files with 190 additions and 117 deletions
|
@ -9,13 +9,16 @@ INSTALL_ONLY_COMPRESSED?=
|
|||
|
||||
JADEFLAGS+= -V %generate-article-toc%
|
||||
|
||||
SRCS= article.sgml pam_app.c pam_module.c
|
||||
SRCS= article.sgml pam_app.c pam_conv.c pam_module.c
|
||||
|
||||
CLEANFILES+= pam_app.c pam_module.c
|
||||
CLEANFILES+= pam_app.c pam_conv.c pam_module.c
|
||||
|
||||
pam_app.c: su.c
|
||||
sed -e '/^[\/ ]\*/d' ${.ALLSRC} >${.TARGET}
|
||||
|
||||
pam_conv.c: converse.c
|
||||
sed -e '/^[\/ ]\*/d' ${.ALLSRC} >${.TARGET}
|
||||
|
||||
pam_module.c: pam_unix.c
|
||||
sed -e '/^[\/ ]\*/d' ${.ALLSRC} >${.TARGET}
|
||||
|
||||
|
|
|
@ -76,13 +76,13 @@
|
|||
At the time of this writing, this specification has not yet been
|
||||
adopted as a standard.</para>
|
||||
|
||||
<para>Although this article focuses on FreeBSD's implementation of
|
||||
PAM, which is based on Linux-PAM, most of it should be
|
||||
applicable to most other operating systems which implement PAM,
|
||||
including Solaris.</para>
|
||||
<para>Although this article focuses primarily on FreeBSD 5.x,
|
||||
which uses OpenPAM, it should be equally applicable to FreeBSD
|
||||
4.x, which uses Linux-PAM, and other operating systems such as
|
||||
Linux and Solaris.</para>
|
||||
|
||||
<section>
|
||||
<title>Trademarks</title>
|
||||
<section id="pam-trademarks">
|
||||
<title id="pam-trademarks.title">Trademarks</title>
|
||||
|
||||
<para>Sun, Sun Microsystems and Solaris are trademarks or
|
||||
registered trademarks of Sun Microsystems, Inc.</para>
|
||||
|
@ -245,8 +245,8 @@
|
|||
</glosslist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Usage examples</title>
|
||||
<section id="pam-usage-examples">
|
||||
<title id="pam-usage-examples.title">Usage examples</title>
|
||||
|
||||
<para>This section aims to illustrate the meanings of some of
|
||||
the terms defined above by way of a handful of simple
|
||||
|
@ -342,11 +342,14 @@ Welcome to FreeBSD!
|
|||
<para>The following is FreeBSD's default policy for
|
||||
<literal>sshd</literal>:</para>
|
||||
|
||||
<programlisting>sshd auth required pam_nologin.so no_warn
|
||||
sshd auth required pam_unix.so no_warn try_first_pass
|
||||
sshd account required pam_unix.so
|
||||
sshd session required pam_permit.so
|
||||
sshd password required pam_permit.so</programlisting>
|
||||
<programlisting>
|
||||
sshd auth required pam_nologin.so no_warn
|
||||
sshd auth required pam_unix.so no_warn try_first_pass
|
||||
sshd account required pam_login_access.so
|
||||
sshd account required pam_unix.so
|
||||
sshd session required pam_lastlog.so no_fail
|
||||
sshd password required pam_permit.so
|
||||
</programlisting>
|
||||
|
||||
|
||||
<itemizedlist>
|
||||
|
@ -362,19 +365,21 @@ sshd password required pam_permit.so</programlisting>
|
|||
</listitem>
|
||||
<listitem>
|
||||
<para><filename>pam_nologin.so</filename>,
|
||||
<filename>pam_unix.so</filename> and
|
||||
<filename>pam_unix.so</filename>,
|
||||
<filename>pam_login_access.so</filename>,
|
||||
<filename>pam_lastlog.so</filename> and
|
||||
<filename>pam_permit.so</filename> are modules. It is
|
||||
clear from this example that
|
||||
<filename>pam_unix.so</filename> and
|
||||
<filename>pam_permit.so</filename> provide at least two
|
||||
facilities each.</para>
|
||||
<filename>pam_unix.so</filename> provides at least two
|
||||
facilities (authentication and account
|
||||
management.)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Conventions</title>
|
||||
<section id="pam-conventions">
|
||||
<title id="pam-conventions.title">Conventions</title>
|
||||
|
||||
<para><!--XXX-->This section has not yet been written.</para>
|
||||
</section>
|
||||
|
@ -401,17 +406,17 @@ sshd password required pam_permit.so</programlisting>
|
|||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><function>pam_authenticate</function>
|
||||
authenticates the applicant, usually by requesting
|
||||
an authentication token and comparing it with a
|
||||
value stored in a database or obtained from an
|
||||
authentication server.</para>
|
||||
<para>&man.pam.authenticate.3; authenticates the
|
||||
applicant, usually by requesting an authentication
|
||||
token and comparing it with a value stored in a
|
||||
database or obtained from an authentication
|
||||
server.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><function>pam_setcred</function> establishes
|
||||
account credentials such as user ID, group
|
||||
membership and resource limits.</para>
|
||||
<para>&man.pam.setcred.3; establishes account
|
||||
credentials such as user ID, group membership and
|
||||
resource limits.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
@ -428,8 +433,8 @@ sshd password required pam_permit.so</programlisting>
|
|||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><function>pam_acct_mgmt</function> verifies that
|
||||
the requested account is available.</para>
|
||||
<para>&man.pam.acct.mgmt.3; verifies that the
|
||||
requested account is available.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
@ -445,17 +450,17 @@ sshd password required pam_permit.so</programlisting>
|
|||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><function>pam_open_session</function> performs
|
||||
tasks associated with session set-up: add an entry
|
||||
in the <filename>utmp</filename> and
|
||||
<para>&man.pam.open.session.3; performs tasks
|
||||
associated with session set-up: add an entry in the
|
||||
<filename>utmp</filename> and
|
||||
<filename>wtmp</filename> databases, start an SSH
|
||||
agent, etc.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><function>pam_close_session</function> performs
|
||||
tasks associated with session tear-down: add an
|
||||
entry in the <filename>utmp</filename> and
|
||||
<para>&man.pam.close.session.3; performs tasks
|
||||
associated with session tear-down: add an entry in
|
||||
the <filename>utmp</filename> and
|
||||
<filename>wtmp</filename> databases, stop the SSH
|
||||
agent, etc.</para>
|
||||
</listitem>
|
||||
|
@ -474,10 +479,10 @@ sshd password required pam_permit.so</programlisting>
|
|||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><function>pam_chauthtok</function> changes the
|
||||
authentication token, optionally verifying that it
|
||||
is sufficiently hard to guess, has not been used
|
||||
previously, etc.</para>
|
||||
<para>&man.pam.chauthtok.3; changes the authentication
|
||||
token, optionally verifying that it is sufficiently
|
||||
hard to guess, has not been used previously,
|
||||
etc.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
@ -486,8 +491,8 @@ sshd password required pam_permit.so</programlisting>
|
|||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Modules</title>
|
||||
<section id="pam-modules">
|
||||
<title id="pam-modules.title">Modules</title>
|
||||
|
||||
<para>Modules are a very central concept in PAM; after all,
|
||||
they are the <quote>M</quote> in <quote>PAM</quote>. A PAM
|
||||
|
@ -497,14 +502,44 @@ sshd password required pam_permit.so</programlisting>
|
|||
authentication facility, for instance, include the UNIX
|
||||
password database, NIS, LDAP and Radius.</para>
|
||||
|
||||
<para>FreeBSD groups all facilities for the same mechanism in
|
||||
one module called
|
||||
<literal>pam_<replaceable>mechanism</replaceable>.so</literal> (e.g.
|
||||
<literal>pam_unix.so</literal>.) The original PAM
|
||||
implementation, on the other hand, had separate modules for
|
||||
each facility, called
|
||||
<literal>pam_<replaceable>mechanism</replaceable>_<replaceable>facility</replaceable>.so</literal>
|
||||
(e.g. <literal>pam_unix_auth.so</literal>.)</para>
|
||||
<section id="pam-module-naming">
|
||||
<title id="pam-module-naming.title">Module Naming</title>
|
||||
|
||||
<para>FreeBSD implements each mechanism in a single module,
|
||||
named
|
||||
<literal>pam_<replaceable>mechanism</replaceable>.so</literal>
|
||||
(for instance, <literal>pam_unix.so</literal> for the Unix
|
||||
mechanism.) Other implementations sometimes have separate
|
||||
modules for separate facilities, and include the facility
|
||||
name as well as the mechanism name in the module name. To
|
||||
name one example, Solaris has a
|
||||
<literal>pam_dial_auth.so.1</literal> module which is
|
||||
commonly used to authenticate dialup users.</para>
|
||||
</section>
|
||||
|
||||
<section id="pam-module-versioning">
|
||||
<title id="pam-module-versioning.title">Module Versioning</title>
|
||||
|
||||
<para>FreeBSD's original PAM implementation, based on
|
||||
Linux-PAM, did not use version numbers for PAM modules.
|
||||
This would commonly cause problems with legacy applications,
|
||||
which might be linked against older versions of the system
|
||||
libraries, as there was no way to load a matching version of
|
||||
the required modules.</para>
|
||||
|
||||
<para>OpenPAM, on the other hand, looks for modules that have
|
||||
the same version number as the PAM library (currently 2),
|
||||
and only falls back to an unversioned module if no versioned
|
||||
module could be loaded. Thus legacy modules can be provided
|
||||
for legacy applications, while allowing new (or newly built)
|
||||
applications to take advantage of the most recent
|
||||
modules.</para>
|
||||
|
||||
<para>Although Solaris PAM modules commonly have a version
|
||||
number, they're not truly versioned, because the number is a
|
||||
part of the module name and must be included in the
|
||||
configuration.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="pam-chains-policies">
|
||||
|
@ -513,7 +548,7 @@ sshd password required pam_permit.so</programlisting>
|
|||
|
||||
<para>When a server initiates a PAM transaction, the PAM library
|
||||
tries to load a policy for the service specified in the
|
||||
<function>pam_start</function> call. The policy specifies how
|
||||
&man.pam.start.3; call. The policy specifies how
|
||||
authentication requests should be processed, and is defined in
|
||||
a configuration file. This is the other central concept in
|
||||
PAM: the possibility for the admin to tune the system security
|
||||
|
@ -586,8 +621,8 @@ sshd password required pam_permit.so</programlisting>
|
|||
in the same chain as different, unrelated modules.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Transactions</title>
|
||||
<section id="pam-transactions">
|
||||
<title id="pam-transactions.title">Transactions</title>
|
||||
|
||||
<para>The lifecycle of a typical PAM transaction is described
|
||||
below. Note that if this any of these steps fails, the server
|
||||
|
@ -604,53 +639,51 @@ sshd password required pam_permit.so</programlisting>
|
|||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The server calls <function>pam_start</function> to
|
||||
initialize the PAM library and specify its service name
|
||||
and the target account, and register a suitable
|
||||
conversation function.</para>
|
||||
<para>The server calls &man.pam.start.3; to initialize the
|
||||
PAM library and specify its service name and the target
|
||||
account, and register a suitable conversation
|
||||
function.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The server obtains various information relating to the
|
||||
transaction (such as the applicant's user name and the
|
||||
name of the host the client runs on) and submits it to PAM
|
||||
using <function>pam_set_item</function>.</para>
|
||||
using &man.pam.set.item.3;.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The server calls <function>pam_authenticate</function>
|
||||
to authenticate the applicant.</para>
|
||||
<para>The server calls &man.pam.authenticate.3; to
|
||||
authenticate the applicant.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The server calls <function>pam_acct_mgmt</function> to
|
||||
verify that the requested account is available and valid.
|
||||
The <function>pam_acct_mgmt</function> function will
|
||||
return <literal>PAM_NEW_AUTHTOK_REQD</literal> if the
|
||||
account's password has expired.</para>
|
||||
<para>The server calls &man.pam.acct.mgmt.3; verify that the
|
||||
requested account is available and valid. If the password
|
||||
is correct but has expired, &man.pam.acct.mgmt.3; will
|
||||
return <literal>PAM_NEW_AUTHTOK_REQD</literal> instead of
|
||||
<literal>PAM_SUCCESS</literal>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>If the previous step returned
|
||||
<literal>PAM_NEW_AUTHTOK_REQD</literal>, the server now
|
||||
calls <function>pam_chauthtok</function> to force the
|
||||
client to change the authentication token for the
|
||||
requested account.</para>
|
||||
calls &man.pam.chauthtok.3; to force the client to change
|
||||
the authentication token for the requested account.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Now that the applicant has been properly
|
||||
authenticated, the server calls
|
||||
<function>pam_setcred</function> to establish the
|
||||
credentials of the requested account. It is able to do
|
||||
this because it acts on behalf of the arbitrator, and
|
||||
holds the arbitrator's credentials.</para>
|
||||
authenticated, the server calls &man.pam.setcred.3; to
|
||||
establish the credentials of the requested account. It is
|
||||
able to do this because it acts on behalf of the
|
||||
arbitrator, and holds the arbitrator's credentials.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Once the correct credentials have been established,
|
||||
the server calls <function>pam_open_session</function> to
|
||||
set up the session.</para>
|
||||
the server calls &man.pam.open.session.3; to set up the
|
||||
session.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
|
@ -661,15 +694,14 @@ sshd password required pam_permit.so</programlisting>
|
|||
|
||||
<listitem>
|
||||
<para>Once the server is done serving the client, it calls
|
||||
<function>pam_close_session</function> to tear down the
|
||||
session.</para>
|
||||
&man.pam.close.session.3; to tear down the session.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Finally, the server calls <function>pam_end</function>
|
||||
to notify the PAM library that it is done and that it can
|
||||
release whatever resources it has allocated in the course
|
||||
of the transaction.</para>
|
||||
<para>Finally, the server calls &man.pam.end.3; to notify
|
||||
the PAM library that it is done and that it can release
|
||||
whatever resources it has allocated in the course of the
|
||||
transaction.</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</section>
|
||||
|
@ -679,7 +711,8 @@ sshd password required pam_permit.so</programlisting>
|
|||
<title id="pam-config.title">PAM Configuration</title>
|
||||
|
||||
<section id="pam-config-file-locations">
|
||||
<title>Location of configuration files</title>
|
||||
<title id="pam-config-file-locations.title">Location of
|
||||
configuration files</title>
|
||||
|
||||
<para>The traditional PAM configuration file is
|
||||
<filename>/etc/pam.conf</filename>. This file contains all
|
||||
|
@ -701,20 +734,20 @@ sshd password required pam_permit.so</programlisting>
|
|||
service, which serves as a fall-back, should come last. The
|
||||
examples in the original PAM paper grouped configuration lines
|
||||
by facility, and Solaris' stock <filename>pam.conf</filename>
|
||||
still does that, but Linux-PAM (and hence FreeBSD) groups
|
||||
still does that, but FreeBSD's stock configuration groups
|
||||
configuration lines by service. Either way is fine; either
|
||||
way makes equal sense.</para>
|
||||
|
||||
<para>Linux-PAM offers an alternate configuration mechanism,
|
||||
where policies are contained in separate files, named for the
|
||||
service they apply to, in <filename>/etc/pam.d/</filename>,
|
||||
with only four fields instead of five—the service name
|
||||
field is omitted. In FreeBSD 5.0, starting from mid-January
|
||||
2002, this is the preferred mechanism. Note, however, that if
|
||||
<filename>/etc/pam.conf</filename> exists, and contains
|
||||
configuration statements for services which do not have a
|
||||
specific policy in <filename>/etc/pam.d/</filename>, it will
|
||||
be used as a fall-back for these services.</para>
|
||||
<para>OpenPAM and Linux-PAM offer an alternate configuration
|
||||
mechanism, where policies are contained in separate files,
|
||||
named for the service they apply to, in
|
||||
<filename>/etc/pam.d/</filename>, with only four fields
|
||||
instead of five—the service name field is omitted. This
|
||||
is the preferred mechanism in FreeBSD 5.x.. Note, however,
|
||||
that if <filename>/etc/pam.conf</filename> exists, and
|
||||
contains configuration statements for services which do not
|
||||
have a specific policy in <filename>/etc/pam.d/</filename>, it
|
||||
will be used as a fall-back for these services.</para>
|
||||
|
||||
<para>The great advantage of <filename>/etc/pam.d/</filename>
|
||||
over <filename>/etc/pam.conf</filename> is that it is possible
|
||||
|
@ -729,25 +762,35 @@ sshd password required pam_permit.so</programlisting>
|
|||
|
||||
<para>This works because the service name is determined from the
|
||||
file name rather than specified in the policy file, so the
|
||||
same file can be used for arbitrary services.</para>
|
||||
same file can be used for multiple differently-named
|
||||
services.</para>
|
||||
|
||||
<para>One other advantage is that third-party software can
|
||||
easily install policies for their services without the need to
|
||||
edit <filename>/etc/pam.conf</filename>.</para>
|
||||
edit <filename>/etc/pam.conf</filename>. True to the FreeBSD
|
||||
tradition, OpenPAM will even look for policy files in
|
||||
<filename>/usr/local/etc/pam.d/</filename> if no configuration
|
||||
for the requested service is present in
|
||||
<filename>/etc/pam.d/</filename> or
|
||||
<filename>/etc/pam.conf</filename>.</para>
|
||||
|
||||
<para>Whether you use <filename>/etc/pam.conf</filename> or
|
||||
<filename>/etc/pam.d/</filename>, the policy for the special
|
||||
service <literal>other</literal> is used as a fall-back for
|
||||
any service that does not have its own policy.</para>
|
||||
<para>Finally, whichever configuration mechanism you choose, the
|
||||
<quote>magic</quote> policy <literal>other</literal> is used
|
||||
as a fall-back for any service that does not have its own
|
||||
policy.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Breakdown of a configuration line</title>
|
||||
<section id="pam-config-breakdown">
|
||||
<title id="pam-config-breakdown.title">Breakdown of a
|
||||
configuration line</title>
|
||||
|
||||
<para>As explained in <xref linkend="pam-config-file-locations">,
|
||||
each line in <filename>/etc/pam.conf</filename> consists of four
|
||||
or more fields: the service name, the facility name, the control
|
||||
flag, the module name, and zero or more module arguments.</para>
|
||||
<para>As explained in the <link
|
||||
linkend="pam-config-file-locations"
|
||||
endterm="pam-config-file-locations.title"></link> section,
|
||||
each line in <filename>/etc/pam.conf</filename> consists of
|
||||
four or more fields: the service name, the facility name, the
|
||||
control flag, the module name, and zero or more module
|
||||
arguments.</para>
|
||||
|
||||
<para>The service name is generally (though not always) the name
|
||||
of the application the statement applies to. If you are
|
||||
|
@ -771,19 +814,21 @@ sshd password required pam_permit.so</programlisting>
|
|||
describing how to interpret the return code from the module.
|
||||
Linux-PAM supports an alternate syntax that lets you specify
|
||||
the action to associate with each possible return code, but
|
||||
this should be avoided as it is non-standard and requires very
|
||||
detailed knowledge of the PAM library to use properly.</para>
|
||||
this should be avoided as it is non-standard and closely tied
|
||||
in with the way Linux-PAM dispatches service calls (which
|
||||
differs greatly from the way Solaris and OpenPAM do it.)
|
||||
Unsurprisingly, OpenPAM does not support this syntax.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Policies</title>
|
||||
<section id="pam-policies">
|
||||
<title id="pam-policies.title">Policies</title>
|
||||
|
||||
<para><!--XXX-->This section has not yet been written.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="pam-modules">
|
||||
<title id="pam-modules.title">PAM Modules</title>
|
||||
<section id="pam-freebsd-modules">
|
||||
<title id="pam-freebsd-modules.title">FreeBSD PAM Modules</title>
|
||||
|
||||
<para><!--XXX-->This section has not yet been written.</para>
|
||||
</section>
|
||||
|
@ -815,20 +860,28 @@ sshd password required pam_permit.so</programlisting>
|
|||
</section>
|
||||
|
||||
<appendix id="pam-sample-appl">
|
||||
<title id="pam-sample-appl.title">Sample PAM application</title>
|
||||
<title id="pam-sample-appl.title">Sample PAM Application</title>
|
||||
|
||||
<para>The following is a minimal implementation of &man.su.1;
|
||||
using PAM. Note that it uses the Linux-PAM-specific
|
||||
<function>misc_conv</function> conversation function, which is
|
||||
using PAM. Note that it uses the OpenPAM-specific
|
||||
&man.openpam.ttyconv.3; conversation function, which is
|
||||
prototyped in <filename
|
||||
class="headerfile">security/pam_misc.h</filename>.</para>
|
||||
class="headerfile">security/openpam.h</filename>. If you wish
|
||||
build this application on a system with a different PAM library,
|
||||
you will have to provide your own conversation function. A
|
||||
robust conversation function is surprisingly difficult to
|
||||
implement; the one presented in the <link
|
||||
linkend="pam-sample-conv"
|
||||
endterm="pam-sample-conv.title"></link> appendix is a good
|
||||
starting point, but should not be used in real-world
|
||||
applications.</para>
|
||||
|
||||
<programlisting><inlinegraphic fileref="pam_app.c"
|
||||
format="linespecific"></programlisting>
|
||||
</appendix>
|
||||
|
||||
<appendix id="pam-sample-module">
|
||||
<title id="pam-sample-module.title">Sample PAM module</title>
|
||||
<title id="pam-sample-module.title">Sample PAM Module</title>
|
||||
|
||||
<para>The following is a minimal implementation of
|
||||
&man.pam.unix.8;, offering only authentication services. It
|
||||
|
@ -841,6 +894,23 @@ sshd password required pam_permit.so</programlisting>
|
|||
format="linespecific"></programlisting>
|
||||
</appendix>
|
||||
|
||||
<appendix id="pam-sample-conv">
|
||||
<title id="pam-sample-conv.title">Sample PAM Conversation
|
||||
Function</title>
|
||||
|
||||
<para>The conversation function presented below is a greatly
|
||||
simplified version of OpenPAM's &man.openpam.ttyconv.3;. It is
|
||||
fully functional, and should give the reader a good idea of how
|
||||
a conversation function should behave, but it is far too simple
|
||||
for real-world use. Even if you're not using OpenPAM, feel free
|
||||
to download the source code and adapt &man.openpam.ttyconv.3; to
|
||||
your uses; we believe it to be as robust as a tty-oriented
|
||||
convesation function can reasonably get.</para>
|
||||
|
||||
<programlisting><inlinegraphic fileref="pam_conv.c"
|
||||
format="linespecific"></programlisting>
|
||||
</appendix>
|
||||
|
||||
<bibliography id="pam-further">
|
||||
<title id="pam-further.title">Further Reading</title>
|
||||
|
||||
|
|
Loading…
Reference in a new issue