* NEWS, src/gpasswd.c: Only report success to audit and syslog

when the changes are committed to the system. Do not log failure
	for on-memory changes to audit or syslog. Make sure failures and
	inconsistencies will be reported in case of unexpected failures
	(e.g. malloc failures). Only specify an audit message if it is not
	implicitly implied by the type argument. Removed fail_exit
	(replaced by atexit(do_cleanups)). Log failures in case of
	permission denied.
This commit is contained in:
nekral-guest 2009-01-26 22:03:37 +00:00
parent 7b532f0b44
commit f2d6449374
3 changed files with 416 additions and 302 deletions

View File

@ -1,3 +1,14 @@
2009-01-26 Nicolas François <nicolas.francois@centraliens.net>
* NEWS, src/gpasswd.c: Only report success to audit and syslog
when the changes are committed to the system. Do not log failure
for on-memory changes to audit or syslog. Make sure failures and
inconsistencies will be reported in case of unexpected failures
(e.g. malloc failures). Only specify an audit message if it is not
implicitly implied by the type argument. Removed fail_exit
(replaced by atexit(do_cleanups)). Log failures in case of
permission denied.
2009-01-19 Nicolas François <nicolas.francois@centraliens.net> 2009-01-19 Nicolas François <nicolas.francois@centraliens.net>
* man/login.defs.d/UMASK.xml: Indicate how UMASK is used and * man/login.defs.d/UMASK.xml: Indicate how UMASK is used and

3
NEWS
View File

@ -40,6 +40,9 @@ shadow-4.1.2.2 -> shadow-4.1.3 UNRELEASED
--remove-password (-r), --restrict (-R), --administrators (-A), and --remove-password (-r), --restrict (-R), --administrators (-A), and
--members (-M). --members (-M).
* Added support for usernames with arbitrary length. * Added support for usernames with arbitrary length.
* audit logging improvements.
* error handling improvement (see above).
* Log permission denied to syslog and audit.
- groupadd - groupadd
* audit logging improvements. * audit logging improvements.
* error handling improvement (see above). * error handling improvement (see above).

View File

@ -2,7 +2,7 @@
* Copyright (c) 1990 - 1994, Julianne Frances Haugh * Copyright (c) 1990 - 1994, Julianne Frances Haugh
* Copyright (c) 1996 - 2000, Marek Michałkiewicz * Copyright (c) 1996 - 2000, Marek Michałkiewicz
* Copyright (c) 2001 - 2006, Tomasz Kłoczko * Copyright (c) 2001 - 2006, Tomasz Kłoczko
* Copyright (c) 2007 - 2008, Nicolas François * Copyright (c) 2007 - 2009, Nicolas François
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -60,9 +60,7 @@ char *Prog;
/* Indicate if shadow groups are enabled on the system /* Indicate if shadow groups are enabled on the system
* (/etc/gshadow present) */ * (/etc/gshadow present) */
static bool is_shadowgrp; static bool is_shadowgrp;
static bool sgr_locked = false;
#endif #endif
static bool gr_locked = false;
/* Flags set by options */ /* Flags set by options */
static bool aflg = false; static bool aflg = false;
@ -96,7 +94,6 @@ static uid_t bywho;
/* local function prototypes */ /* local function prototypes */
static void usage (void); static void usage (void);
static RETSIGTYPE catch_signals (int killed); static RETSIGTYPE catch_signals (int killed);
static void fail_exit (int status);
static bool is_valid_user_list (const char *users); static bool is_valid_user_list (const char *users);
static void process_flags (int argc, char **argv); static void process_flags (int argc, char **argv);
static void check_flags (int argc, int opt_index); static void check_flags (int argc, int opt_index);
@ -113,6 +110,18 @@ static void check_perms (const struct group *gr);
static void update_group (struct group *gr); static void update_group (struct group *gr);
static void change_passwd (struct group *gr); static void change_passwd (struct group *gr);
#endif #endif
static void log_gpasswd_failure (const char *suffix);
static void log_gpasswd_failure_system (void *unused(arg));
static void log_gpasswd_failure_group (void *unused(arg));
#ifdef SHADOWGRP
static void log_gpasswd_failure_gshadow (void *unused(arg));
#endif
static void log_gpasswd_success (const char *suffix);
static void log_gpasswd_success_system (void *unused(arg));
static void log_gpasswd_success_group (void *unused(arg));
#ifdef SHADOWGRP
static void log_gpasswd_success_gshadow (void *unused(arg));
#endif
/* /*
* usage - display usage message * usage - display usage message
@ -135,7 +144,6 @@ static void usage (void)
_(" -A, --administrators ADMIN,...\n" _(" -A, --administrators ADMIN,...\n"
" set the list of administrators for GROUP\n" " set the list of administrators for GROUP\n"
"Except for the -A and -M options, the options cannot be combined.\n") "Except for the -A and -M options, the options cannot be combined.\n")
#else #else
_("The options cannot be combined.\n") _("The options cannot be combined.\n")
#endif #endif
@ -164,43 +172,10 @@ static RETSIGTYPE catch_signals (int killed)
if (0 != killed) { if (0 != killed) {
(void) putchar ('\n'); (void) putchar ('\n');
(void) fflush (stdout); (void) fflush (stdout);
fail_exit (killed); exit (killed);
} }
} }
/*
* fail_exit - undo as much as possible
*/
static void fail_exit (int status)
{
if (gr_locked) {
if (gr_unlock () == 0) {
fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ());
SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"unlocking group file",
group, AUDIT_NO_ID, 0);
#endif
}
}
#ifdef SHADOWGRP
if (sgr_locked) {
if (sgr_unlock () == 0) {
fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ());
SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"unlocking gshadow file",
group, AUDIT_NO_ID, 0);
#endif
}
}
#endif
exit (status);
}
/* /*
* is_valid_user_list - check a comma-separated list of user names for validity * is_valid_user_list - check a comma-separated list of user names for validity
* *
@ -244,7 +219,8 @@ static bool is_valid_user_list (const char *users)
static void failure (void) static void failure (void)
{ {
fprintf (stderr, _("%s: Permission denied.\n"), Prog); fprintf (stderr, _("%s: Permission denied.\n"), Prog);
fail_exit (1); log_gpasswd_failure (": Permission denied");
exit (1);
} }
/* /*
@ -267,62 +243,41 @@ static void process_flags (int argc, char **argv)
while ((flag = getopt_long (argc, argv, "a:A:d:gM:rR", long_options, &option_index)) != -1) { while ((flag = getopt_long (argc, argv, "a:A:d:gM:rR", long_options, &option_index)) != -1) {
switch (flag) { switch (flag) {
case 'a': /* add a user */ case 'a': /* add a user */
aflg = true;
user = optarg; user = optarg;
/* local, no need for xgetpwnam */ /* local, no need for xgetpwnam */
if (getpwnam (user) == NULL) { if (getpwnam (user) == NULL) {
fprintf (stderr, fprintf (stderr,
_("%s: user '%s' does not exist\n"), Prog, _("%s: user '%s' does not exist\n"), Prog,
user); user);
#ifdef WITH_AUDIT exit (1);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"adding to group",
user, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
aflg = true;
break; break;
#ifdef SHADOWGRP #ifdef SHADOWGRP
case 'A': case 'A': /* set the list of administrators */
if (!amroot) {
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"Listing administrators",
NULL, (unsigned int) bywho, 0);
#endif
failure ();
}
if (!is_shadowgrp) { if (!is_shadowgrp) {
fprintf (stderr, fprintf (stderr,
_("%s: shadow group passwords required for -A\n"), _("%s: shadow group passwords required for -A\n"),
Prog); Prog);
fail_exit (2); exit (2);
} }
admins = optarg; admins = optarg;
if (!is_valid_user_list (admins)) { if (!is_valid_user_list (admins)) {
fail_exit (1); exit (1);
} }
Aflg = true; Aflg = true;
break; break;
#endif #endif /* SHADOWGRP */
case 'd': /* delete a user */ case 'd': /* delete a user */
dflg = true; dflg = true;
user = optarg; user = optarg;
break; break;
case 'g': /* no-op from normal password */ case 'g': /* no-op from normal password */
break; break;
case 'M': case 'M': /* set the list of members */
if (!amroot) {
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"listing members",
NULL, (unsigned int) bywho, 0);
#endif
failure ();
}
members = optarg; members = optarg;
if (!is_valid_user_list (members)) { if (!is_valid_user_list (members)) {
fail_exit (1); exit (1);
} }
Mflg = true; Mflg = true;
break; break;
@ -390,54 +345,317 @@ static void open_files (void)
fprintf (stderr, fprintf (stderr,
_("%s: cannot lock %s; try again later.\n"), _("%s: cannot lock %s; try again later.\n"),
Prog, gr_dbname ()); Prog, gr_dbname ());
#ifdef WITH_AUDIT exit (1);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"locking /etc/group",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
gr_locked = true; add_cleanup (cleanup_unlock_group, NULL);
#ifdef SHADOWGRP #ifdef SHADOWGRP
if (is_shadowgrp) { if (is_shadowgrp) {
if (sgr_lock () == 0) { if (sgr_lock () == 0) {
fprintf (stderr, fprintf (stderr,
_("%s: cannot lock %s; try again later.\n"), _("%s: cannot lock %s; try again later.\n"),
Prog, sgr_dbname ()); Prog, sgr_dbname ());
#ifdef WITH_AUDIT exit (1);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"locking /etc/gshadow",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
sgr_locked = true; add_cleanup (cleanup_unlock_gshadow, NULL);
} }
#endif #endif /* SHADOWGRP */
add_cleanup (log_gpasswd_failure_system, NULL);
if (gr_open (O_RDWR) == 0) { if (gr_open (O_RDWR) == 0) {
fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); fprintf (stderr,
_("%s: cannot open %s\n"),
Prog, gr_dbname ());
SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ())); SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
#ifdef WITH_AUDIT exit (1);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"opening /etc/group",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
#ifdef SHADOWGRP #ifdef SHADOWGRP
if (is_shadowgrp && (sgr_open (O_RDWR) == 0)) { if (is_shadowgrp) {
fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ()); if (sgr_open (O_RDWR) == 0) {
SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ())); fprintf (stderr,
#ifdef WITH_AUDIT _("%s: cannot open %s\n"),
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, Prog, sgr_dbname ());
"opening /etc/gshadow", SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
group, AUDIT_NO_ID, 0); exit (1);
#endif }
fail_exit (1); add_cleanup (log_gpasswd_failure_gshadow, NULL);
} }
#endif #endif /* SHADOWGRP */
add_cleanup (log_gpasswd_failure_group, NULL);
del_cleanup (log_gpasswd_failure_system);
} }
static void log_gpasswd_failure (const char *suffix)
{
#ifdef WITH_AUDIT
char buf[1024];
#endif
if (aflg) {
SYSLOG ((LOG_ERR,
"%s failed to add user %s to group %s%s",
myname, user, group, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"%s failed to add user %s to group %s%s",
myname, user, group, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_ACCT, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_FAILURE);
#endif
} else if (dflg) {
SYSLOG ((LOG_ERR,
"%s failed to remove user %s from group %s%s",
myname, user, group, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"%s failed to remove user %s from group %s%s",
myname, user, group, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_ACCT, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_FAILURE);
#endif
} else if (rflg) {
SYSLOG ((LOG_ERR,
"%s failed to remove password of group %s%s",
myname, group, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"%s failed to remove password of group %s%s",
myname, group, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_FAILURE);
#endif
} else if (Rflg) {
SYSLOG ((LOG_ERR,
"%s failed to restrict access to group %s%s",
myname, group, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"%s failed to restrict access to group %s%s",
myname, group, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_FAILURE);
#endif
} else if (Aflg || Mflg) {
#ifdef SHADOWGRP
if (Aflg) {
SYSLOG ((LOG_ERR,
"%s failed to set the administrators of group %s to %s%s",
myname, group, admins, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"%s failed to set the administrators of group %s to %s%s",
myname, group, admins, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_ACCT, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_FAILURE);
#endif
}
#endif /* SHADOWGRP */
if (Mflg) {
SYSLOG ((LOG_ERR,
"%s failed to set the members of group %s to %s%s",
myname, group, members, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"%s failed to set the members of group %s to %s%s",
myname, group, members, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_ACCT, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_FAILURE);
#endif
}
} else {
SYSLOG ((LOG_ERR,
"%s failed to change password of group %s%s",
myname, group, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"%s failed to change password of group %s%s",
myname, group, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_FAILURE);
#endif
}
}
static void log_gpasswd_failure_system (void *unused(arg))
{
log_gpasswd_failure ("");
}
static void log_gpasswd_failure_group (void *unused(arg))
{
char buf[1024];
snprintf (buf, 1023, " in %s", gr_dbname ());
buf[1023] = '\0';
log_gpasswd_failure (buf);
}
#ifdef SHADOWGRP
static void log_gpasswd_failure_gshadow (void *unused(arg))
{
char buf[1024];
snprintf (buf, 1023, " in %s", sgr_dbname ());
buf[1023] = '\0';
log_gpasswd_failure (buf);
}
#endif /* SHADOWGRP */
static void log_gpasswd_success (const char *suffix)
{
#ifdef WITH_AUDIT
char buf[1024];
#endif
if (aflg) {
SYSLOG ((LOG_INFO,
"user %s added by %s to group %s%s",
user, myname, group, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"user %s added by %s to group %s%s",
user, myname, group, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_ACCT, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_SUCCESS);
#endif
} else if (dflg) {
SYSLOG ((LOG_INFO,
"user %s removed by %s from group %s%s",
user, myname, group, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"user %s removed by %s from group %s%s",
user, myname, group, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_ACCT, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_SUCCESS);
#endif
} else if (rflg) {
SYSLOG ((LOG_INFO,
"password of group %s removed by %s%s",
group, myname, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"password of group %s removed by %s%s",
group, myname, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_SUCCESS);
#endif
} else if (Rflg) {
SYSLOG ((LOG_INFO,
"access to group %s restricted by %s%s",
group, myname, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"access to group %s restricted by %s%s",
group, myname, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_SUCCESS);
#endif
} else if (Aflg || Mflg) {
#ifdef SHADOWGRP
if (Aflg) {
SYSLOG ((LOG_INFO,
"administrators of group %s set by %s to %s%s",
group, myname, admins, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"administrators of group %s set by %s to %s%s",
group, myname, admins, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_ACCT, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_SUCCESS);
#endif
}
#endif /* SHADOWGRP */
if (Mflg) {
SYSLOG ((LOG_INFO,
"members of group %s set by %s to %s%s",
group, myname, members, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"members of group %s set by %s to %s%s",
group, myname, members, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_ACCT, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_SUCCESS);
#endif
}
} else {
SYSLOG ((LOG_INFO,
"password of group %s changed by %s%s",
group, myname, suffix));
#ifdef WITH_AUDIT
snprintf (buf, 1023,
"password of group %s changed by %s%s",
group, myname, suffix);
buf[1023] = '\0';
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
buf,
group, AUDIT_NO_ID,
SHADOW_AUDIT_SUCCESS);
#endif
}
}
static void log_gpasswd_success_system (void *unused(arg))
{
log_gpasswd_success ("");
}
static void log_gpasswd_success_group (void *unused(arg))
{
char buf[1024];
snprintf (buf, 1023, " in %s", gr_dbname ());
buf[1023] = '\0';
log_gpasswd_success (buf);
}
#ifdef SHADOWGRP
static void log_gpasswd_success_gshadow (void *unused(arg))
{
char buf[1024];
snprintf (buf, 1023, " in %s", sgr_dbname ());
buf[1023] = '\0';
log_gpasswd_success (buf);
}
#endif /* SHADOWGRP */
/* /*
* close_files - close and unlock the group databases * close_files - close and unlock the group databases
* *
@ -448,51 +666,36 @@ static void open_files (void)
static void close_files (void) static void close_files (void)
{ {
if (gr_close () == 0) { if (gr_close () == 0) {
fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); fprintf (stderr,
SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); _("%s: failure while writing changes to %s\n"),
#ifdef WITH_AUDIT Prog, gr_dbname ());
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, exit (1);
"rewriting /etc/group",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
add_cleanup (log_gpasswd_success_group, NULL);
del_cleanup (log_gpasswd_failure_group);
cleanup_unlock_group (NULL);
del_cleanup (cleanup_unlock_group);
#ifdef SHADOWGRP #ifdef SHADOWGRP
if (is_shadowgrp) { if (is_shadowgrp) {
if (sgr_close () == 0) { if (sgr_close () == 0) {
fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sgr_dbname ()); fprintf (stderr,
SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ())); _("%s: failure while writing changes to %s\n"),
#ifdef WITH_AUDIT Prog, sgr_dbname ());
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, exit (1);
"rewriting /etc/gshadow",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
if (sgr_unlock () == 0) { add_cleanup (log_gpasswd_success_gshadow, NULL);
fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); del_cleanup (log_gpasswd_failure_gshadow);
SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ()));
#ifdef WITH_AUDIT cleanup_unlock_gshadow (NULL);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, del_cleanup (cleanup_unlock_gshadow);
"unlocking gshadow file",
group, AUDIT_NO_ID, 0);
#endif
/* continue */
}
sgr_locked = false;
} }
#endif #endif /* SHADOWGRP */
if (gr_unlock () == 0) {
fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); log_gpasswd_success_system (NULL);
SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); del_cleanup (log_gpasswd_success_group);
#ifdef WITH_AUDIT del_cleanup (log_gpasswd_success_gshadow);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"unlocking group file",
group, AUDIT_NO_ID, 0);
#endif
/* continue */
}
gr_locked = false;
} }
/* /*
@ -507,6 +710,13 @@ static void check_perms (const struct group *gr, const struct sgrp *sg)
static void check_perms (const struct group *gr) static void check_perms (const struct group *gr)
#endif #endif
{ {
/*
* Only root can use the -M and -A options.
*/
if (!amroot && (Aflg || Mflg)) {
failure ();
}
#ifdef SHADOWGRP #ifdef SHADOWGRP
if (is_shadowgrp) { if (is_shadowgrp) {
/* /*
@ -517,15 +727,10 @@ static void check_perms (const struct group *gr)
* the root user can. * the root user can.
*/ */
if (!amroot && !is_on_list (sg->sg_adm, myname)) { if (!amroot && !is_on_list (sg->sg_adm, myname)) {
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"modify group",
group, AUDIT_NO_ID, 0);
#endif
failure (); failure ();
} }
} else } else
#endif /* ! SHADOWGRP */ #endif /* SHADOWGRP */
{ {
#ifdef FIRST_MEMBER_IS_ADMIN #ifdef FIRST_MEMBER_IS_ADMIN
/* /*
@ -544,30 +749,15 @@ static void check_perms (const struct group *gr)
*/ */
if (!amroot) { if (!amroot) {
if (gr->gr_mem[0] == (char *) 0) { if (gr->gr_mem[0] == (char *) 0) {
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"modifying group",
group, AUDIT_NO_ID, 0);
#endif
failure (); failure ();
} }
if (strcmp (gr->gr_mem[0], myname) != 0) { if (strcmp (gr->gr_mem[0], myname) != 0) {
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"modifying group",
myname, AUDIT_NO_ID, 0);
#endif
failure (); failure ();
} }
} }
#else /* ! FIRST_MEMBER_IS_ADMIN */ #else /* ! FIRST_MEMBER_IS_ADMIN */
if (!amroot) { if (!amroot) {
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"modifying group",
group, AUDIT_NO_ID, 0);
#endif
failure (); failure ();
} }
#endif #endif
@ -587,28 +777,16 @@ static void update_group (struct group *gr)
fprintf (stderr, fprintf (stderr,
_("%s: failed to prepare the new %s entry '%s'\n"), _("%s: failed to prepare the new %s entry '%s'\n"),
Prog, gr_dbname (), gr->gr_name); Prog, gr_dbname (), gr->gr_name);
SYSLOG ((LOG_WARN, "failed to prepare the new %s entry '%s'", gr_dbname (), gr->gr_name)); exit (1);
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"updating /etc/group",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
#ifdef SHADOWGRP #ifdef SHADOWGRP
if (is_shadowgrp && (sgr_update (sg) == 0)) { if (is_shadowgrp && (sgr_update (sg) == 0)) {
fprintf (stderr, fprintf (stderr,
_("%s: failed to prepare the new %s entry '%s'\n"), _("%s: failed to prepare the new %s entry '%s'\n"),
Prog, sgr_dbname (), sg->sg_name); Prog, sgr_dbname (), sg->sg_name);
SYSLOG ((LOG_WARN, "failed to prepare the new %s entry '%s'", sgr_dbname (), sg->sg_name)); exit (1);
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"updating /etc/gshadow",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
#endif #endif /* SHADOWGRP */
} }
/* /*
@ -633,23 +811,15 @@ static void get_group (struct group *gr)
if (gr_open (O_RDONLY) == 0) { if (gr_open (O_RDONLY) == 0) {
fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ())); SYSLOG ((LOG_WARN, "cannot open %s", gr_dbname ()));
#ifdef WITH_AUDIT exit (1);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"opening /etc/group",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
tmpgr = gr_locate (group); tmpgr = gr_locate (group);
if (NULL == tmpgr) { if (NULL == tmpgr) {
fprintf (stderr, _("%s: group '%s' does not exist in %s\n"), Prog, group, gr_dbname ()); fprintf (stderr,
#ifdef WITH_AUDIT _("%s: group '%s' does not exist in %s\n"),
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, Prog, group, gr_dbname ());
"group lookup", exit (1);
group, AUDIT_NO_ID, 0);
#endif
failure ();
} }
*gr = *tmpgr; *gr = *tmpgr;
@ -658,28 +828,23 @@ static void get_group (struct group *gr)
gr->gr_mem = dup_list (tmpgr->gr_mem); gr->gr_mem = dup_list (tmpgr->gr_mem);
if (gr_close () == 0) { if (gr_close () == 0) {
fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); fprintf (stderr,
SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ())); _("%s: failure while closing read-only %s\n"),
#ifdef WITH_AUDIT Prog, gr_dbname ());
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, SYSLOG ((LOG_ERR,
"closing /etc/group", "failure while closing read-only %s",
group, AUDIT_NO_ID, 0); gr_dbname ()));
#endif exit (1);
fail_exit (1);
} }
#ifdef SHADOWGRP #ifdef SHADOWGRP
if (is_shadowgrp) { if (is_shadowgrp) {
if (sgr_open (O_RDONLY) == 0) { if (sgr_open (O_RDONLY) == 0) {
fprintf (stderr, fprintf (stderr,
_("%s: cannot open %s\n"), Prog, sgr_dbname ()); _("%s: cannot open %s\n"),
Prog, sgr_dbname ());
SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ())); SYSLOG ((LOG_WARN, "cannot open %s", sgr_dbname ()));
#ifdef WITH_AUDIT exit (1);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"opening /etc/gshadow",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
tmpsg = sgr_locate (group); tmpsg = sgr_locate (group);
if (NULL != tmpsg) { if (NULL != tmpsg) {
@ -710,14 +875,12 @@ static void get_group (struct group *gr)
} }
if (sgr_close () == 0) { if (sgr_close () == 0) {
fprintf (stderr, fprintf (stderr,
_("%s: failure while writing changes to %s\n"), Prog, sgr_dbname ()); _("%s: failure while closing read-only %s\n"),
SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ())); Prog, sgr_dbname ());
#ifdef WITH_AUDIT SYSLOG ((LOG_ERR,
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "failure while closing read-only %s",
"closing /etc/gshadow", sgr_dbname ()));
group, AUDIT_NO_ID, 0); exit (1);
#endif
fail_exit (1);
} }
} }
#endif /* SHADOWGRP */ #endif /* SHADOWGRP */
@ -752,14 +915,14 @@ static void change_passwd (struct group *gr)
for (retries = 0; retries < RETRIES; retries++) { for (retries = 0; retries < RETRIES; retries++) {
cp = getpass (_("New Password: ")); cp = getpass (_("New Password: "));
if (NULL == cp) { if (NULL == cp) {
fail_exit (1); exit (1);
} }
STRFCPY (pass, cp); STRFCPY (pass, cp);
strzero (cp); strzero (cp);
cp = getpass (_("Re-enter new password: ")); cp = getpass (_("Re-enter new password: "));
if (NULL == cp) { if (NULL == cp) {
fail_exit (1); exit (1);
} }
if (strcmp (pass, cp) == 0) { if (strcmp (pass, cp) == 0) {
@ -772,17 +935,12 @@ static void change_passwd (struct group *gr)
if (retries + 1 < RETRIES) { if (retries + 1 < RETRIES) {
puts (_("They don't match; try again")); puts (_("They don't match; try again"));
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"changing password",
group, AUDIT_NO_ID, 0);
#endif
} }
} }
if (retries == RETRIES) { if (retries == RETRIES) {
fprintf (stderr, _("%s: Try again later\n"), Prog); fprintf (stderr, _("%s: Try again later\n"), Prog);
fail_exit (1); exit (1);
} }
cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL)); cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL));
@ -795,13 +953,6 @@ static void change_passwd (struct group *gr)
{ {
gr->gr_passwd = cp; gr->gr_passwd = cp;
} }
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"changing password",
group, AUDIT_NO_ID, 1);
#endif
SYSLOG ((LOG_INFO, "change the password for group %s by %s", group,
myname));
} }
/* /*
@ -835,7 +986,7 @@ int main (int argc, char **argv)
* Make a note of whether or not this command was invoked by root. * Make a note of whether or not this command was invoked by root.
* This will be used to bypass certain checks later on. Also, set * This will be used to bypass certain checks later on. Also, set
* the real user ID to match the effective user ID. This will * the real user ID to match the effective user ID. This will
* prevent the invoker from issuing signals which would interfer * prevent the invoker from issuing signals which would interfere
* with this command. * with this command.
*/ */
bywho = getuid (); bywho = getuid ();
@ -849,31 +1000,35 @@ int main (int argc, char **argv)
is_shadowgrp = sgr_file_present (); is_shadowgrp = sgr_file_present ();
#endif #endif
/* Parse the options */
process_flags (argc, argv);
/* /*
* Determine the name of the user that invoked this command. This * Determine the name of the user that invoked this command. This
* is really hit or miss because there are so many ways that command * is really hit or miss because there are so many ways that command
* can be executed and so many ways to trip up the routines that * can be executed and so many ways to trip up the routines that
* report the user name. * report the user name.
*/ */
pw = get_my_pwent (); pw = get_my_pwent ();
if (NULL == pw) { if (NULL == pw) {
fprintf (stderr, _("%s: Cannot determine your user name.\n"), fprintf (stderr, _("%s: Cannot determine your user name.\n"),
Prog); Prog);
#ifdef WITH_AUDIT SYSLOG ((LOG_WARN,
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "Cannot determine the user name of the caller (UID %lu)",
"user lookup",
NULL, (unsigned int) bywho, 0);
#endif
SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
(unsigned long) getuid ())); (unsigned long) getuid ()));
failure (); exit (1);
} }
myname = xstrdup (pw->pw_name); myname = xstrdup (pw->pw_name);
/*
* Register an exit function to warn for any inconsistency that we
* could create.
*/
if (atexit (do_cleanups) != 0) {
fprintf(stderr, "%s: cannot set exit function\n", Prog);
exit(EXIT_FAILURE);
}
/* Parse the options */
process_flags (argc, argv);
/* /*
* Replicate the group so it can be modified later on. * Replicate the group so it can be modified later on.
*/ */
@ -901,13 +1056,6 @@ int main (int argc, char **argv)
#ifdef SHADOWGRP #ifdef SHADOWGRP
sgent.sg_passwd = ""; /* XXX warning: const */ sgent.sg_passwd = ""; /* XXX warning: const */
#endif #endif
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"deleting group password",
group, AUDIT_NO_ID, 1);
#endif
SYSLOG ((LOG_INFO, "remove password from group %s by %s",
group, myname));
goto output; goto output;
} else if (Rflg) { } else if (Rflg) {
/* /*
@ -918,13 +1066,6 @@ int main (int argc, char **argv)
#ifdef SHADOWGRP #ifdef SHADOWGRP
sgent.sg_passwd = "!"; /* XXX warning: const */ sgent.sg_passwd = "!"; /* XXX warning: const */
#endif #endif
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"restrict access to group",
group, AUDIT_NO_ID, 1);
#endif
SYSLOG ((LOG_INFO, "restrict access to group %s by %s",
group, myname));
goto output; goto output;
} }
@ -940,13 +1081,6 @@ int main (int argc, char **argv)
sgent.sg_mem = add_list (sgent.sg_mem, user); sgent.sg_mem = add_list (sgent.sg_mem, user);
} }
#endif #endif
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"adding group member",
user, AUDIT_NO_ID, 1);
#endif
SYSLOG ((LOG_INFO, "add member %s to group %s by %s", user,
group, myname));
goto output; goto output;
} }
@ -972,22 +1106,11 @@ int main (int argc, char **argv)
} }
#endif #endif
if (!removed) { if (!removed) {
fprintf (stderr, _("%s: user '%s' is not a member of '%s'\n"), fprintf (stderr,
_("%s: user '%s' is not a member of '%s'\n"),
Prog, user, group); Prog, user, group);
#ifdef WITH_AUDIT exit (1);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"deleting member",
user, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"deleting member",
user, AUDIT_NO_ID, 1);
#endif
SYSLOG ((LOG_INFO, "remove member %s from group %s by %s",
user, group, myname));
goto output; goto output;
} }
#ifdef SHADOWGRP #ifdef SHADOWGRP
@ -997,19 +1120,12 @@ int main (int argc, char **argv)
* in place. * in place.
*/ */
if (Aflg) { if (Aflg) {
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"setting group admin",
group, AUDIT_NO_ID, 1);
#endif
SYSLOG ((LOG_INFO, "set administrators of %s to %s",
group, admins));
sgent.sg_adm = comma_to_list (admins); sgent.sg_adm = comma_to_list (admins);
if (!Mflg) { if (!Mflg) {
goto output; goto output;
} }
} }
#endif #endif /* SHADOWGRP */
/* /*
* Replacing the entire list of members is simple. Check the list to * Replacing the entire list of members is simple. Check the list to
@ -1017,12 +1133,6 @@ int main (int argc, char **argv)
* place. * place.
*/ */
if (Mflg) { if (Mflg) {
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"setting group members",
group, AUDIT_NO_ID, 1);
#endif
SYSLOG ((LOG_INFO, "set members of %s to %s", group, members));
#ifdef SHADOWGRP #ifdef SHADOWGRP
sgent.sg_mem = comma_to_list (members); sgent.sg_mem = comma_to_list (members);
#endif #endif
@ -1037,12 +1147,7 @@ int main (int argc, char **argv)
*/ */
if ((isatty (0) == 0) || (isatty (1) == 0)) { if ((isatty (0) == 0) || (isatty (1) == 0)) {
fprintf (stderr, _("%s: Not a tty\n"), Prog); fprintf (stderr, _("%s: Not a tty\n"), Prog);
#ifdef WITH_AUDIT exit (1);
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"changing password",
group, AUDIT_NO_ID, 0);
#endif
fail_exit (1);
} }
catch_signals (0); /* save tty modes */ catch_signals (0); /* save tty modes */
@ -1072,13 +1177,8 @@ int main (int argc, char **argv)
if (setuid (0) != 0) { if (setuid (0) != 0) {
fputs (_("Cannot change ID to root.\n"), stderr); fputs (_("Cannot change ID to root.\n"), stderr);
SYSLOG ((LOG_ERR, "can't setuid(0)")); SYSLOG ((LOG_ERR, "can't setuid(0)"));
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"changing id to root",
group, AUDIT_NO_ID, 0);
#endif
closelog (); closelog ();
fail_exit (1); exit (1);
} }
pwd_init (); pwd_init ();