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