1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * Copyright (c) 2013 RackTop Systems.
31 */
32
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <stdio.h>
36 #include <grp.h>
37 #include <libcmdutils.h>
38
39 static int findunusedgid(gid_t start, gid_t stop, gid_t *ret);
40 static boolean_t isreservedgid(gid_t gid);
41
42 /*
43 * Find the highest unused uid. If the highest unused gid is "stop",
44 * then attempt to find a hole in the range. Returns 0 on success.
45 */
46 int
47 findnextgid(gid_t start, gid_t stop, gid_t *ret)
48 {
49 gid_t gid = start;
50 struct group *grp;
51 boolean_t overflow = B_FALSE;
52
53 setgrent();
54 for (grp = getgrent(); grp != NULL; grp = getgrent()) {
55 if (isreservedgid(grp->gr_gid)) /* Skip reserved IDs */
56 continue;
57 if (grp->gr_gid >= gid) {
58 if (grp->gr_gid == stop) { /* Overflow check */
59 overflow = B_TRUE;
60 break;
61 }
62 gid = grp->gr_gid + 1;
63 }
64 }
65 if (grp == NULL && errno != 0) {
66 endgrent();
67 return (-1);
68 }
69 endgrent();
70 if (overflow == B_TRUE) /* Find a hole */
71 return (findunusedgid(start, stop, ret));
72 while (isreservedgid(gid) && gid < stop) /* Skip reserved IDs */
73 gid++;
74 *ret = gid;
75 return (0);
76 }
77
78 /*
79 * Check to see whether the gid is a reserved gid
80 * -- nobody, noaccess or nogroup
81 */
82 static boolean_t
83 isreservedgid(gid_t gid)
84 {
85 return (gid == 60001 || gid == 60002 || gid == 65534);
86 }
87
88 /*
89 * findunusedgid() attempts to return the next valid usable id between the
90 * supplied upper and lower limits. Returns 0 on success.
91 */
92 static int
93 findunusedgid(gid_t start, gid_t stop, gid_t *ret)
94 {
95 gid_t gid;
96
97 for (gid = start; gid <= stop; gid++) {
98 if (isreservedgid(gid))
99 continue;
100 if (getgrgid(gid) == NULL) {
101 if (errno != 0)
102 return (-1);
103 break;
104 }
105 }
106 if (gid > stop)
107 return (-1);
108 *ret = gid;
109 return (0);
110 }