getgrouplist.c revision 1.20 1 1.20 lukem /* $NetBSD: getgrouplist.c,v 1.20 2004/09/28 10:46:19 lukem Exp $ */
2 1.19 lukem
3 1.19 lukem /*-
4 1.19 lukem * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 1.19 lukem * All rights reserved.
6 1.19 lukem *
7 1.19 lukem * This code is derived from software contributed to The NetBSD Foundation
8 1.19 lukem * by Luke Mewburn.
9 1.19 lukem *
10 1.19 lukem * Redistribution and use in source and binary forms, with or without
11 1.19 lukem * modification, are permitted provided that the following conditions
12 1.19 lukem * are met:
13 1.19 lukem * 1. Redistributions of source code must retain the above copyright
14 1.19 lukem * notice, this list of conditions and the following disclaimer.
15 1.19 lukem * 2. Redistributions in binary form must reproduce the above copyright
16 1.19 lukem * notice, this list of conditions and the following disclaimer in the
17 1.19 lukem * documentation and/or other materials provided with the distribution.
18 1.19 lukem * 3. All advertising materials mentioning features or use of this software
19 1.19 lukem * must display the following acknowledgement:
20 1.19 lukem * This product includes software developed by the NetBSD
21 1.19 lukem * Foundation, Inc. and its contributors.
22 1.19 lukem * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.19 lukem * contributors may be used to endorse or promote products derived
24 1.19 lukem * from this software without specific prior written permission.
25 1.19 lukem *
26 1.19 lukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.19 lukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.19 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.19 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.19 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.19 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.19 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.19 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.19 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.19 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.19 lukem * POSSIBILITY OF SUCH DAMAGE.
37 1.19 lukem */
38 1.4 cgd
39 1.1 cgd /*
40 1.1 cgd * Copyright (c) 1991, 1993
41 1.1 cgd * The Regents of the University of California. All rights reserved.
42 1.1 cgd *
43 1.1 cgd * Redistribution and use in source and binary forms, with or without
44 1.1 cgd * modification, are permitted provided that the following conditions
45 1.1 cgd * are met:
46 1.1 cgd * 1. Redistributions of source code must retain the above copyright
47 1.1 cgd * notice, this list of conditions and the following disclaimer.
48 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
49 1.1 cgd * notice, this list of conditions and the following disclaimer in the
50 1.1 cgd * documentation and/or other materials provided with the distribution.
51 1.17 agc * 3. Neither the name of the University nor the names of its contributors
52 1.1 cgd * may be used to endorse or promote products derived from this software
53 1.1 cgd * without specific prior written permission.
54 1.1 cgd *
55 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 1.1 cgd * SUCH DAMAGE.
66 1.1 cgd */
67 1.1 cgd
68 1.6 christos #include <sys/cdefs.h>
69 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint)
70 1.4 cgd #if 0
71 1.8 perry static char sccsid[] = "@(#)getgrouplist.c 8.2 (Berkeley) 12/8/94";
72 1.4 cgd #else
73 1.20 lukem __RCSID("$NetBSD: getgrouplist.c,v 1.20 2004/09/28 10:46:19 lukem Exp $");
74 1.4 cgd #endif
75 1.1 cgd #endif /* LIBC_SCCS and not lint */
76 1.1 cgd
77 1.1 cgd /*
78 1.19 lukem * calculate group access list
79 1.1 cgd */
80 1.19 lukem
81 1.7 jtc #include "namespace.h"
82 1.12 lukem #include <sys/param.h>
83 1.12 lukem
84 1.13 lukem #include <assert.h>
85 1.19 lukem #include <errno.h>
86 1.12 lukem #include <grp.h>
87 1.19 lukem #include <nsswitch.h>
88 1.19 lukem #include <stdarg.h>
89 1.19 lukem #include <stdlib.h>
90 1.1 cgd #include <string.h>
91 1.6 christos #include <unistd.h>
92 1.7 jtc
93 1.19 lukem #ifdef HESIOD
94 1.19 lukem #include <hesiod.h>
95 1.19 lukem #endif
96 1.19 lukem
97 1.7 jtc #ifdef __weak_alias
98 1.15 mycroft __weak_alias(getgrouplist,_getgrouplist)
99 1.7 jtc #endif
100 1.1 cgd
101 1.19 lukem #ifdef HESIOD
102 1.19 lukem
103 1.19 lukem /*ARGSUSED*/
104 1.19 lukem static int
105 1.19 lukem _nss_dns_getgrouplist(void *retval, void *cb_data, va_list ap)
106 1.19 lukem {
107 1.20 lukem int *result = va_arg(ap, int *);
108 1.19 lukem const char *uname = va_arg(ap, const char *);
109 1.19 lukem gid_t agroup = va_arg(ap, gid_t);
110 1.19 lukem gid_t *groups = va_arg(ap, gid_t *);
111 1.19 lukem int *grpcnt = va_arg(ap, int *);
112 1.19 lukem
113 1.19 lukem unsigned long id;
114 1.19 lukem void *context;
115 1.19 lukem char **hp, *cp, *ep;
116 1.19 lukem int rv, ret, ngroups, maxgroups;
117 1.19 lukem
118 1.19 lukem hp = NULL;
119 1.19 lukem rv = NS_NOTFOUND;
120 1.19 lukem ret = 0;
121 1.19 lukem
122 1.19 lukem if (hesiod_init(&context) == -1) /* setup hesiod */
123 1.19 lukem return NS_UNAVAIL;
124 1.19 lukem
125 1.19 lukem hp = hesiod_resolve(context, uname, "grplist"); /* find grplist */
126 1.19 lukem if (hp == NULL) {
127 1.19 lukem if (errno != ENOENT)
128 1.19 lukem rv = NS_NOTFOUND;
129 1.19 lukem goto dnsgrouplist_out;
130 1.19 lukem }
131 1.19 lukem
132 1.19 lukem if ((ep = strchr(hp[0], '\n')) != NULL)
133 1.19 lukem *ep = '\0'; /* clear trailing \n */
134 1.19 lukem
135 1.19 lukem ret = 0;
136 1.19 lukem ngroups = 0;
137 1.19 lukem maxgroups = *grpcnt;
138 1.19 lukem
139 1.19 lukem if (ngroups < maxgroups) /* add primary gid */
140 1.19 lukem groups[ngroups] = agroup;
141 1.19 lukem else
142 1.19 lukem ret = -1;
143 1.19 lukem ngroups++;
144 1.19 lukem
145 1.19 lukem for (cp = hp[0]; *cp != '\0'; ) { /* parse grplist */
146 1.19 lukem if ((cp = strchr(cp, ':')) == NULL) /* skip grpname */
147 1.19 lukem break;
148 1.19 lukem cp++;
149 1.19 lukem id = strtoul(cp, &ep, 10); /* parse gid */
150 1.19 lukem if (id > GID_MAX || (*ep != ':' && *ep != '\0')) {
151 1.19 lukem rv = NS_UNAVAIL;
152 1.19 lukem goto dnsgrouplist_out;
153 1.19 lukem }
154 1.19 lukem cp = ep;
155 1.19 lukem if (*cp == ':')
156 1.19 lukem cp++;
157 1.19 lukem if (ngroups < maxgroups) /* add this gid */
158 1.19 lukem groups[ngroups] = (gid_t)id;
159 1.19 lukem else
160 1.19 lukem ret = -1;
161 1.19 lukem ngroups++;
162 1.19 lukem }
163 1.19 lukem
164 1.20 lukem *result = ret;
165 1.19 lukem *grpcnt = ngroups;
166 1.19 lukem rv = NS_SUCCESS;
167 1.19 lukem
168 1.19 lukem dnsgrouplist_out:
169 1.19 lukem if (hp)
170 1.19 lukem hesiod_free_list(context, hp);
171 1.19 lukem hesiod_end(context);
172 1.19 lukem return rv;
173 1.19 lukem }
174 1.19 lukem
175 1.19 lukem #endif /* HESIOD */
176 1.16 elric
177 1.1 cgd int
178 1.18 lukem getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt)
179 1.1 cgd {
180 1.9 perry struct group *grp;
181 1.20 lukem int i, ngroups, maxgroups, ret;
182 1.19 lukem
183 1.19 lukem static const ns_dtab dtab[] = {
184 1.19 lukem NS_DNS_CB(_nss_dns_getgrouplist, NULL)
185 1.19 lukem { 0 }
186 1.19 lukem };
187 1.13 lukem
188 1.13 lukem _DIAGASSERT(uname != NULL);
189 1.20 lukem /* groups may be NULL if just sizing when invoked with *grpcnt = 0 */
190 1.13 lukem _DIAGASSERT(grpcnt != NULL);
191 1.1 cgd
192 1.19 lukem /* first, try source-specific optimized getgrouplist */
193 1.20 lukem i = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrouplist",
194 1.19 lukem __nsdefaultsrc,
195 1.20 lukem &ret, uname, agroup, groups, grpcnt);
196 1.20 lukem if (i == NS_SUCCESS)
197 1.20 lukem return ret;
198 1.19 lukem
199 1.19 lukem /* fallback to scan the group(5) database */
200 1.1 cgd ret = 0;
201 1.1 cgd ngroups = 0;
202 1.1 cgd maxgroups = *grpcnt;
203 1.5 jtc
204 1.1 cgd /*
205 1.5 jtc * install primary group
206 1.1 cgd */
207 1.10 mycroft if (ngroups < maxgroups)
208 1.10 mycroft groups[ngroups] = agroup;
209 1.10 mycroft else
210 1.10 mycroft ret = -1;
211 1.10 mycroft ngroups++;
212 1.5 jtc
213 1.1 cgd /*
214 1.1 cgd * Scan the group file to find additional groups.
215 1.1 cgd */
216 1.1 cgd setgrent();
217 1.12 lukem nextgroup:
218 1.19 lukem while ((grp = getgrent()) != NULL) {
219 1.1 cgd if (grp->gr_gid == agroup)
220 1.1 cgd continue;
221 1.19 lukem for (i = 0; grp->gr_mem[i]; i++) {
222 1.19 lukem if (strcmp(grp->gr_mem[i], uname) != 0)
223 1.19 lukem continue;
224 1.19 lukem for (i = 0; i < MIN(ngroups, maxgroups); i++) {
225 1.19 lukem if (grp->gr_gid == groups[i])
226 1.19 lukem goto nextgroup;
227 1.19 lukem }
228 1.19 lukem if (ngroups < maxgroups)
229 1.19 lukem groups[ngroups] = grp->gr_gid;
230 1.19 lukem else
231 1.19 lukem ret = -1;
232 1.19 lukem ngroups++;
233 1.19 lukem break;
234 1.1 cgd }
235 1.1 cgd }
236 1.1 cgd endgrent();
237 1.1 cgd *grpcnt = ngroups;
238 1.19 lukem return ret;
239 1.1 cgd }
240