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