Sophie

Sophie

distrib > Mandriva > 2007.0 > x86_64 > media > main-release-src > by-pkgid > f01202932fbd367fcf86f895d058ab36 > files > 7

shadow-utils-4.0.12-3mdv2007.0.src.rpm

--- shadow-4.0.12/man/groupadd.8.mdk	2005-08-03 18:18:37.000000000 +0200
+++ shadow-4.0.12/man/groupadd.8	2005-09-13 16:11:22.000000000 +0200
@@ -11,7 +11,7 @@
 groupadd \- Create a new group
 .SH "SYNOPSIS"
 .HP 9
-\fBgroupadd\fR [\-g\ \fIgid\fR\ [\-o\ ]] [\-f] [\-K\ \fIKEY\fR=\fIVALUE\fR] \fIgroup\fR
+\fBgroupadd\fR [\-g\ \fIgid\fR\ [\-o\ ]] [\-f] [\-f] [\-K\ \fIKEY\fR=\fIVALUE\fR] \fIgroup\fR
 .SH "DESCRIPTION"
 .PP
 The 
@@ -32,7 +32,7 @@
 \fB\-g\fR \fIgid\fR
 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 999 and greater than every other group. Values between 0 and 999 are typically reserved for system accounts.
+option is used. The value must be non\-negative. The default is to use the smallest ID value greater than 499 and greater than every other group. Values between 0 and 499 are typically reserved for system accounts.
 .TP
 \fB\-K \fR\fB\fIKEY\fR\fR\fB=\fR\fB\fIVALUE\fR\fR
 Overrides /etc/login.defs defaults (GID_MIN, GID_MAX and others). Multiple 
@@ -46,6 +46,15 @@
 .TP
 \fB\-o\fR
 Allow add group wit non\-unique GID.
+
+.TP
+\fB\-r\fR
+This flag instructs \fBgroupadd\fR to add a system
+account. The first available \fIgid\fR lower than 499 will be
+automatically selected unless the \fB-g\fR option is also given on the command line.
+.br
+This is an option added by Red Hat.
+
 .SH "FILES"
 .TP
 \fI/etc/group\fR
--- shadow-4.0.12/man/useradd.8.mdk	2005-08-10 10:58:05.000000000 +0200
+++ shadow-4.0.12/man/useradd.8	2005-09-13 16:11:22.000000000 +0200
@@ -23,7 +23,7 @@
 \fB\-D\fR 
 option, the 
 \fBuseradd\fR 
-command creates a new user account using the values specified on the command line and the default values from the system. Depending on command line options, the useradd command will update system files and may also create the new user's home directory and copy initial files.
+command creates a new user account using the values specified on the command line and the default values from the system. Depending on command line options, the useradd command will update system files and may also create the new user's home directory and copy initial files. The version provided with Mandriva Linux will create a group for each user added to the system, unless the \fB-n\fR option is given.
 .SH "OPTIONS"
 .PP
 The options which apply to the 
@@ -87,6 +87,17 @@
 \fB\-m\fR 
 option. The default is to not create the directory and to not copy any files.
 .TP
+\fB\-M\fR
+The user's home directory will not be created, even if the system
+wise settings from \fI/etc/login.defs\fR is to create home dirs.
+
+.TP
+\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 Mandriva
+Linux specific behaviour.
+
+.TP
 \fB\-K\fR, \fB\-\-key\fR \fIKEY\fR=\fIVALUE\fR
 Overrides /etc/login.defs defaults (UID_MIN, UID_MAX, UMASK, PASS_MAX_DAYS and others). For example: 
 \fB\-K\fR \fIPASS_MAX_DAYS\fR=\fI\-1\fR 
@@ -106,6 +117,16 @@
 The encrypted password, as returned by 
 \fBcrypt\fR(3). The default is to disable the account.
 .TP
+\fB\-r\fR
+This flag is used to create a system account. That is, a user with a UID lower
+than the value of UID_MIN defined in \fI/etc/login.defs\fR and whose
+password does not expire. Note that \fBuseradd\fR will not create a home
+directory for such a 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 Mandriva.
+.TP
 \fB\-s\fR, \fB\-\-shell\fR \fISHELL\fR
 The name of the user's login shell. The default is to leave this field blank, which causes the system to select the default login shell.
 .TP
@@ -162,9 +183,15 @@
 \fI/etc/group\fR
 group account information
 .TP
+\fI/etc/gshadow\fR
+secure group infromation
+.TP
 \fI/etc/default/useradd\fR
 default information
 .TP
+\fI/etc/login.defs\fR
+system-wide settings
+.TP
 \fI/etc/skel/\fR
 directory containing default files
 .SH "EXIT VALUES"
--- shadow-4.0.12/src/useradd.c.mdk	2005-08-11 18:23:34.000000000 +0200
+++ shadow-4.0.12/src/useradd.c	2005-09-13 16:11:45.000000000 +0200
@@ -71,7 +71,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 = "/sbin/nologin";
 static const char *def_template = SKEL_DIR;
 static const char *def_create_mail_spool = "no";
 
@@ -83,7 +83,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 = "";
@@ -114,8 +114,10 @@
     Gflg = 0,			/* secondary group set for new account */
     kflg = 0,			/* specify a directory to fill new user directory */
     mflg = 0,			/* create user's home directory if it doesn't exist */
-    nflg = 0,			/* create a group having the same name as the user */
+    Mflg = 0,			/* do NOT create user's home directory no matter what */
+    nflg = 0,			/* do NOT create a group having the same name as the user */
     oflg = 0,			/* permit non-unique user ID to be specified with -u */
+    rflg = 0,			/* create a system account */
     sflg = 0,			/* shell program for new account */
     uflg = 0;			/* specify user ID for new account */
 
@@ -650,10 +652,14 @@
 			   "  -K, --key KEY=VALUE		overrides /etc/login.defs defaults\n"
 			   "  -m, --create-home		create home directory for the new user\n"
 			   "				account\n"
+			   "  -M, 			do not create home directory for the new user\n"
+			   "  -n,			do NOT create a group with the same name\n"
+			   "				as the user\n"	
 			   "  -o, --non-unique		allow create user with duplicate\n"
 			   "				(non-unique) UID\n"
 			   "  -p, --password PASSWORD	use encrypted password for the new user\n"
 			   "				account\n"
+			   "  -r 			create a system account\n"
 			   "  -s, --shell SHELL		the login shell for the new user account\n"
 			   "  -u, --uid UID			force use the UID for the new user account\n"));
 	exit (E_USAGE);
@@ -703,11 +709,19 @@
 	spent->sp_namp = (char *) user_name;
 	spent->sp_pwdp = (char *) user_pass;
 	spent->sp_lstchg = time ((time_t *) 0) / SCALE;
-	spent->sp_min = scale_age (getdef_num ("PASS_MIN_DAYS", -1));
-	spent->sp_max = scale_age (getdef_num ("PASS_MAX_DAYS", -1));
-	spent->sp_warn = scale_age (getdef_num ("PASS_WARN_AGE", -1));
-	spent->sp_inact = scale_age (def_inactive);
-	spent->sp_expire = scale_age (user_expire);
+        if (!rflg) {
+                spent->sp_min = scale_age (getdef_num ("PASS_MIN_DAYS", -1));
+                spent->sp_max = scale_age (getdef_num ("PASS_MAX_DAYS", -1));
+                spent->sp_warn = scale_age (getdef_num ("PASS_WARN_AGE", -1));
+                spent->sp_inact = scale_age (def_inactive);
+                spent->sp_expire = scale_age (user_expire);
+        } else {
+                spent->sp_min = scale_age(-1);
+                spent->sp_max = scale_age(-1);
+                spent->sp_warn = scale_age(-1);
+                spent->sp_inact = scale_age(-1);
+                spent->sp_expire = scale_age(-1);
+        }
 	spent->sp_flag = -1;
 }
 
@@ -728,31 +742,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
@@ -857,8 +847,13 @@
 	const struct passwd *pwd;
 	uid_t uid_min, uid_max;
 
-	uid_min = getdef_unum ("UID_MIN", 100);
-	uid_max = getdef_unum ("UID_MAX", 60000);
+        if (!rflg) {
+                uid_min = getdef_unum ("UID_MIN", 500);
+                uid_max = getdef_unum ("UID_MAX", 60000);
+        } else {
+                uid_min = 1;
+                uid_max = getdef_unum ("UID_MIN", 500) - 1;
+        }
 
 	/*
 	 * Start with some UID value if the user didn't provide us with
@@ -886,7 +881,7 @@
 				 Prog, user_name);
 			exit (E_NAME_IN_USE);
 		}
-		if (uflg && user_id == pwd->pw_uid) {
+		if (!oflg && uflg && user_id == pwd->pw_uid) {
 			fprintf (stderr, _("%s: UID %u is not unique\n"),
 				 Prog, (unsigned int) user_id);
 			exit (E_UID_IN_USE);
@@ -924,6 +919,86 @@
 }
 
 /*
+ * 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 = getdef_num("GID_MIN", 500) - 1;
+       }
+
+       /*
+        * 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 /* glibc 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);
+               }
+       }
+}
+
+/*
  * process_flags - perform command line argument setting
  *
  *	process_flags() interprets the command line arguments and sets
@@ -962,7 +1037,7 @@
 			{NULL, 0, NULL, '\0'}
 		};
 		while ((c =
-			getopt_long (argc, argv, "b:c:d:De:f:g:G:k:K:mMop:s:u:",
+			getopt_long (argc, argv, "b:c:d:De:f:g:G:k:K:mMnop:rs:u:",
 				     long_options, NULL)) != -1) {
 			switch (c) {
 			case 'b':
@@ -1134,11 +1209,23 @@
 				user_id = get_uid (optarg);
 				uflg++;
 				break;
+			case 'n':
+				nflg++;
+				break;
+			case 'r':
+				rflg++;
+				break;
+			case 'M':
+				Mflg++;
+				break;
 			default:
 				usage ();
 			}
 			anyflag++;
 		}
+		if(mflg && Mflg) /* the admin is not decided .. create or not ? */
+			usage();
+
 	}
 	/*
 	 * Certain options are only valid in combination with others.
@@ -1213,7 +1300,6 @@
 				 _("%s: cannot rewrite group file\n"), Prog);
 			fail_exit (E_GRP_UPDATE);
 		}
-		gr_unlock ();
 #ifdef	SHADOWGRP
 		if (is_shadow_grp && !sgr_close ()) {
 			fprintf (stderr,
@@ -1226,9 +1312,6 @@
 			sgr_unlock ();
 #endif
 	}
-	if (is_shadow_pwd)
-		spw_unlock ();
-	pw_unlock ();
 }
 
 /*
@@ -1261,6 +1344,31 @@
 		pw_unlock ();
 		exit (E_PW_UPDATE);
 	}
+        /*
+         * 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*/
 }
 
 
@@ -1367,6 +1475,118 @@
 		grp_update ();
 }
 
+/* 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);
+       grent->gr_name = (char *) 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);
+       sgent->sg_name = (char *) 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++;
+}
+
 /*
  * create_home - create the user's home directory
  *
@@ -1541,13 +1761,21 @@
 		exit (E_NAME_IN_USE);
 	}
 
+	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;
+
 	/*
 	 * Don't blindly overwrite a group when a user is added...
 	 * If you already have a group username, and want to add the user
 	 * to that group, use useradd -g username username.
 	 * --bero
 	 */
-	if (!gflg) {
+	if ( !(nflg || gflg) ) {
 		if (getgrnam (user_name)) {
 			fprintf (stderr,
 				 _
@@ -1569,6 +1797,18 @@
 
 	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 */
+ 	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) {
@@ -1581,25 +1821,20 @@
 				 ("%s: warning: the home directory already exists.\n"
 				  "Not copying any file from skel directory into it.\n"), Prog);
 
-	} 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);
 	}
-
+ 	/* Warning removed to protect the innocent. */
+ 	/*
+ 	 * 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 begin
+          * with --gafton
+          */
+ 
+ 
 	create_mail ();
 
 	nscd_flush_cache ("passwd");
--- shadow-4.0.12/src/userdel.c.mdk	2005-08-11 18:23:34.000000000 +0200
+++ shadow-4.0.12/src/userdel.c	2005-09-13 16:11:22.000000000 +0200
@@ -59,7 +59,9 @@
 #define E_HOMEDIR	12	/* can't remove home directory */
 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;
@@ -228,6 +230,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
  *
@@ -379,7 +475,8 @@
 			continue;
 		fprintf (stderr,
 			 _("%s: user %s is currently logged in\n"), Prog, name);
-		exit (E_USER_BUSY);
+		if (!fflg)
+			exit (E_USER_BUSY);
 	}
 }
 
@@ -508,6 +605,7 @@
 int main (int argc, char **argv)
 {
 	struct passwd *pwd;
+	struct group *grp;
 	int arg;
 	int errors = 0;
 
@@ -607,6 +705,10 @@
 #endif
 	user_id = pwd->pw_uid;
 	user_home = xstrdup (pwd->pw_dir);
+	user_gid = pwd->pw_gid;
+	grp = getgrgid(user_gid);
+	if (grp)
+		user_group = xstrdup(grp->gr_name);
 	/*
 	 * Check to make certain the user isn't logged in.
 	 */
@@ -659,6 +761,9 @@
 	}
 #endif
 
+	/* Remove the user's group if appropriate. */
+	remove_group();
+
 	if (rflg) {
 		if (remove_tree (user_home)
 		    || rmdir (user_home)) {
--- shadow-4.0.12/src/groupadd.c.mdk	2005-08-11 15:45:41.000000000 +0200
+++ shadow-4.0.12/src/groupadd.c	2005-09-13 16:12:08.000000000 +0200
@@ -73,6 +73,8 @@
 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 (Red Hat) */
+
 
 /* local function prototypes */
 static void usage (void);
@@ -104,7 +106,8 @@
 			   "  -h, --help			display this help message and exit\n"
 			   "  -K, --key KEY=VALUE		overrides /etc/login.defs defaults\n"
 			   "  -o, --non-unique		allow create group with duplicate\n"
-			   "				(non-unique) GID\n"));
+			   "				(non-unique) GID\n"
+			   "  -r 			create a system group\n"));
 	exit (E_USAGE);
 }
 
@@ -197,8 +200,13 @@
 	const struct group *grp;
 	gid_t gid_min, gid_max;
 
-	gid_min = getdef_unum ("GID_MIN", 100);
-	gid_max = getdef_unum ("GID_MAX", 60000);
+	if (!rflg) {
+		gid_min = getdef_unum ("GID_MIN", 500);
+		gid_max = getdef_unum ("GID_MAX", 60000);
+	} else {
+		gid_min = 1;
+		gid_max = getdef_unum ("GID_MIN", 500) - 1;
+	}
 
 	/*
 	 * Start with some GID value if the user didn't provide us with
@@ -409,7 +417,7 @@
 		};
 
 		while ((c =
-			getopt_long (argc, argv, "fg:hK:o", long_options,
+			getopt_long (argc, argv, "fg:hK:or", long_options,
 				     &option_index)) != -1) {
 			switch (c) {
 			case 'f':
@@ -460,7 +468,13 @@
 			case 'o':
 				oflg++;
 				break;
-			default:
+ 			case 'r':
+ 		       		/*
+ 				* create a system group
+ 				*/
+ 				rflg++;
+ 				break;
+			 default:
 				usage ();
 			}
 		}