getgrouplist.c revision 1.19 1 1.19 lukem /* $NetBSD: getgrouplist.c,v 1.19 2004/09/25 12:27:35 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.19 lukem __RCSID("$NetBSD: getgrouplist.c,v 1.19 2004/09/25 12:27:35 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.19 lukem const char *uname = va_arg(ap, const char *);
108 1.19 lukem gid_t agroup = va_arg(ap, gid_t);
109 1.19 lukem gid_t *groups = va_arg(ap, gid_t *);
110 1.19 lukem int *grpcnt = va_arg(ap, int *);
111 1.19 lukem
112 1.19 lukem unsigned long id;
113 1.19 lukem void *context;
114 1.19 lukem char **hp, *cp, *ep;
115 1.19 lukem int rv, ret, ngroups, maxgroups;
116 1.19 lukem
117 1.19 lukem hp = NULL;
118 1.19 lukem rv = NS_NOTFOUND;
119 1.19 lukem ret = 0;
120 1.19 lukem
121 1.19 lukem if (hesiod_init(&context) == -1) /* setup hesiod */
122 1.19 lukem return NS_UNAVAIL;
123 1.19 lukem
124 1.19 lukem hp = hesiod_resolve(context, uname, "grplist"); /* find grplist */
125 1.19 lukem if (hp == NULL) {
126 1.19 lukem if (errno != ENOENT)
127 1.19 lukem rv = NS_NOTFOUND;
128 1.19 lukem goto dnsgrouplist_out;
129 1.19 lukem }
130 1.19 lukem
131 1.19 lukem if ((ep = strchr(hp[0], '\n')) != NULL)
132 1.19 lukem *ep = '\0'; /* clear trailing \n */
133 1.19 lukem
134 1.19 lukem ret = 0;
135 1.19 lukem ngroups = 0;
136 1.19 lukem maxgroups = *grpcnt;
137 1.19 lukem
138 1.19 lukem if (ngroups < maxgroups) /* add primary gid */
139 1.19 lukem groups[ngroups] = agroup;
140 1.19 lukem else
141 1.19 lukem ret = -1;
142 1.19 lukem ngroups++;
143 1.19 lukem
144 1.19 lukem for (cp = hp[0]; *cp != '\0'; ) { /* parse grplist */
145 1.19 lukem if ((cp = strchr(cp, ':')) == NULL) /* skip grpname */
146 1.19 lukem break;
147 1.19 lukem cp++;
148 1.19 lukem id = strtoul(cp, &ep, 10); /* parse gid */
149 1.19 lukem if (id > GID_MAX || (*ep != ':' && *ep != '\0')) {
150 1.19 lukem rv = NS_UNAVAIL;
151 1.19 lukem goto dnsgrouplist_out;
152 1.19 lukem }
153 1.19 lukem cp = ep;
154 1.19 lukem if (*cp == ':')
155 1.19 lukem cp++;
156 1.19 lukem if (ngroups < maxgroups) /* add this gid */
157 1.19 lukem groups[ngroups] = (gid_t)id;
158 1.19 lukem else
159 1.19 lukem ret = -1;
160 1.19 lukem ngroups++;
161 1.19 lukem }
162 1.19 lukem
163 1.19 lukem *(int *)retval = ret;
164 1.19 lukem *grpcnt = ngroups;
165 1.19 lukem rv = NS_SUCCESS;
166 1.19 lukem
167 1.19 lukem dnsgrouplist_out:
168 1.19 lukem if (hp)
169 1.19 lukem hesiod_free_list(context, hp);
170 1.19 lukem hesiod_end(context);
171 1.19 lukem return rv;
172 1.19 lukem }
173 1.19 lukem
174 1.19 lukem #endif /* HESIOD */
175 1.16 elric
176 1.1 cgd int
177 1.18 lukem getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt)
178 1.1 cgd {
179 1.9 perry struct group *grp;
180 1.19 lukem int i, ngroups, maxgroups, ret, glretval;
181 1.19 lukem
182 1.19 lukem static const ns_dtab dtab[] = {
183 1.19 lukem NS_DNS_CB(_nss_dns_getgrouplist, NULL)
184 1.19 lukem { 0 }
185 1.19 lukem };
186 1.13 lukem
187 1.13 lukem _DIAGASSERT(uname != NULL);
188 1.13 lukem _DIAGASSERT(groups != NULL);
189 1.13 lukem _DIAGASSERT(grpcnt != NULL);
190 1.1 cgd
191 1.19 lukem /* first, try source-specific optimized getgrouplist */
192 1.19 lukem ret = nsdispatch(&glretval, dtab, NSDB_GROUP, "getgrouplist",
193 1.19 lukem __nsdefaultsrc,
194 1.19 lukem uname, agroup, groups, grpcnt);
195 1.19 lukem if (ret == NS_SUCCESS)
196 1.19 lukem return glretval;
197 1.19 lukem
198 1.19 lukem /* fallback to scan the group(5) database */
199 1.1 cgd ret = 0;
200 1.1 cgd ngroups = 0;
201 1.1 cgd maxgroups = *grpcnt;
202 1.5 jtc
203 1.1 cgd /*
204 1.5 jtc * install primary group
205 1.1 cgd */
206 1.10 mycroft if (ngroups < maxgroups)
207 1.10 mycroft groups[ngroups] = agroup;
208 1.10 mycroft else
209 1.10 mycroft ret = -1;
210 1.10 mycroft ngroups++;
211 1.5 jtc
212 1.1 cgd /*
213 1.1 cgd * Scan the group file to find additional groups.
214 1.1 cgd */
215 1.1 cgd setgrent();
216 1.12 lukem nextgroup:
217 1.19 lukem while ((grp = getgrent()) != NULL) {
218 1.1 cgd if (grp->gr_gid == agroup)
219 1.1 cgd continue;
220 1.19 lukem for (i = 0; grp->gr_mem[i]; i++) {
221 1.19 lukem if (strcmp(grp->gr_mem[i], uname) != 0)
222 1.19 lukem continue;
223 1.19 lukem for (i = 0; i < MIN(ngroups, maxgroups); i++) {
224 1.19 lukem if (grp->gr_gid == groups[i])
225 1.19 lukem goto nextgroup;
226 1.19 lukem }
227 1.19 lukem if (ngroups < maxgroups)
228 1.19 lukem groups[ngroups] = grp->gr_gid;
229 1.19 lukem else
230 1.19 lukem ret = -1;
231 1.19 lukem ngroups++;
232 1.19 lukem break;
233 1.1 cgd }
234 1.1 cgd }
235 1.1 cgd endgrent();
236 1.1 cgd *grpcnt = ngroups;
237 1.19 lukem return ret;
238 1.1 cgd }
239