xref: /titanic_51/usr/src/lib/libcmdutils/common/uid.c (revision a7fe1d5bb55904d4c79638b8778bc9dd8ed7fd7b)
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