This will get completed as we develop the library
libpwdb offers the following generic interface:
int pwdb{[lowbar]}start(void)
Initialize the library for use by the current application Will read
the configuration file and publicize the database policies (as they are
listed in /etc/pwdb.conf) in const int *pwdb{[lowbar]}policy
and const int *pwdb{[lowbar]}group{[lowbar]}policy. The library maintains a
count of the number of times it has been pwdb{[lowbar]}start()ed.
int pwdb{[lowbar]}end(void)
Once the pwdb{[lowbar]}start()ed count returns to zero, this function
closes down the library and free()'s all memory allocated by it. Any
attempt to pwdb{[lowbar]}end() the library more times than it has been
pwdb{[lowbar]}start()ed will cause PWDB{[lowbar]}ABORT to be
returned. This feature can be used by an application to guarantee
the library is shutdown..
while (pwdb_end() == PWDB_SUCCESS);
int pwdb{[lowbar]}entry{[lowbar]}delete(const struct pwdb{[lowbar]}entry **e)
free() the memory associated with the pointer
*e. Its value will be overwritten with '{[bsol ]}{[bsol ]}0's before
the memory is free()d. This is reassuring from the point of
view of minimizing security problems. This function should be used to
liberate a pwdb{[lowbar]}entry returned by pwdb{[lowbar]}get{[lowbar]}entry().
int pwdb{[lowbar]}get{[lowbar]}entry(const struct pwdb *p, const char *entry, const
struct pwdb{[lowbar]}entry **e);
Read (and duplicate) an entry from the argument pwdb structure. Should
the requested entry not prove to be present, PWDB{[lowbar]}NOT{[lowbar]}FOUND is
returned.
int pwdb{[lowbar]}set{[lowbar]}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{[lowbar]}strval{[lowbar]}size))
Set an entry in the argument pwdb structure. One can delete an
entry from a struct pwdb by calling this function with NULL for
datum and -1 for length.
The two functions passed as arguments in this call are as follows:
int compare(const void *value1, const void *value2, int length)compare the two entry values. They are both of given length
in chars.
int strvalue(const void *value, char *buffer, int length)Produce a text version of the given entry value. The buffer
is the destination of the output text and the length is that of
the *value in bytes. Note, the buffer is guaranteed by the
calling process to be long enough for the output text.
int pwdb{[lowbar]}delete(const struct pwdb **old)
Applications use this to liberate the memory associated with a
pwdb structure. Following a successful free(),
*old is set to NULL.
int pwdb{[lowbar]}new(const struct pwdb **new, int life{[lowbar]}sec)
Applications can request a new (blank) pwdb structure with this
call. Note that it is returned as a 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 life{[lowbar]}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 life{[lowbar]}sec is non-zero, the pwdb structure will
expire in that many seconds. Zero indicates the pwdb structure
will non expire.
int pwdb_merge(const struct pwdb *target, const struct pwdb *source,
int overwrite)
this function copies the elements of source to target. If
overwrite is PWDB{[lowbar]}TRUE then all elements of source that
are also in target will be overwritten by this call.
int pwdb{[lowbar]}expire(const struct pwdb *p, int life{[lowbar]}sec)
This function can shorten the lifetime of a the referenced struct
pwdb. It computes the expiry time from the present with respect to
life{[lowbar]}sec and if this is before the expiration time currently
associated with the *p structure, it shortens the life of the
structure accordingly.
Note, it is not possible to extend the life of a pwdb structure,
only to shorten it. An argument of 0 or less will result in
the immediate expiry of the pwdb structure.
int pwdb{[lowbar]}source(const struct pwdb *old, const pwdb{[lowbar]}type *src,
const char *class, const char *name, const int id)
This function is used to set the source of the indicate pwdb
structure. The argument src is a pointer to a list of
pwdb{[lowbar]}type entries. This list is terminated with a
{[lowbar]}PWDB{[lowbar]}MAX{[lowbar]}TYPES item. Valid types are listed in the
{[lt ]}security/pwdb{[lowbar]}public.h{[gt ]} file. The remaining arguments
are used to initialize the caching facilities.
int pwdb{[lowbar]}locate(const char *class, const pwdb{[lowbar]}type *src, const char
*name, const int id, struct pwdb **p)
Obtain the entry for a given name and/or id in the indicated
database. If *p is not 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
*p structure. If *p is NULL, then a struct pwdb is
allocated by the pwdb{[lowbar]}locate() function in the first module used
(and eventually merged with the subsequent modules, depending on the
local setup). The class is the kind of database we are searching,
examples include user and group.
int pwdb{[lowbar]}request(const char *class, const pwdb{[lowbar]}type *src, const char *entry, struct pwdb **p)
This function will further query the database, for an entry
that may depend on the entries already present in the *p
structure. The entrys that can be appended to the existing
*p structure are defined for the class of database.
For example, one may request the "groupids" entry from
"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 pwdb structure.
int pwdb{[lowbar]}replace(const char *class, const pwdb{[lowbar]}type *src,
const char *name, const int id, struct pwdb **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
p argument. The src argument is the list of entries that
will be updated.
int pwdb{[lowbar]}remove(const char *class, const pwdb{[lowbar]}type *src,
const char *name, const int id, struct pwdb **p)
Remove the entry for the indicated name and/or id in the
indicated database. If not NULL the remove function may obtain
access information from the p argument.
Note, this function only acts on the specified class of
database. If reference to a name or id is present in another
class of database, then it is the responsibility of the
application to purge these databases too. The pwdb{[lowbar]}remove()
function is not sufficiently powerful to follow up on
cross-references.
As an example of the above concern, consider the removal of name
``joe'' from the "user" database. The "group" database
entries that refer to ``joe'' as a group-member are unaffected by this
pwdb{[lowbar]}remove() request. Instead, it is the responsibility of the
calling application to search for such entries and systematically
pwdb{[lowbar]}remove()
them.
int pwdb{[lowbar]}support(const char *class, const pwdb{[lowbar]}type *src,
const char *entry{[lowbar]}name)
Indicate whether the given entry name is supported by the given
database(s). PWDB{[lowbar]}SUCCESS indicates yes. Anything else is NO (or
something more specific, could be ``yes, if you supply a pass{[lowbar]}phrase''
for example).
int pwdb{[lowbar]}flags(const char *class, const pwdb{[lowbar]}type *db, pwdb{[lowbar]}flag *flag{[lowbar]}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 class of database (user,
group etc.), db (the database(s) we are going to use)
and some storage space for the returned flags.
Valid return flags which can be logically OR'd together are:
PWDB{[lowbar]}F{[lowbar]}NOACCESSinsufficient privilege to access database
PWDB{[lowbar]}F{[lowbar]}NOUPDATEinsufficient privilege to alter an entry
PWDB{[lowbar]}F{[lowbar]}PASS{[lowbar]}PHRASEto access the database, the process must supply a "pass{[lowbar]}phrase" entry with a preallocated pwdb structure (use pwdb{[lowbar]}new() call)
more flags are likely to be added
To establish if a given flag is set the following macro is supplied:
pwdb{[lowbar]}on(flag, PWDB{[lowbar]}F{[lowbar]}XXX)
it returns TRUE(1) or FALSE(0).
const char *pwdb{[lowbar]}strerror(int pwdb{[lowbar]}error)
return a textual description of the indicated return value.
Valid return codes are:
PWDB{[lowbar]}SUCCESStask completed successfully
PWDB{[lowbar]}BAD{[lowbar]}REQUESTrequest not recognized
PWDB{[lowbar]}TOO{[lowbar]}WEAKinsufficient privilege for operation
PWDB{[lowbar]}ABORTinternal failure - seek help
PWDB{[lowbar]}BLOCKEDanother process has locked resource
PWDB{[lowbar]}MALLOCinsufficient memory for operation
PWDB{[lowbar]}NOT{[lowbar]}FOUNDrequested item was not found
PWDB{[lowbar]}PASS{[lowbar]}PHRASE{[lowbar]}REQDpass{[lowbar]}phrase needed to satisfy request here the application should supply a pwdb structure with a "pass{[lowbar]}phrase" entry and call the function again
PWDB{[lowbar]}CONF{[lowbar]}ERRthere is a problem with the PWDB{[lowbar]}CONF file.
PWDB{[lowbar]}EXPIREDthe referenced pwdb structure has expired it is no longer valid and should be deleted.
PWDB{[lowbar]}UNSUPPORTEDthis function is not supported by some module (not supported means also unimplemented, for a while...)
PWDB{[lowbar]}TIMEOUTa timeout occured while performing the function. Presently could show up only when using RADIUS interface.
The pwdb{[lowbar]}type of database a request is associated with is given by one of the following values:
PWDB{[lowbar]}DEFAULTno database indicated, use configured list
PWDB{[lowbar]}UNIXgeneric /etc/passwd and /etc/group files
PWDB{[lowbar]}SHADOW/etc/shadow and /etc/gshadow Intended to supplement other databases
PWDB{[lowbar]}NISUse NIS server
PWDB{[lowbar]}RADIUSUse RADIUS server
PWDB{[lowbar]}DECNISUse a NIS server configured for Digital Equipment Corp Enhanced Security, or a Solaris server with an adjunct NIS password file.
const char *pwdb{[lowbar]}db{[lowbar]}name(pwdb{[lowbar]}type src)
return a character representation of the database functions
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:
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);
};
For the functions above taking a name and an id entry, the
application may choose to leave one unspecified with the following
defaults:
PWDB{[lowbar]}NAME{[lowbar]}UNKNOWNjust look at the id field
PWDB{[lowbar]}ID{[lowbar]}UNKNOWNjust look at the name field
In the case that the application supplies neither the name or the
id, the module functions will try to obtain the relevant
information from the argument pwdb structure.
It is legal for both the name and 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, PWDB{[lowbar]}BAD{[lowbar]}REQUEST
is returned.
The structure is registered via an entry in the modules list (see pwdb{[lowbar]}module.c).
The following are standard entries in the pwdb structure. They can be
read/written with calls to pwdb{[lowbar]}g/set{[lowbar]}entry.
First, we consider the "user" class of databases. For these, two
entries are mandatory. They correspond to the name of the user and the
user's uid.
usercharacter string; the user's login id.
uiduid{[lowbar]}t; the user's user-id.
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 /etc/passwd
file.
passwdcharacter string; the encrypted password for the user.
defer{[lowbar]}passThis entry is intended to take care of situations that the normal
passwd field is not used for the password. The defer{[lowbar]}pass
entry contains a character string that has typically two functions:
For example, for a unix+shadow setup, defer{[lowbar]}pass would have
the value ``x''. The unix (no shadow) value for this
entry is ``U'' which implies that the passwd field came from the
user's entry in the /etc/passwd file.
gidgid{[lowbar]}t; the user's principal group-id.
groupcharacter string; naming the user's principal group.
gecoscharacter 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.
dircharacter string; the home directory of the user.
shellcharacter string; the shell that the user prefers to use.
These entries correspond to the entries in the /etc/group file
in addition to the user and gid entries above. They can be
pwdb{[lowbar]}request()d from the "group" class of databases.
groupscharacter string; listing the group memberships of the user. The field separators are commas -- no spaces.
groupidsarray of gid{[lowbar]}t; an array containing the group id's of the user in
numerical form.
The following are intended to correspond to /etc/shadow
entries.
last{[lowbar]}changelong integer; day of last change of password
min{[lowbar]}changelong integer; minimum number of days between password changes
max{[lowbar]}changeinteger; maximum number of days between password changes
warn{[lowbar]}changelong integer; number of days to warn user to change their password before it expires
defer{[lowbar]}changelong integer; number of days after a user's password has expired before the user is denied access
expirelong integer; day the user's account expires
The following is the entry used to supply a clear-text password for access to the database.
pass{[lowbar]}phrasecharacter string; this is the password required to access the user's record in a database
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.
char *{[lowbar]}pwdb{[lowbar]}delete{[lowbar]}string(char *s)
overwrite the string 's' and return NULL. usage:
old{[lowbar]}ptr = {[lowbar]}pwdb{[lowbar]}delete(old{[lowbar]}ptr);
char *{[lowbar]}pwdb{[lowbar]}dup{[lowbar]}string(const char *s)
malloc() a copy of the string 's'. Return its address or
NULL if s == NULL or on error.
this memory will not be free()'d by a call to
pwdb{[lowbar]}end().
void pwdb{[lowbar]}print{[lowbar]}pwdb{[lowbar]}struct(const struct pwdb *p)
Dump the contents of *p to the stderr. Useful for debugging.
static struct pwdb *{[lowbar]}pwd{[lowbar]}check(const struct pwdb *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.
this function is strictly designed for the use of the generic code. Both modules and applications should never need to call it.
Here is a skeleton usage for a login type program.
pwdb_start();
pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN, {[amp ]}pw);
pwdb_request_group("group", PWDB_DEFAULT, "groupids", {[amp ]}pw);
pwdb_get_entry(pw, "uid", {[amp ]}e1);
pwdb_get_entry(pw, "gid", {[amp ]}e2);
pwdb_get_entry(pw, "groupids", {[amp ]}e3);
pwdb_end();