1/* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1996-1999 by Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#if defined(LIBC_SCCS) && !defined(lint) 19static const char rcsid[] = "$Id: dns_gr.c,v 1.4 2005/04/27 04:56:21 sra Exp $"; 20#endif 21 22/*! \file 23 * \brief 24 * dns_gr.c --- this file contains the functions for accessing 25 * group information from Hesiod. 26 */ 27 28#include "port_before.h" 29 30#ifndef WANT_IRS_GR 31static int __bind_irs_gr_unneeded; 32#else 33 34#include <sys/param.h> 35#include <sys/types.h> 36 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <errno.h> 41#include <unistd.h> 42 43#include <sys/types.h> 44#include <netinet/in.h> 45#include <arpa/nameser.h> 46#include <resolv.h> 47 48#include <isc/memcluster.h> 49 50#include <irs.h> 51 52#include "port_after.h" 53 54#include "irs_p.h" 55#include "hesiod.h" 56#include "dns_p.h" 57 58/* Types. */ 59 60struct pvt { 61 /* 62 * This is our private accessor data. It has a shared hesiod context. 63 */ 64 struct dns_p * dns; 65 /* 66 * Need space to store the entries read from the group file. 67 * The members list also needs space per member, and the 68 * strings making up the user names must be allocated 69 * somewhere. Rather than doing lots of small allocations, 70 * we keep one buffer and resize it as needed. 71 */ 72 struct group group; 73 size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */ 74 char * membuf; 75 size_t membufsize; 76}; 77 78/* Forward. */ 79 80static struct group * gr_next(struct irs_gr *); 81static struct group * gr_byname(struct irs_gr *, const char *); 82static struct group * gr_bygid(struct irs_gr *, gid_t); 83static void gr_rewind(struct irs_gr *); 84static void gr_close(struct irs_gr *); 85static int gr_list(struct irs_gr *, const char *, 86 gid_t, gid_t *, int *); 87static void gr_minimize(struct irs_gr *); 88static struct __res_state * gr_res_get(struct irs_gr *); 89static void gr_res_set(struct irs_gr *, 90 struct __res_state *, 91 void (*)(void *)); 92 93static struct group * get_hes_group(struct irs_gr *this, 94 const char *name, 95 const char *type); 96 97/* Public. */ 98 99struct irs_gr * 100irs_dns_gr(struct irs_acc *this) { 101 struct dns_p *dns = (struct dns_p *)this->private; 102 struct irs_gr *gr; 103 struct pvt *pvt; 104 105 if (!dns || !dns->hes_ctx) { 106 errno = ENODEV; 107 return (NULL); 108 } 109 if (!(pvt = memget(sizeof *pvt))) { 110 errno = ENOMEM; 111 return (NULL); 112 } 113 memset(pvt, 0, sizeof *pvt); 114 pvt->dns = dns; 115 if (!(gr = memget(sizeof *gr))) { 116 memput(pvt, sizeof *pvt); 117 errno = ENOMEM; 118 return (NULL); 119 } 120 memset(gr, 0x5e, sizeof *gr); 121 gr->private = pvt; 122 gr->next = gr_next; 123 gr->byname = gr_byname; 124 gr->bygid = gr_bygid; 125 gr->rewind = gr_rewind; 126 gr->close = gr_close; 127 gr->list = gr_list; 128 gr->minimize = gr_minimize; 129 gr->res_get = gr_res_get; 130 gr->res_set = gr_res_set; 131 return (gr); 132} 133 134/* methods */ 135 136static void 137gr_close(struct irs_gr *this) { 138 struct pvt *pvt = (struct pvt *)this->private; 139 140 if (pvt->group.gr_mem) 141 free(pvt->group.gr_mem); 142 if (pvt->membuf) 143 free(pvt->membuf); 144 memput(pvt, sizeof *pvt); 145 memput(this, sizeof *this); 146} 147 148static struct group * 149gr_next(struct irs_gr *this) { 150 151 UNUSED(this); 152 153 return (NULL); 154} 155 156static struct group * 157gr_byname(struct irs_gr *this, const char *name) { 158 return (get_hes_group(this, name, "group")); 159} 160 161static struct group * 162gr_bygid(struct irs_gr *this, gid_t gid) { 163 char name[32]; 164 165 sprintf(name, "%ld", (long)gid); 166 return (get_hes_group(this, name, "gid")); 167} 168 169static void 170gr_rewind(struct irs_gr *this) { 171 172 UNUSED(this); 173 174 /* NOOP */ 175} 176 177static int 178gr_list(struct irs_gr *this, const char *name, 179 gid_t basegid, gid_t *groups, int *ngroups) 180{ 181 UNUSED(this); 182 UNUSED(name); 183 UNUSED(basegid); 184 UNUSED(groups); 185 186 *ngroups = 0; 187 /* There's some way to do this in Hesiod. */ 188 return (-1); 189} 190 191static void 192gr_minimize(struct irs_gr *this) { 193 194 UNUSED(this); 195 /* NOOP */ 196} 197 198/* Private. */ 199 200static struct group * 201get_hes_group(struct irs_gr *this, const char *name, const char *type) { 202 struct pvt *pvt = (struct pvt *)this->private; 203 char **hes_list, *cp, **new; 204 size_t num_members = 0; 205 u_long t; 206 207 hes_list = hesiod_resolve(pvt->dns->hes_ctx, name, type); 208 if (!hes_list) 209 return (NULL); 210 211 /* 212 * Copy the returned hesiod string into storage space. 213 */ 214 if (pvt->membuf) 215 free(pvt->membuf); 216 pvt->membuf = strdup(*hes_list); 217 hesiod_free_list(pvt->dns->hes_ctx, hes_list); 218 219 cp = pvt->membuf; 220 pvt->group.gr_name = cp; 221 if (!(cp = strchr(cp, ':'))) 222 goto cleanup; 223 *cp++ = '\0'; 224 225 pvt->group.gr_passwd = cp; 226 if (!(cp = strchr(cp, ':'))) 227 goto cleanup; 228 *cp++ = '\0'; 229 230 errno = 0; 231 t = strtoul(cp, NULL, 10); 232 if (errno == ERANGE) 233 goto cleanup; 234 pvt->group.gr_gid = (gid_t) t; 235 if (!(cp = strchr(cp, ':'))) 236 goto cleanup; 237 cp++; 238 239 /* 240 * Parse the members out. 241 */ 242 while (*cp) { 243 if (num_members+1 >= pvt->nmemb || pvt->group.gr_mem == NULL) { 244 pvt->nmemb += 10; 245 new = realloc(pvt->group.gr_mem, 246 pvt->nmemb * sizeof(char *)); 247 if (new == NULL) 248 goto cleanup; 249 pvt->group.gr_mem = new; 250 } 251 pvt->group.gr_mem[num_members++] = cp; 252 if (!(cp = strchr(cp, ','))) 253 break; 254 *cp++ = '\0'; 255 } 256 if (!pvt->group.gr_mem) { 257 pvt->group.gr_mem = malloc(sizeof(char*)); 258 if (!pvt->group.gr_mem) 259 goto cleanup; 260 } 261 pvt->group.gr_mem[num_members] = NULL; 262 263 return (&pvt->group); 264 265 cleanup: 266 if (pvt->group.gr_mem) { 267 free(pvt->group.gr_mem); 268 pvt->group.gr_mem = NULL; 269 } 270 if (pvt->membuf) { 271 free(pvt->membuf); 272 pvt->membuf = NULL; 273 } 274 return (NULL); 275} 276 277static struct __res_state * 278gr_res_get(struct irs_gr *this) { 279 struct pvt *pvt = (struct pvt *)this->private; 280 struct dns_p *dns = pvt->dns; 281 282 return (__hesiod_res_get(dns->hes_ctx)); 283} 284 285static void 286gr_res_set(struct irs_gr *this, struct __res_state * res, 287 void (*free_res)(void *)) { 288 struct pvt *pvt = (struct pvt *)this->private; 289 struct dns_p *dns = pvt->dns; 290 291 __hesiod_res_set(dns->hes_ctx, res, free_res); 292} 293 294#endif /* WANT_IRS_GR */ 295