summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'sys-apps/shadow/files/shadow-19990827-redhat.patch')
-rw-r--r--sys-apps/shadow/files/shadow-19990827-redhat.patch865
1 files changed, 865 insertions, 0 deletions
diff --git a/sys-apps/shadow/files/shadow-19990827-redhat.patch b/sys-apps/shadow/files/shadow-19990827-redhat.patch
new file mode 100644
index 000000000000..75e332db2fd8
--- /dev/null
+++ b/sys-apps/shadow/files/shadow-19990827-redhat.patch
@@ -0,0 +1,865 @@
+--- shadow-19990827/man/shadowconfig.8.redhat Sat Sep 12 11:38:24 1998
++++ shadow-19990827/man/shadowconfig.8 Wed Sep 22 15:56:41 1999
+@@ -19,6 +19,3 @@
+ Turning shadow passwords on when they are already on, or off when they
+ are already off, is harmless.
+
+-Read
+-.I /usr/doc/passwd/README.debian.gz
+-for a brief introduction to shadow passwords and related features.
+--- shadow-19990827/man/useradd.8.redhat Sun Mar 7 14:14:47 1999
++++ shadow-19990827/man/useradd.8 Wed Sep 22 15:56:41 1999
+@@ -51,7 +51,7 @@
+ .IR group [,...]]
+ .br
+ .RB [ -m " [" -k
+-.IR skeleton_dir ]]
++.IR skeleton_dir ] " |" " " -M ]
+ .RB [ -p
+ .IR passwd ]
+ .br
+@@ -60,6 +60,8 @@
+ .RB [ -u
+ .IR uid " ["
+ .BR -o ]]
++.RB [ -n ]
++.RB [ -r ]
+ .I login
+ .TP 8
+ .B useradd
+@@ -79,6 +81,8 @@
+ The new user account will be entered into the system files as needed,
+ the home directory will be created, and initial files copied, depending
+ on the command line options.
++The version provided with Red Hat Linux will create a group for each
++user added to the system, unless \fB-n\fR option is given.
+ The options which apply to the \fBuseradd\fR command are
+ .\" .IP "\fB-A {\fImethod\fR|\fBDEFAULT\fR},..."
+ .\" The value of the user's authentication method.
+@@ -128,6 +132,21 @@
+ option.
+ The default is to not create the directory and to not copy any
+ files.
++.IP \fB-M\fR
++The user home directory will not be created, even if the system
++wide settings from \fI/etc/login.defs\fR is to create home dirs.
++.IP \fB-n\fR
++A group having the same name as the user being added to the system
++will be created by default. This option will turn off this Red Hat
++Linux specific behavior.
++.IP \fB-r\fR
++This flag is used to create a system account. That is, an user with an
++UID lower than value of UID_MIN defined in \fI/etc/login.defs\fR. Note
++that \fBuseradd\fR will not create a home directory for such an user,
++regardless of the default setting in \fI/etc/login.defs\fR.
++You have to specify \fB-m\fR option if you want a home directory
++for a system account to be created.
++This is an option added by Red Hat.
+ .IP "\fB-p \fIpasswd\fR"
+ The encrypted password, as returned by \fBcrypt\fR(3).
+ The default is to disable the account.
+@@ -170,19 +189,24 @@
+ .SH NOTES
+ The system administrator is responsible for placing the default
+ user files in the \fI/etc/skel\fR directory.
++.br
++This version of useradd was modified by Red Hat to suit Red Hat
++user/group convention.
+ .SH CAVEATS
+ You may not add a user to an NIS group.
+ This must be performed on the NIS server.
+ .SH FILES
+-/etc/passwd \- user account information
++\fB/etc/passwd\fR \- user account information
++.br
++\fB/etc/shadow\fR \- secure user account information
+ .br
+-/etc/shadow \- secure user account information
++\fB/etc/group\fR \- group information
+ .br
+-/etc/group \- group information
++\fB/etc/default/useradd\fR \- default information
+ .br
+-/etc/default/useradd \- default information
++\fB/etc/login.defs\fR \- system-wide settings
+ .br
+-/etc/skel \- directory containing default files
++\fB/etc/skel\fR \- directory containing default files
+ .SH SEE ALSO
+ .BR chfn (1),
+ .BR chsh (1),
+--- shadow-19990827/man/groupadd.8.redhat Mon Dec 28 15:35:05 1998
++++ shadow-19990827/man/groupadd.8 Wed Sep 22 15:56:41 1999
+@@ -32,7 +32,7 @@
+ groupadd \- Create a new group
+ .SH SYNOPSIS
+ .B groupadd
+-[\fB-g\fI gid \fR[\fB-o\fR]]
++[\fB-g\fI gid \fR[\fB-o\fR]] [\fB-r\fR] [\fB-f\fR]
+ .I group
+ .SH DESCRIPTION
+ The \fBgroupadd\fR command
+@@ -44,9 +44,29 @@
+ The numerical value of the group's ID.
+ This value must be unique, unless the \fB-o\fR option is used.
+ The value must be non-negative.
+-The default is to use the smallest ID value greater than 99 and
++The default is to use the smallest ID value greater than 500 and
+ greater than every other group.
+-Values between 0 and 99 are typically reserved for system accounts.
++Values between 0 and 499 are typically reserved for \fIsystem accounts\fR.
++.IP \fB-r\fR
++This flag instructs \fBgroupadd\fR to add a \fIsystem
++account\fR. First available \fIgid\fR lower than 499 will be
++automatically selected unless \fB-g\fR option is given also on the
++command line.
++.br
++This is an option added by Red Hat Software.
++.IP \fB-f\fR
++This is \fIforce\fR flag. This will stop \fBgroupadd\fR exit with
++error when the group about to be added already exists on the
++system. If that is the case, the group won't be altered (or added
++again, for that matter).
++.br
++This option also modifies the way \fB-g\fR option works. When you
++request a \fIgid\fR that it is not unique and you don't give \fB-o\fR
++option too, the group creation will fall back to the standard behavior
++(adding a group as neither \fB-g\fR or \fB-o\fR options were
++specified).
++.br
++This is an option added by Red Hat Software.
+ .SH FILES
+ /etc/group \- group account information
+ .br
+--- shadow-19990827/src/useradd.c.redhat Mon Jun 7 12:40:45 1999
++++ shadow-19990827/src/useradd.c Wed Sep 22 15:56:41 1999
+@@ -61,7 +61,7 @@
+ #define USER_DEFAULTS_FILE "/etc/default/useradd"
+ #define NEW_USER_FILE "/etc/default/nuaddXXXXXX"
+ #endif
+-
++
+ /*
+ * Needed for MkLinux DR1/2/2.1 - J.
+ */
+@@ -75,7 +75,7 @@
+ static gid_t def_group = 100;
+ static const char *def_gname = "other";
+ static const char *def_home = "/home";
+-static const char *def_shell = "";
++static const char *def_shell = "/dev/null";
+ static const char *def_template = SKEL_DIR;
+ #ifdef SHADOWPWD
+ static long def_inactive = -1;
+@@ -87,7 +87,7 @@
+ #define VALID(s) (strcspn (s, ":\n") == strlen (s))
+
+ static const char *user_name = "";
+-static const char *user_pass = "!";
++static const char *user_pass = "!!";
+ static uid_t user_id;
+ static gid_t user_gid;
+ static const char *user_comment = "";
+@@ -115,10 +115,13 @@
+ sflg = 0, /* shell program for new account */
+ cflg = 0, /* comment (GECOS) field for new account */
+ mflg = 0, /* create user's home directory if it doesn't exist */
+- kflg = 0, /* specify a directory to fill new user directory */
++ Mflg = 0, /* do NOT create user's home directory no matter what */
++ kflg = 0, /* specify a directory to fill new user directory */
+ fflg = 0, /* days until account with expired password is locked */
+ eflg = 0, /* days since 1970-01-01 when account is locked */
+- Dflg = 0; /* set/show new user default values */
++ Dflg = 0, /* set/show new user default values */
++ nflg = 0, /* do not add a group for this user */
++ rflg = 0; /* create a system account */
+
+ #ifdef AUTH_METHODS
+ static int Aflg = 0; /* specify authentication method for user */
+@@ -181,19 +184,19 @@
+ #define E_HOMEDIR 12 /* can't create home directory */
+
+ #ifdef SVR4
+-#define DGROUP "defgroup="
+-#define HOME "defparent="
+-#define SHELL "defshell="
+-#define INACT "definact="
+-#define EXPIRE "defexpire="
+-#define SKEL "defskel="
++#define DGROUP "defgroup="
++#define HOME "defparent="
++#define SHELL "defshell="
++#define INACT "definact="
++#define EXPIRE "defexpire="
++#define SKEL "defskel="
+ #else
+-#define DGROUP "GROUP="
+-#define HOME "HOME="
+-#define SHELL "SHELL="
+-#define INACT "INACTIVE="
+-#define EXPIRE "EXPIRE="
+-#define SKEL "SKEL="
++#define DGROUP "GROUP="
++#define HOME "HOME="
++#define SHELL "SHELL="
++#define INACT "INACTIVE="
++#define EXPIRE "EXPIRE="
++#define SKEL "SKEL="
+ #endif
+
+ /* local function prototypes */
+@@ -711,7 +714,7 @@
+ #ifdef AUTH_METHODS
+ fprintf(stderr, _("[-A program] "));
+ #endif
+- fprintf(stderr, _("[-p passwd] name\n"));
++ fprintf(stderr, _("[-p passwd] [-n] [-r] name\n"));
+
+ fprintf(stderr, _(" %s\t-D [-g group] [-b base] [-s shell]\n"),
+ Prog);
+@@ -807,31 +810,7 @@
+ struct sgrp *nsgrp;
+ #endif
+
+- /*
+- * Lock and open the group file. This will load all of the group
+- * entries.
+- */
+-
+- if (! gr_lock ()) {
+- fprintf(stderr, _("%s: error locking group file\n"), Prog);
+- fail_exit(E_GRP_UPDATE);
+- }
+- if (! gr_open (O_RDWR)) {
+- fprintf(stderr, _("%s: error opening group file\n"), Prog);
+- fail_exit(E_GRP_UPDATE);
+- }
+-#ifdef SHADOWGRP
+- if (is_shadow_grp && ! sgr_lock ()) {
+- fprintf(stderr, _("%s: error locking shadow group file\n"),
+- Prog);
+- fail_exit(E_GRP_UPDATE);
+- }
+- if (is_shadow_grp && ! sgr_open (O_RDWR)) {
+- fprintf(stderr, _("%s: error opening shadow group file\n"),
+- Prog);
+- fail_exit(E_GRP_UPDATE);
+- }
+-#endif
++ /* Locking and opening of the group files moved to open_files() --gafton */
+
+ /*
+ * Scan through the entire group file looking for the groups that
+@@ -969,8 +948,13 @@
+ const struct passwd *pwd;
+ uid_t uid_min, uid_max;
+
+- uid_min = getdef_num("UID_MIN", 100);
+- uid_max = getdef_num("UID_MAX", 60000);
++ if (!rflg) {
++ uid_min = getdef_num("UID_MIN", 500);
++ uid_max = getdef_num("UID_MAX", 60000);
++ } else {
++ uid_min = 1;
++ uid_max = 499;
++ }
+
+ /*
+ * Start with some UID value if the user didn't provide us with
+@@ -1036,6 +1020,88 @@
+ }
+ }
+
++/*
++ * find_new_gid - find the next available GID
++ *
++ * find_new_gid() locates the next highest unused GID in the group
++ * file, or checks the given group ID against the existing ones for
++ * uniqueness.
++ */
++
++static void
++find_new_gid()
++{
++ const struct group *grp;
++ gid_t gid_min, gid_max;
++
++ if (!rflg) {
++ gid_min = getdef_num("GID_MIN", 500);
++ gid_max = getdef_num("GID_MAX", 60000);
++ } else {
++ gid_min = 1;
++ gid_max = 499;
++ }
++
++ /*
++ * Start with some GID value if the user didn't provide us with
++ * one already.
++ */
++
++ user_gid = gid_min;
++
++ /*
++ * Search the entire group file, either looking for this
++ * GID (if the user specified one with -g) or looking for the
++ * largest unused value.
++ */
++
++#ifdef NO_GETGRENT
++ gr_rewind();
++ while ((grp = gr_next()))
++#else
++ setgrent();
++ while ((grp = getgrent()))
++#endif
++ {
++ if (strcmp(user_name, grp->gr_name) == 0) {
++ user_gid = grp->gr_gid;
++ return;
++ }
++ if (grp->gr_gid >= user_gid) {
++ if (grp->gr_gid > gid_max)
++ continue;
++ user_gid = grp->gr_gid + 1;
++ }
++ }
++#ifndef NO_GETGRENT /* RH Linux does have this, so ... */
++ /* A quick test gets here: if the UID is available
++ * as a GID, go ahead and use it */
++ if (!getgrgid(user_id)) {
++ user_gid = user_id;
++ return;
++ }
++#endif
++ if (user_gid == gid_max + 1) {
++ for (user_gid = gid_min; user_gid < gid_max; user_gid++) {
++#ifdef NO_GETGRENT
++ gr_rewind();
++ while ((grp = gr_next()) && grp->gr_gid != user_gid)
++ ;
++ if (!grp)
++ break;
++#else
++ if (!getgrgid(user_gid))
++ break;
++#endif
++ }
++ if (user_gid == gid_max) {
++ fprintf(stderr, "%s: can't get unique gid (run out of GIDs)\n",
++ Prog);
++ fail_exit(4);
++ }
++ }
++}
++
+ #ifdef AUTH_METHODS
+ /*
+ * convert_auth - convert the argument list to a authentication list
+@@ -1126,9 +1192,9 @@
+ char *cp;
+
+ #ifdef SHADOWPWD
+-#define FLAGS "A:Du:og:G:d:s:c:mk:p:f:e:b:O:M"
++#define FLAGS "A:Du:og:G:d:s:c:mk:p:f:e:b:O:Mnr"
+ #else
+-#define FLAGS "A:Du:og:G:d:s:c:mk:p:b:O:M"
++#define FLAGS "A:Du:og:G:d:s:c:mk:p:b:O:Mnr"
+ #endif
+ while ((arg = getopt(argc, argv, FLAGS)) != EOF) {
+ #undef FLAGS
+@@ -1252,12 +1318,6 @@
+ case 'm':
+ mflg++;
+ break;
+- case 'M':
+- /*
+- * don't create home dir - this is the default,
+- * ignored for RedHat/PLD adduser compatibility.
+- */
+- break;
+ case 'o':
+ oflg++;
+ break;
+@@ -1302,6 +1362,15 @@
+ user_id = get_number(optarg);
+ uflg++;
+ break;
++ case 'n':
++ nflg++;
++ break;
++ case 'r':
++ rflg++;
++ break;
++ case 'M':
++ Mflg++;
++ break;
+ default:
+ usage();
+ }
+@@ -1312,9 +1381,12 @@
+ * Certain options are only valid in combination with others.
+ * Check it here so that they can be specified in any order.
+ */
+- if ((oflg && !uflg) || (kflg && !mflg))
++ if (kflg && !mflg)
+ usage();
+
++ if (mflg && Mflg) /* the admin is not decided .. create or not ? */
++ usage();
++
+ /*
+ * Either -D or username is required. Defaults can be set with -D
+ * for the -b, -e, -f, -g, -s options only.
+@@ -1435,6 +1507,31 @@
+ exit(E_PW_UPDATE);
+ }
+ #endif
++ /*
++ * Lock and open the group file. This will load all of the group
++ * entries.
++ */
++
++ if (! gr_lock ()) {
++ fprintf(stderr, _("%s: error locking group file\n"), Prog);
++ fail_exit(E_GRP_UPDATE);
++ }
++ if (! gr_open (O_RDWR)) {
++ fprintf(stderr, _("%s: error opening group file\n"), Prog);
++ fail_exit(E_GRP_UPDATE);
++ }
++#ifdef SHADOWGRP
++ if (is_shadow_grp && ! sgr_lock ()) {
++ fprintf(stderr, _("%s: error locking shadow group file\n"),
++ Prog);
++ fail_exit(E_GRP_UPDATE);
++ }
++ if (is_shadow_grp && ! sgr_open (O_RDWR)) {
++ fprintf(stderr, _("%s: error opening shadow group file\n"),
++ Prog);
++ fail_exit(E_GRP_UPDATE);
++ }
++#endif /* SHADOWGRP*/
+ }
+
+
+@@ -1483,9 +1580,6 @@
+ struct spwd spent;
+ #endif
+
+- if (! oflg)
+- find_new_uid ();
+-
+ #ifdef AUTH_METHODS
+ if (Aflg) {
+ convert_auth(user_auth, auth_arg);
+@@ -1643,6 +1737,118 @@
+ }
+ }
+
++/* a fake something */
++static char *empty_list = NULL;
++
++/*
++ * new_grent - initialize the values in a group file entry
++ *
++ * new_grent() takes all of the values that have been entered and
++ * fills in a (struct group) with them.
++ */
++
++static void
++new_grent(grent)
++ struct group *grent;
++{
++ bzero ((char *) grent, sizeof *grent);
++ (const char *) (grent->gr_name) = user_name;
++ grent->gr_passwd = "x";
++ grent->gr_gid = user_gid;
++ grent->gr_mem = &empty_list;
++}
++
++#ifdef SHADOWGRP
++/*
++ * new_sgent - initialize the values in a shadow group file entry
++ *
++ * new_sgent() takes all of the values that have been entered and
++ * fills in a (struct sgrp) with them.
++ */
++
++static void
++new_sgent(sgent)
++ struct sgrp *sgent;
++{
++ bzero ((char *) sgent, sizeof *sgent);
++ (const char *)(sgent->sg_name) = user_name;
++ sgent->sg_passwd = "!";
++ sgent->sg_adm = &empty_list;
++ sgent->sg_mem = &empty_list;
++}
++#endif /* SHADOWGRP */
++
++/*
++ * grp_update - add new group file entries
++ *
++ * grp_update() writes the new records to the group files.
++ */
++
++static void grp_add()
++{
++ struct group grp;
++#ifdef SHADOWGRP
++ struct sgrp sgrp;
++#endif /* SHADOWGRP */
++
++ /*
++ * Create the initial entries for this new group.
++ */
++
++ new_grent (&grp);
++#ifdef SHADOWGRP
++ new_sgent (&sgrp);
++#endif /* SHADOWGRP */
++
++ /*
++ * Write out the new group file entry.
++ */
++ if (! gr_update (&grp)) {
++ fprintf (stderr, "%s: error adding new group entry\n", Prog);
++ fail_exit (10);
++ }
++#ifdef NDBM
++
++ /*
++ * Update the DBM group file with the new entry as well.
++ */
++
++ if (gr_dbm_present() && ! gr_dbm_update (&grp)) {
++ fprintf (stderr, "%s: cannot add new dbm group entry\n", Prog);
++ fail_exit (10);
++ }
++ endgrent ();
++#endif /* NDBM */
++
++#ifdef SHADOWGRP
++
++ /*
++ * Write out the new shadow group entries as well.
++ */
++
++ if (is_shadow_grp && ! sgr_update (&sgrp)) {
++ fprintf (stderr, "%s: error adding new group entry\n", Prog);
++ fail_exit (10);
++ }
++#ifdef NDBM
++
++ /*
++ * Update the DBM group file with the new entry as well.
++ */
++
++ if (is_shadow_grp && sg_dbm_present() && ! sg_dbm_update (&sgrp)) {
++ fprintf (stderr, "%s: cannot add new dbm group entry\n", Prog);
++ fail_exit (10);
++ }
++ endsgent ();
++#endif /* NDBM */
++#endif /* SHADOWGRP */
++ SYSLOG((LOG_INFO, "new group: name=%s, gid=%d\n",
++ user_name, user_gid));
++ /* we need to remeber we have to close the group file... */
++ do_grp_update++;
++}
++
+ /*
+ * main - useradd command
+ */
+@@ -1688,6 +1894,14 @@
+
+ process_flags(argc, argv);
+
++ if (!rflg) /* for system accounts defaults are ignored and we
++ * do not create a home dir -- gafton */
++ if (getdef_bool("CREATE_HOME"))
++ mflg = 1;
++
++ if (Mflg) /* absolutely sure that we do not create home dirs */
++ mflg = 0;
++
+ /*
+ * See if we are messing with the defaults file, or creating
+ * a new user.
+@@ -1706,8 +1920,12 @@
+ */
+
+ if (getpwnam(user_name)) {
++ if (!oflg) {
+ fprintf(stderr, _("%s: user %s exists\n"), Prog, user_name);
+ exit(E_NAME_IN_USE);
++ } else {
++ exit(E_SUCCESS);
++ }
+ }
+
+ /*
+@@ -1717,28 +1935,33 @@
+
+ open_files ();
+
++ /* first, seek for a valid uid to use for this user.
++ * We do this because later we can use the uid we found as
++ * gid too ... --gafton */
++ if (! uflg)
++ find_new_uid ();
++ /* do we have to add a group for that user? This is why we need to
++ * open the group files in the open_files() function --gafton */
++ if (! (nflg || gflg)) {
++ find_new_gid();
++ grp_add();
++ }
++
+ usr_update ();
+
+ if (mflg) {
+ create_home ();
+ copy_tree (def_template, user_home, user_id, user_gid);
+- } else if (getdef_str("CREATE_HOME")) {
+- /*
+- * RedHat added the CREATE_HOME option in login.defs in their
+- * version of shadow-utils (which makes -m the default, with
+- * new -M option to turn it off). Unfortunately, this
+- * changes the way useradd works (it can be run by scripts
+- * expecting some standard behaviour), compared to other
+- * Unices and other Linux distributions, and also adds a lot
+- * of confusion :-(.
+- * So we now recognize CREATE_HOME and give a warning here
+- * (better than "configuration error ... notify administrator"
+- * errors in every program that reads /etc/login.defs). -MM
+- */
+- fprintf(stderr,
+- _("%s: warning: CREATE_HOME not supported, please use -m instead.\n"),
+- Prog);
+- }
++ } /* Stupid warning removed for the innocent's protection */
++ /*
++ * The whole idea about breaking some stupid scripts by creating a new
++ * variable is crap - I could care less about the scripts. Historically
++ * adduser type programs have always created the home directories and
++ * I don't like the idea of providing a script when we can fix the binary
++ * itself. And if the scripts are using the right options to the useradd
++ * then they will not break. If not, they depend on unspecified behavior
++ * and they will break, but they were broken anyway to beging with --gafton
++ */
+
+ close_files ();
+ exit(E_SUCCESS);
+--- shadow-19990827/src/groupadd.c.redhat Mon Jun 7 12:40:45 1999
++++ shadow-19990827/src/groupadd.c Wed Sep 22 15:56:41 1999
+@@ -72,6 +72,10 @@
+ static int oflg = 0; /* permit non-unique group ID to be specified with -g */
+ static int gflg = 0; /* ID value for the new group */
+ static int fflg = 0; /* if group already exists, do nothing and exit(0) */
++static int rflg = 0; /* for adding system accounts (RedHat) */
++
++/* For adding "system" accounts */
++#define MIN_GID 10
+
+ #ifdef NDBM
+ extern int gr_dbm_mode;
+@@ -103,7 +107,7 @@
+ static void
+ usage(void)
+ {
+- fprintf(stderr, _("usage: groupadd [-g gid [-o]] group\n"));
++ fprintf(stderr, _("usage: groupadd [-g gid [-o]] [-r] [-f] group\n"));
+ exit(E_USAGE);
+ }
+
+@@ -228,8 +232,13 @@
+ const struct group *grp;
+ gid_t gid_min, gid_max;
+
+- gid_min = getdef_num("GID_MIN", 100);
+- gid_max = getdef_num("GID_MAX", 60000);
++ if (!rflg) {
++ gid_min = getdef_num("GID_MIN", 500);
++ gid_max = getdef_num("GID_MAX", 60000);
++ } else {
++ gid_min = MIN_GID;
++ gid_max = getdef_num("GID_MIN", 499);
++ }
+
+ /*
+ * Start with some GID value if the user didn't provide us with
+@@ -339,7 +348,7 @@
+ char *cp;
+ int arg;
+
+- while ((arg = getopt(argc, argv, "og:O:f")) != EOF) {
++ while ((arg = getopt(argc, argv, "og:O:fr")) != EOF) {
+ switch (arg) {
+ case 'g':
+ gflg++;
+@@ -384,7 +393,13 @@
+ */
+ fflg++;
+ break;
+- default:
++ case 'r':
++ /*
++ * create a system group
++ */
++ rflg++;
++ break;
++ default:
+ usage();
+ }
+ }
+--- shadow-19990827/src/userdel.c.redhat Mon Jun 7 12:40:45 1999
++++ shadow-19990827/src/userdel.c Wed Sep 22 15:59:40 1999
+@@ -59,7 +59,9 @@
+
+ static char *user_name;
+ static uid_t user_id;
++static gid_t user_gid;
+ static char *user_home;
++static char *user_group;
+
+ static char *Prog;
+ static int fflg = 0, rflg = 0;
+@@ -248,6 +250,100 @@
+ #endif /* SHADOWGRP */
+ }
+
++/* remove_group()
++ * remove the user's group unless it is not really a user-private group
++ */
++static void
++remove_group ()
++{
++ char *glist_name;
++ struct group *gr;
++ struct passwd *pwd;
++#ifdef NDBM
++ struct group *ogrp;
++#endif
++
++ if (user_group == NULL || user_name == NULL)
++ return;
++
++ if (strcmp(user_name, user_group)) {
++ return;
++ }
++
++ glist_name = NULL;
++ gr = getgrnam(user_group);
++ if (gr)
++ glist_name = *(gr->gr_mem);
++ while (glist_name) {
++ while (glist_name && *glist_name) {
++ if (strncmp(glist_name, user_name, 16)) {
++ return;
++ }
++ glist_name++;
++ }
++ }
++
++ setpwent();
++ while ((pwd = getpwent())) {
++ if (strcmp(pwd->pw_name, user_name) == 0)
++ continue;
++
++ if (pwd->pw_gid == user_gid) {
++ return;
++ }
++ }
++
++ /* now actually do the removal if we haven't already returned */
++
++ if (! gr_remove (user_group)) {
++ fprintf (stderr, "%s: error removing group entry\n", Prog);
++ }
++#ifdef NDBM
++
++ /*
++ * Update the DBM group file
++ */
++
++ if (gr_dbm_present()) {
++ if ((ogrp = getgrnam (user_group)) &&
++ ! gr_dbm_remove (ogrp)) {
++ fprintf (stderr, "%s: error removing group dbm entry\n",
++ Prog);
++ }
++ }
++ endgrent ();
++#endif /* NDBM */
++
++#ifdef SHADOWGRP
++
++ /*
++ * Delete the shadow group entries as well.
++ */
++
++ if (is_shadow_grp && ! sgr_remove (user_group)) {
++ fprintf (stderr, "%s: error removing shadow group entry\n",
++ Prog);
++ }
++#ifdef NDBM
++
++ /*
++ * Update the DBM shadow group file
++ */
++
++ if (is_shadow_grp && sg_dbm_present()) {
++ if (! sg_dbm_remove (user_group)) {
++ fprintf (stderr,
++ "%s: error removing shadow group dbm entry\n",
++ Prog);
++ }
++ }
++ endsgent ();
++#endif /* NDBM */
++#endif /* SHADOWGRP */
++ SYSLOG((LOG_INFO, "remove group `%s'\n", user_group));
++ return;
++}
++
+ /*
+ * close_files - close all of the files that were opened
+ *
+@@ -512,7 +608,8 @@
+
+ fprintf(stderr, _("%s: user %s is currently logged in\n"),
+ Prog, name);
+- exit(E_USER_BUSY);
++ if (!fflg)
++ exit(E_USER_BUSY);
+ }
+ }
+
+@@ -647,6 +744,7 @@
+ main(int argc, char **argv)
+ {
+ struct passwd *pwd;
++ struct group *gr;
+ int arg;
+ int errors = 0;
+
+@@ -736,6 +834,9 @@
+ #endif
+ user_id = pwd->pw_uid;
+ user_home = xstrdup(pwd->pw_dir);
++ user_gid = pwd->pw_gid;
++ gr = getgrgid(pwd->pw_gid);
++ if (gr) user_group = xstrdup(gr->gr_name);
+
+ /*
+ * Check to make certain the user isn't logged in.
+@@ -792,6 +893,9 @@
+ }
+ }
+ #endif
++
++ /* remove user's group if appropriate */
++ remove_group ();
+
+ if (rflg) {
+ if (remove_tree(user_home) || rmdir(user_home)) {