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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * files/getgrent.c -- "files" backend for nsswitch "group" database
26  */
27 
28 #include <grp.h>
29 #include <unistd.h>		/* for GF_PATH */
30 #include <stdlib.h>		/* for GF_PATH */
31 #include "files_common.h"
32 #include <strings.h>
33 
34 static uint_t
hash_grname(nss_XbyY_args_t * argp,int keyhash,const char * line,int linelen)35 hash_grname(nss_XbyY_args_t *argp, int keyhash, const char *line,
36 	int linelen)
37 {
38 	const char 	*name;
39 	int		namelen, i;
40 	uint_t		hash = 0;
41 
42 	if (keyhash) {
43 		name = argp->key.name;
44 		namelen = strlen(name);
45 	} else {
46 		name = line;
47 		namelen = 0;
48 		while (linelen-- && *line++ != ':')
49 			namelen++;
50 	}
51 
52 	for (i = 0; i < namelen; i++)
53 		hash = hash * 15 + name[i];
54 	return (hash);
55 }
56 
57 static uint_t
hash_grgid(nss_XbyY_args_t * argp,int keyhash,const char * line,int linelen)58 hash_grgid(nss_XbyY_args_t *argp, int keyhash, const char *line,
59 	int linelen)
60 {
61 	uint_t		id;
62 	const char	*linep, *limit, *end;
63 
64 	linep = line;
65 	limit = line + linelen;
66 
67 	if (keyhash)
68 		return ((uint_t)argp->key.gid);
69 
70 	while (linep < limit && *linep++ != ':') /* skip groupname */
71 		continue;
72 	while (linep < limit && *linep++ != ':') /* skip password */
73 		continue;
74 	if (linep == limit)
75 		return (GID_NOBODY);
76 
77 	/* gid */
78 	end = linep;
79 	id = (uint_t)strtoul(linep, (char **)&end, 10);
80 	/* empty gid */
81 	if (linep == end)
82 		return (GID_NOBODY);
83 
84 	return (id);
85 }
86 
87 static files_hash_func hash_gr[2] = { hash_grname, hash_grgid };
88 
89 static files_hash_t hashinfo = {
90 	DEFAULTMUTEX,
91 	sizeof (struct group),
92 	NSS_BUFLEN_GROUP,
93 	2,
94 	hash_gr
95 };
96 
97 static int
check_grname(nss_XbyY_args_t * argp,const char * line,int linelen)98 check_grname(nss_XbyY_args_t *argp, const char *line, int linelen)
99 {
100 	const char *linep, *limit;
101 	const char *keyp = argp->key.name;
102 
103 	linep = line;
104 	limit = line + linelen;
105 
106 	/* +/- entries valid for compat source only */
107 	if (linelen == 0 || *line == '+' || *line == '-')
108 		return (0);
109 	while (*keyp && linep < limit && *keyp == *linep) {
110 		keyp++;
111 		linep++;
112 	}
113 	return (linep < limit && *keyp == '\0' && *linep == ':');
114 }
115 
116 static nss_status_t
getbyname(be,a)117 getbyname(be, a)
118 	files_backend_ptr_t	be;
119 	void			*a;
120 {
121 	return (_nss_files_XY_hash(be, a, 0, &hashinfo, 0, check_grname));
122 }
123 
124 static int
check_grgid(nss_XbyY_args_t * argp,const char * line,int linelen)125 check_grgid(nss_XbyY_args_t *argp, const char *line, int linelen)
126 {
127 	const char	*linep, *limit, *end;
128 	ulong_t		gr_gid;
129 
130 	linep = line;
131 	limit = line + linelen;
132 
133 	/* +/- entries valid for compat source only */
134 	if (linelen == 0 || *line == '+' || *line == '-')
135 		return (0);
136 
137 	while (linep < limit && *linep++ != ':') /* skip groupname */
138 		continue;
139 	while (linep < limit && *linep++ != ':') /* skip password */
140 		continue;
141 	if (linep == limit)
142 		return (0);
143 
144 	/* gid */
145 	end = linep;
146 	gr_gid = strtoul(linep, (char **)&end, 10);
147 
148 	/* check if gid is empty or overflows */
149 	if (linep == end || gr_gid > UINT32_MAX)
150 		return (0);
151 
152 	return ((gid_t)gr_gid == argp->key.gid);
153 }
154 
155 static nss_status_t
getbygid(be,a)156 getbygid(be, a)
157 	files_backend_ptr_t	be;
158 	void			*a;
159 {
160 	nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
161 
162 	if (argp->key.gid > MAXUID)
163 		return (NSS_NOTFOUND);
164 	return (_nss_files_XY_hash(be, argp, 0, &hashinfo, 1, check_grgid));
165 }
166 
167 /*
168  * Validates group entry replacing gid > MAXUID by GID_NOBODY.
169  */
170 int
validate_group_ids(char * line,int * linelenp,int buflen,int extra_chars,files_XY_check_func check)171 validate_group_ids(char *line, int *linelenp, int buflen, int extra_chars,
172 		files_XY_check_func check)
173 {
174 	char	*linep, *limit, *gidp;
175 	ulong_t	gid;
176 	int	oldgidlen, idlen;
177 	int	linelen = *linelenp, newlinelen;
178 
179 	/*
180 	 * getbygid() rejects searching by ephemeral gid therefore
181 	 * no need to validate because the matched entry won't have
182 	 * an ephemeral gid.
183 	 */
184 	if (check != NULL && check == check_grgid)
185 		return (NSS_STR_PARSE_SUCCESS);
186 
187 	/* +/- entries valid for compat source only */
188 	if (linelen == 0 || *line == '+' || *line == '-')
189 		return (NSS_STR_PARSE_SUCCESS);
190 
191 	linep = line;
192 	limit = line + linelen;
193 
194 	while (linep < limit && *linep++ != ':') /* skip groupname */
195 		continue;
196 	while (linep < limit && *linep++ != ':') /* skip password */
197 		continue;
198 	if (linep == limit)
199 		return (NSS_STR_PARSE_PARSE);
200 
201 	gidp = linep;
202 	gid = strtoul(gidp, (char **)&linep, 10); /* grab gid */
203 	oldgidlen = linep - gidp;
204 	if (linep >= limit || oldgidlen == 0)
205 		return (NSS_STR_PARSE_PARSE);
206 
207 	if (gid <= MAXUID)
208 		return (NSS_STR_PARSE_SUCCESS);
209 
210 	idlen = snprintf(NULL, 0, "%u", GID_NOBODY);
211 	newlinelen = linelen + idlen - oldgidlen;
212 	if (newlinelen + extra_chars > buflen)
213 		return (NSS_STR_PARSE_ERANGE);
214 
215 	(void) bcopy(linep, gidp + idlen, limit - linep + extra_chars);
216 	(void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY);
217 	*(gidp + idlen) = ':';
218 	*linelenp = newlinelen;
219 	return (NSS_STR_PARSE_SUCCESS);
220 }
221 
222 static nss_status_t
getbymember(be,a)223 getbymember(be, a)
224 	files_backend_ptr_t	be;
225 	void			*a;
226 {
227 	struct nss_groupsbymem	*argp = (struct nss_groupsbymem *)a;
228 
229 	return (_nss_files_do_all(be, argp, argp->username,
230 				(files_do_all_func_t)argp->process_cstr));
231 }
232 
233 static files_backend_op_t group_ops[] = {
234 	_nss_files_destr,
235 	_nss_files_endent,
236 	_nss_files_setent,
237 	_nss_files_getent_rigid,
238 	getbyname,
239 	getbygid,
240 	getbymember
241 };
242 
243 /*ARGSUSED*/
244 nss_backend_t *
_nss_files_group_constr(dummy1,dummy2,dummy3)245 _nss_files_group_constr(dummy1, dummy2, dummy3)
246 	const char	*dummy1, *dummy2, *dummy3;
247 {
248 	return (_nss_files_constr(group_ops,
249 				sizeof (group_ops) / sizeof (group_ops[0]),
250 				GF_PATH,
251 				NSS_LINELEN_GROUP,
252 				&hashinfo));
253 }
254