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