Print this page
4078 groupadd execs getent unnecessarily
Reviewed by: Rich Lowe <richlowe@richlowe.net>
Reviewed by: Gary Mills <gary_mills@fastmail.fm>
Reviewed by: Milan Jurik <milan.jurik@xylab.cz>
Reviewed by: Gordon Ross <Gordon.W.Ross@gmail.com>
@@ -20,90 +20,92 @@
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
+/*
+ * Copyright (c) 2013 RackTop Systems.
+ */
-#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
-
+#include <errno.h>
#include <sys/types.h>
#include <stdio.h>
#include <userdefs.h>
+#include <grp.h>
+#include <libcmdutils.h>
-#include <sys/param.h>
-#ifndef MAXUID
-#include <limits.h>
-#ifdef UID_MAX
-#define MAXUID UID_MAX
-#else
-#define MAXUID 60000
-#endif
-#endif
+static int findunusedgid(gid_t start, gid_t stop, gid_t *ret);
+static boolean_t isreservedgid(gid_t gid);
/*
- * Check to see that the gid is not a reserved gid
- * -- nobody, noaccess or nogroup
+ * Find the highest unused uid. If the highest unused gid is "stop",
+ * then attempt to find a hole in the range. Returns 0 on success.
*/
-static int
-isvalidgid(gid_t gid)
+int
+findnextgid(gid_t start, gid_t stop, gid_t *ret)
{
- return (gid != 60001 && gid != 60002 && gid != 65534);
+ gid_t gid = start;
+ struct group *grp;
+ boolean_t overflow = B_FALSE;
+
+ setgrent();
+ for (grp = getgrent(); grp != NULL; grp = getgrent()) {
+ if (isreservedgid(grp->gr_gid)) /* Skip reserved IDs */
+ continue;
+ if (grp->gr_gid >= gid) {
+ if (grp->gr_gid == stop) { /* Overflow check */
+ overflow = B_TRUE;
+ break;
+ }
+ gid = grp->gr_gid + 1;
+ }
+ }
+ if (grp == NULL && errno != 0) {
+ endgrent();
+ return (-1);
+ }
+ endgrent();
+ if (overflow == B_TRUE) /* Find a hole */
+ return (findunusedgid(start, stop, ret));
+ while (isreservedgid(gid) && gid < stop) /* Skip reserved IDs */
+ gid++;
+ *ret = gid;
+ return (0);
}
-gid_t
-findnextgid()
+/*
+ * Check to see whether the gid is a reserved gid
+ * -- nobody, noaccess or nogroup
+ */
+static boolean_t
+isreservedgid(gid_t gid)
{
- FILE *fptr;
- gid_t last, next;
- gid_t gid;
+ return (gid == 60001 || gid == 60002 || gid == 65534);
+}
- /*
- * Sort the used GIDs in decreasing order to return MAXUSED + 1
+/*
+ * findunusedgid() attempts to return the next valid usable id between the
+ * supplied upper and lower limits. Returns 0 on success.
*/
- if ((fptr = popen("exec sh -c "
- "\"getent group|cut -f3 -d:|sort -nr|uniq \" 2>/dev/null",
- "r")) == NULL)
- return (-1);
+static int
+findunusedgid(gid_t start, gid_t stop, gid_t *ret)
+{
+ gid_t gid;
- if (fscanf(fptr, "%u\n", &next) == EOF) {
- (void) pclose(fptr);
- return (DEFRID + 1);
- }
-
- /*
- * 'next' is now the highest allocated gid.
- *
- * The simplest allocation is where we just add one, and obtain
- * a valid gid. If this fails look for a hole in the gid range ..
- */
-
- last = MAXUID; /* upper limit */
- gid = -1; /* start invalid */
- do {
- if (!isvalidgid(next))
+ for (gid = start; gid <= stop; gid++) {
+ if (isreservedgid(gid))
continue;
-
- if (next <= DEFRID) {
- if (last != DEFRID + 1)
- gid = DEFRID + 1;
+ if (getgrgid(gid) == NULL) {
+ if (errno != 0)
+ return (-1);
break;
}
-
- if ((gid = next + 1) != last) {
- while (!isvalidgid(gid))
- gid++;
- if (gid > 0 && gid < last)
- break;
}
-
- gid = -1;
- last = next;
-
- } while (fscanf(fptr, "%u\n", &next) != EOF);
-
- (void) pclose(fptr);
-
- return (gid);
+ if (gid > stop)
+ return (-1);
+ *ret = gid;
+ return (0);
}