Initial revision
authormelissa <melissa>
Fri, 20 Mar 1992 23:48:15 +0000 (23:48 +0000)
committermelissa <melissa>
Fri, 20 Mar 1992 23:48:15 +0000 (23:48 +0000)
manual/users.texi [new file with mode: 0644]

diff --git a/manual/users.texi b/manual/users.texi
new file mode 100644 (file)
index 0000000..92aa86d
--- /dev/null
@@ -0,0 +1,1016 @@
+@node Users and Groups
+@chapter Users and Groups
+@cindex persona
+
+Every user who can log in on the system is identified by a unique number
+called the @dfn{user ID}.  Each process has an effective user ID which
+says which user's access permissions it has.
+
+Users are classified into @dfn{groups} for access control purposes.  Each
+process has one or more @dfn{group ID values} which say which groups the
+process can use for access to files.
+
+The effective user and group IDs of a process collectively form its
+@dfn{persona}.  This determines which files the process can access.
+Normally, a process inherits its persona from the parent process, but
+under special circumstances a process can change its persona and thus
+change its access permissions.
+
+Each file in the system also has a user ID and a group ID.  Access
+control works by comparing the user and group IDs of the file with those
+of the running process.
+
+The system keeps a database of all the registered users, and another
+database of all the defined groups.  There are library functions you
+can use to examine these databases.
+
+@menu
+* User and Group IDs::  Each user has a unique numeric ID; likewise for groups.
+* Process Persona::    The user IDs and group IDs of a process.
+* Why Change Persona:: Why a program might need to change
+                        its user and/or group IDs.
+* How Change Persona:: Restrictions on changing the user and group IDs.
+* Reading Persona::    How to examine the process's user and group IDs.
+* Setting User ID::
+* Setting Groups::
+* Enable/Disable Setuid:: 
+* Setuid Example::     A program designed to use setuid.
+
+* Tips for Setuid::
+
+* Who Logged In::      Getting the name of the user who logged in,
+                        or of the real user ID of the current process.
+
+* User Database::      Functions and data structures for
+                         accessing the user database.
+* Group Database::     Functions and data structures for
+                         accessing the group database.
+* Database Example::   Example program showing use of database
+                        inquiry functions.
+@end menu
+
+@node User and Group IDs
+@section User and Group IDs
+
+@cindex login name
+@cindex user name
+@cindex user ID
+Each user account on a computer system is identified by a @dfn{user
+name} (or @dfn{login name}) and @dfn{user ID}.  Normally, each user name
+has a unique user ID, but it is possible for several login names to have
+the same user ID.  The user names and corresponding user IDs are stored
+in a data base which you can access as described in @ref{User Database}.
+
+@cindex group name
+@cindex group ID
+Users are classified in @dfn{groups}.  Each user name also belongs to
+one or more groups, and has one @dfn{default group}.  Users who are
+members of the same group can share resources (such as files) that are
+not accessible to users who are not a member of that group.  Each group
+has a @dfn{group name} and @dfn{group ID}.  @xref{Group Database},
+for how to find information about a group ID or group name.
+
+@node Process Persona
+@section The Persona of a Process
+
+@cindex effective user ID
+@cindex effective group ID
+At any time, each process has a single user ID and a group ID which
+determine the privileges of the process.  These are collectively called
+the @dfn{persona} of the process, because they determine ``who it is''
+for purposes of access control.  These IDs are also called the
+@dfn{effective user ID} and @dfn{effective group ID} of the process.
+
+Your login shell starts out with a persona which consists of your user
+ID and your default group ID.  In normal circumstances. all your other
+processes inherit these values.
+
+@cindex real user ID
+@cindex real group ID
+A process also has a @dfn{real user ID} which identifies the user who
+created the process, and a @dfn{real group ID} which identifies that
+user's default group.  These values do not play a role in access
+control, so we do not consider them part of the persona.  But they are
+also important.
+
+Both the real and effective user ID can be changed during the lifetime
+of a process.  @xref{Changing Persona}.
+
+@cindex supplementary group IDs
+In addition, a user can belong to multiple groups, so the persona
+includes have @dfn{supplementary group IDs} that also contribute to
+access permission.
+
+For details on how a process's effective user IDs and group IDs affect
+its permission to access files, see @ref{Access Permission}.
+
+The user ID of a process also controls permissions for sending signals
+using the @code{kill} function.  @xref{Signaling Another Process}.
+
+@node Why Change Persona
+@section Why Change the Persona of a Process?
+
+The most obvious situation where it is necessary for a process to change
+its user and/or group IDs is the @code{login} program.  When
+@code{login} starts running, its user ID is @code{root}.  Its job is to
+start a shell whose user and group IDs are those of the user who is
+logging in.  In fact, @code{login} must set the real user and group IDs
+as well as its persona.  But this is a special case.
+
+The more common case of changing persona is when an ordinary user
+programs needs access to a resource that wouldn't ordinarily be
+accessible to the user actually running it.
+
+For example, you may have a file that is controlled by your program but
+that shouldn't be read or modified directly by other users, either
+because it implements some kind of locking protocol, or because you want
+to preserve the integrity or privacy of the information it contains.
+This kind of restricted access can be implemented by having the program
+change its effective user or group ID to match that of the resource.
+
+Thus, imagine a game program that saves scores in a file.  The game
+program itself needs to be able to update this file no matter who is
+running it, but if users can write the file without going through the
+game, they can give themselves any scores they like.  Some people
+consider this undesirable, or even reprehensible.  It can be prevented
+by creating a new user ID and login name (say, @samp{games}) to own the
+scores file, and make the file writable only by this user.  Then, when
+the game program wants to update this file, it can change its effective
+user ID to be that for @samp{games}.  In effect, the program must
+adopt the persona of @samp{games} so it can write the scores file.
+
+@node How Change Persona
+@section How an Application can Change Persona
+@cindex @code{setuid} programs
+
+The ability to change the persona of a process can be a source of
+unintentional privacy violations, or even intentional abuse.  Because of
+the potential for problems, changing persona is restricted to special
+circumstances.
+
+You can't just arbitrarily set your user ID or group ID to anything you
+want; only privileged users can do that.  Instead, the normal way for a
+program to change its persona is that it has been set up in advance to
+change to a particular user or group.  This is the function of the suid
+and sgid bits of a file's access mode.
+
+When the suid bit of an executable file is set, executing that file
+automatically changes the effective user ID to the user that owns the
+file.  Likewise, executing a file whose sgid bit is set changes the
+effective group ID to the group of the file.  @xref{Executing a File}.
+Creating a file that changes to a particular user or group ID thus
+requires full access to that user or group ID.
+
+@xref{File Attributes}, for a more general discussion of file modes and
+accessibility.
+
+A process can always change its effective user (or group) ID back to its
+real ID.  Programs do this so as to turn off their special privileges
+when they are not needed, which makes for more robustness.
+
+@node Reading Persona
+@section Reading the Persona of a Process
+
+Here are detailed descriptions of the functions for reading the user and
+group IDs of a process, both real and effective.  To use these
+facilities, you must include the header files @file{sys/types.h} and
+@file{unistd.h}.
+@pindex unistd.h
+@pindex sys/types.h
+
+@comment sys/types.h
+@comment POSIX.1
+@deftp {Data Type} uid_t
+This is an integer data type used to represent user IDs.  In the GNU
+library, this is an alias for @code{unsigned short int}.
+@end deftp
+
+@comment sys/types.h
+@comment POSIX.1
+@deftp {Data Type} gid_t
+This is an integer data type used to represent group IDs.  In the GNU
+library, this is an alias for @code{unsigned short int}.
+@end deftp
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun uid_t getuid ()
+The @code{getuid} function returns the real user ID of the process.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun gid_t getgid ()
+The @code{getgid} function returns the real group ID of the process.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun uid_t geteuid ()
+The @code{geteuid} function returns the effective user ID of the process.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun gid_t getegid ()
+The @code{getegid} function returns the effective group ID of the process.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int getgroups (int @var{count}, gid_t *@var{groups})
+The @code{getgroups} function is used to inquire about the supplementary
+group IDs of the process.  Up to @var{count} of these group IDs are
+stored in the array @var{groups}; the return value from the function is
+the number of group IDs actually stored.  If @var{count} is smaller than
+the total number of supplementary group IDs, then @code{getgroups}
+returns a value of @code{-1} and @code{errno} is set to @code{EINVAL}.
+
+If @var{count} is zero, then @code{getgroups} just returns the total
+number of supplementary group IDs.
+
+Here's how to use @code{getgroups} to read all the supplementary group
+IDs:
+
+@example
+gid_t *
+read_all_groups ()
+@{
+  int ngroups = getgroups (0, 0);
+  gid_t *groups = (gid_t *) xmalloc (ngroups * sizeof (gid_t));
+  int val = getgroups (ngroups, groups);
+  if (val < 0)
+    return 0;
+  return groups;
+@}
+@end example
+@end deftypefun
+
+@node Setting User ID
+@section Setting the User ID
+
+This section describes the functions for altering the user ID
+of a process.  To use these facilities, you must include the header
+files @file{sys/types.h} and @file{unistd.h}.
+@pindex unistd.h
+@pindex sys/types.h
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int setuid (@var{newuid})
+This function sets both the real and effective user ID of the process
+to @var{newuid}, provided that the process has appropriate privileges.
+
+If the process is not privileged, then @var{newuid} must either be equal
+to the real user ID or the saved user ID (but only if the system
+supports the @code{_POSIX_SAVED_IDS} feature).  In this case,
+@code{setuid} sets only the effective user ID and not the real user ID.
+
+The @code{setuid} function returns a value of @code{0} to indicate
+successful completion, and a value of @code{-1} to indicate an error.
+The following @code{errno} error conditions are defined for this
+function:
+
+@table @code
+@item EINVAL
+The value of the @var{newuid} argument is invalid.
+
+@item EPERM
+The process does not have the appropriate privileges; you do not
+have permission to change to the specified ID.  @xref{Controlling Process
+Privileges}.
+@end table
+@end deftypefun
+
+@comment unistd.h
+@comment BSD
+@deftypefun int setreuid (int @var{ruid}, int @var{euid})
+This function sets the real user ID of the process to @var{ruid} and
+the effective user ID to @var{euid}.
+
+The @code{setreuid} function is provided for compatibility with 4.2 BSD
+Unix, which does not support saved IDs.  You can use this function to
+swap the effective and real user IDs of the process.  (Privileged users
+can make other changes as well.)  If saved IDs are supported, you should
+use that feature instead of this function.
+
+The return value is @code{0} on success and @code{-1} on failure.
+The following @code{errno} error conditions are defined for this
+function:
+
+@table @code
+@item EPERM
+The process does not have the appropriate privileges; you do not
+have permission to change to the specified ID.  @xref{Controlling Process
+Privileges}.
+@end table
+@end deftypefun
+
+@node Setting Groups
+@section Setting the Group IDs
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int setgid (@var{newgid})
+This function sets both the real and effective group ID of the process
+to @var{newgid}, provided that the process has appropriate privileges.
+
+If the process is not privileged, then @var{newgid} must either be equal
+to the real group ID or the saved group ID.  In this case, @code{setgid}
+sets only the effective group ID and not the real group ID.
+
+The return values and error conditions for @code{setgid} are the same
+as those for @code{setuid}.
+@end deftypefun
+
+
+@comment unistd.h
+@comment BSD
+@deftypefun int setregid (int @var{rgid}, int @var{egid})
+This function sets the real group ID of the process to @var{rgid} and
+the effective group ID to @var{egid}.
+
+The @code{setregid} function is provided for compatibility with 4.2 BSD
+Unix, which does not support saved IDs.  You can use this function to
+swap the effective and real group IDs of the process.  (Privileged users
+can make other changes.)  If saved IDs are supported, you should make use 
+of that feature instead of using this function.
+
+The return values and error conditions for @code{setregid} are the same
+as those for @code{setreuid}.
+@end deftypefun
+
+The GNU system also lets privileged processes change their supplementary 
+group IDs.  To use @code{setgroups} or @code{initgroups}, your programs
+should include the header file @file{grp.h}.
+@pindex grp.h
+
+@comment grp.h
+@comment BSD
+@deftypefun int setgroups (size_t @var{count}, gid_t *@var{groups})
+This function sets the process's supplementary group IDs.  It can only
+be called from privileged processes.  The @var{count} argument specifies
+the number of group IDs in the array @var{groups}.
+
+This function returns @code{0} if successful and @code{-1} on error.
+The following @code{errno} error conditions are defined for this
+function:
+
+@table @code
+@item EPERM
+The calling process is not privileged.
+@end table
+@end deftypefun
+
+@comment grp.h
+@comment BSD
+@deftypefun int initgroups (const char *@var{user}, gid_t @var{gid})
+The @code{initgroups} function effectively calls @code{setgroups} to
+set the process's supplementary group IDs to be the normal default for
+the user name @var{user}.  The group ID @var{gid} is also included.
+@end deftypefun
+
+@node Enable/Disable Setuid
+@section Turning Setuid Access On and Off
+
+You can use @code{setreuid} to swap the real and effective user IDs of
+the process, as follows:
+
+@example
+setreuid (geteuid (), getuid ());
+@end example
+
+@noindent
+This special case is always allowed---it cannot fail.  A @code{setuid}
+program can use this to turn its special access on and off.  For
+example, suppose a game program has just started, and its real user ID
+is @code{jdoe} while its effective user ID is @code{games}.  In this
+state, the game can write the scores file.  If it swaps the two uids,
+the real becomes @code{games} and the effective becomes @code{jdoe}; now
+the program has only @code{jdoe} to access.  Another swap brings
+@code{games} back to the effective user ID and restores access to the
+scores file.
+
+If the system supports the saved user ID feature, you can accomplish 
+the same job with @code{setuid}.  When the game program starts, its
+real user ID is @code{jdoe}, its effective user ID is @code{games}, and
+its saved user ID is also @code{games}.  The program should record both
+user ID values once at the beginning, like this:
+
+@example
+user_user_id = getuid ();
+game_user_id = geteuid ();
+@end example
+
+Then it can turn off game file access with 
+
+@example
+setuid (user_user_id);
+@end example
+
+@noindent
+and turn it on with 
+
+@example
+setuid (game_user_id);
+@end example
+
+@noindent
+Throughout the process, the real user ID remains @code{jdoe} and the 
+saved user ID remains @code{games}.
+
+@node Setuid Program Example
+@section Setuid Program Example
+
+Here's an example showing how to set up a program that changes its
+effective user ID.
+
+This is part of a game program called @code{caber-toss} that
+manipulates a file @file{scores} that should be writable only by the game
+program itself.  The program assumes that its executable
+file will be installed with the set-user-ID bit set and owned by the
+same user as the @file{scores} file.  Typically, a system
+administrator will set up an account like @samp{games} for this purpose.
+
+The executable file is given mode @code{4755}, so that doing an 
+@samp{ls -l} on it produces output like:
+
+@example
+-rwsr-xr-x   1 games    184422 Jul 30 15:17 caber-toss
+@end example
+
+@noindent
+The set-user-ID bit shows up in the file modes as the @samp{s}.
+
+The scores file is given mode @code{644}, and doing an @samp{ls -l} on
+it shows:
+
+@example
+-rw-r--r--  1 games           0 Jul 31 15:33 scores
+@end example
+
+Here are the parts of the program that show how to set up the changed
+user ID.  This program is conditionalized so that it makes use of the
+saved IDs feature if it is supported, and otherwise uses @code{setreuid}
+to swap the effective and real user IDs.
+
+@example
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+
+/* @r{Save the effective and real UIDs.} */
+
+uid_t euid, ruid;
+
+
+/* @r{Restore the effective UID to its original value.} */
+
+void
+do_setuid ()
+@{
+  int status;
+
+#ifdef _POSIX_SAVED_IDS
+  status = setuid (euid);
+#else
+  status = setreuid (ruid, euid);
+#endif
+  if (status < 0) @{
+    fprintf (stderr, "Couldn't set uid.\n");
+    exit (status);
+    @}
+@}
+
+
+/* @r{Set the effective UID to the real UID.} */
+
+void
+undo_setuid ()
+@{
+  int status;
+
+#ifdef _POSIX_SAVED_IDS
+  status = setuid (ruid);
+#else
+  status = setreuid (euid, ruid);
+#endif
+  if (status < 0) @{
+    fprintf (stderr, "Couldn't set uid.\n");
+    exit (status);
+    @}
+@}
+
+
+/* @r{Main program.} */
+
+void
+main ()
+@{
+  /* @r{Save the real and effective user IDs.}  */
+  ruid = getuid ();
+  euid = geteuid ();
+  undo_setuid ();
+
+  /* @r{Do the game and record the score.}  */
+  @dots{}
+@}
+@end example
+
+Notice how the first thing the @code{main} function does is to set the
+effective user ID back to the real user ID.  This is so that any other
+file accesses that are performed while the user is playing the game use
+the real user ID for determining permissions.  Only when the program
+needs to open the scores file does it switch back to the original
+effective user ID, like this:
+
+@example
+/* @r{Record the score.} */
+
+int
+record_score (int score)
+@{
+  FILE *stream;
+  char *myname;
+
+  /* @r{Open the scores file.} */
+  do_setuid ();
+  stream = fopen (SCORES_FILE, "a");
+  undo_setuid ();
+
+  /* @r{Write the score to the file.} */
+  if (stream) @{
+    myname = cuserid (NULL);
+    if (score < 0)
+      fprintf (stream, "%10s: Couldn't lift the caber.\n", myname);
+    else
+      fprintf (stream, "%10s: %d feet.\n", myname, score);
+    fclose (stream);
+    return 0;
+    @}
+  else
+    return -1;
+@}
+@end example
+
+@node Tips for Setuid
+@section Tips for Writing Setuid Programs
+
+It is easy for setuid programs to give the user access that isn't 
+intended---in fact, if you want to avoid this, you need to be careful.
+Here are some guidelines for preventing unintended access and
+minimizing its consequences when it does occur:
+
+@itemize @bullet
+@item
+Don't have @code{setuid} programs with privileged user IDs such as
+@samp{root} unless it is absolutely necessary.  If the resource is
+specific to your particular program, it's better to define a new,
+nonprivileged user ID or group ID just to manage that resource.
+
+@item
+Be cautious about using the @code{system} and @code{exec} functions in
+combination with changing the effective user ID.  Don't let users of
+your program execute arbitrary programs under a changed user ID.
+Executing a shell is especially bad news.  Less obviously, the
+@code{execlp} and @code{execvp} functions are a potential risk (since
+the program they execute depends on the user's @code{PATH} environment
+variable).
+
+If you must @code{exec} another program under a changed ID, specify an
+absolute file name (@pxref{File Name Resolution}) for the executable,
+and make sure that the protections on that executable and @emph{all}
+containing directories are such that ordinary users cannot replace it
+with some other program.
+
+@item
+Only use the user ID controlling the resource in the part of the program
+that actually uses that resource.  When you're finished with it, restore
+the effective user ID back to the actual user's user ID.
+@xref{Enable/Disable Setuid}.
+
+@item
+If the @code{setuid} part of your program needs to access other files
+besides the controlled resource, it should verify that the real user
+would ordinarily have permission to access those files.  You can use the
+@code{access} function (@pxref{Access Permission}) to check this; it
+uses the real user and group IDs, rather than the effective IDs.
+@end itemize
+
+@node Who Logged In
+@section Identifying Who Logged In
+@cindex login name, determining
+@cindex user ID, determining
+
+You can use the functions listed in this section to determine the login
+name of the user who is running a process, and the name of the user who
+logged in the current session.  See also the function @code{getuid} and
+friends (@pxref{User and Group ID Functions}).
+
+The @code{getlogin} function is declared in @file{unistd.h}, while
+@code{cuserid} and @code{L_cuserid} are declared in @file{stdio.h}.
+@pindex stdio.h
+@pindex unistd.h
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun {char *} getlogin ()
+The @code{getlogin} function returns a pointer to string containing the
+name of the user logged in on the controlling terminal of the process,
+or a null pointer if this information cannot be determined.  The string
+is statically allocated and might be overwritten on subsequent calls to
+this function or to @code{cuserid}.
+@end deftypefun
+
+@comment stdio.h
+@comment POSIX.1
+@deftypefun {char *} cuserid (@var{string})
+The @code{cuserid} function returns a pointer to a string containing a
+user name associated with the effective ID of the process.  If
+@var{string} is not a null pointer, it should be an array that can hold
+at least @code{L_cuserid} characters; the string is returned in this
+array.  Otherwise, a pointer to a string in a static area is returned.
+This string is statically allocated and might be overwritten on
+subsequent calls to this function or to @code{getlogin}.
+@end deftypefun
+
+@comment stdio.h
+@comment POSIX.1
+@deftypevr Macro int L_cuserid
+An integer constant that indicates how long an array you might need to
+store a user name.
+@end deftypevr
+
+These functions let your program identify positively the user who is
+running or the user who logged in this session.  (These can differ when
+setuid programs are involved; @xref{Controlling Access Privileges}.)
+The user cannot do anything to fool these functions.
+
+For most purposes, it is more useful to use the environment variable
+@code{LOGNAME} to find out who the user is.  This is more flexible
+precisely because the user can set @code{LOGNAME} arbitrarily.
+@xref{Environment Variables}.
+
+@node User Database
+@section User Database
+@cindex user database
+@cindex password database
+@pindex /etc/passwd
+
+This section describes all about now to search and scan the database of
+registered users.  The database itself is kept in the file
+@file{/etc/passwd} on most systems, but on some systems a special
+network server gives access to it.
+
+@menu
+* User Data Structure::
+* Lookup User::
+* Scan All Users::
+* Writing a User Entry::
+@end menu
+
+@node User Data Structure
+@subsection The Data Structure that Describes a User
+
+The functions and data structures for accessing the system user database
+are declared in the header file @file{pwd.h}.
+@pindex pwd.h
+
+@comment pwd.h
+@comment POSIX.1
+@deftp {struct Type} passwd
+The @code{passwd} data structure is used to hold information about 
+entries in the system user data base.  It has at least the following members:
+
+@table @code
+@item char *pw_name
+The user's login name.
+
+@item char *pw_passwd.
+The encrypted password string.
+
+@item uid_t pw_uid
+The user ID number.
+
+@item gid_t pw_gid
+The user's default group ID number.
+
+@item char *pw_gecos
+A string typically containing the user's real name, and possibly other
+information such as a phone number.
+
+@item char *pw_dir
+The user's home directory, or initial working directory.  This might be
+a null pointer, in which case the interpretation is system-dependent.
+
+@item char *pw_shell
+The user's default shell, or the initial program run when the user logs in.
+This might be a null pointer, indicating that the system default should
+be used.
+@end table
+@end deftp
+
+@node Lookup User
+@subsection Looking Up One User
+@cindex converting user ID to user name
+@cindex converting user name to user ID
+
+You can search the system user database for information about a
+specific user using @code{getpwuid} or @code{getpwnam}.  These
+functions are declared in @file{pwd.h}.
+
+@comment pwd.h
+@comment POSIX.1
+@deftypefun {struct passwd *} getpwuid (uid_t @var{uid})
+This function returns a pointer to a statically-allocated structure
+containing information about the user whose user ID is @var{uid}.  This
+structure may be overwritten on subsequent calls to @code{getpwuid}.
+
+A null pointer value indicates there is no user in the data base with
+user ID @var{uid}.
+@end deftypefun
+
+@comment pwd.h
+@comment POSIX.1
+@deftypefun {struct passwd *} getpwnam (const char *@var{name})
+This function returns a pointer to a statically-allocated structure
+containing information about the user whose user name is @var{name}.
+This structure may be overwritten on subsequent calls to
+@code{getpwnam}.
+
+A null pointer value indicates there is no user named @var{name}.
+@end deftypefun
+
+@node Scanning All Users
+@subsection Scanning the List of All Users
+@cindex scanning the user list
+
+This section explains how a program can read the list of all users in
+the system, one user at a time.  The functions described here are
+declared in @file{pwd.h}.
+
+The recommended way to scan the users is to open the user file and
+then call @code{fgetgrent} for each successive user:
+
+@comment pwd.h
+@comment SVID
+@deftypefun {struct passwd *} fgetpwent (FILE *@var{stream})
+This function reads the next user entry from @var{stream} and returns a
+pointer to the entry.  The structure is statically allocated and is
+rewritten on subsequent calls to @code{getpwent}.  You must copy the
+contents of the structure if you wish to save the information.
+
+This stream must correspond to a file in the same format as the standard
+password database file.  This function comes from System V.
+@end deftypefun
+
+Another way to scan all the entries in the group database is with
+@code{setpwent}, @code{getpwent}, and @code{endpwent}.  But this method
+is less robust than @code{fgetpwent}, so we provide it only for
+compatibility with SVID.  In particular, these functions are not
+reentrant and are not suitable for use in programs with multiple threads
+of control.  Calling @code{getpwgid} or @code{getpwnam} can also confuse
+the internal state of these functions.
+
+@comment pwd.h
+@comment SVID, GNU
+@deftypefun void setpwent ()
+This function initializes a stream which @code{getpwent} uses to read
+the user database.
+@end deftypefun
+
+@comment pwd.h
+@comment SVID, GNU
+@deftypefun {struct passwd *} getpwent ()
+The @code{getpwent} function reads the next entry from the stream
+initialized by @code{setpwent}.  It returns a pointer to the entry.  The
+structure is statically allocated and is rewritten on subsequent calls
+to @code{getpwent}.  You must copy the contents of the structure if you
+wish to save the information.
+@end deftypefun
+
+@comment pwd.h
+@comment SVID, GNU
+@deftypefun void endpwent ()
+This function closes the internal stream used by @code{getpwent}.
+@end deftypefun
+
+@node Writing a User Entry
+@subsection Writing a User Entry
+
+@comment pwd.h
+@comment SVID
+@deftypefun int putpwent (const struct passwd *@var{p}, FILE *@var{stream})
+This function writes the user entry @code{*@var{p}} to the stream
+@var{stream}, in the format used for the standard user database
+file.  The return value is zero on success and non-zero on failure.
+
+This function exists for compatibility with SVID.  We recommend that you
+avoid using it, because it makes sense only on the assumption that the
+@code{struct passwd} structure has no members except the standard ones;
+on a system which merges the traditional Unix data base with other
+extended information about users, adding an entry using this function
+would inevitably leave out much of the important information.
+
+The function @code{putpwent} is declared in @file{pwd.h}.
+@end deftypefun
+
+@node Group Database
+@section Group Database
+@cindex group database
+@pindex /etc/group
+
+This section describes all about now to search and scan the database of
+registered groups.  The database itself is kept in the file
+@file{/etc/group} on most systems, but on some systems a special network
+service provides access to it.
+
+@menu
+* Group Data Structure::
+* Lookup Group::
+* Scan All Groups::
+@end menu
+
+@node Group Data Structure
+@subsection The Data Structure for a Group
+
+The functions and data structures for accessing the system group
+database are declared in the header file @file{grp.h}.
+@pindex grp.h
+
+@comment grp.h
+@comment POSIX.1
+@deftp {Data Type} {struct group} 
+The @code{group} structure is used to hold information about an entry in
+the system group database.  It has at least the following members:
+
+@table @code
+@item char *gr_name
+The name of the group.
+
+@item gid_t gr_gid
+The group ID of the group.
+
+@item char **gr_mem
+A vector of pointers to the names of users in the group.  Each user name
+is a null-terminated string, and the vector itself is terminated by a
+null pointer.
+@end table
+@end deftp
+
+@node Lookup Group
+@subsection Looking Up One Group
+@cindex converting group name to group ID
+@cindex converting group ID to group name
+
+You can search the group database for information about a specific
+group using @code{getgrgid} or @code{getgrnam}.  These functions are
+declared in @file{grp.h}.
+
+@comment grp.h
+@comment POSIX.1
+@deftypefun {struct group *} getgrgid (gid_t @var{gid})
+This function returns a pointer to a statically-allocated structure
+containing information about the group whose group ID is @var{gid}.
+This structure may be overwritten by subsequent calls to
+@code{getgrgid}.
+
+A null pointer indicates there is no group with ID @var{gid}.
+@end deftypefun
+
+@comment grp.h
+@comment POSIX.1
+@deftypefun {struct group *} getgrnam (const char *@var{name})
+This function returns a pointer to a statically-allocated structure
+containing information about the group whose group name is @var{name}.
+This structure may be overwritten by subsequent calls to
+@code{getgrnam}.
+
+A null pointer indicates there is no group named @var{name}.
+@end deftypefun
+
+@node Scanning All Groups
+@subsection Scanning the List of All Groups
+@cindex scanning the group list
+
+This section explains how a program can read the list of all groups in
+the system, one group at a time.  The functions described here are
+declared in @file{grp.h}.
+
+The recommended way to scan the groups is to open the group file and
+then call @code{fgetgrent} for each successive group:
+
+@comment grp.h
+@comment SVID
+@deftypefun {struct group *} fgetgrent (FILE *@var{stream})
+The @code{fgetgrent} function reads the next entry from @var{stream}.
+It returns a pointer to the entry.  The structure is statically
+allocated and is rewritten on subsequent calls to @code{getgrent}.  You
+must copy the contents of the structure if you wish to save the
+information.
+
+The stream must correspond to a file in the same format as the standard
+group database file.
+@end deftypefun
+
+Another way to scan all the entries in the group database is with
+@code{setgrent}, @code{getgrent}, and @code{endgrent}.  But this method
+is less robust than @code{fgetgrent}, so we provide it only for
+compatibility with SVID.  In particular, these functions are not
+reentrant and are not suitable for use in programs with multiple threads
+of control.  Calling @code{getgrgid} or @code{getgrnam} can also confuse
+the internal state of these functions.
+
+@comment grp.h
+@comment SVID, GNU
+@deftypefun void setgrent ()
+This function initializes a stream for reading from the group data base.
+You use this stream by calling @code{getgrent}.
+@end deftypefun
+
+@comment grp.h
+@comment SVID, GNU
+@deftypefun {struct group *} getgrent ()
+The @code{getgrent} function reads the next entry from the stream
+initialized by @code{setgrent}.  It returns a pointer to the entry.  The
+structure is statically allocated and is rewritten on subsequent calls
+to @code{getgrent}.  You must copy the contents of the structure if you
+wish to save the information.
+@end deftypefun
+
+@comment grp.h
+@comment SVID, GNU
+@deftypefun void endgrent ()
+This function closes the internal stream used by @code{getgrent}.
+@end deftypefun
+
+@node Database Example
+@section User and Group Database Example
+
+Here is an example program showing the use of the system database inquiry
+functions.  The program prints some information about the user running
+the program.
+
+@example
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+void
+main ()
+@{
+  uid_t me;
+  struct passwd *my_passwd;
+  struct group *my_group;
+  char **members;
+
+  /* @r{Get information about the user ID.} */
+  me = getuid ();
+  my_passwd = getpwuid (me);
+  if (!my_passwd) @{
+    printf ("Couldn't find out about user %d.\n", me);
+    exit (EXIT_FAILURE);
+    @}
+
+  /* @r{Print the information.} */
+  printf ("My login name is %s.\n", my_passwd->pw_name);
+  printf ("My uid is %d.\n", my_passwd->pw_uid);
+  printf ("My home directory is %s.\n", my_passwd->pw_dir);
+  printf ("My default shell is %s.\n", my_passwd->pw_shell);
+
+  /* @r{Get information about the default group ID.} */
+  my_group = getgrgid (my_passwd->pw_gid);
+  if (!my_group) @{
+    printf ("Couldn't find out about group %d.\n",
+            my_passwd->pw_gid);
+    exit (EXIT_FAILURE);
+    @}
+
+  /* @r{Print the information.} */
+  printf ("My default group is %s (%d).\n",
+         my_group->gr_name, my_passwd->pw_gid);
+  printf ("The members of this group are:\n");
+  members = my_group->gr_mem;
+  while (*members)
+    printf ("  %s\n", *members++);
+
+  exit (EXIT_SUCCESS);
+@}
+@end example
+
+Here is some output from this program:
+
+@example
+My login name is snurd.
+My uid is 31093.
+My home directory is /home/fsg/snurd.
+My default shell is /bin/sh.
+My default group is guest (12).
+The members of this group are:
+  friedman
+  @dots{}
+@end example