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