2007-10-07 17:17:57 +05:30
|
|
|
/*
|
2008-04-27 06:10:09 +05:30
|
|
|
* Copyright (c) 2000 , International Business Machines
|
|
|
|
* George Kraft IV, gk4@us.ibm.com, 03/23/2000
|
|
|
|
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
|
2011-11-07 00:08:26 +05:30
|
|
|
* Copyright (c) 2007 - 2011, Nicolas François
|
2007-10-07 17:17:57 +05:30
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2008-04-27 06:10:09 +05:30
|
|
|
* 3. The name of the copyright holders or contributors may not be used to
|
|
|
|
* endorse or promote products derived from this software without
|
|
|
|
* specific prior written permission.
|
2007-10-07 17:17:57 +05:30
|
|
|
*
|
2008-04-27 06:10:09 +05:30
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
|
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
2007-10-07 17:17:57 +05:30
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#ifdef USE_PAM
|
|
|
|
#include "pam_defs.h"
|
|
|
|
#endif /* USE_PAM */
|
2007-10-07 17:18:07 +05:30
|
|
|
#include <pwd.h>
|
2007-10-07 17:17:57 +05:30
|
|
|
#include "defines.h"
|
2008-07-27 05:51:42 +05:30
|
|
|
#include "prototypes.h"
|
2007-10-07 17:17:57 +05:30
|
|
|
#include "groupio.h"
|
2008-08-31 22:59:34 +05:30
|
|
|
#ifdef SHADOWGRP
|
|
|
|
#include "sgroupio.h"
|
|
|
|
#endif
|
2007-10-07 17:17:57 +05:30
|
|
|
|
|
|
|
/* Exit Status Values */
|
* src/newgrp.c, src/chfn.c, src/groupmems.c, src/usermod.c,
src/userdel.c, src/chpasswd.c, src/grpck.c, src/gpasswd.c,
src/groupdel.c, src/chgpasswd.c, src/vipw.c, src/useradd.c,
src/su.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/faillog.c,
src/sulogin.c, src/chsh.c, src/pwconv.c: Added splint annotations.
* src/userdel.c, src/pwconv.c, src/lastlog.c, src/grpck.c,
src/vipw.c, src/groupmod.c, src/passwd.c, src/pwck.c, src/login.c,
src/sulogin.c, src/usermod.c: Use return instead of exit at the
end of main().
* src/gpasswd.c, src/passwd.c, src/faillog.c: Use the exitcodes.h
exit codes.
* src/chpasswd.c: Added missing ||.
* src/nologin.c: Do not include exitcodes.h.
* src/nologin.c: Added brackets.
* src/nologin.c: Avoid assignments in comparisons.
2009-05-01 03:09:38 +05:30
|
|
|
/*@-exitarg@*/
|
2007-10-07 17:17:57 +05:30
|
|
|
#define EXIT_SUCCESS 0 /* success */
|
|
|
|
#define EXIT_USAGE 1 /* invalid command syntax */
|
|
|
|
#define EXIT_GROUP_FILE 2 /* group file access problems */
|
2007-10-07 20:06:51 +05:30
|
|
|
#define EXIT_NOT_ROOT 3 /* not superuser */
|
|
|
|
#define EXIT_NOT_EROOT 4 /* not effective superuser */
|
2007-10-07 17:17:57 +05:30
|
|
|
#define EXIT_NOT_PRIMARY 5 /* not primary owner of group */
|
|
|
|
#define EXIT_NOT_MEMBER 6 /* member of group does not exist */
|
|
|
|
#define EXIT_MEMBER_EXISTS 7 /* member of group already exists */
|
2008-07-26 21:41:49 +05:30
|
|
|
#define EXIT_INVALID_USER 8 /* specified user does not exist */
|
|
|
|
#define EXIT_INVALID_GROUP 9 /* specified group does not exist */
|
2007-10-07 17:17:57 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* Global variables
|
|
|
|
*/
|
* src/newgrp.c, src/userdel.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/pwconv.c, src/chpasswd.c, src/logoutd.c,
src/chfn.c, src/groupmems.c, src/usermod.c, src/pwunconv.c,
src/expiry.c, src/groupdel.c, src/chgpasswd.c, src/useradd.c,
src/su.c, src/groupmod.c, src/passwd.c, src/pwck.c, src/chage.c,
src/groupadd.c, src/login.c, src/grpconv.c, src/groups.c,
src/grpunconv.c, src/chsh.c: Prog changed to a constant string.
2010-08-23 01:06:09 +05:30
|
|
|
const char *Prog;
|
* src/newgrp.c, src/userdel.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/pwconv.c, src/chpasswd.c, src/logoutd.c,
src/chfn.c, src/groupmems.c, src/usermod.c, src/pwunconv.c,
src/expiry.c, src/groupdel.c, src/chgpasswd.c, src/useradd.c,
src/su.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/grpconv.c,
src/groups.c, src/grpunconv.c, src/chsh.c: Prog is now global (not
static to the file) so that it can be used by the helper functions
of libmisc.
* lib/prototypes.h: Added extern char *Prog.
* libmisc/find_new_gid.c, libmisc/find_new_uid.c: Indicate the
program name with the warning.
2008-09-06 18:21:53 +05:30
|
|
|
|
2007-10-07 17:17:57 +05:30
|
|
|
static char *adduser = NULL;
|
|
|
|
static char *deluser = NULL;
|
|
|
|
static char *thisgroup = NULL;
|
2008-07-26 21:54:27 +05:30
|
|
|
static bool purge = false;
|
|
|
|
static bool list = false;
|
2007-10-07 17:17:57 +05:30
|
|
|
static int exclusive = 0;
|
* src/chfn.c, src/chgpasswd.c, src/chpasswd.c, src/gpasswd.c,
src/groupadd.c, src/groupdel.c, src/groupmems.c, src/groupmod.c,
src/grpconv.c, src/grpunconv.c, src/newusers.c, src/pwconv.c,
src/pwunconv.c, src/useradd.c, src/userdel.c: Harmonize the name
of the variables keeping the lock status, to match the shadow
library prefixes.
2008-08-22 07:52:34 +05:30
|
|
|
static bool gr_locked = false;
|
2008-08-31 22:59:34 +05:30
|
|
|
#ifdef SHADOWGRP
|
|
|
|
/* Indicate if shadow groups are enabled on the system
|
|
|
|
* (/etc/gshadow present) */
|
|
|
|
static bool is_shadowgrp;
|
|
|
|
static bool sgr_locked = false;
|
|
|
|
#endif
|
2007-10-07 17:17:57 +05:30
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
/* local function prototypes */
|
2008-07-27 07:17:56 +05:30
|
|
|
static char *whoami (void);
|
2008-08-31 00:04:24 +05:30
|
|
|
static void add_user (const char *user,
|
2008-08-31 22:59:08 +05:30
|
|
|
const struct group *grp);
|
2008-08-31 00:04:24 +05:30
|
|
|
static void remove_user (const char *user,
|
2008-08-31 22:59:08 +05:30
|
|
|
const struct group *grp);
|
|
|
|
static void purge_members (const struct group *grp);
|
|
|
|
static void display_members (const char *const *members);
|
2011-11-07 00:08:26 +05:30
|
|
|
static /*@noreturn@*/void usage (int status);
|
2008-07-27 06:29:42 +05:30
|
|
|
static void process_flags (int argc, char **argv);
|
|
|
|
static void check_perms (void);
|
2008-07-27 07:05:08 +05:30
|
|
|
static void fail_exit (int code);
|
2008-07-27 05:41:25 +05:30
|
|
|
#define isroot() (getuid () == 0)
|
2007-10-07 17:17:57 +05:30
|
|
|
|
|
|
|
static char *whoami (void)
|
|
|
|
{
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
/* local, no need for xgetgrgid */
|
2007-10-07 17:17:57 +05:30
|
|
|
struct group *grp = getgrgid (getgid ());
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
/* local, no need for xgetpwuid */
|
2007-10-07 17:17:57 +05:30
|
|
|
struct passwd *usr = getpwuid (getuid ());
|
|
|
|
|
2008-07-28 04:00:31 +05:30
|
|
|
if ( (NULL != usr)
|
|
|
|
&& (NULL != grp)
|
|
|
|
&& (0 == strcmp (usr->pw_name, grp->gr_name))) {
|
2008-07-28 04:00:22 +05:30
|
|
|
return xstrdup (usr->pw_name);
|
2007-10-07 17:17:57 +05:30
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-31 00:04:24 +05:30
|
|
|
/*
|
|
|
|
* add_user - Add an user to the specified group
|
|
|
|
*/
|
|
|
|
static void add_user (const char *user,
|
2008-08-31 22:59:08 +05:30
|
|
|
const struct group *grp)
|
2008-08-31 00:04:24 +05:30
|
|
|
{
|
2008-08-31 22:59:08 +05:30
|
|
|
struct group *newgrp;
|
|
|
|
|
2008-08-31 00:04:24 +05:30
|
|
|
/* Make sure the user is not already part of the group */
|
|
|
|
if (is_on_list (grp->gr_mem, user)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: user '%s' is already a member of '%s'\n"),
|
|
|
|
Prog, user, grp->gr_name);
|
|
|
|
fail_exit (EXIT_MEMBER_EXISTS);
|
|
|
|
}
|
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
newgrp = __gr_dup(grp);
|
|
|
|
if (NULL == newgrp) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Out of memory. Cannot update %s.\n"),
|
|
|
|
Prog, gr_dbname ());
|
2008-08-31 22:59:34 +05:30
|
|
|
fail_exit (13);
|
2008-08-31 22:59:08 +05:30
|
|
|
}
|
|
|
|
|
2008-08-31 00:04:24 +05:30
|
|
|
/* Add the user to the /etc/group group */
|
2008-08-31 22:59:08 +05:30
|
|
|
newgrp->gr_mem = add_list (newgrp->gr_mem, user);
|
2008-08-31 22:59:34 +05:30
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (is_shadowgrp) {
|
|
|
|
const struct sgrp *sg = sgr_locate (newgrp->gr_name);
|
|
|
|
struct sgrp *newsg;
|
|
|
|
|
|
|
|
if (NULL == sg) {
|
|
|
|
/* Create a shadow group based on this group */
|
|
|
|
static struct sgrp sgrent;
|
|
|
|
sgrent.sg_name = xstrdup (newgrp->gr_name);
|
|
|
|
sgrent.sg_mem = dup_list (newgrp->gr_mem);
|
|
|
|
sgrent.sg_adm = (char **) xmalloc (sizeof (char *));
|
|
|
|
#ifdef FIRST_MEMBER_IS_ADMIN
|
|
|
|
if (sgrent.sg_mem[0]) {
|
|
|
|
sgrent.sg_adm[0] = xstrdup (sgrent.sg_mem[0]);
|
|
|
|
sgrent.sg_adm[1] = NULL;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
sgrent.sg_adm[0] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Move any password to gshadow */
|
|
|
|
sgrent.sg_passwd = newgrp->gr_passwd;
|
|
|
|
newgrp->gr_passwd = SHADOW_PASSWD_STRING;
|
|
|
|
|
|
|
|
newsg = &sgrent;
|
|
|
|
} else {
|
|
|
|
newsg = __sgr_dup (sg);
|
|
|
|
if (NULL == newsg) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Out of memory. Cannot update %s.\n"),
|
|
|
|
Prog, sgr_dbname ());
|
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
/* Add the user to the members */
|
|
|
|
newsg->sg_mem = add_list (newsg->sg_mem, user);
|
|
|
|
/* Do not touch the administrators */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sgr_update (newsg) == 0) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to prepare the new %s entry '%s'\n"),
|
|
|
|
Prog, sgr_dbname (), newsg->sg_name);
|
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
if (gr_update (newgrp) == 0) {
|
2008-08-31 00:04:24 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to prepare the new %s entry '%s'\n"),
|
2008-08-31 22:59:08 +05:30
|
|
|
Prog, gr_dbname (), newgrp->gr_name);
|
2008-08-31 00:04:24 +05:30
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* remove_user - Remove an user from a given group
|
|
|
|
*/
|
|
|
|
static void remove_user (const char *user,
|
2008-08-31 22:59:08 +05:30
|
|
|
const struct group *grp)
|
2008-08-31 00:04:24 +05:30
|
|
|
{
|
2008-08-31 22:59:08 +05:30
|
|
|
struct group *newgrp;
|
|
|
|
|
2008-08-31 00:04:24 +05:30
|
|
|
/* Check if the user is a member of the specified group */
|
|
|
|
if (!is_on_list (grp->gr_mem, user)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: user '%s' is not a member of '%s'\n"),
|
|
|
|
Prog, user, grp->gr_name);
|
|
|
|
fail_exit (EXIT_NOT_MEMBER);
|
|
|
|
}
|
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
newgrp = __gr_dup (grp);
|
|
|
|
if (NULL == newgrp) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Out of memory. Cannot update %s.\n"),
|
|
|
|
Prog, gr_dbname ());
|
2008-08-31 22:59:34 +05:30
|
|
|
fail_exit (13);
|
2008-08-31 22:59:08 +05:30
|
|
|
}
|
|
|
|
|
2008-08-31 00:04:24 +05:30
|
|
|
/* Remove the user from the /etc/group group */
|
2008-08-31 22:59:08 +05:30
|
|
|
newgrp->gr_mem = del_list (newgrp->gr_mem, user);
|
2008-08-31 22:59:34 +05:30
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (is_shadowgrp) {
|
|
|
|
const struct sgrp *sg = sgr_locate (newgrp->gr_name);
|
|
|
|
struct sgrp *newsg;
|
|
|
|
|
|
|
|
if (NULL == sg) {
|
|
|
|
/* Create a shadow group based on this group */
|
|
|
|
static struct sgrp sgrent;
|
|
|
|
sgrent.sg_name = xstrdup (newgrp->gr_name);
|
|
|
|
sgrent.sg_mem = dup_list (newgrp->gr_mem);
|
|
|
|
sgrent.sg_adm = (char **) xmalloc (sizeof (char *));
|
|
|
|
#ifdef FIRST_MEMBER_IS_ADMIN
|
|
|
|
if (sgrent.sg_mem[0]) {
|
|
|
|
sgrent.sg_adm[0] = xstrdup (sgrent.sg_mem[0]);
|
|
|
|
sgrent.sg_adm[1] = NULL;
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
sgrent.sg_adm[0] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Move any password to gshadow */
|
|
|
|
sgrent.sg_passwd = newgrp->gr_passwd;
|
|
|
|
newgrp->gr_passwd = SHADOW_PASSWD_STRING;
|
|
|
|
|
|
|
|
newsg = &sgrent;
|
|
|
|
} else {
|
|
|
|
newsg = __sgr_dup (sg);
|
|
|
|
if (NULL == newsg) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Out of memory. Cannot update %s.\n"),
|
|
|
|
Prog, sgr_dbname ());
|
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
/* Remove the user from the members */
|
|
|
|
newsg->sg_mem = del_list (newsg->sg_mem, user);
|
|
|
|
/* Remove the user from the administrators */
|
|
|
|
newsg->sg_adm = del_list (newsg->sg_adm, user);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sgr_update (newsg) == 0) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to prepare the new %s entry '%s'\n"),
|
|
|
|
Prog, sgr_dbname (), newsg->sg_name);
|
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
if (gr_update (newgrp) == 0) {
|
2008-08-31 00:04:24 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to prepare the new %s entry '%s'\n"),
|
2008-08-31 22:59:08 +05:30
|
|
|
Prog, gr_dbname (), newgrp->gr_name);
|
2008-08-31 00:04:24 +05:30
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* purge_members - Rmeove every members of the specified group
|
|
|
|
*/
|
2008-08-31 22:59:08 +05:30
|
|
|
static void purge_members (const struct group *grp)
|
2008-08-31 00:04:24 +05:30
|
|
|
{
|
2008-08-31 22:59:08 +05:30
|
|
|
struct group *newgrp = __gr_dup (grp);
|
|
|
|
|
|
|
|
if (NULL == newgrp) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Out of memory. Cannot update %s.\n"),
|
|
|
|
Prog, gr_dbname ());
|
2008-08-31 22:59:34 +05:30
|
|
|
fail_exit (13);
|
2008-08-31 22:59:08 +05:30
|
|
|
}
|
|
|
|
|
2008-08-31 00:04:24 +05:30
|
|
|
/* Remove all the members of the /etc/group group */
|
2008-08-31 22:59:08 +05:30
|
|
|
newgrp->gr_mem[0] = NULL;
|
2008-08-31 22:59:34 +05:30
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (is_shadowgrp) {
|
|
|
|
const struct sgrp *sg = sgr_locate (newgrp->gr_name);
|
|
|
|
struct sgrp *newsg;
|
|
|
|
|
|
|
|
if (NULL == sg) {
|
|
|
|
/* Create a shadow group based on this group */
|
|
|
|
static struct sgrp sgrent;
|
|
|
|
sgrent.sg_name = xstrdup (newgrp->gr_name);
|
|
|
|
sgrent.sg_mem = (char **) xmalloc (sizeof (char *));
|
|
|
|
sgrent.sg_mem[0] = NULL;
|
|
|
|
sgrent.sg_adm = (char **) xmalloc (sizeof (char *));
|
|
|
|
sgrent.sg_adm[0] = NULL;
|
|
|
|
|
|
|
|
/* Move any password to gshadow */
|
|
|
|
sgrent.sg_passwd = newgrp->gr_passwd;
|
|
|
|
newgrp->gr_passwd = xstrdup(SHADOW_PASSWD_STRING);
|
|
|
|
|
|
|
|
newsg = &sgrent;
|
|
|
|
} else {
|
|
|
|
newsg = __sgr_dup (sg);
|
|
|
|
if (NULL == newsg) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Out of memory. Cannot update %s.\n"),
|
|
|
|
Prog, sgr_dbname ());
|
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
/* Remove all the members of the /etc/gshadow
|
|
|
|
* group */
|
|
|
|
newsg->sg_mem[0] = NULL;
|
|
|
|
/* Remove all the administrators of the
|
|
|
|
* /etc/gshadow group */
|
|
|
|
newsg->sg_adm[0] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sgr_update (newsg) == 0) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to prepare the new %s entry '%s'\n"),
|
|
|
|
Prog, sgr_dbname (), newsg->sg_name);
|
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
if (gr_update (newgrp) == 0) {
|
2008-08-31 00:04:24 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to prepare the new %s entry '%s'\n"),
|
2008-08-31 22:59:08 +05:30
|
|
|
Prog, gr_dbname (), newgrp->gr_name);
|
2008-08-31 00:04:24 +05:30
|
|
|
fail_exit (13);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
static void display_members (const char *const *members)
|
2007-10-07 17:17:57 +05:30
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; NULL != members[i]; i++) {
|
|
|
|
printf ("%s ", members[i]);
|
|
|
|
|
|
|
|
if (NULL == members[i + 1]) {
|
|
|
|
printf ("\n");
|
|
|
|
} else {
|
|
|
|
printf (" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-07 00:08:26 +05:30
|
|
|
static /*@noreturn@*/void usage (int status)
|
2007-10-07 17:17:57 +05:30
|
|
|
{
|
* src/userdel.c, src/lastlog.c, src/gpasswd.c, src/newusers.c,
src/chpasswd.c, src/groupmems.c, src/usermod.c, src/chgpasswd.c,
src/vipw.c, src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c,
src/groupadd.c, src/chage.c, src/faillog.c, src/chsh.c: Use
booleans for tests.
* src/userdel.c, src/gpasswd.c, src/groupmems.c, src/usermod.c,
src/groupmod.c, src/passwd.c: Use a break even after usage().
2009-09-06 04:01:29 +05:30
|
|
|
FILE *usageout = (EXIT_SUCCESS != status) ? stderr : stdout;
|
2009-09-06 01:55:40 +05:30
|
|
|
(void) fprintf (usageout,
|
|
|
|
_("Usage: %s [options] [action]\n"
|
|
|
|
"\n"
|
|
|
|
"Options:\n"),
|
|
|
|
Prog);
|
|
|
|
(void) fputs (_(" -g, --group groupname change groupname instead of the user's group\n"
|
|
|
|
" (root only)\n"), usageout);
|
2011-11-07 00:08:26 +05:30
|
|
|
(void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout);
|
2009-09-06 01:55:40 +05:30
|
|
|
(void) fputs (_("\n"), usageout);
|
|
|
|
(void) fputs (_("Actions:\n"), usageout);
|
|
|
|
(void) fputs (_(" -a, --add username add username to the members of the group\n"), usageout);
|
|
|
|
(void) fputs (_(" -d, --delete username remove username from the members of the group\n"), usageout);
|
|
|
|
(void) fputs (_(" -h, --help display this help message and exit\n"), usageout);
|
|
|
|
(void) fputs (_(" -p, --purge purge all members from the group\n"), usageout);
|
|
|
|
(void) fputs (_(" -l, --list list the members of the group\n"), usageout);
|
* src/chage.c, src/chfn.c, src/chgpasswd.c, src/chpasswd.c,
src/chsh.c, src/groupadd.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/newusers.c, src/useradd.c, src/userdel.c,
src/usermod.c: Provide the PAM error
message instead of our own, and log error to syslog.
* src/groupmems.c: Exit with exit rather than fail_exit in usage().
* src/newusers.c: Check the number of arguments.
* src/newusers.c: Do not create the home directory when it is not
changed.
* src/useradd.c: Set the group password to "!" rather "x" if there
are no gshadow file.
2011-11-13 21:54:57 +05:30
|
|
|
exit (status);
|
2007-10-07 17:17:57 +05:30
|
|
|
}
|
|
|
|
|
2008-07-27 06:29:42 +05:30
|
|
|
/*
|
|
|
|
* process_flags - perform command line argument setting
|
|
|
|
*/
|
|
|
|
static void process_flags (int argc, char **argv)
|
2007-10-07 17:17:57 +05:30
|
|
|
{
|
2011-11-07 00:08:26 +05:30
|
|
|
int c;
|
2007-10-07 17:17:57 +05:30
|
|
|
static struct option long_options[] = {
|
* src/chage.c, src/chgpasswd.c, src/chpasswd.c, src/chsh.c,
src/faillog.c, src/gpasswd.c, src/groupadd.c, src/groupdel.c,
src/groupmems.c, src/groupmod.c, src/grpconv.c, src/grpunconv.c,
src/lastlog.c, src/newusers.c, src/passwd.c, src/pwconv.c,
src/pwunconv.c, src/su.c, src/useradd.c, src/userdel.c,
src/usermod.c, src/vipw.c: Align and sort options.
2011-11-07 00:09:59 +05:30
|
|
|
{"add", required_argument, NULL, 'a'},
|
2007-10-07 17:17:57 +05:30
|
|
|
{"delete", required_argument, NULL, 'd'},
|
* src/chage.c, src/chgpasswd.c, src/chpasswd.c, src/chsh.c,
src/faillog.c, src/gpasswd.c, src/groupadd.c, src/groupdel.c,
src/groupmems.c, src/groupmod.c, src/grpconv.c, src/grpunconv.c,
src/lastlog.c, src/newusers.c, src/passwd.c, src/pwconv.c,
src/pwunconv.c, src/su.c, src/useradd.c, src/userdel.c,
src/usermod.c, src/vipw.c: Align and sort options.
2011-11-07 00:09:59 +05:30
|
|
|
{"group", required_argument, NULL, 'g'},
|
|
|
|
{"help", no_argument, NULL, 'h'},
|
|
|
|
{"list", no_argument, NULL, 'l'},
|
|
|
|
{"purge", no_argument, NULL, 'p'},
|
|
|
|
{"root", required_argument, NULL, 'R'},
|
2007-10-07 17:17:57 +05:30
|
|
|
{NULL, 0, NULL, '\0'}
|
|
|
|
};
|
|
|
|
|
2011-11-07 00:08:26 +05:30
|
|
|
while ((c = getopt_long (argc, argv, "a:d:g:hlpR:",
|
|
|
|
long_options, NULL)) != EOF) {
|
|
|
|
switch (c) {
|
2007-10-07 17:17:57 +05:30
|
|
|
case 'a':
|
2008-07-28 04:00:22 +05:30
|
|
|
adduser = xstrdup (optarg);
|
2007-10-07 17:17:57 +05:30
|
|
|
++exclusive;
|
|
|
|
break;
|
|
|
|
case 'd':
|
2008-07-28 04:00:22 +05:30
|
|
|
deluser = xstrdup (optarg);
|
2007-10-07 17:17:57 +05:30
|
|
|
++exclusive;
|
|
|
|
break;
|
|
|
|
case 'g':
|
2008-07-28 04:00:22 +05:30
|
|
|
thisgroup = xstrdup (optarg);
|
2007-10-07 17:17:57 +05:30
|
|
|
break;
|
* NEWS, src/userdel.c, src/lastlog.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/groupmems.c, src/usermod.c,
src/chgpasswd.c, src/vipw.c, src/su.c, src/useradd.c,
src/groupmod.c, src/passwd.c, src/groupadd.c, src/chage.c,
src/faillog.c, src/chsh.c: If someone uses the -h/--help options,
the usage should not go to stderr nor should the utility exit with
non-zero status. All of the shadow utils do just this
unfortunately, so convert them over to sanity.
* man/groupmems.8.xml, man/gpasswd.1.xml: Added option -h/--help.
2009-09-05 04:32:33 +05:30
|
|
|
case 'h':
|
|
|
|
usage (EXIT_SUCCESS);
|
2011-11-07 00:08:26 +05:30
|
|
|
/*@notreached@*/break;
|
2007-10-07 17:17:57 +05:30
|
|
|
case 'l':
|
2008-07-26 21:54:27 +05:30
|
|
|
list = true;
|
2007-10-07 17:17:57 +05:30
|
|
|
++exclusive;
|
|
|
|
break;
|
2008-08-30 23:59:31 +05:30
|
|
|
case 'p':
|
|
|
|
purge = true;
|
|
|
|
++exclusive;
|
|
|
|
break;
|
2011-11-07 00:08:26 +05:30
|
|
|
case 'R': /* no-op, handled in process_root_flag () */
|
|
|
|
break;
|
2007-10-07 17:17:57 +05:30
|
|
|
default:
|
* NEWS, src/userdel.c, src/lastlog.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/groupmems.c, src/usermod.c,
src/chgpasswd.c, src/vipw.c, src/su.c, src/useradd.c,
src/groupmod.c, src/passwd.c, src/groupadd.c, src/chage.c,
src/faillog.c, src/chsh.c: If someone uses the -h/--help options,
the usage should not go to stderr nor should the utility exit with
non-zero status. All of the shadow utils do just this
unfortunately, so convert them over to sanity.
* man/groupmems.8.xml, man/gpasswd.1.xml: Added option -h/--help.
2009-09-05 04:32:33 +05:30
|
|
|
usage (EXIT_USAGE);
|
2007-10-07 17:17:57 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-28 04:00:12 +05:30
|
|
|
if ((exclusive > 1) || (optind < argc)) {
|
* NEWS, src/userdel.c, src/lastlog.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/groupmems.c, src/usermod.c,
src/chgpasswd.c, src/vipw.c, src/su.c, src/useradd.c,
src/groupmod.c, src/passwd.c, src/groupadd.c, src/chage.c,
src/faillog.c, src/chsh.c: If someone uses the -h/--help options,
the usage should not go to stderr nor should the utility exit with
non-zero status. All of the shadow utils do just this
unfortunately, so convert them over to sanity.
* man/groupmems.8.xml, man/gpasswd.1.xml: Added option -h/--help.
2009-09-05 04:32:33 +05:30
|
|
|
usage (EXIT_USAGE);
|
2007-10-07 17:17:57 +05:30
|
|
|
}
|
|
|
|
|
2008-07-26 21:54:27 +05:30
|
|
|
/* local, no need for xgetpwnam */
|
2008-07-30 19:41:09 +05:30
|
|
|
if ( (NULL != adduser)
|
|
|
|
&& (getpwnam (adduser) == NULL)) {
|
* src/chfn.c, src/chsh.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/grpck.c, src/login.c, src/logoutd.c,
src/newgrp.c, src/newusers.c, src/passwd.c, src/pwck.c,
src/suauth.c, src/useradd.c, src/userdel.c, src/usermod.c,
src/vipw.c: Complete the switch from the `' quotation style to ''.
Do it also in SYSLOG messages. Quote some parameters. All this
permits to merge some messages.
2008-08-06 21:21:52 +05:30
|
|
|
fprintf (stderr, _("%s: user '%s' does not exist\n"),
|
2008-07-26 21:41:49 +05:30
|
|
|
Prog, adduser);
|
2008-07-27 07:05:08 +05:30
|
|
|
fail_exit (EXIT_INVALID_USER);
|
2008-07-26 21:41:49 +05:30
|
|
|
}
|
|
|
|
|
2008-07-27 06:29:42 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static void check_perms (void)
|
|
|
|
{
|
2008-08-31 22:59:17 +05:30
|
|
|
if (!list) {
|
2008-07-27 06:29:42 +05:30
|
|
|
#ifdef USE_PAM
|
2008-08-31 22:59:24 +05:30
|
|
|
pam_handle_t *pamh = NULL;
|
* src/userdel.c, src/newusers.c, src/chpasswd.c, src/chfn.c,
src/groupmems.c, src/usermod.c, src/groupdel.c, src/chgpasswd.c,
src/useradd.c, src/groupmod.c, src/groupadd.c, src/chage.c,
src/chsh.c: Simplify the PAM error handling. Do not keep the pamh
handle, but terminate the PAM transaction as soon as possible if
there are no PAM session opened.
2008-09-06 18:58:02 +05:30
|
|
|
int retval;
|
2008-08-31 22:59:24 +05:30
|
|
|
struct passwd *pampw;
|
2007-10-07 17:17:57 +05:30
|
|
|
|
2008-08-31 22:59:24 +05:30
|
|
|
pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
|
|
|
|
if (NULL == pampw) {
|
Additional PAM cleanup:
* src/userdel.c, src/newusers.c, src/chpasswd.c, src/chfn.c,
src/groupmems.c, src/usermod.c, src/groupdel.c, src/chgpasswd.c,
src/useradd.c, src/groupmod.c, src/groupadd.c, src/chage.c,
src/chsh.c: If the username cannot be determined, report it as
such (not a PAM authentication failure).
2008-09-07 05:16:44 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Cannot determine your user name.\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (1);
|
2008-08-31 22:59:24 +05:30
|
|
|
}
|
2007-10-07 17:17:57 +05:30
|
|
|
|
Additional PAM cleanup:
* src/userdel.c, src/newusers.c, src/chpasswd.c, src/chfn.c,
src/groupmems.c, src/usermod.c, src/groupdel.c, src/chgpasswd.c,
src/useradd.c, src/groupmod.c, src/groupadd.c, src/chage.c,
src/chsh.c: If the username cannot be determined, report it as
such (not a PAM authentication failure).
2008-09-07 05:16:44 +05:30
|
|
|
retval = pam_start ("groupmems", pampw->pw_name, &conv, &pamh);
|
|
|
|
|
2008-08-31 22:59:24 +05:30
|
|
|
if (PAM_SUCCESS == retval) {
|
|
|
|
retval = pam_authenticate (pamh, 0);
|
|
|
|
}
|
2007-10-07 17:17:57 +05:30
|
|
|
|
2008-08-31 22:59:24 +05:30
|
|
|
if (PAM_SUCCESS == retval) {
|
|
|
|
retval = pam_acct_mgmt (pamh, 0);
|
|
|
|
}
|
2007-10-07 17:17:57 +05:30
|
|
|
|
2008-08-31 22:59:24 +05:30
|
|
|
if (PAM_SUCCESS != retval) {
|
* src/chage.c, src/chfn.c, src/chgpasswd.c, src/chpasswd.c,
src/chsh.c, src/groupadd.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/newusers.c, src/useradd.c, src/userdel.c,
src/usermod.c: Provide the PAM error
message instead of our own, and log error to syslog.
* src/groupmems.c: Exit with exit rather than fail_exit in usage().
* src/newusers.c: Check the number of arguments.
* src/newusers.c: Do not create the home directory when it is not
changed.
* src/useradd.c: Set the group password to "!" rather "x" if there
are no gshadow file.
2011-11-13 21:54:57 +05:30
|
|
|
fprintf (stderr, _("%s: PAM: %s\n"),
|
|
|
|
Prog, pam_strerror (pamh, retval));
|
|
|
|
SYSLOG((LOG_ERR, "%s", pam_strerror (pamh, retval)));
|
|
|
|
if (NULL != pamh) {
|
|
|
|
(void) pam_end (pamh, retval);
|
|
|
|
}
|
2008-08-31 22:59:24 +05:30
|
|
|
fail_exit (1);
|
|
|
|
}
|
* src/chage.c, src/chfn.c, src/chgpasswd.c, src/chpasswd.c,
src/chsh.c, src/groupadd.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/newusers.c, src/useradd.c, src/userdel.c,
src/usermod.c: Provide the PAM error
message instead of our own, and log error to syslog.
* src/groupmems.c: Exit with exit rather than fail_exit in usage().
* src/newusers.c: Check the number of arguments.
* src/newusers.c: Do not create the home directory when it is not
changed.
* src/useradd.c: Set the group password to "!" rather "x" if there
are no gshadow file.
2011-11-13 21:54:57 +05:30
|
|
|
(void) pam_end (pamh, retval);
|
2007-10-07 17:17:57 +05:30
|
|
|
#endif
|
2008-08-31 22:59:17 +05:30
|
|
|
}
|
2008-07-27 06:29:42 +05:30
|
|
|
}
|
|
|
|
|
2008-07-27 07:05:08 +05:30
|
|
|
static void fail_exit (int code)
|
|
|
|
{
|
* src/chfn.c, src/chgpasswd.c, src/chpasswd.c, src/gpasswd.c,
src/groupadd.c, src/groupdel.c, src/groupmems.c, src/groupmod.c,
src/grpconv.c, src/grpunconv.c, src/newusers.c, src/pwconv.c,
src/pwunconv.c, src/useradd.c, src/userdel.c: Harmonize the name
of the variables keeping the lock status, to match the shadow
library prefixes.
2008-08-22 07:52:34 +05:30
|
|
|
if (gr_locked) {
|
2008-07-27 07:05:08 +05:30
|
|
|
if (gr_unlock () == 0) {
|
|
|
|
fprintf (stderr,
|
2008-08-10 05:03:46 +05:30
|
|
|
_("%s: failed to unlock %s\n"),
|
2008-08-10 04:58:30 +05:30
|
|
|
Prog, gr_dbname ());
|
|
|
|
SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ()));
|
|
|
|
/* continue */
|
2008-07-27 07:05:08 +05:30
|
|
|
}
|
|
|
|
}
|
2008-08-31 22:59:41 +05:30
|
|
|
|
|
|
|
#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 ()));
|
|
|
|
/* continue */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-07-27 07:05:08 +05:30
|
|
|
exit (code);
|
|
|
|
}
|
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
static void open_files (void)
|
|
|
|
{
|
|
|
|
if (!list) {
|
|
|
|
if (gr_lock () == 0) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: cannot lock %s; try again later.\n"),
|
|
|
|
Prog, gr_dbname ());
|
|
|
|
fail_exit (EXIT_GROUP_FILE);
|
|
|
|
}
|
|
|
|
gr_locked = true;
|
2008-08-31 22:59:41 +05:30
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (is_shadowgrp) {
|
|
|
|
if (sgr_lock () == 0) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: cannot lock %s; try again later.\n"),
|
|
|
|
Prog, sgr_dbname ());
|
|
|
|
fail_exit (EXIT_GROUP_FILE);
|
|
|
|
}
|
|
|
|
sgr_locked = true;
|
|
|
|
}
|
|
|
|
#endif
|
2008-08-31 22:59:08 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (gr_open (list ? O_RDONLY : O_RDWR) == 0) {
|
|
|
|
fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ());
|
|
|
|
fail_exit (EXIT_GROUP_FILE);
|
|
|
|
}
|
2008-08-31 22:59:41 +05:30
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (is_shadowgrp) {
|
|
|
|
if (sgr_open (list ? O_RDONLY : O_RDWR) == 0) {
|
|
|
|
fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ());
|
|
|
|
fail_exit (EXIT_GROUP_FILE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2008-08-31 22:59:08 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static void close_files (void)
|
|
|
|
{
|
|
|
|
if ((gr_close () == 0) && !list) {
|
|
|
|
fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ());
|
|
|
|
SYSLOG ((LOG_ERR, "failure while writing changes to %s", gr_dbname ()));
|
|
|
|
fail_exit (EXIT_GROUP_FILE);
|
|
|
|
}
|
|
|
|
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 ()));
|
|
|
|
/* continue */
|
|
|
|
}
|
|
|
|
gr_locked = false;
|
|
|
|
}
|
2008-08-31 22:59:41 +05:30
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (is_shadowgrp) {
|
|
|
|
if ((sgr_close () == 0) && !list) {
|
|
|
|
fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sgr_dbname ());
|
|
|
|
SYSLOG ((LOG_ERR, "failure while writing changes to %s", sgr_dbname ()));
|
|
|
|
fail_exit (EXIT_GROUP_FILE);
|
|
|
|
}
|
|
|
|
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 ()));
|
|
|
|
/* continue */
|
|
|
|
}
|
|
|
|
sgr_locked = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2008-08-31 22:59:08 +05:30
|
|
|
}
|
|
|
|
|
2008-08-10 04:58:30 +05:30
|
|
|
int main (int argc, char **argv)
|
2008-07-27 06:29:42 +05:30
|
|
|
{
|
|
|
|
char *name;
|
2008-08-31 22:59:08 +05:30
|
|
|
const struct group *grp;
|
2008-07-27 06:29:42 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* Get my name so that I can use it to report errors.
|
|
|
|
*/
|
|
|
|
Prog = Basename (argv[0]);
|
|
|
|
|
|
|
|
(void) setlocale (LC_ALL, "");
|
|
|
|
(void) bindtextdomain (PACKAGE, LOCALEDIR);
|
|
|
|
(void) textdomain (PACKAGE);
|
|
|
|
|
2011-11-07 00:08:26 +05:30
|
|
|
process_root_flag ("-R", argc, argv);
|
|
|
|
|
|
|
|
OPENLOG ("groupmems");
|
|
|
|
|
2008-08-31 22:59:41 +05:30
|
|
|
#ifdef SHADOWGRP
|
|
|
|
is_shadowgrp = sgr_file_present ();
|
|
|
|
#endif
|
|
|
|
|
2008-07-27 06:29:42 +05:30
|
|
|
process_flags (argc, argv);
|
|
|
|
|
2008-07-27 06:46:13 +05:30
|
|
|
if (NULL == thisgroup) {
|
|
|
|
name = whoami ();
|
2008-07-27 08:03:37 +05:30
|
|
|
if (!list && (NULL == name)) {
|
2008-07-27 06:46:13 +05:30
|
|
|
fprintf (stderr, _("%s: your groupname does not match your username\n"), Prog);
|
2008-07-27 07:05:08 +05:30
|
|
|
fail_exit (EXIT_NOT_PRIMARY);
|
2008-07-27 06:46:13 +05:30
|
|
|
}
|
|
|
|
} else {
|
2008-07-27 06:29:42 +05:30
|
|
|
name = thisgroup;
|
2008-07-27 08:03:37 +05:30
|
|
|
if (!list && !isroot ()) {
|
2008-07-27 06:46:13 +05:30
|
|
|
fprintf (stderr, _("%s: only root can use the -g/--group option\n"), Prog);
|
2008-07-27 07:05:08 +05:30
|
|
|
fail_exit (EXIT_NOT_ROOT);
|
2008-07-27 06:46:13 +05:30
|
|
|
}
|
2008-07-27 06:29:42 +05:30
|
|
|
}
|
|
|
|
|
2008-09-06 21:57:21 +05:30
|
|
|
check_perms ();
|
2007-10-07 17:17:57 +05:30
|
|
|
|
2008-09-06 21:57:21 +05:30
|
|
|
open_files ();
|
2007-10-07 17:17:57 +05:30
|
|
|
|
2008-08-31 22:59:08 +05:30
|
|
|
grp = gr_locate (name);
|
2008-07-28 04:00:12 +05:30
|
|
|
if (NULL == grp) {
|
2008-08-10 04:58:30 +05:30
|
|
|
fprintf (stderr, _("%s: group '%s' does not exist in %s\n"),
|
|
|
|
Prog, name, gr_dbname ());
|
2008-07-27 07:05:08 +05:30
|
|
|
fail_exit (EXIT_INVALID_GROUP);
|
2008-07-26 21:41:49 +05:30
|
|
|
}
|
|
|
|
|
2008-07-27 08:03:37 +05:30
|
|
|
if (list) {
|
2008-08-31 22:59:08 +05:30
|
|
|
display_members ((const char *const *)grp->gr_mem);
|
2008-07-27 08:03:37 +05:30
|
|
|
} else if (NULL != adduser) {
|
2008-08-31 00:04:24 +05:30
|
|
|
add_user (adduser, grp);
|
2007-10-07 17:17:57 +05:30
|
|
|
} else if (NULL != deluser) {
|
2008-08-31 00:04:24 +05:30
|
|
|
remove_user (deluser, grp);
|
2007-10-07 17:17:57 +05:30
|
|
|
} else if (purge) {
|
2008-08-31 00:04:24 +05:30
|
|
|
purge_members (grp);
|
2007-10-07 17:17:57 +05:30
|
|
|
}
|
|
|
|
|
2008-09-06 21:57:21 +05:30
|
|
|
close_files ();
|
2007-10-07 17:17:57 +05:30
|
|
|
|
2008-08-10 04:58:30 +05:30
|
|
|
exit (EXIT_SUCCESS);
|
2007-10-07 17:17:57 +05:30
|
|
|
}
|
2008-07-27 07:05:08 +05:30
|
|
|
|