<!doctype linuxdoc system>

<!--

 $Id: pwdb.sgml,v 1.1.1.4 2002/12/10 02:21:40 nalin Exp $

    Copyright (C) Cristian Gafton and Andrew G. Morgan 1996.
					  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1. Redistributions of source code must retain the above copyright
   notice, and the entire permission notice in its entirety,
   including the disclaimer of warranties.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

3. The name of the author may not be used to endorse or promote
   products derived from this software without specific prior
   written permission.

ALTERNATIVELY, this product may be distributed under the terms of the
GNU General Public License, in which case the provisions of the GNU
GPL are required INSTEAD OF the above restrictions.  (This clause is
necessary due to a potential bad interaction between the GNU GPL and
the restrictions contained in a BSD-style copyright.)

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

 -->

<article>

<title>The PWDB Library Guide
<author>Cristian Gafton and Andrew G. Morgan
<date>DRAFT v0.54 1996/12/4
<abstract>
This manual documents the <em/Password database/ library
(<tt/libpwdb/). This is a library implementing a generic user
information database. It was specifically designed to satisfy the
needs of <bf/Linux-PAM/.
</abstract>

<!-- Table of contents -->
<toc>

<!-- Begin the document -->

<sect>Introduction

<p>
This is a document describing the libpwdb functions (or how they will
function).  Cristian and Andrew will be modifying this file as we go
along. Hopefully it will describe the library when it is finished.

<sect1>
Motivation

<p>
Linux, at the level of the kernel, identifies a user by a 16-bit
integer--their <em/UID/. At the level of a functioning system, the
user has other characteristics; a name, group memberships, a home, a
number of aliases (email address etc.) and a password.

<p>
The mapping of a UID to each of these pieces of personal data is with
respect to a database file.  Unfortunately, depending on circumstances
there is no single location for this database.  The most basic Linux
system might have a single <tt>/etc/passwd</tt> file, with a single
entry for each user, and an <tt>/etc/group</tt> file containing a list
of the groups defined on the local system.  In shadow aware systems a
user might additionally have an <tt>/etc/shadow</tt> entry.  In a
networked environment, all of the users might be identified by entries
in a file located on a remote computer.

<p>
While it is possible for a local system to adopt one scheme to satisfy
the demands of the POSIX <tt/getpw../ commands, it is problematic for
an individual system to simultaneously support a variety of databases
to define its users and groups.

<p>
It is desirable for applications to be able to obtain user-information
in a transparent manner.  At the same time certain applications might
like to obtain information from a specific database for a given user -
these applications might perform the task of maintaining and updating
databases for example.  The functions of libc, do not currently offer
this flexibility.  It is for this reason that <em/libpwdb/ has been
created.  It is intended to provide a flexible and yet simple database
management primarily for user and group information under Linux
systems.  An API that all applications can use.

<p>
Should this library become popular, it is anticipated that the
database will be extended to include other types of database files.

<sect>
Configuration

<sect1>
The configuration file

<p>
Use of <tt>libpwdb</tt> requires the presence of a correctly formatted
configuration file: <tt>/etc/pwdb.conf</tt>. It has the following
syntax:

<p>
<tscreen>
<verb>
    #
    # first the list of user databases
    #
        user: 
		list1
		list2
		list3
		...
    #
    # next, the list of group databases
    #
        group:
		list1
		list2
		...
    #
    # end of file
    #
</verb>
</tscreen>

<p>
Here, <tt>listN</tt> has the following form
<tt>name1+name2+name3</tt>. It indicates a collection of databases
that are merged to form the record for the user/group.  When selecting
the default database (PWDB_DEFAULT) the library chooses the list whose
first <tt/name/d database contains an entry for the requested
<tt/user/ (<tt/id/). Currently, the <tt>nameN</tt> items are from the
following selection: <tt>nis</tt>, <tt>unix</tt>, <tt>radius</tt> and
<tt>shadow</tt>.

<p>
Newlines are ignored except where they terminate comments;
comments are preceded with `<tt>#</tt>' characters.

<p>
A simple example <tt>/etc/pwdb.conf</tt> file would be:
<tscreen>
<verb>
    # This is an example /etc/pwdb.conf file. It defines the
    # database information sources for users in this system

    # First, we define where user information is stored
    # (here, users are listed in /etc/passwd and may have
    # supplementary information in the /etc/shadow file)
    # Should the user have a shadow entry the combination is
    # used

        user: 
		shadow + unix
		unix

    # Second, we define where the users' groups are listed
    # (here the groups are listed in the /etc/group file
    # in addition, there is group information to be found
    # in the /etc/sgroup file)

        group:
		unix + shadow

    #
    # end of file
</verb>
</tscreen>

<sect>
Implementation

<p>
<em>
This will get completed as we develop the library
</em>

<sect1>
The core (public) functions

<p>
<tt>libpwdb</tt> offers the following generic interface:

<sect2>
Initialization and termination

<p>
<itemize>
<item>
<tt>int pwdb_start(void)</tt>

<p>
Initialize the library for use by the current application Will read
the configuration file and publicize the database policies (as they are
listed in <tt>/etc/pwdb.conf</tt>) in <tt>const int *pwdb_policy</tt>
and <tt>const int *pwdb_group_policy</tt>.  The library maintains a
count of the number of times it has been <tt>pwdb_start()</tt>ed.

<item>
<tt>int pwdb_end(void)</tt>

<p>
Once the <tt>pwdb_start()</tt>ed count returns to zero, this function
closes down the library and free()'s all memory allocated by it.  Any
attempt to <tt>pwdb_end()</tt> the library more times than it has been
<tt>pwdb_start()</tt>ed will cause <tt>PWDB_ABORT</tt> to be
returned. <em>This feature can be used by an application to guarantee
the library is shutdown..</em>
<tscreen>
<verb>
    while (pwdb_end() == PWDB_SUCCESS);
</verb>
</tscreen>

</itemize>

<sect2>
Structure management

<p>
<itemize>

<item>
<tt>
int pwdb_entry_delete(const struct pwdb_entry **e)
</tt>

<p>
<tt>free()</tt> the memory associated with the pointer
<tt>*e</tt>. Its value will be overwritten with <tt>'\\0'</tt>s before
the memory is <tt>free()</tt>d. This is reassuring from the point of
view of minimizing security problems. This function should be used to
liberate a <tt>pwdb_entry</tt> returned by <tt>pwdb_get_entry()</tt>.

<item>
<tt>
int pwdb_get_entry(const struct pwdb *p, const char *entry, const
struct pwdb_entry **e);
</tt>

<p>
Read (and duplicate) an entry from the argument pwdb structure. Should
the requested entry not prove to be present, <tt>PWDB_NOT_FOUND</tt> is
returned.

<item>
<tt>
int pwdb_set_entry(const struct pwdb *p, const char *entry, const void
*datum, const int length,
int (*compare)(const void *, const void *, int),
int (*strvalue)(const void *, char *, int),
int max_strval_size))
</tt>

<p>
Set an entry in the argument pwdb structure. One can delete an
entry from a struct pwdb by calling this function with <tt/NULL/ for
<tt/datum/ and <tt/-1/ for <tt/length/.

<p>
The two functions passed as arguments in this call are as follows:

<p>
<descrip>
<tag>
<tt>
int compare(const void *value1, const void *value2, int length)
</tt>
</tag>
compare the two entry <tt/value/s. They are both of given <tt/length/
in <tt/char/s.

<tag>
<tt>
int strvalue(const void *value, char *buffer, int length)
</tt>
</tag>
Produce a text version of the given entry <tt/value/. The <tt/buffer/
is the destination of the output text and the <tt/length/ is that of
the <tt/*value/ in bytes. Note, the buffer is guaranteed by the
calling process to be long enough for the output text.

</descrip>

<item>
<tt>
int pwdb_delete(const struct pwdb **old)
</tt>

<p>
Applications use this to liberate the memory associated with a
<tt>pwdb</tt> structure.  Following a successful <tt>free()</tt>,
<tt>*old</tt> is set to <tt/NULL/.

<item>
<tt>
int pwdb_new(const struct pwdb **new, int life_sec)
</tt>

<p>
Applications can request a new (blank) <tt/pwdb/ structure with this
call. Note that it is returned as a <tt/const/ structure.  This is to
prevent the application from altering the structure directly. An
application should use the library functions to modify this structure.
The <tt/life_sec/ time is used to limit the length of time this pwdb
structure will be valid for. It is some number of seconds from the
present. If <tt/life_sec/ is non-zero, the <tt/pwdb/ structure will
expire in that many seconds. Zero indicates the <tt/pwdb/ structure
will non expire.

<p>
<tscreen>
<verb>
int pwdb_merge(const struct pwdb *target, const struct pwdb *source,
	       int overwrite)
</verb>
</tscreen>

<p>
this function copies the elements of <tt/source/ to <tt/target/. If
<tt/overwrite/ is <tt/PWDB_TRUE/ then all elements of <tt/source/ that
are also in <tt/target/ will be overwritten by this call.


<item>
<tt>
int pwdb_expire(const struct pwdb *p, int life_sec)
</tt>

This function can shorten the lifetime of a the referenced <tt/struct
pwdb/. It computes the expiry time from the present with respect to
<tt/life_sec/ and if this is <em/before/ the expiration time currently
associated with the <tt/*p/ structure, it shortens the life of the
structure accordingly.

<p>
Note, it is not possible to extend the life of a <tt/pwdb/ structure,
only to <em/shorten/ it. An argument of <tt/0/ or less will result in
the immediate expiry of the <tt/pwdb/ structure.

<item>
<tt>
int pwdb_source(const struct pwdb *old, const pwdb_type *src,
const char *class, const char *name, const int id)
</tt>

This function is used to set the source of the indicate <tt/pwdb/
structure. The argument <tt/src/ is a pointer to a list of
<tt/pwdb_type/ entries. This list is terminated with a
<tt/_PWDB_MAX_TYPES/ item.  Valid types are listed in the
<tt>&lt;security/pwdb_public.h&gt</tt> file. The remaining arguments
are used to initialize the caching facilities.

</itemize>

<sect2>
Database query functions

<p>
<itemize>

<item>
<tt>
int pwdb_locate(const char *class, const pwdb_type *src, const char
*name, const int id, struct pwdb **p)
</tt>

<p>
Obtain the entry for a given name and/or id in the indicated
database. If <tt/*p/ is not <tt/NULL/ the database-module may choose
to use the information it contains. It is intended that information
obtained with this function is merged with that of the original
<tt/*p/ structure. If <tt/*p/ is <tt/NULL/, then a struct pwdb is
allocated by the <tt/pwdb_locate()/ function in the first module used
(and eventually merged with the subsequent modules, depending on the
local setup). The <tt/class/ is the kind of database we are searching,
examples include <tt/user/ and <tt/group/.

<item>
<tt>
int pwdb_request(const char *class, const pwdb_type *src, 
const char *entry, struct pwdb **p)
</tt>

<p>
This function will further query the database, for an entry
that may depend on the entries already present in the <tt/*p/
structure. The <tt/entry/s that can be appended to the existing
<tt/*p/ structure are defined for the <tt/class/ of database.
For example, one may request the <em/"groupids"/ <tt/entry/ from
<tt/"group"/ class, which will search the group database for the list
of groups to which a given user belongs. The name of the user is
passed as an entry in the preexisting <tt/pwdb/ structure.

<item>
<tt>
int pwdb_replace(const char *class, const pwdb_type *src,
const char *name, const int id, struct pwdb **p)
</tt>

<p>
Add/replace the entry for a name and/or id in the indicated list of
databases. The fields for the new database entries are taken from the
<tt/p/ argument. The <tt/src/ argument is the list of entries that
will be updated.

<item>
<tt>
int pwdb_remove(const char *class, const pwdb_type *src,
const char *name, const int id, struct pwdb **p)
</tt>

<p>
Remove the entry for the indicated <tt/name/ and/or <tt/id/ in the
indicated database. If not <tt/NULL/ the remove function may obtain
access information from the <tt/p/ argument.

<p>
Note, this function only acts on the specified <tt/class/ of
database. If reference to a <tt/name/ or <tt/id/ is present in another
<tt/class/ of database, then it is the responsibility of the
application to purge these databases too. The <tt/pwdb_remove()/
function is not sufficiently powerful to follow up on
cross-references.

<p>
As an example of the above concern, consider the removal of <tt/name/
``joe'' from the <tt/"user"/ database. The <tt/"group"/ database
entries that refer to ``joe'' as a group-member are unaffected by this
<tt/pwdb_remove()/ request.  Instead, it is the responsibility of the
calling application to search for such entries and systematically
<tt/pwdb_remove()/
them.

<item>
<tt>
int pwdb_support(const char *class, const pwdb_type *src,
const char *entry_name)
</tt>

<p>
Indicate whether the given entry name is supported by the given
database(s). <tt/PWDB_SUCCESS/ indicates yes. Anything else is NO (or
something more specific, could be ``yes, if you supply a pass_phrase''
for example).

<item>
<tt>
int pwdb_flags(const char *class, const pwdb_type *db, pwdb_flag *flag_p)
</tt>

<p>
In order to know in advance whether a process is able to read/modify a
specified database, this command is provided by each module.
The input arguments are the <tt/class/ of database (<tt/user/,
<tt/group/ etc.), <tt/db/ (the database(s) we are going to use)
and some storage space for the returned flags.

<p>
Valid return flags which can be logically OR'd together are:

<p>
<descrip>
<tag>
<tt>
PWDB_F_NOACCESS
</tt>
</tag>
insufficient privilege to access database

<tag>
<tt>
PWDB_F_NOUPDATE
</tt>
</tag>
insufficient privilege to alter an entry

<tag>
<tt>
PWDB_F_PASS_PHRASE
</tt>
</tag>
to access the database, the process must supply a "pass_phrase" entry
with a preallocated pwdb structure (use pwdb_new() call)

<tag>
<em>
..and..
</em>
</tag>
<em>more flags are likely to be added</em>

</descrip>

<p>
To establish if a given flag is set the following macro is
supplied:

<item>
<tt>
pwdb_on(flag, PWDB_F_XXX)
</tt>

<p>
it returns TRUE(<tt/1/) or FALSE(<tt/0/).

</itemize>

<sect2>
Diagnostics

<p>
<itemize>

<item>
<tt>
const char *pwdb_strerror(int pwdb_error)
</tt>

<p>
return a textual description of the indicated return value.

<p>
Valid return codes are:

<p>
<descrip>

<tag>
<tt/PWDB_SUCCESS/
</tag>
task completed successfully

<tag>
<tt/PWDB_BAD_REQUEST/
</tag>
request not recognized

<tag>
<tt/PWDB_TOO_WEAK/
</tag>
insufficient privilege for operation

<tag>
<tt/PWDB_ABORT/
</tag>
internal failure - seek help

<tag>
<tt/PWDB_BLOCKED/
</tag>
another process has locked resource

<tag>
<tt/PWDB_MALLOC/
</tag>
insufficient memory for operation

<tag>
<tt/PWDB_NOT_FOUND/
</tag>
requested item was not found

<tag>
<tt/PWDB_PASS_PHRASE_REQD/
</tag>
pass_phrase needed to satisfy request <em>here the application should
supply a pwdb structure with a "pass_phrase" entry and call the
function again</em>

<tag>
<tt/PWDB_CONF_ERR/
</tag>
there is a problem with the PWDB_CONF file.

<tag>
<tt/PWDB_EXPIRED/
</tag>
the referenced pwdb structure has expired it is no longer valid and
should be deleted.

<tag>
<tt/PWDB_UNSUPPORTED/
</tag>
this function is not supported by some module (not supported means
also unimplemented, for a while...)

<tag>
<tt/PWDB_TIMEOUT/
</tag>
a timeout occured while performing the function. Presently could show up
only when using RADIUS interface.

</descrip>

</itemize>

<sect2>
Types of database

<p>
The pwdb_type of database a request is associated with is
given by one of the following values:

<descrip>

<tag>
<tt/PWDB_DEFAULT/
</tag>
no database indicated, use configured list

<tag>
<tt/PWDB_UNIX/
</tag>
generic /etc/passwd and /etc/group files

<tag>
<tt/PWDB_SHADOW/
</tag>
/etc/shadow and /etc/gshadow <em>Intended to supplement other databases</em>

<tag>
<tt/PWDB_NIS/
</tag>
Use NIS server

<tag>
<tt/PWDB_RADIUS/
</tag>
Use RADIUS server

<tag>
<tt/PWDB_DECNIS/
</tag>
Use a NIS server configured for Digital Equipment Corp Enhanced Security,
or a Solaris server with an adjunct NIS password file.

</descrip>

<p>
<itemize>

<item>
<tt>
const char *pwdb_db_name(pwdb_type src)
</tt>

<p>
return a character representation of the database functions

</itemize>

<sect1>
Functions supplied by database modules

<p>
Each module must provide 7 functions to the generic pwdb
interface. They are registered with the generic interface via a
structure of the following form:

<p>
<tscreen>
<verb>
struct _pwdb_module {
    pwdb_type type;                    /* type of database (code) */
    const char *name;                  /* type of database (text) */
    const char *class;                 /* class of database (user/group) */

    /* FUNCTIONS: used to access the relevant database */

    int (*locate)(const char *name, const int id, const struct pwdb **p);
    int (*request)(const char *entry_name, const struct pwdb **p);
    int (*replace)(const char *name, const int id, const struct pwdb **p);
    int (*delete)(const char *name, const int id, const struct pwdb **p);
    int (*support)(const char *entry_name);
    int (*flags)(pwdb_flag *flags);
    int (*cleanup)(int code);
};
</verb>
</tscreen>

<p>
For the functions above taking a <tt/name/ and an <tt/id/ entry, the
application may choose to leave one unspecified with the following
defaults:

<descrip>
<tag>
<tt>
PWDB_NAME_UNKNOWN
</tt>
</tag>
just look at the id field

<tag>
<tt>
PWDB_ID_UNKNOWN
</tt>
</tag>
just look at the name field

</descrip>

In the case that the application supplies neither the <tt/name/ or the
<tt/id/, the module functions will try to obtain the relevant
information from the argument <tt/pwdb/ structure.

<p>
It is legal for both the <tt/name/ and <tt/id/ to be specified. In
this case they must both match an entry in the database to satisfy one
of the above function calls. If both values are supplied and there is
no entry in the database which matches them, <tt>PWDB_BAD_REQUEST</tt>
is returned.

<p>
The structure is registered via an entry in the modules list (see
pwdb_module.c).

<sect1>
Standard entries in pwdb structures

<p>
The following are standard entries in the pwdb structure. They can be
read/written with calls to <tt>pwdb_g/set_entry</tt>.

<p>
First, we consider the <tt/"user"/ class of databases. For these, two
entries are mandatory. They correspond to the name of the user and the
user's uid.

<descrip>

<tag>
<tt>
user
</tt>
</tag>
character string; the user's login id.

<tag>
<tt>
uid
</tt>
</tag>
uid_t; the user's <em/user-id/.

</descrip>

<p>
The next entries are named by convention. Where possible new database
functions should map these entries into their corresponding fields.
These entries correspond to the entries in the <tt>/etc/passwd</tt>
file.

<p>
<descrip>

<tag>
<tt>
passwd
</tt>
</tag>
character string; the <em/encrypted/ password for the user.

<tag>
<tt>
defer_pass
</tt>
</tag>
This entry is intended to take care of situations that the normal
<tt/passwd/ field is not used for the password. The <tt/defer_pass/
entry contains a character string that has typically two functions:
<itemize>
<item> it indicates that the password is to be stored in the database
that sets this entry.
<item> it serves as a substitution string for databases that would
normally contain the password entry.
</itemize>

<p>
For example, for a <tt/unix+shadow/ setup, <tt/defer_pass/ would have
the value ``<tt/x/''. The <tt/unix/ (no <tt/shadow/) value for this
entry is ``U'' which implies that the <tt/passwd/ field came from the
user's entry in the <tt>/etc/passwd</tt> file.

<tag>
<tt>
gid
</tt>
</tag>
gid_t; the user's principal <em/group-id/.

<tag>
<tt>
group
</tt>
</tag>
character string; naming the user's principal group.

<tag>
<tt>
gecos
</tt>
</tag>
character string; giving a more complete name for the user. It is
conventional for this field to contain office and other information
concerning the real-world identity of the user.

<tag>
<tt>
dir
</tt>
</tag>
character string; the home directory of the user.

<tag>
<tt>
shell
</tt>
</tag>
character string; the shell that the user prefers to use.

</descrip>

<p>
These entries correspond to the entries in the <tt>/etc/group</tt> file
<em>in addition to the user and gid entries above</em>. They can be
<tt>pwdb_request()</tt>d from the "group" class of databases.

<p>
<descrip>

<tag>
<tt>
groups
</tt>
</tag>
character string; listing the group memberships of the user. The field
separators are commas -- no spaces.

<tag>
<tt>
groupids
</tt>
</tag>
array of <tt/gid_t/; an array containing the group id's of the user in
numerical form.

</descrip>

<p>
The following are intended to correspond to <tt>/etc/shadow</tt>
entries.

<p>
<descrip>
<tag>
<tt>
last_change
</tt>
</tag>
long integer; day of last change of password

<tag>
<tt>
min_change
</tt>
</tag>
long integer; minimum number of days between password changes

<tag>
<tt>
max_change
</tt>
</tag>
integer; maximum number of days between password changes

<tag>
<tt>
warn_change
</tt>
</tag>
long integer; number of days to warn user to change their password
before it expires

<tag>
<tt>
defer_change
</tt>
</tag>
long integer; number of days after a user's password has expired
before the user is denied access

<tag>
<tt>
expire
</tt>
</tag>
long integer; day the user's account expires

<tag>
<tt>
shadow_flags
</tt>
</tag>
long integer; reserved for use by underlying shadow implementation

</descrip>

<p>
The following is the entry used to supply a <em/clear-text/ password
for access to the database.

<descrip>

<tag>
<tt>
pass_phrase
</tt>
</tag>
character string; this is the password required to access the user's
record in a database

</descrip>

<p>
When integrating another database format the implementor is strongly
encouraged to try to reuse the entries above to the extent they are
appropriate. Should there be an absent entry in any database, the
database management functions should be able to supply a reasonable
default but only when updating its database.

<sect1>
Helper functions

<sect2>
Public functions

<p>
<itemize>

<item>
<tt>
char *_pwdb_delete_string(char *s)
</tt>

<p>
overwrite the string '<tt/s/' and return <tt/NULL/. usage:

<p>
<tt>
old_ptr = _pwdb_delete(old_ptr);
</tt>

<item>
<tt>
char *_pwdb_dup_string(const char *s)
</tt>

<p>
<tt/malloc()/ a copy of the string '<tt/s/'. Return its address or
<tt/NULL/ if <tt/s == NULL/ or on error.

<p>
this memory will <em/not/ be <tt/free()/'d by a call to
<tt/pwdb_end()/.

<item>
<tt>
void pwdb_print_pwdb_struct(const struct pwdb *p)
</tt>

<p>
Dump the contents of <tt/*p/ to the <tt/stderr/. Useful for debugging.

</itemize>

<sect2>
Private functions

<p>
<itemize>
<item>
<tt>
static struct pwdb *_pwd_check(const struct pwdb *p)
</tt>

<p>
Establish if the pwdb structure was allocated by the library
This library should not honor requests from elsewhere.
return the local version (non-const) of this structure or NULL
on error.

<p>
this function is strictly designed for the use of the
generic code. Both modules and applications should never
need to call it.

</itemize>

<sect1>
Typical usage

<p>
Here is a skeleton usage for a login type program.

<p>
<tscreen>
<verb>
    pwdb_start();
    pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN, &ero;pw);
    pwdb_request_group("group", PWDB_DEFAULT, "groupids", &ero;pw);
    pwdb_get_entry(pw, "uid", &ero;e1);
    pwdb_get_entry(pw, "gid", &ero;e2);
    pwdb_get_entry(pw, "groupids", &ero;e3);
    pwdb_end();
</verb>
</tscreen>

<sect>
Supported modules

<p>
PLEASE NOTE. Currently few group functions have been implemented.

<sect1>
UNIX module

<p>
This section documents the current state of the UNIX module. From the
point of view of the application, it is named "unix" and has the
<tt/pwdb_type/ <tt/PWDB_UNIX/.

<p>
Entries supported by the "user" class of the UNIX module are as follows:
<descrip>
<tag><tt>user</tt></tag> - username
<tag><tt>uid</tt></tag> - user-id
<tag><tt>gid</tt></tag> - group-id
<tag><tt>passwd</tt></tag> - encrypted password
<tag><tt>defer_pass</tt></tag> - "U" unless set by other database
<tag><tt>gecos</tt></tag> - user information
<tag><tt>dir</tt></tag> - home directory
<tag><tt>shell</tt></tag> - shell executable
</descrip>

<p>
Entries supported by the "group" class of the UNIX module are as follows:
<descrip>
<tag><tt>group</tt></tag> - username
<tag><tt>gid</tt></tag> - group-id
<tag><tt>passwd</tt></tag> - encrypted password
<tag><tt>users</tt></tag> - text list of user names separated by
commas
</descrip>

<p>
The <tt/pwdb_request()/ function call is only supported for the
"group" class. The two entries that may be requested are:
<descrip>
<tag><tt>groups</tt></tag> - text list of group names separated by
commas 
<tag><tt>groupids</tt></tag> - array of <tt/gid_t/ values that
contain the numerical form of the "groups" entry.
</descrip>
Note, for such requests to be honored the name of the user should be
contained in the <tt/pwdb **/ argument prior to the
<tt/pwdb_request()/ call.

<sect1>
Shadow module

<p>
This section documents the current implementation of the <em>shadow</em>
database module.

<p>
The <em/shadow/ module does not make any use of the <tt>id</tt>
parameter. Since the shadow database does not contain such an entry,
the only way of identifying a user is with a <tt>name</tt> argument.
However, an <tt>id</tt> based lookup is possible, if the <tt>shadow</tt>
database is searched after a database that contains a user-uid
mapping. In this case the ``<tt>user</tt>'' entry in the partially
built <tt>pwdb</tt> structure is used to locate the appropriate entry in
the shadow file.

<p>
The shadow module is designed to work in conjunction with a database
that provides the standard <tt>user-uid</tt> mapping.  It should be
noted that it does not provide sufficient information to support a
user login session.

<p>
Entries supported by the "user" class of the shadow module are:
<descrip>
<tag><tt>user</tt></tag> - username
<tag><tt>passwd</tt></tag> - encrypted password
<tag><tt>last_change</tt></tag> - date password was last changed
<tag><tt>min_change</tt></tag> - minimum period before password can
be changed
<tag><tt>max_change</tt></tag> - lifetime of current password
<tag><tt>warn_change</tt></tag> - number of days prior to expiry
that the user should be warned
<tag><tt>defer_change</tt></tag> - grace period before password is
finally invalid
<tag><tt>expire</tt></tag> - date account expires
</descrip>

<p>
Entries supported by the "group" class of the shadow module are:
<descrip>
<tag><tt>group</tt></tag> - groupname
<tag><tt>passwd</tt></tag> - encrypted group password
<tag><tt>users</tt></tag> - text list of user names separated by
commas (members of the group)
<tag><tt>admins</tt></tag> - text list of user names separated by
commas (administrators of the group)
</descrip>


<sect1>
NIS module

<p>
<itemize>
<item>
user removal is not possible. (lack of documentation)
<item>
user creation is not possible (lack of documentation)
</itemize>

<sect1>
DECNIS module

<p> The decnis module allows use of some extensions to the basic NIS maps.
The two current extensions supported are the Solaris passwd.adjunct
and the Digital Equipment Corp prpasswd maps. Both of these are shadow 
password schemes for basic (non-secure) NIS. The solaris support is untested.
This option encompasses the NIS option, and the decnis option should replace
the standard nis option in the pwdb.conf file. In the event of a user not
having a shadow NIS password entry, the result should be identical to that
returned by the NIS module above. <p>
<em>Warning1</em> Support for many of the extensions (password expiry, life time,
account locking etc..) is not present in this version. Just raw
authentication.<p>
<em>Warning2</em> Clustering your Linux boxes with this software will reduce the
security level of your NIS server/cluster. Users may have access to encrypted
passwords of other users. <p>

<p>
<itemize>
<item>
user removal is not possible. (lack of documentation)
<item>
user creation is not possible (lack of documentation)
</itemize>

<sect1>
RADIUS module
	
<p>
The RADIUS module is acting just as a user validation mechanism. The
official Livingston radiusd 2.0 is supported, but in order to take
advantage of the all information and auth tokens the radius server can
provide, a session PAM module should be written, and be stacked over
pam_unix.

<p>
The following should be taken into consideration when writing
applications to authenticate to a radius server:

<p>
<itemize>
<item>
the pwdb group functions are not supported (RADIUS does not have
this concept)

<item>
Other than checking for username/password pairs, the radius module
can not be used alone with the stock radiusd server to handle the
user login without a suitable RADIUS client (for example there
is no way to get an UID for a user).
<p>
However, with few hacks to the radius server and proper modification
of the <tt>/etc/raddb/dictionary</tt> file this module uses, a NIS-like
environment could be achieved. Full documentation on how to achieve this
will be added later.

<item>
All radius module functions that access the remote server require the
presence of the "pass_phrase" pwdb entry which contains the user
password in <em/clear text/. The radius module will destroy this
information as soon as it can dispose of it, so an application can
assume that after a call to a function in the radius module which
returned with <tt/PWDB_SUCCESS/, the pass_phrase entry is wiped out.

<item>
When updating a RADIUS user password, one should supply <bf/both/
<tt/pass_phrase/ and <tt/passwd/ entries in <em/clear text/. By
convention, the <tt/pass_phrase/ contains the old password (which is
required by the RADIUS server to authenticate the user) and the
<tt/passwd/ entry contains the new password.  One should be very
careful about this issue, as some other modules used before RADIUS
authentication may set the value of <tt/passwd/ entry, and the
application should make sure that the clear text password is passed to
the RADIUS module for changing password. The RADIUS module will wipe
out both <tt/pass_phrase/ and <tt/password/ entries - thus the
application can not rely on validity of any of those entries in the
pwdb structure after a call to the update function of the RADIUS
module.
<p>

Note that the RADIUS server must permit changing of the 
passwords user passwords. IF the RADIUS does not accept changing the
user passwords, a PWDB_TIMEOUT will occur.

<item>
The password update is the <bf/only/ function supported by the
RADIUS update function.

</itemize>

<p>
Entries supported by this database are set according to the definitions 
from <tt>/etc/raddb/dictionary</tt> file. Three entries have a special
meaning when calling the RADIUS functions: <tt/user/, <tt/passwd/ and
<tt/pass_phrase/. The <tt/passwd/ and <tt/pass_phrase/ will be wiped out by
the RADIUS functions as soon as the module can dispose them. The reponse
from the RADIUS server is processed and entries are set in the <tt/pwdb/
structure according to the names from the dictionary file.
<p>

A sample <tt/RADIUS dictionary/ entry list is provided here - valid for
Livingston RADIUSD 2.0:

<tscreen>
<verb>

#---------------------------------------------------------------------------
#
# @(#)dictionary	1.3 10/1/96  Copyright 1991 Livingston Enterprises Inc
#
#---------------------------------------------------------------------------
#
#	This file contains dictionary translations for parsing
#	requests and generating responses.  All transactions are
#	composed of Attribute/Value Pairs.  The value of each attribute
#	is specified as one of 4 data types.  Valid data types are:
#
#	string - 0-253 octets
#	ipaddr - 4 octets in network byte order
#	integer - 32 bit value in big endian order (high byte first)
#	date - 32 bit value in big endian order - seconds since
#					00:00:00 GMT,  Jan.  1,	 1970
#

ATTRIBUTE	User-Name		1	string
ATTRIBUTE	Password		2	string
ATTRIBUTE	CHAP-Password		3	string
ATTRIBUTE	NAS-IP-Address		4	ipaddr
ATTRIBUTE	NAS-Port		5	integer
ATTRIBUTE	Service-Type		6	integer
ATTRIBUTE	Framed-Protocol		7	integer
ATTRIBUTE	Framed-IP-Address	8	ipaddr
ATTRIBUTE	Framed-IP-Netmask	9	ipaddr
ATTRIBUTE	Framed-Routing		10	integer
ATTRIBUTE	Filter-Id		11	string
ATTRIBUTE	Framed-MTU		12	integer
ATTRIBUTE	Framed-Compression	13	integer
ATTRIBUTE	Login-IP-Host		14	ipaddr
ATTRIBUTE	Login-Service		15	integer
ATTRIBUTE	Login-TCP-Port		16	integer
ATTRIBUTE	Reply-Message		18	string
ATTRIBUTE	Callback-Number		19	string
ATTRIBUTE	Callback-Id		20	string
ATTRIBUTE	Framed-Route		22	string
ATTRIBUTE	Framed-IPX-Network	23	ipaddr
ATTRIBUTE	State			24	string
ATTRIBUTE	Session-Timeout		27	integer
ATTRIBUTE	Idle-Timeout		28	integer
ATTRIBUTE	Termination-Action	29	integer
ATTRIBUTE	Called-Station-Id	30	string
ATTRIBUTE	Calling-Station-Id	31	string
ATTRIBUTE	Acct-Status-Type	40	integer
ATTRIBUTE	Acct-Delay-Time		41	integer
ATTRIBUTE	Acct-Input-Octets	42	integer
ATTRIBUTE	Acct-Output-Octets	43	integer
ATTRIBUTE	Acct-Session-Id		44	string
ATTRIBUTE	Acct-Authentic		45	integer
ATTRIBUTE	Acct-Session-Time	46	integer
ATTRIBUTE	Acct-Terminate-Cause	49	integer
ATTRIBUTE	NAS-Port-Type		61	integer
ATTRIBUTE	Port-Limit		62	integer

</verb>
</tscreen>


<sect>
Proposals/unresolved issues

<p>
There have been proposals to offer other flavors of database access
through this library. It is hoped that the library will prove flexible
enough to support this need. But such support is not currently the
primary goal. In other words Cristian and Andrew will not be doing it
in the short term.. so unless you want to volunteer, please don't hold
your breath! :)

<sect>
References

<sect>
Acknowledgments

<p>
This document was written by Cristian Gafton and Andrew G. Morgan.

<p>
Thanks are also due to the following for their many helpful comments
and suggestions: Nalin Dahyabhai, Torsten Duwe, Elliot Lee, Marek
Michalkiewicz, Aleph One and Roland Schemers.

<p>
<em>More names to be added..</em>

</article>
