  libuser 0.5
  Nalin Dahyabhai <nalin@redhat.com>
  2 January 2001

  This is the libuser administrator and programmer's guide.  It first
  describes the motivation for the existence of this library, and then
  delves into the library interface used by both libuser modules and
  applications.

  11..  IInnttrroodduuccttiioonn

  This section describes libuser: why it was written, and how it works.
  How the library is to be used will be described later.


  11..11..  MMoottiivvaattiioonn

  When proper nsswitch functionality was introduced into glibc 2.0, it
  became possible to supply third-party facilities which would allow the
  standard C library (and by extension, all of a system's binaries) to
  pull information about users, protocols, and services from a variety
  of sources the glibc authors might not have anticipated.


  The most common use for a new nsswitch module is supplementing the
  user and group databases, extending the data sources accessed over a
  network to a centrally-managed information store.  This, along with
  the ability to authenticate users using networked servers
  (functionality provided by the increasingly-ubiquitous Linux-PAM
  library) and an enterprise-class networked filesystem, allows a
  properly-configured Linux workstation to participate as a full-fledged
  client in a large-scale network.


  The facilities provided by PAM allow a user to log in and change her
  authentication tokens.  The nsswitch interface allows any user (even
  unprivileged users like nnoobbooddyy) to look up information needed to run
  applications.


  However, there are certain functions supplied by traditional isolated
  systems which such a networked workstation can't provide.  Users have
  no method for modifying their information (cchhffnn is broken), and the
  system administrator who previously had total power over the user and
  group databases must now perform all administration at the server
  using tools which are designed for general modification of the
  information store (hand-editing zone files for hesiod databases,
  llddaappmmooddiiffyy, kkaaddmmiinn) instead of the traditionally-used tools.


  11..22..  AAlltteerrnnaattiivvee SSoolluuttiioonnss

  The software which comes closest to meeting these needs is ppwwddbb.
  However, the pwdb library has a few design limitations which make it
  unsuitable for this purpose.  Like the standard files-based
  mechanisms, pwdb assumes that the superuser wields full access over
  the databases it interfaces with.  The current version of pwdb
  provides no facilities for managing groups.  The current version of
  pwdb can not be extended easily by third parties due to its reliance
  on static linking.


  11..33..  TThhee lliibbuusseerr LLiibbrraarryy

  The libuser library implements a fully-modular system for reading,
  modifying, creating, and removing user and group accounts and account
  information.  Modules which provide access to information stores can
  request information from the accessing user in order to authenticate
  to the information store.


  22..  SSyysstteemm AAddmmiinniissttrraattiioonn

  This section describes libuser's configuration file and bundled
  applications which may be of use to system administrators.


  22..11..  CCoonnffiigguurraattiioonn

  The libuser configuration file is named lliibbuusseerr..ccoonnff and usually lives
  in //eettcc.  Its format is the common format used by numerous other
  programs.  Sections are marked by the section name enclosed in square
  brackets ([[sseeccttiioonn]]), and configuration directives within these
  sections are of the form kkeeyy == vvaalluuee.


  The ddeeffaauullttss, uusseerrddeeffaauullttss, and ggrroouuppddeeffaauullttss sections are used by the
  library itself.  The ddeeffaauullttss section specifies the directory where
  modules can be found (mmoodduulleeddiirr) and lists the modules to be consulted
  when looking up user information.


  There are two lists of modules because lliibbuusseerr separates an account's
  authentication information from other information.  This is done to
  allow different information stores to be used for these functions, and
  because some information stores can only hold authentication data (for
  example, shadow and krb5).


  For the iinnffoo__mmoodduulleess and aauutthh__mmoodduulleess lists, order is only important
  for account creation -- the library will attempt to create a data
  entry for the user in each of the modules until one of them succeeds
  (so if you prefer new accounts to be created in your LDAP directory,
  then you'd make sure "ldap" was listed _b_e_f_o_r_e "files").  For looking
  up account information, the order determines precedence because the
  library stops searching after a module returns success (so again,
  you'd want "ldap" listed before "files").  Account modifications and
  deletions go straight to the information store which is known to hold
  the user's information.


  22..22..  MMoodduulleess

  Specific modules implement access to specific information stores.  The
  modules included in the source distribution are the ffiilleess and sshhaaddooww
  modules.  Modules can supply and manipulate either (or both) of two
  distinct types of data about a user: generic user information (the
  UID, home directory, etc.), and authentication-related information.


  22..22..11..  ffiilleess

  The files module implements both information and authentication data
  stores using the standard ppaasssswwdd and ggrroouupp files.


  This module uses the ffiilleess section of the configuration file to store
  configuration data.  It presently recognizes these flags:


  +o  directory - the directory the ppaasssswwdd and ggrroouupp files are to be
     stored in
  22..22..22..  sshhaaddooww

  The shadow module implements only an authentication data store using
  the sshhaaddooww and the ggsshhaaddooww files.  While the format of these files
  (and even the existence of the ggsshhaaddooww file) varies between OSs, this
  module supports the same file formats used by the shadow password
  suite.


  This module uses the sshhaaddooww section of the configuration file to store
  configuration data.  It presently recognizes these flags:


  +o  directory - the directory the sshhaaddooww and ggsshhaaddooww files are to be
     stored in.


  22..22..33..  kkrrbb55

  The krb5 module implements only an authentication data store using a
  connection to the Kerberos realm's administrative server and the
  kadmin protocols.


  This module uses the kkrrbb55 section of the configuration file to store
  configuration data.  It presently recognizes these flags:


  +o  realm - the default realm to administer accounts in.  If not
     specified, the value is taken from kkrrbb55..ccoonnff by the Kerberos
     libraries the module links with.


  22..22..44..  llddaapp

  The ldap module implements both information and authentication data
  stores using an LDAP directory and a schema which (should) conform to
  RFC2307.  The module expects the client and server to support access
  using LDAPv3 with TLS.


  This module uses the llddaapp section of the configuration file to store
  configuration data.  It presently recognizes these flags:


  +o  server - the hostname of the LDAP server

  +o  basedn - the distinguished name which is the root of your tree

  +o  user - the user name with which to perform SASL binds

  +o  authuser - the authorization user name with which to perform SASL
     binds

  +o  binddn - the distinguished name to connect as for administrative
     access

  +o  userBranch - the distinguished name (relative to the basedn) under
     which user account data is kept

  +o  groupBranch - the distinguished name (relative to the basedn) under
     which group account data is kept




  22..33..  AApppplliiccaattiioonnss

  Sample testbed applications which mimic the behavior of certain parts
  of the shadow password suite are included in the libuser distribution.
  To allow them to be used alongside existing utilities, their names
  have been prefixed with the letter 'l'.


  As of this writing (version 0.7), this list of tools includes
  workalikes for uusseerraadddd, uusseerrmmoodd, uusseerrddeell, ggrroouuppaadddd, ggrroouuppmmoodd,
  ggrroouuppddeell, and cchhaaggee.  It should be noted that none of these tools
  provide a means for modifying the defaults they use, and no functions
  for creating, populating, moving, or deleting user home directories
  are implemented.


  33..  TThhee AApppplliiccaattiioonn IInntteerrffaaccee

  This section describes the public libuser API, which is available to
  applications.


  33..11..  IInniittiiaalliizzaattiioonn aanndd TTeerrmmiinnaattiioonn

  This section describes how to start up and shut down the library.


  +o  struct lu_context* lu_start(const char *auth_user, enum lu_type
     auth_type, const char *info_modules, const char *auth_modules,
     lu_prompt_fn *prompter, gpointer callback_data)

     Initializes the library, loads the specified modules, and returns a
     context structure on success, or NNUULLLL on failure.

     The aauutthh__uusseerr and aauutthh__nnaammee arguments are hints to the modules for
     determining the identity to connect to information stores as.  The
     default administrator can be specified by passing in NNUULLLL as the
     aauutthh__uusseerr argument.

     The iinnffoo__mmoodduulleess and aauutthh__mmoodduulleess arguments allow the application
     to override the lists of modules set in the library's configuration
     file.  The application can specify NNUULLLL for both values to use the
     configured defaults.

     The pprroommpptteerr argument is the address of a function which modules
     can call in order to obtain information needed for accessing
     information stores.  The library provides lluu__pprroommpptt__ccoonnssoollee for
     console-based applications.  If the application passes in NNUULLLL,
     then no prompts will be made, and library initialization may fail.

     The ccaallllbbaacckk__ddaattaa argument is a pointer to application-specific
     data which the pprroommpptteerr function will be passed whenever it is
     called.


  +o  void lu_set_info_modules(struct lu_context *context, const char
     *list)

     Sets the list of information modules used.  The ccoonntteexxtt argument is
     a structure obtained through a previous call to lluu__ssttaarrtt, and the
     lliisstt argument is identical to the iinnffoo__mmoodduulleess argument used by
     lluu__ssttaarrtt.


  +o  void lu_set_auth_modules(struct lu_context *context, const char
     *list)
     Sets the list of authentication modules used.  The ccoonntteexxtt argument
     is a structure obtained through a previous call to lluu__ssttaarrtt, and
     the lliisstt argument is identical to the aauutthh__mmoodduulleess argument used by
     lluu__ssttaarrtt.


  +o  void lu_end(struct lu_context *context)

     Shuts down the library, unloads the modules in use, and frees
     memory.



  33..22..  EEnnttiittyy SSttrruuccttuurreess

  This section describes the entity data structure and how it is used to
  look up, create, modify, and destroy users and groups.


  +o  struct lu_ent *lu_ent_new()


     Creates a new lluu__eenntt structure.  This is an array of lists, indexed
     by strings, of user/group attributes, similar to a pwdb_entry.  An
     lluu__eenntt also contains a notion of oorriiggiinnaall and wwoorrkkiinngg attribute
     sets.


  +o  void lu_ent_copy(struct lu_ent *source, struct lu_ent *dest)


     Copies the contents of one lluu__eenntt to another.


  +o  void lu_ent_revert(struct lu_ent *ent)


     Sets the lluu__eenntt's working attribute set to match the values stored
     in its original attribute set.


  +o  void lu_ent_free(struct lu_ent *ent)


     Frees an lluu__eenntt structure.


  +o  GList *lu_ent_get_attributes(struct lu_ent *ent)


     Returns a GGLLiisstt of the names of the attributes the entity has
     defined values for.


  +o  GList *lu_ent_get(struct lu_ent *ent, const char *attribute)


     Returns a GGLLiisstt of the values for the named attribute which the
     entity structure contains.


  +o  GList *lu_ent_get_original(struct lu_ent *ent, const char
     *attribute)


     Like lluu__eenntt__ggeett, but accesses the original attribute set instead of
     the working attribute set.


  +o  gboolean lu_ent_set(struct lu_ent *ent, const char *attr, const
     char *val)


     Most attributes only contain a single value.  This function can be
     used to set that value.  Returns TTRRUUEE on success, and FFAALLSSEE on
     failure.


  +o  gboolean lu_ent_set_original(struct lu_ent *ent, const char *attr,
     const char *val)


     Like lluu__eenntt__sseett, but access the original attribute set instead of
     the working attribute set.  This is used when populating new
     structures and creating accounts.


  +o  gboolean lu_ent_add(struct lu_ent *ent, const char *attr, const
     char *val)


     Adds a value to the list of values for the named attribute.
     Returns TTRRUUEE on success, and FFAALLSSEE on failure.


  +o  gboolean lu_ent_add_original(struct lu_ent *ent, const char *attr,
     const char *val)


     Like lluu__eenntt__aadddd, but accesses the original attribute set instead of
     the working attribute set.


  +o  gboolean lu_ent_del(struct lu_ent *ent, const char *attr, const
     char *val)


     Removes a value from the list of values for the named attribute.
     Returns TTRRUUEE on success, and FFAALLSSEE on failure.


  +o  gboolean lu_ent_clear(struct lu_ent *ent, const char *attr)


     Removes all values from the list of values for the named attribute,
     and removes the attribute.  Returns TTRRUUEE on success, and FFAALLSSEE on
     failure.


  +o  gboolean lu_ent_clear_original(struct lu_ent *ent, const char
     *attr)


     Like lluu__eenntt__cclleeaarr, but accesses the original attribute set instead
     of the working attribute set.



  33..33..  MMaanniippuullaattiinngg UUsseerrss aanndd GGrroouuppss

  This section describes how an application can look up user and group
  information, and add, modify, and delete accounts.  Although the
  library provides distinct user and group access functions, the
  function declarations are similar enough that the group variants are
  omitted here.


  +o  gboolean lu_user_lookup_name(struct lu_context *context, const char
     *name, struct lu_ent *ent)


     Looks up information for the named user, and stores the information
     in the passed lluu__eenntt structure if such information is found.
     Returns TTRRUUEE on success, FFAALLSSEE on failure.


  +o  gboolean lu_user_lookup_id(struct lu_context *context, uid_t uid,
     struct lu_ent *ent)


     Like lluu__uusseerr__llooookkuupp__nnaammee, but takes a uuiidd__tt instead of a name.  The
     group variant takes a ggiidd__tt.


  +o  gboolean lu_user_add(struct lu_context *context, struct lu_ent
     *ent)


     Creates a new user account using information stored in the lluu__eenntt
     structure.  Returns TTRRUUEE if the operation is successful.  The
     library does this by attempting to create an authentication entity
     for the user (this is a purposefully vague description --
     individual back-end modules will do this in different ways) using
     one of the configured aauutthh__mmoodduulleess.  If this succeeds, the library
     will create a general information entity for the user using one of
     the configured iinnffoo__mmoodduulleess.


  +o  gboolean lu_user_modify(struct lu_context *context, struct lu_ent
     *ent)


     Brings the user's account information (as reflected in information
     stores) in line with the working attribute set in the passed-in
     lluu__eenntt structure.  Returns TTRRUUEE if the operation is successful,
     FFAALLSSEE if it fails.  The library keeps track of the information
     stores accessed for the user's aauutthh and iinnffoo attributes, and
     modifies only these.


  +o  gboolean lu_user_delete(struct lu_context *context, struct lu_ent
     *ent)


     Deletes the named user account from the information stores which
     contain the user's aauutthh and iinnffoo attributes.  Returns TTRRUUEE if the
     deletion operation is successful.


  +o  gboolean lu_user_lock(struct lu_context *context, struct lu_ent
     *ent)


     Locks the account of the user who was passed in.  Returns TTRRUUEE if
     the locking operation is successful, or FFAALLSSEE if the locking fails
     (for example, if the account is already locked or if account
     locking is not supported by the aauutthh information store).

  +o  gboolean lu_user_unlock(struct lu_context *context, struct lu_ent
     *ent)


     Unlocks the account of the user who was passed in.  Returns TTRRUUEE if
     the unlocking operation is successful or FFAALLSSEE if the account was
     not locked or could not be unlocked.



  33..44..  RReeaaddiinngg tthhee CCoonnffiigguurraattiioonn

  This section describes the mechanism libuser provides for applications
  and modules to access configuration data.


  +o  GList *lu_cfg_read(struct lu_context *context, const char *key,
     const char *default_value)


     Reads the contents of a particular key in the configuration file,
     and returns a GGLLiisstt of the results.  The key is of the form
     "sseeccttiioonn/kkeeyy".  An example key is "defaults/moduledir".  If no
     matches are found, a list containing ddeeffaauulltt__vvaalluuee will be
     returned.


  +o  const char *lu_cfg_read_single(struct lu_context *context, const
     char *key, const char *default_value)


     Reads the contents of a particular key in the configuration file,
     and returns a single item from the list of results.  This is a
     simple wrapper around lluu__ccffgg__rreeaadd meant for use when only one value
     is expected to be returned.


  +o  GList *lu_cfg_read_keys(struct lu_context *context, const char
     *parent_key)


     Reads and returns a list of the keys within the section named by
     the ppaarreenntt__kkeeyy.  This function is useful for iterating over an
     entire section of the configuration file.






















