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