Prev: memory-allocation Next: process-credentials
/etc/passwd
The system password file, etc/passwd
contains a line
separated by colons for each user account on the system:
mtk:x:1000:100:Michael Kerrisk:/home/mtk:/bin/bash
The fields are:
x
normally if logins are contained in the shadow password
file./etc/shadow
Since many programs needed to read /etc/passwd
, having
encrypted password data there was a security risk. Thus, the shadow
password file at /etc/shadow
was created. Encrypted
passwords are placed in /etc/shadow
, and only privileged
programs can read it.
/etc/group
The group file is in /etc/group
. It might look like
this:
users:x:100:
jambit:x:106:claus,felli,frank,harti,markus,martin,mtk,paul
The fields look like this:
x
if
there is a password, and placed in /etc/gshadow
.getpwnam
and getpwuid
retrieve records from
the password file.
#include <pwd.h>
struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid); // Both return a pointer on success, or NULL on error; see main text for description of the “not found” case
Given a login name in name
, getpwnam
returns a pointer to a struct, passwd
that looks like the
following:
struct passwd {
char *pw_name; /* Login name (username) */
char *pw_passwd; /* Encrypted password */
; /* User ID */
uid_t pw_uid; /* Group ID */
gid_t pw_gidchar *pw_gecos; /* Comment (user information) */
char *pw_dir; /* Initial working (home) directory */
char *pw_shell; /* Login shell */
};
getpwuid
does the same, but with the numeric user id
passed in.
Both functions return a statically allocated struct, which is
overwritten on the next call to either getpwnam
,
getpwuid
or getpwnam
. Thus, the functions are
not reentrant, and the reentrant versions (getpwnam_r
,
getpwduid_r
, pgetgrgid_r
) must be used.
#include <grp.h>
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid); // Both return a pointer on success, or NULL on error; see main text for description of the “not found” case
getgrnam
and getgrgid
are similar, but work
for groups. They return this struct:
struct group {
char *gr_name; /* Group name */
char *gr_passwd; /* Encrypted password (if not password shadowing) */
; /* Group ID */
gid_t gr_gidchar **gr_mem; /* NULL-terminated array of pointers to names of members listed in /etc/group */
};
#include <pwd.h>
struct passwd *getpwent(void); // Returns pointer on success, or NULL on end of stream or error
void setpwent(void);
void endpwent(void);
getpwent
opens and returns records one by one from the
password file, returning NULL
when there are no more
records. setpwent
can be used to set a password, and
endpwent
is used to close the file.
To loop through all the passwords, something like this can be used:
struct passwd *pwd;
while ((pwd = getpwent()) != NULL) {
("%-8s %5ld\n", pwd->pw_name, (long) pwd->pw_uid);
printf}
(); endpwent
getgrent
, setgrent
, and
endgrent
are similar for the group id.
Similar functions exist for the shadow password file.
#include <shadow.h>
struct spwd *getspnam(const char *name); // Returns pointer on success, or NULL on not found or error
struct spwd *getspent(void); // Returns pointer on success, or NULL on end of stream or error
void setspent(void);
void endspent(void);
getspnam
and getspent
return pointers to a
structure of type spwd
.
struct spwd {
char *sp_namp; /* Login name (username) */
char *sp_pwdp; /* Encrypted password */
/* Remaining fields support "password aging", an optional
feature that forces users to regularly change their
passwords, so that even if an attacker manages to obtain
a password, it will eventually cease to be usable. */
long sp_lstchg; /* Time of last password change (days since 1 Jan 1970) */
long sp_min; /* Min. number of days between password changes */
long sp_max; /* Max. number of days before change required */
long sp_warn; /* Number of days beforehand that user is warned of upcoming password expiration */
long sp_inact; /* Number of days after expiration that account is considered inactive and locked */
long sp_expire; /* Date when account expires (days since 1 Jan 1970) */
unsigned long sp_flag; /* Reserved for future use */
};
To authenticate users in the unix way, passwords must be encrypted
using crypt
which uses the DES
algorithm.
crypt
looks like this:
#define _XOPEN_SOURCE
#include <unistd.h>
char *crypt(const char *key, const char *salt); // Returns pointer to statically allocated string containing encrypted password on success, or NULL on error
crypt
takes a key, which is the password, up to 8
characters, and applies a 2 character salt to change the algorithm. The
encrypted password starts with the original salt value as its first two
characters.
To read a password from the terminal, getpass
can be
used:
#define _BSD_SOURCE
#include <unistd.h>
char *getpass(const char *prompt); // Returns pointer to statically allocated input password string on success, or NULL on error
Prev: memory-allocation Next: process-credentials