Module Name:    src
Committed By:   mlelstv
Date:           Thu Dec 31 19:59:31 UTC 2009

Modified Files:
        src/usr.sbin/user: user.c usermgmt.conf.5

Log Message:
Add new keyword gid_range to usermgmt.conf which specifies a default
GID range for groupadd(8).


To generate a diff of this commit:
cvs rdiff -u -r1.124 -r1.125 src/usr.sbin/user/user.c
cvs rdiff -u -r1.5 -r1.6 src/usr.sbin/user/usermgmt.conf.5

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/user/user.c
diff -u src/usr.sbin/user/user.c:1.124 src/usr.sbin/user/user.c:1.125
--- src/usr.sbin/user/user.c:1.124	Thu Oct 15 23:03:02 2009
+++ src/usr.sbin/user/user.c	Thu Dec 31 19:59:31 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: user.c,v 1.124 2009/10/15 23:03:02 hubertf Exp $ */
+/* $NetBSD: user.c,v 1.125 2009/12/31 19:59:31 mlelstv Exp $ */
 
 /*
  * Copyright (c) 1999 Alistair G. Crooks.  All rights reserved.
@@ -33,7 +33,7 @@
 #ifndef lint
 __COPYRIGHT("@(#) Copyright (c) 1999\
  The NetBSD Foundation, Inc.  All rights reserved.");
-__RCSID("$NetBSD: user.c,v 1.124 2009/10/15 23:03:02 hubertf Exp $");
+__RCSID("$NetBSD: user.c,v 1.125 2009/12/31 19:59:31 mlelstv Exp $");
 #endif
 
 #include <sys/types.h>
@@ -71,7 +71,14 @@
 	int	r_to;		/* high uid */
 } range_t;
 
-/* this struct encapsulates the user information */
+typedef struct rangelist_t {
+	unsigned	rl_rsize;		/* size of range array */
+	unsigned	rl_rc;			/* # of ranges */
+	range_t	       *rl_rv;			/* the ranges */
+	unsigned	rl_defrc;		/* # of ranges in defaults */
+} rangelist_t;
+
+/* this struct encapsulates the user and group information */
 typedef struct user_t {
 	int		u_flags;		/* see below */
 	int		u_uid;			/* uid of user */
@@ -88,14 +95,30 @@
 	char	       *u_inactive;		/* when account will expire */
 	char	       *u_skeldir;		/* directory for startup files */
 	char	       *u_class;		/* login class */
-	unsigned	u_rsize;		/* size of range array */
-	unsigned	u_rc;			/* # of ranges */
-	range_t	       *u_rv;			/* the ranges */
+	rangelist_t 	u_r;			/* list of ranges */
 	unsigned	u_defrc;		/* # of ranges in defaults */
 	int		u_preserve;		/* preserve uids on deletion */
 	int		u_allow_samba;		/* allow trailing '$' for samba login names */
 	int		u_locked;		/* user account lock */
 } user_t;
+#define u_rsize u_r.rl_rsize
+#define u_rc    u_r.rl_rc
+#define u_rv    u_r.rl_rv
+#define u_defrc u_r.rl_defrc
+
+/* this struct encapsulates the user and group information */
+typedef struct group_t {
+	rangelist_t	g_r;			/* list of ranges */
+} group_t;
+#define g_rsize g_r.rl_rsize
+#define g_rc    g_r.rl_rc
+#define g_rv    g_r.rl_rv
+#define g_defrc g_r.rl_defrc
+
+typedef struct def_t {
+	user_t user;
+	group_t group;
+} def_t;
 
 /* flags for which fields of the user_t replace the passwd entry */
 enum {
@@ -182,9 +205,6 @@
 	PasswordLength = 2048,
 
 	DES_Len = 13,
-
-	LowGid = DEF_LOWUID,
-	HighGid = DEF_HIGHUID
 };
 
 /* Full paths of programs used here */
@@ -682,30 +702,30 @@
 #ifdef EXTENSIONS
 /* save a range of uids */
 static int
-save_range(user_t *up, char *cp)
+save_range(rangelist_t *rlp, char *cp)
 {
 	int	from;
 	int	to;
 	int	i;
 
-	if (up->u_rsize == 0) {
-		up->u_rsize = 32;
-		NEWARRAY(range_t, up->u_rv, up->u_rsize, return(0));
-	} else if (up->u_rc == up->u_rsize) {
-		up->u_rsize *= 2;
-		RENEW(range_t, up->u_rv, up->u_rsize, return(0));
-	}
-	if (up->u_rv && sscanf(cp, "%d..%d", &from, &to) == 2) {
-		for (i = up->u_defrc ; i < up->u_rc ; i++) {
-			if (up->u_rv[i].r_from == from &&
-			    up->u_rv[i].r_to == to) {
+	if (rlp->rl_rsize == 0) {
+		rlp->rl_rsize = 32;
+		NEWARRAY(range_t, rlp->rl_rv, rlp->rl_rsize, return(0));
+	} else if (rlp->rl_rc == rlp->rl_rsize) {
+		rlp->rl_rsize *= 2;
+		RENEW(range_t, rlp->rl_rv, rlp->rl_rsize, return(0));
+	}
+	if (rlp->rl_rv && sscanf(cp, "%d..%d", &from, &to) == 2) {
+		for (i = rlp->rl_defrc ; i < rlp->rl_rc ; i++) {
+			if (rlp->rl_rv[i].r_from == from &&
+			    rlp->rl_rv[i].r_to == to) {
 				break;
 			}
 		}
-		if (i == up->u_rc) {
-			up->u_rv[up->u_rc].r_from = from;
-			up->u_rv[up->u_rc].r_to = to;
-			up->u_rc += 1;
+		if (i == rlp->rl_rc) {
+			rlp->rl_rv[rlp->rl_rc].r_from = from;
+			rlp->rl_rv[rlp->rl_rc].r_to = to;
+			rlp->rl_rc += 1;
 		}
 	} else {
 		warnx("Bad range `%s'", cp);
@@ -778,7 +798,7 @@
 
 /* read the defaults file */
 static void
-read_defaults(user_t *up)
+read_defaults(def_t *dp)
 {
 	struct stat	st;
 	size_t		lineno;
@@ -786,6 +806,10 @@
 	FILE		*fp;
 	char		*cp;
 	char		*s;
+	user_t		*up = &dp->user;
+	group_t		*gp = &dp->group;
+
+	(void)memset(dp, 0, sizeof(*dp));
 
 	memsave(&up->u_primgrp, DEF_GROUP, strlen(DEF_GROUP));
 	memsave(&up->u_basedir, DEF_BASEDIR, strlen(DEF_BASEDIR));
@@ -800,6 +824,9 @@
 	NEWARRAY(range_t, up->u_rv, up->u_rsize, exit(1));
 	up->u_inactive = DEF_INACTIVE;
 	up->u_expire = DEF_EXPIRE;
+	gp->g_rsize = 16;
+	gp->g_defrc = 0;
+	NEWARRAY(range_t, gp->g_rv, gp->g_rsize, exit(1));
 	if ((fp = fopen(_PATH_USERMGMT_CONF, "r")) == NULL) {
 		if (stat(_PATH_USERMGMT_CONF, &st) < 0 && !setdefaults(up)) {
 			warn("Can't create `%s' defaults file",
@@ -846,7 +873,7 @@
 #ifdef EXTENSIONS
 			} else if (strncmp(s, "range", 5) == 0) {
 				cp = skipspace(s + 5);
-				(void)save_range(up, cp);
+				(void)save_range(&up->u_r, cp);
 #endif
 #ifdef EXTENSIONS
 			} else if (strncmp(s, "preserve", 8) == 0) {
@@ -865,6 +892,11 @@
 				} else {
 					memsave(&up->u_expire, cp, strlen(cp));
 				}
+#ifdef EXTENSIONS
+			} else if (strncmp(s, "gid_range", 9) == 0) {
+				cp = skipspace(s + 9);
+				(void)save_range(&gp->g_r, cp);
+#endif
 			}
 			(void)free(s);
 		}
@@ -1808,7 +1840,8 @@
 int
 useradd(int argc, char **argv)
 {
-	user_t	u;
+	def_t	def;
+	user_t	*up = &def.user;
 	int	defaultfield;
 	int	bigD;
 	int	c;
@@ -1816,9 +1849,8 @@
 	int	i;
 #endif
 
-	(void)memset(&u, 0, sizeof(u));
-	read_defaults(&u);
-	u.u_uid = -1;
+	read_defaults(&def);
+	up->u_uid = -1;
 	defaultfield = bigD = 0;
 	while ((c = getopt(argc, argv, "DFG:b:c:d:e:f:g:k:mou:s:"
 	    ADD_OPT_EXTENSIONS)) != -1) {
@@ -1833,13 +1865,13 @@
 			 * next log in - passwd(5).
 			 */
 			defaultfield = 1;
-			memsave(&u.u_inactive, "-1", strlen("-1"));
+			memsave(&up->u_inactive, "-1", strlen("-1"));
 			break;
 		case 'G':
-			while (u.u_groupc < NGROUPS_MAX  &&
-			       (u.u_groupv[u.u_groupc] = strsep(&optarg, ",")) != NULL) {
-				if (u.u_groupv[u.u_groupc][0] != 0) {
-					u.u_groupc++;
+			while (up->u_groupc < NGROUPS_MAX  &&
+			       (up->u_groupv[up->u_groupc] = strsep(&optarg, ",")) != NULL) {
+				if (up->u_groupv[up->u_groupc][0] != 0) {
+					up->u_groupc++;
 				}
 			}
 			if (optarg != NULL) {
@@ -1849,72 +1881,72 @@
 			break;
 #ifdef EXTENSIONS
 		case 'S':
-			u.u_allow_samba = 1;
+			up->u_allow_samba = 1;
 			break;
 #endif
 		case 'b':
 			defaultfield = 1;
-			memsave(&u.u_basedir, optarg, strlen(optarg));
+			memsave(&up->u_basedir, optarg, strlen(optarg));
 			break;
 		case 'c':
-			memsave(&u.u_comment, optarg, strlen(optarg));
+			memsave(&up->u_comment, optarg, strlen(optarg));
 			break;
 		case 'd':
-			memsave(&u.u_home, optarg, strlen(optarg));
-			u.u_flags |= F_HOMEDIR;
+			memsave(&up->u_home, optarg, strlen(optarg));
+			up->u_flags |= F_HOMEDIR;
 			break;
 		case 'e':
 			defaultfield = 1;
-			memsave(&u.u_expire, optarg, strlen(optarg));
+			memsave(&up->u_expire, optarg, strlen(optarg));
 			break;
 		case 'f':
 			defaultfield = 1;
-			memsave(&u.u_inactive, optarg, strlen(optarg));
+			memsave(&up->u_inactive, optarg, strlen(optarg));
 			break;
 		case 'g':
 			defaultfield = 1;
-			memsave(&u.u_primgrp, optarg, strlen(optarg));
+			memsave(&up->u_primgrp, optarg, strlen(optarg));
 			break;
 		case 'k':
 			defaultfield = 1;
-			memsave(&u.u_skeldir, optarg, strlen(optarg));
+			memsave(&up->u_skeldir, optarg, strlen(optarg));
 			break;
 #ifdef EXTENSIONS
 		case 'L':
 			defaultfield = 1;
-			memsave(&u.u_class, optarg, strlen(optarg));
+			memsave(&up->u_class, optarg, strlen(optarg));
 			break;
 #endif
 		case 'm':
-			u.u_flags |= F_MKDIR;
+			up->u_flags |= F_MKDIR;
 			break;
 #ifdef EXTENSIONS
 		case 'M':
 			defaultfield = 1;
-			u.u_homeperm = strtoul(optarg, NULL, 8);
+			up->u_homeperm = strtoul(optarg, NULL, 8);
 			break;
 #endif
 		case 'o':
-			u.u_flags |= F_DUPUID;
+			up->u_flags |= F_DUPUID;
 			break;
 #ifdef EXTENSIONS
 		case 'p':
-			memsave(&u.u_password, optarg, strlen(optarg));
+			memsave(&up->u_password, optarg, strlen(optarg));
 			break;
 #endif
 #ifdef EXTENSIONS
 		case 'r':
 			defaultfield = 1;
-			(void)save_range(&u, optarg);
+			(void)save_range(&up->u_r, optarg);
 			break;
 #endif
 		case 's':
-			u.u_flags |= F_SHELL;
+			up->u_flags |= F_SHELL;
 			defaultfield = 1;
-			memsave(&u.u_shell, optarg, strlen(optarg));
+			memsave(&up->u_shell, optarg, strlen(optarg));
 			break;
 		case 'u':
-			u.u_uid = check_numeric(optarg, "uid");
+			up->u_uid = check_numeric(optarg, "uid");
 			break;
 #ifdef EXTENSIONS
 		case 'v':
@@ -1929,24 +1961,24 @@
 	if (bigD) {
 		if (defaultfield) {
 			checkeuid();
-			return setdefaults(&u) ? EXIT_SUCCESS : EXIT_FAILURE;
+			return setdefaults(up) ? EXIT_SUCCESS : EXIT_FAILURE;
 		}
-		(void)printf("group\t\t%s\n", u.u_primgrp);
-		(void)printf("base_dir\t%s\n", u.u_basedir);
-		(void)printf("skel_dir\t%s\n", u.u_skeldir);
-		(void)printf("shell\t\t%s\n", u.u_shell);
-#ifdef EXTENSIONS
-		(void)printf("class\t\t%s\n", u.u_class);
-		(void)printf("homeperm\t0%o\n", u.u_homeperm);
-#endif
-		(void)printf("inactive\t%s\n", (u.u_inactive == NULL) ?
-		    UNSET_INACTIVE : u.u_inactive);
-		(void)printf("expire\t\t%s\n", (u.u_expire == NULL) ?
-		    UNSET_EXPIRY : u.u_expire);
+		(void)printf("group\t\t%s\n", up->u_primgrp);
+		(void)printf("base_dir\t%s\n", up->u_basedir);
+		(void)printf("skel_dir\t%s\n", up->u_skeldir);
+		(void)printf("shell\t\t%s\n", up->u_shell);
+#ifdef EXTENSIONS
+		(void)printf("class\t\t%s\n", up->u_class);
+		(void)printf("homeperm\t0%o\n", up->u_homeperm);
+#endif
+		(void)printf("inactive\t%s\n", (up->u_inactive == NULL) ?
+		    UNSET_INACTIVE : up->u_inactive);
+		(void)printf("expire\t\t%s\n", (up->u_expire == NULL) ?
+		    UNSET_EXPIRY : up->u_expire);
 #ifdef EXTENSIONS
-		for (i = 0 ; i < u.u_rc ; i++) {
+		for (i = 0 ; i < up->u_rc ; i++) {
 			(void)printf("range\t\t%d..%d\n",
-			    u.u_rv[i].r_from, u.u_rv[i].r_to);
+			    up->u_rv[i].r_from, up->u_rv[i].r_to);
 		}
 #endif
 		return EXIT_SUCCESS;
@@ -1958,7 +1990,7 @@
 	}
 	checkeuid();
 	openlog("useradd", LOG_PID, LOG_USER);
-	return adduser(*argv, &u) ? EXIT_SUCCESS : EXIT_FAILURE;
+	return adduser(*argv, up) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 #ifdef EXTENSIONS
@@ -1970,46 +2002,46 @@
 int
 usermod(int argc, char **argv)
 {
-	user_t	u;
+	def_t	def;
+	user_t	*up = &def.user;
 	char	newuser[MaxUserNameLen + 1];
 	int	c, have_new_user;
 
-	(void)memset(&u, 0, sizeof(u));
 	(void)memset(newuser, 0, sizeof(newuser));
-	read_defaults(&u);
+	read_defaults(&def);
 	have_new_user = 0;
-	u.u_locked = -1;
+	up->u_locked = -1;
 	while ((c = getopt(argc, argv, "C:FG:c:d:e:f:g:l:mos:u:"
 	    MOD_OPT_EXTENSIONS)) != -1) {
 		switch(c) {
 		case 'G':
-			while (u.u_groupc < NGROUPS_MAX &&
-			    (u.u_groupv[u.u_groupc] =
+			while (up->u_groupc < NGROUPS_MAX &&
+			    (up->u_groupv[up->u_groupc] =
 			    strsep(&optarg, ",")) != NULL) {
-				if (u.u_groupv[u.u_groupc][0] != 0) {
-					u.u_groupc++;
+				if (up->u_groupv[up->u_groupc][0] != 0) {
+					up->u_groupc++;
 				}
 			}
 			if (optarg != NULL) {
 				warnx("Truncated list of secondary groups "
 				    "to %d entries", NGROUPS_MAX);
 			}
-			u.u_flags |= F_SECGROUP;
+			up->u_flags |= F_SECGROUP;
 			break;
 #ifdef EXTENSIONS
 		case 'S':
-			u.u_allow_samba = 1;
+			up->u_allow_samba = 1;
 			break;
 #endif
 		case 'c':
-			memsave(&u.u_comment, optarg, strlen(optarg));
-			u.u_flags |= F_COMMENT;
+			memsave(&up->u_comment, optarg, strlen(optarg));
+			up->u_flags |= F_COMMENT;
 			break;
 		case 'C':
 			if (strcasecmp(optarg, "yes") == 0) {
-				u.u_locked = LOCK;
+				up->u_locked = LOCK;
 			} else if (strcasecmp(optarg, "no") == 0) {
-				u.u_locked = UNLOCK;
+				up->u_locked = UNLOCK;
 			} else {
 				/* No idea. */
 				errx(EXIT_FAILURE,
@@ -2017,55 +2049,55 @@
 			}
 			break;
 		case 'F':
-			memsave(&u.u_inactive, "-1", strlen("-1"));
-			u.u_flags |= F_INACTIVE;
+			memsave(&up->u_inactive, "-1", strlen("-1"));
+			up->u_flags |= F_INACTIVE;
 			break;
 		case 'd':
-			memsave(&u.u_home, optarg, strlen(optarg));
-			u.u_flags |= F_HOMEDIR;
+			memsave(&up->u_home, optarg, strlen(optarg));
+			up->u_flags |= F_HOMEDIR;
 			break;
 		case 'e':
-			memsave(&u.u_expire, optarg, strlen(optarg));
-			u.u_flags |= F_EXPIRE;
+			memsave(&up->u_expire, optarg, strlen(optarg));
+			up->u_flags |= F_EXPIRE;
 			break;
 		case 'f':
-			memsave(&u.u_inactive, optarg, strlen(optarg));
-			u.u_flags |= F_INACTIVE;
+			memsave(&up->u_inactive, optarg, strlen(optarg));
+			up->u_flags |= F_INACTIVE;
 			break;
 		case 'g':
-			memsave(&u.u_primgrp, optarg, strlen(optarg));
-			u.u_flags |= F_GROUP;
+			memsave(&up->u_primgrp, optarg, strlen(optarg));
+			up->u_flags |= F_GROUP;
 			break;
 		case 'l':
 			(void)strlcpy(newuser, optarg, sizeof(newuser));
 			have_new_user = 1;
-			u.u_flags |= F_USERNAME;
+			up->u_flags |= F_USERNAME;
 			break;
 #ifdef EXTENSIONS
 		case 'L':
-			memsave(&u.u_class, optarg, strlen(optarg));
-			u.u_flags |= F_CLASS;
+			memsave(&up->u_class, optarg, strlen(optarg));
+			up->u_flags |= F_CLASS;
 			break;
 #endif
 		case 'm':
-			u.u_flags |= F_MKDIR;
+			up->u_flags |= F_MKDIR;
 			break;
 		case 'o':
-			u.u_flags |= F_DUPUID;
+			up->u_flags |= F_DUPUID;
 			break;
 #ifdef EXTENSIONS
 		case 'p':
-			memsave(&u.u_password, optarg, strlen(optarg));
-			u.u_flags |= F_PASSWORD;
+			memsave(&up->u_password, optarg, strlen(optarg));
+			up->u_flags |= F_PASSWORD;
 			break;
 #endif
 		case 's':
-			memsave(&u.u_shell, optarg, strlen(optarg));
-			u.u_flags |= F_SHELL;
+			memsave(&up->u_shell, optarg, strlen(optarg));
+			up->u_flags |= F_SHELL;
 			break;
 		case 'u':
-			u.u_uid = check_numeric(optarg, "uid");
-			u.u_flags |= F_UID;
+			up->u_uid = check_numeric(optarg, "uid");
+			up->u_flags |= F_UID;
 			break;
 #ifdef EXTENSIONS
 		case 'v':
@@ -2077,10 +2109,10 @@
 			/* NOTREACHED */
 		}
 	}
-	if ((u.u_flags & F_MKDIR) && !(u.u_flags & F_HOMEDIR) &&
-	    !(u.u_flags & F_USERNAME)) {
+	if ((up->u_flags & F_MKDIR) && !(up->u_flags & F_HOMEDIR) &&
+	    !(up->u_flags & F_USERNAME)) {
 		warnx("Option 'm' useless without 'd' or 'l' -- ignored");
-		u.u_flags &= ~F_MKDIR;
+		up->u_flags &= ~F_MKDIR;
 	}
 	argc -= optind;
 	argv += optind;
@@ -2089,8 +2121,8 @@
 	}
 	checkeuid();
 	openlog("usermod", LOG_PID, LOG_USER);
-	return moduser(*argv, (have_new_user) ? newuser : *argv, &u,
-	    u.u_allow_samba) ? EXIT_SUCCESS : EXIT_FAILURE;
+	return moduser(*argv, (have_new_user) ? newuser : *argv, up,
+	    up->u_allow_samba) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 #ifdef EXTENSIONS
@@ -2103,15 +2135,15 @@
 userdel(int argc, char **argv)
 {
 	struct passwd	*pwp;
-	user_t		u;
+	def_t		def;
+	user_t		*up = &def.user;
 	char		password[PasswordLength + 1];
 	int		defaultfield;
 	int		rmhome;
 	int		bigD;
 	int		c;
 
-	(void)memset(&u, 0, sizeof(u));
-	read_defaults(&u);
+	read_defaults(&def);
 	defaultfield = bigD = rmhome = 0;
 	while ((c = getopt(argc, argv, "r" DEL_OPT_EXTENSIONS)) != -1) {
 		switch(c) {
@@ -2122,13 +2154,13 @@
 #endif
 #ifdef EXTENSIONS
 		case 'S':
-			u.u_allow_samba = 1;
+			up->u_allow_samba = 1;
 			break;
 #endif
 #ifdef EXTENSIONS
 		case 'p':
 			defaultfield = 1;
-			u.u_preserve = (strcmp(optarg, "true") == 0) ? 1 :
+			up->u_preserve = (strcmp(optarg, "true") == 0) ? 1 :
 					(strcmp(optarg, "yes") == 0) ? 1 :
 					 atoi(optarg);
 			break;
@@ -2150,9 +2182,9 @@
 	if (bigD) {
 		if (defaultfield) {
 			checkeuid();
-			return setdefaults(&u) ? EXIT_SUCCESS : EXIT_FAILURE;
+			return setdefaults(up) ? EXIT_SUCCESS : EXIT_FAILURE;
 		}
-		(void)printf("preserve\t%s\n", (u.u_preserve) ? "true" :
+		(void)printf("preserve\t%s\n", (up->u_preserve) ? "true" :
 		    "false");
 		return EXIT_SUCCESS;
 	}
@@ -2170,22 +2202,22 @@
 	if (rmhome) {
 		(void)removehomedir(pwp);
 	}
-	if (u.u_preserve) {
-		u.u_flags |= F_SHELL;
-		memsave(&u.u_shell, NOLOGIN, strlen(NOLOGIN));
+	if (up->u_preserve) {
+		up->u_flags |= F_SHELL;
+		memsave(&up->u_shell, NOLOGIN, strlen(NOLOGIN));
 		(void)memset(password, '*', DES_Len);
 		password[DES_Len] = 0;
-		memsave(&u.u_password, password, strlen(password));
-		u.u_flags |= F_PASSWORD;
+		memsave(&up->u_password, password, strlen(password));
+		up->u_flags |= F_PASSWORD;
 		openlog("userdel", LOG_PID, LOG_USER);
-		return moduser(*argv, *argv, &u, u.u_allow_samba) ?
+		return moduser(*argv, *argv, up, up->u_allow_samba) ?
 		    EXIT_SUCCESS : EXIT_FAILURE;
 	}
 	if (!rm_user_from_groups(*argv)) {
 		return 0;
 	}
 	openlog("userdel", LOG_PID, LOG_USER);
-	return moduser(*argv, *argv, NULL, u.u_allow_samba) ?
+	return moduser(*argv, *argv, NULL, up->u_allow_samba) ?
 	    EXIT_SUCCESS : EXIT_FAILURE;
 }
 
@@ -2199,16 +2231,15 @@
 int
 groupadd(int argc, char **argv)
 {
+	def_t	def;
+	group_t	*gp = &def.group;
 	int	dupgid;
 	int	gid;
 	int	c;
-	int	lowgid;
-	int	highgid;
 
 	gid = -1;
 	dupgid = 0;
-	lowgid = LowGid;
-	highgid = HighGid;
+	read_defaults(&def);
 	while ((c = getopt(argc, argv, "g:o" GROUP_ADD_OPT_EXTENSIONS)) != -1) {
 		switch(c) {
 		case 'g':
@@ -2219,9 +2250,7 @@
 			break;
 #ifdef EXTENSIONS
 		case 'r':
-			if (sscanf(optarg, "%d..%d", &lowgid, &highgid) != 2) {
-				errx(EXIT_FAILURE, "Bad range `%s'", optarg);
-			}
+			(void)save_range(&gp->g_r, optarg);
 			break;
 		case 'v':
 			verbose = 1;
@@ -2237,9 +2266,36 @@
 	if (argc != 1) {
 		usermgmt_usage("groupadd");
 	}
+	if (gp->g_rc == 0) {
+		gp->g_rv[gp->g_rc].r_from = DEF_LOWUID;
+		gp->g_rv[gp->g_rc].r_to = DEF_HIGHUID;
+		gp->g_rc += 1;
+	}
+	gp->g_defrc = gp->g_rc;
 	checkeuid();
-	if (gid < 0 && !getnextgid(&gid, lowgid, highgid)) {
-		err(EXIT_FAILURE, "Can't add group: can't get next gid");
+	if (gid == -1) {
+		int	got_id = 0;
+		int	i;
+
+		/*
+		 * Look for a free GID in the command line ranges (if any).
+		 * These start after the ranges specified in the config file.
+		 */
+		for (i = gp->g_defrc; !got_id && i < gp->g_rc ; i++) {
+			got_id = getnextgid(&gid,
+					gp->g_rv[i].r_from, gp->g_rv[i].r_to);
+		}
+		/*
+		 * If there were no free GIDs in the command line ranges,
+		 * try the ranges from the config file (there will always
+		 * be at least one default).
+		 */
+		for (i = 0; !got_id && i < gp->g_defrc; i++) {
+			got_id = getnextgid(&gid,
+					gp->g_rv[i].r_from, gp->g_rv[i].r_to);
+		}
+		if (!got_id)
+			errx(EXIT_FAILURE, "Can't add group: can't get next gid");
 	}
 	if (!dupgid && getgrgid((gid_t) gid) != NULL) {
 		errx(EXIT_FAILURE, "Can't add group: gid %d is a duplicate",

Index: src/usr.sbin/user/usermgmt.conf.5
diff -u src/usr.sbin/user/usermgmt.conf.5:1.5 src/usr.sbin/user/usermgmt.conf.5:1.6
--- src/usr.sbin/user/usermgmt.conf.5:1.5	Fri Jul 18 21:03:03 2008
+++ src/usr.sbin/user/usermgmt.conf.5	Thu Dec 31 19:59:31 2009
@@ -1,4 +1,4 @@
-.\" $NetBSD: usermgmt.conf.5,v 1.5 2008/07/18 21:03:03 apb Exp $
+.\" $NetBSD: usermgmt.conf.5,v 1.6 2009/12/31 19:59:31 mlelstv Exp $
 .\"
 .\" Copyright (c) 2002 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -121,6 +121,14 @@
 .Bd -unfilled -offset indent -compact
 .Ic range Ar starting-uid Ns Li .. Ns Ar ending-uid
 .Ed
+.It Ic gid_range
+specifies the gid boundaries for new groups.
+If unspecified, the default is
+.Dq 1000..60000 .
+It has the format:
+.Bd -unfilled -offset indent -compact
+.Ic gid_range Ar starting-gid Ns Li .. Ns Ar ending-gid
+.Ed
 .It Ic shell
 sets the default login shell for new users.
 .It Ic skel_dir

Reply via email to