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 <userdefs.h> 37 #include <grp.h> 38 #include <libcmdutils.h> 39 40 static int findunusedgid(gid_t start, gid_t stop, gid_t *ret); 41 static boolean_t isreservedgid(gid_t gid); 42 43 /* 44 * Find the highest unused uid. If the highest unused gid is "stop", 45 * then attempt to find a hole in the range. Returns 0 on success. 46 */ 47 int 48 findnextgid(gid_t start, gid_t stop, gid_t *ret) 49 { 50 gid_t gid = start; 51 struct group *grp; 52 boolean_t overflow = B_FALSE; 53 54 setgrent(); 55 for (grp = getgrent(); grp != NULL; grp = getgrent()) { 56 if (isreservedgid(grp->gr_gid)) /* Skip reserved IDs */ 57 continue; 58 if (grp->gr_gid >= gid) { 59 if (grp->gr_gid == stop) { /* Overflow check */ 60 overflow = B_TRUE; 61 break; 62 } 63 gid = grp->gr_gid + 1; 64 } 65 } 66 if (grp == NULL && errno != 0) { 67 endgrent(); 68 return (-1); 69 } 70 endgrent(); 71 if (overflow == B_TRUE) /* Find a hole */ 72 return (findunusedgid(start, stop, ret)); 73 while (isreservedgid(gid) && gid < stop) /* Skip reserved IDs */ 74 gid++; 75 *ret = gid; 76 return (0); 77 } 78 79 /* 80 * Check to see whether the gid is a reserved gid 81 * -- nobody, noaccess or nogroup 82 */ 83 static boolean_t 84 isreservedgid(gid_t gid) 85 { 86 return (gid == 60001 || gid == 60002 || gid == 65534); 87 } 88 89 /* 90 * findunusedgid() attempts to return the next valid usable id between the 91 * supplied upper and lower limits. Returns 0 on success. 92 */ 93 static int 94 findunusedgid(gid_t start, gid_t stop, gid_t *ret) 95 { 96 gid_t gid; 97 98 for (gid = start; gid <= stop; gid++) { 99 if (isreservedgid(gid)) 100 continue; 101 if (getgrgid(gid) == NULL) { 102 if (errno != 0) 103 return (-1); 104 break; 105 } 106 } 107 if (gid > stop) 108 return (-1); 109 *ret = gid; 110 return (0); 111 }