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 }