* NEWS, src/newusers.c, src/Makefile.am: Added support for

changing the passwords with PAM.
	* src/newusers.c: Split the usage string in smaller parts to
	allow enabling single parts.
	* man/newusers.8.xml: Indicate the options and configuration
	variables valid for PAM and non-PAM versions.
	* man/newusers.8.xml: Added pointer to /etc/pam.d/chpasswd.
This commit is contained in:
nekral-guest 2009-05-09 13:15:57 +00:00
parent 8bcb2c1e71
commit 7f9e196903
5 changed files with 167 additions and 42 deletions

View File

@ -1,3 +1,13 @@
2009-05-09 Nicolas François <nicolas.francois@centraliens.net>
* NEWS, src/newusers.c, src/Makefile.am: Added support for
changing the passwords with PAM.
* src/newusers.c: Split the usage string in smaller parts to
allow enabling single parts.
* man/newusers.8.xml: Indicate the options and configuration
variables valid for PAM and non-PAM versions.
* man/newusers.8.xml: Added pointer to /etc/pam.d/chpasswd.
2009-05-09 Nicolas François <nicolas.francois@centraliens.net> 2009-05-09 Nicolas François <nicolas.francois@centraliens.net>
* src/userdel.c: Remove duplicate definitions of exit codes. * src/userdel.c: Remove duplicate definitions of exit codes.
@ -52,7 +62,7 @@
* src/chpasswd.c: Added the line number when an error is reported * src/chpasswd.c: Added the line number when an error is reported
instead of only the username. instead of only the username.
* src/chpasswd.c: PAM enabled chpasswd do may change the password * src/chpasswd.c: PAM enabled chpasswd may change the password
database (for the user where the password update succeeded) even database (for the user where the password update succeeded) even
if there were a failure for one user. Do not indicate that changes if there were a failure for one user. Do not indicate that changes
were ignored. were ignored.
@ -127,7 +137,7 @@
* NEWS, src/chpasswd.c: Added support for changing the passwords * NEWS, src/chpasswd.c: Added support for changing the passwords
with PAM. with PAM.
* src/chpasswd.c: Split the usage string in smaller parts to * src/chpasswd.c: Split the usage string in smaller parts to
allows enabling single parts. allow enabling single parts.
* src/chpasswd.c: Do not set a global lock on the password files. * src/chpasswd.c: Do not set a global lock on the password files.
This is done by PAM each time a password is updated. This is done by PAM each time a password is updated.

8
NEWS
View File

@ -12,8 +12,8 @@ shadow-4.1.3.1 -> shadow-4.1.3.2 UNRELEASED
- chpasswd - chpasswd
* Change the passwords using PAM. This permits to define the password * Change the passwords using PAM. This permits to define the password
policy in a central place. The -c/--crypt-method, -e/--encrypted, policy in a central place. The -c/--crypt-method, -e/--encrypted,
-m/--md5, -s/--sha-rounds are no more supported on PAM enabled -m/--md5 and -s/--sha-rounds options are no more supported on PAM
systems. enabled systems.
- login - login
* Do not trust the current utmp entry's ut_line to set PAM_TTY. This could * Do not trust the current utmp entry's ut_line to set PAM_TTY. This could
lead to DOS attacks. lead to DOS attacks.
@ -21,6 +21,10 @@ shadow-4.1.3.1 -> shadow-4.1.3.2 UNRELEASED
user to update his authentication token if needed. user to update his authentication token if needed.
- lastlog - lastlog
* Fix regression causing empty reports. * Fix regression causing empty reports.
- newusers
* Change the passwords using PAM. This permits to define the password
policy in a central place. The -c/--crypt-method and -s/--sha-rounds
options are no more supported on PAM enabled systems.
*** translation *** translation
- Updated Korean translation - Updated Korean translation

View File

@ -60,6 +60,7 @@
<cmdsynopsis> <cmdsynopsis>
<command>newusers</command> <command>newusers</command>
<arg choice='opt'> <arg choice='opt'>
<replaceable>options</replaceable>
<replaceable>new_users</replaceable> <replaceable>new_users</replaceable>
</arg> </arg>
</cmdsynopsis> </cmdsynopsis>
@ -219,9 +220,10 @@
<refsect1 id='options'> <refsect1 id='options'>
<title>OPTIONS</title> <title>OPTIONS</title>
<para>The options which apply to the <command>newusers</command> command are: <para>
The options which apply to the <command>newusers</command> command are:
</para> </para>
<variablelist remap='IP'> <variablelist remap='IP' condition="no_pam">
<varlistentry> <varlistentry>
<term><option>-c</option>, <option>--crypt-method</option></term> <term><option>-c</option>, <option>--crypt-method</option></term>
<listitem> <listitem>
@ -232,6 +234,14 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist>
<variablelist remap='IP'>
<varlistentry>
<term><option>-h</option>, <option>--help</option></term>
<listitem>
<para>Display help message and exit.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<option>-r</option>, <option>--system</option> <option>-r</option>, <option>--system</option>
@ -251,6 +261,8 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist>
<variablelist remap='IP' condition="no_pam">
<varlistentry condition="sha_crypt"> <varlistentry condition="sha_crypt">
<term><option>-s</option>, <option>--sha-rounds</option></term> <term><option>-s</option>, <option>--sha-rounds</option></term>
<listitem> <listitem>
@ -300,15 +312,25 @@
<filename>/etc/login.defs</filename> change the behavior of this <filename>/etc/login.defs</filename> change the behavior of this
tool: tool:
</para> </para>
<variablelist> <variablelist condition="no_pam">
&ENCRYPT_METHOD; &ENCRYPT_METHOD;
</variablelist>
<variablelist>
&GID_MAX; <!-- documents also GID_MIN --> &GID_MAX; <!-- documents also GID_MIN -->
&MAX_MEMBERS_PER_GROUP; &MAX_MEMBERS_PER_GROUP;
</variablelist>
<variablelist condition="no_pam">
&MD5_CRYPT_ENAB; &MD5_CRYPT_ENAB;
</variablelist>
<variablelist>
&PASS_MAX_DAYS; &PASS_MAX_DAYS;
&PASS_MIN_DAYS; &PASS_MIN_DAYS;
&PASS_WARN_AGE; &PASS_WARN_AGE;
</variablelist>
<variablelist condition="no_pam">
&SHA_CRYPT_MIN_ROUNDS; <!-- documents also SHA_CRYPT_MAX_ROUNDS--> &SHA_CRYPT_MIN_ROUNDS; <!-- documents also SHA_CRYPT_MAX_ROUNDS-->
</variablelist>
<variablelist>
&SYS_GID_MAX; <!-- documents also SYS_GID_MIN --> &SYS_GID_MAX; <!-- documents also SYS_GID_MIN -->
&SYS_UID_MAX; <!-- documents also SYS_UID_MIN --> &SYS_UID_MAX; <!-- documents also SYS_UID_MIN -->
&UID_MAX; <!-- documents also UID_MIN --> &UID_MAX; <!-- documents also UID_MIN -->
@ -349,6 +371,12 @@
<para>Shadow password suite configuration.</para> <para>Shadow password suite configuration.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry condition="pam">
<term><filename>/etc/pam.d/newusers</filename></term>
<listitem>
<para>PAM configuration for <command>newusers</command>.</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View File

@ -88,7 +88,7 @@ login_SOURCES = \
login_nopam.c login_nopam.c
login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) login_LDADD = $(LDADD) $(LIBPAM) $(LIBAUDIT) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD)
newgrp_LDADD = $(LDADD) $(LIBAUDIT) $(LIBCRYPT) newgrp_LDADD = $(LDADD) $(LIBAUDIT) $(LIBCRYPT)
newusers_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBSELINUX) $(LIBCRYPT) newusers_LDADD = $(LDADD) $(LIBPAM) $(LIBSELINUX) $(LIBCRYPT)
nologin_LDADD = nologin_LDADD =
passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBCRACK) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM) passwd_LDADD = $(LDADD) $(LIBPAM) $(LIBCRACK) $(LIBAUDIT) $(LIBSELINUX) $(LIBCRYPT_NOPAM)
pwck_LDADD = $(LDADD) $(LIBSELINUX) pwck_LDADD = $(LDADD) $(LIBSELINUX)

View File

@ -72,16 +72,15 @@
*/ */
char *Prog; char *Prog;
static bool cflg = false;
static bool rflg = false; /* create a system account */ static bool rflg = false; /* create a system account */
#ifdef USE_SHA_CRYPT #ifndef USE_PAM
static bool sflg = false; static bool cflg = false;
#endif
static char *crypt_method = NULL; static char *crypt_method = NULL;
#ifdef USE_SHA_CRYPT #ifdef USE_SHA_CRYPT
static bool sflg = false;
static long sha_rounds = 5000; static long sha_rounds = 5000;
#endif #endif /* USE_SHA_CRYPT */
#endif /* !USE_PAM */
static bool is_shadow; static bool is_shadow;
#ifdef SHADOWGRP #ifdef SHADOWGRP
@ -98,7 +97,9 @@ static void fail_exit (int);
static int add_group (const char *, const char *, gid_t *, gid_t); static int add_group (const char *, const char *, gid_t *, gid_t);
static int get_user_id (const char *, uid_t *); static int get_user_id (const char *, uid_t *);
static int add_user (const char *, uid_t, gid_t); static int add_user (const char *, uid_t, gid_t);
#ifndef USE_PAM
static void update_passwd (struct passwd *, const char *); static void update_passwd (struct passwd *, const char *);
#endif /* !USE_PAM */
static int add_passwd (struct passwd *, const char *); static int add_passwd (struct passwd *, const char *);
static void process_flags (int argc, char **argv); static void process_flags (int argc, char **argv);
static void check_flags (void); static void check_flags (void);
@ -111,21 +112,32 @@ static void close_files (void);
*/ */
static void usage (void) static void usage (void)
{ {
fprintf (stderr, _("Usage: %s [options] [input]\n" (void) fprintf (stderr,
_("Usage: %s [options]\n"
"\n" "\n"
" -c, --crypt-method the crypt method (one of %s)\n" "Options:\n"),
" -r, --system create system accounts\n" Prog);
"%s" #ifndef USE_PAM
"\n"), (void) fprintf (stderr,
Prog, _(" -c, --crypt-method the crypt method (one of %s)\n"),
#ifndef USE_SHA_CRYPT #ifndef USE_SHA_CRYPT
"NONE DES MD5", "" "NONE DES MD5"
#else #else /* USE_SHA_CRYPT */
"NONE DES MD5 SHA256 SHA512", "NONE DES MD5 SHA256 SHA512"
_(" -s, --sha-rounds number of SHA rounds for the SHA*\n" #endif /* USE_SHA_CRYPT */
" crypt algorithms\n")
#endif
); );
#endif /* !USE_PAM */
(void) fputs (_(" -h, --help display this help message and exit\n"), stderr);
(void) fputs (_(" -r, --system create system accounts\n"), stderr);
#ifndef USE_PAM
#ifdef USE_SHA_CRYPT
(void) fputs (_(" -s, --sha-rounds number of SHA rounds for the SHA*\n"
" crypt algorithms\n"),
stderr);
#endif /* USE_SHA_CRYPT */
#endif /* !USE_PAM */
(void) fputs ("\n", stderr);
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
@ -243,7 +255,7 @@ static int add_group (const char *name, const char *gid, gid_t *ngid, uid_t uid)
grent.gr_name = xstrdup (gid); grent.gr_name = xstrdup (gid);
} else { } else {
grent.gr_name = xstrdup (name); grent.gr_name = xstrdup (name);
/* FIXME: check if the group exist */ /* FIXME: check if the group exists */
} }
/* Check if this is a valid group name */ /* Check if this is a valid group name */
@ -368,6 +380,7 @@ static int add_user (const char *name, uid_t uid, gid_t gid)
return (pw_update (&pwent) == 0); return (pw_update (&pwent) == 0);
} }
#ifndef USE_PAM
static void update_passwd (struct passwd *pwd, const char *password) static void update_passwd (struct passwd *pwd, const char *password)
{ {
void *crypt_arg = NULL; void *crypt_arg = NULL;
@ -387,6 +400,7 @@ static void update_passwd (struct passwd *pwd, const char *password)
crypt_arg)); crypt_arg));
} }
} }
#endif /* !USE_PAM */
/* /*
* add_passwd - add or update the encrypted password * add_passwd - add or update the encrypted password
@ -395,13 +409,15 @@ static int add_passwd (struct passwd *pwd, const char *password)
{ {
const struct spwd *sp; const struct spwd *sp;
struct spwd spent; struct spwd spent;
#ifndef USE_PAM
void *crypt_arg = NULL; void *crypt_arg = NULL;
if (crypt_method != NULL) { if (crypt_method != NULL) {
#ifdef USE_SHA_CRYPT #ifdef USE_SHA_CRYPT
if (sflg) { if (sflg) {
crypt_arg = &sha_rounds; crypt_arg = &sha_rounds;
} }
#endif #endif /* USE_SHA_CRYPT */
} }
/* /*
@ -413,12 +429,14 @@ static int add_passwd (struct passwd *pwd, const char *password)
update_passwd (pwd, password); update_passwd (pwd, password);
return 0; return 0;
} }
#endif /* USE_PAM */
/* /*
* Do the first and easiest shadow file case. The user already * Do the first and easiest shadow file case. The user already
* exists in the shadow password file. * exists in the shadow password file.
*/ */
sp = spw_locate (pwd->pw_name); sp = spw_locate (pwd->pw_name);
#ifndef USE_PAM
if (NULL != sp) { if (NULL != sp) {
spent = *sp; spent = *sp;
if ( (NULL != crypt_method) if ( (NULL != crypt_method)
@ -429,6 +447,12 @@ static int add_passwd (struct passwd *pwd, const char *password)
crypt_arg); crypt_arg);
spent.sp_pwdp = pw_encrypt (password, salt); spent.sp_pwdp = pw_encrypt (password, salt);
} }
spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
if (0 == spent.sp_lstchg) {
/* Better disable aging than requiring a password
* change */
spent.sp_lstchg = -1;
}
return (spw_update (&spent) == 0); return (spw_update (&spent) == 0);
} }
@ -442,18 +466,38 @@ static int add_passwd (struct passwd *pwd, const char *password)
update_passwd (pwd, password); update_passwd (pwd, password);
return 0; return 0;
} }
#else /* USE_PAM */
/*
* If there is already a shadow entry, do not touch it.
* If there is already a passwd entry with a password, do not
* touch it.
* The password will be updated later for all users using PAM.
*/
if ( (NULL != sp)
|| (strcmp (pwd->pw_passwd, "x") != 0)) {
return 0;
}
#endif /* USE_PAM */
/* /*
* Now the really hard case - I need to create an entirely new * Now the really hard case - I need to create an entirely new
* shadow password file entry. * shadow password file entry.
*/ */
spent.sp_namp = pwd->pw_name; spent.sp_namp = pwd->pw_name;
#ifndef USE_PAM
if ((crypt_method != NULL) && (0 == strcmp(crypt_method, "NONE"))) { if ((crypt_method != NULL) && (0 == strcmp(crypt_method, "NONE"))) {
spent.sp_pwdp = (char *)password; spent.sp_pwdp = (char *)password;
} else { } else {
const char *salt = crypt_make_salt (crypt_method, crypt_arg); const char *salt = crypt_make_salt (crypt_method, crypt_arg);
spent.sp_pwdp = pw_encrypt (password, salt); spent.sp_pwdp = pw_encrypt (password, salt);
} }
#else
/*
* Lock the password.
* The password will be updated later for all users using PAM.
*/
spent.sp_pwdp = "!";
#endif
spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE; spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
if (0 == spent.sp_lstchg) { if (0 == spent.sp_lstchg) {
/* Better disable aging than requiring a password change */ /* Better disable aging than requiring a password change */
@ -480,33 +524,40 @@ static void process_flags (int argc, char **argv)
int option_index = 0; int option_index = 0;
int c; int c;
static struct option long_options[] = { static struct option long_options[] = {
#ifndef USE_PAM
{"crypt-method", required_argument, NULL, 'c'}, {"crypt-method", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'},
#ifdef USE_SHA_CRYPT #ifdef USE_SHA_CRYPT
{"sha-rounds", required_argument, NULL, 's'}, {"sha-rounds", required_argument, NULL, 's'},
#endif #endif /* USE_SHA_CRYPT */
#endif /* !USE_PAM */
{"help", no_argument, NULL, 'h'},
{"system", no_argument, NULL, 'r'}, {"system", no_argument, NULL, 'r'},
{NULL, 0, NULL, '\0'} {NULL, 0, NULL, '\0'}
}; };
while ((c = getopt_long (argc, argv, while ((c = getopt_long (argc, argv,
#ifndef USE_PAM
#ifdef USE_SHA_CRYPT #ifdef USE_SHA_CRYPT
"c:hrs:", "c:hrs:",
#else #else /* !USE_SHA_CRYPT */
"c:hr", "c:hr",
#endif /* !USE_SHA_CRYPT */
#else /* USE_PAM */
"hr",
#endif #endif
long_options, &option_index)) != -1) { long_options, &option_index)) != -1) {
switch (c) { switch (c) {
case 'c':
cflg = true;
crypt_method = optarg;
break;
case 'h': case 'h':
usage (); usage ();
break; break;
case 'r': case 'r':
rflg = true; rflg = true;
break; break;
#ifndef USE_PAM
case 'c':
cflg = true;
crypt_method = optarg;
break;
#ifdef USE_SHA_CRYPT #ifdef USE_SHA_CRYPT
case 's': case 's':
sflg = true; sflg = true;
@ -517,7 +568,8 @@ static void process_flags (int argc, char **argv)
usage (); usage ();
} }
break; break;
#endif #endif /* USE_SHA_CRYPT */
#endif /* !USE_PAM */
default: default:
usage (); usage ();
break; break;
@ -544,6 +596,7 @@ static void process_flags (int argc, char **argv)
*/ */
static void check_flags (void) static void check_flags (void)
{ {
#ifndef USE_PAM
#ifdef USE_SHA_CRYPT #ifdef USE_SHA_CRYPT
if (sflg && !cflg) { if (sflg && !cflg) {
fprintf (stderr, fprintf (stderr,
@ -551,7 +604,7 @@ static void check_flags (void)
Prog, "-s", "-c"); Prog, "-s", "-c");
usage (); usage ();
} }
#endif #endif /* USE_SHA_CRYPT */
if (cflg) { if (cflg) {
if ( (0 != strcmp (crypt_method, "DES")) if ( (0 != strcmp (crypt_method, "DES"))
@ -560,7 +613,7 @@ static void check_flags (void)
#ifdef USE_SHA_CRYPT #ifdef USE_SHA_CRYPT
&& (0 != strcmp (crypt_method, "SHA256")) && (0 != strcmp (crypt_method, "SHA256"))
&& (0 != strcmp (crypt_method, "SHA512")) && (0 != strcmp (crypt_method, "SHA512"))
#endif #endif /* USE_SHA_CRYPT */
) { ) {
fprintf (stderr, fprintf (stderr,
_("%s: unsupported crypt method: %s\n"), _("%s: unsupported crypt method: %s\n"),
@ -568,6 +621,7 @@ static void check_flags (void)
usage (); usage ();
} }
} }
#endif /* !USE_PAM */
} }
/* /*
@ -767,6 +821,12 @@ int main (int argc, char **argv)
int line = 0; int line = 0;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
#ifdef USE_PAM
int *lines = NULL;
char **usernames = NULL;
char **passwords = NULL;
unsigned int nusers = 0;
#endif /* USE_PAM */
Prog = Basename (argv[0]); Prog = Basename (argv[0]);
@ -831,7 +891,7 @@ int main (int argc, char **argv)
} }
/* /*
* First check if we have to create of update an user * First check if we have to create or update an user
*/ */
pw = pw_locate (fields[0]); pw = pw_locate (fields[0]);
/* local, no need for xgetpwnam */ /* local, no need for xgetpwnam */
@ -902,6 +962,16 @@ int main (int argc, char **argv)
} }
newpw = *pw; newpw = *pw;
#if USE_PAM
/* keep the list of user/password for later update by PAM */
nusers++;
lines = realloc (lines, sizeof (lines[0]) * nusers);
usernames = realloc (usernames, sizeof (usernames[0]) * nusers);
passwords = realloc (passwords, sizeof (passwords[0]) * nusers);
lines[nusers-1] = line;
usernames[nusers-1] = strdup (fields[0]);
passwords[nusers-1] = strdup (fields[1]);
#endif
if (add_passwd (&newpw, fields[1])) { if (add_passwd (&newpw, fields[1])) {
fprintf (stderr, fprintf (stderr,
_("%s: line %d: can't update password\n"), _("%s: line %d: can't update password\n"),
@ -971,6 +1041,19 @@ int main (int argc, char **argv)
nscd_flush_cache ("passwd"); nscd_flush_cache ("passwd");
nscd_flush_cache ("group"); nscd_flush_cache ("group");
return EXIT_SUCCESS; #ifdef USE_PAM
unsigned int i;
/* Now update the passwords using PAM */
for (i = 0; i < nusers; i++) {
if (do_pam_passwd_non_interractive ("newusers", usernames[i], passwords[i]) != 0) {
fprintf (stderr,
_("%s: (line %d, user %s) password not changed\n"),
Prog, lines[i], usernames[i]);
errors++;
}
}
#endif /* USE_PAM */
return ((0 == errors) ? EXIT_SUCCESS : EXIT_FAILURE);
} }