1/* $NetBSD: gen_gr.c,v 1.1.1.2 2012/09/09 16:07:58 christos Exp $ */ 2 3/* 4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (c) 1996-1999 by Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20#if !defined(LINT) && !defined(CODECENTER) 21static const char rcsid[] = "Id: gen_gr.c,v 1.8 2005/04/27 04:56:23 sra Exp "; 22#endif 23 24/* Imports */ 25 26#include "port_before.h" 27 28#ifndef WANT_IRS_GR 29static int __bind_irs_gr_unneeded; 30#else 31 32#include <sys/types.h> 33 34#include <isc/assertions.h> 35#include <errno.h> 36#include <stdio.h> 37#include <stdlib.h> 38#include <string.h> 39 40#include <netinet/in.h> 41#include <arpa/nameser.h> 42#include <resolv.h> 43 44#include <isc/memcluster.h> 45#include <irs.h> 46 47#include "port_after.h" 48 49#include "irs_p.h" 50#include "gen_p.h" 51 52/* Definitions */ 53 54struct pvt { 55 struct irs_rule * rules; 56 struct irs_rule * rule; 57 struct irs_gr * gr; 58 /* 59 * Need space to store the entries read from the group file. 60 * The members list also needs space per member, and the 61 * strings making up the user names must be allocated 62 * somewhere. Rather than doing lots of small allocations, 63 * we keep one buffer and resize it as needed. 64 */ 65 struct group group; 66 size_t nmemb; /*%< Malloc'd max index of gr_mem[]. */ 67 char * membuf; 68 size_t membufsize; 69 struct __res_state * res; 70 void (*free_res)(void *); 71}; 72 73/* Forward */ 74 75static void gr_close(struct irs_gr *); 76static struct group * gr_next(struct irs_gr *); 77static struct group * gr_byname(struct irs_gr *, const char *); 78static struct group * gr_bygid(struct irs_gr *, gid_t); 79static void gr_rewind(struct irs_gr *); 80static int gr_list(struct irs_gr *, const char *, 81 gid_t, gid_t *, int *); 82static void gr_minimize(struct irs_gr *); 83static struct __res_state * gr_res_get(struct irs_gr *); 84static void gr_res_set(struct irs_gr *, 85 struct __res_state *, 86 void (*)(void *)); 87 88static int grmerge(struct irs_gr *gr, const struct group *src, 89 int preserve); 90 91static int countvec(char **vec); 92static int isnew(char **old, char *new); 93static int countnew(char **old, char **new); 94static size_t sizenew(char **old, char **new); 95static int newgid(int, gid_t *, gid_t); 96 97/* Macros */ 98 99#define FREE_IF(x) do { if ((x) != NULL) { free(x); (x) = NULL; } } while (0) 100 101/* Public */ 102 103struct irs_gr * 104irs_gen_gr(struct irs_acc *this) { 105 struct gen_p *accpvt = (struct gen_p *)this->private; 106 struct irs_gr *gr; 107 struct pvt *pvt; 108 109 if (!(gr = memget(sizeof *gr))) { 110 errno = ENOMEM; 111 return (NULL); 112 } 113 memset(gr, 0x5e, sizeof *gr); 114 if (!(pvt = memget(sizeof *pvt))) { 115 memput(gr, sizeof *gr); 116 errno = ENOMEM; 117 return (NULL); 118 } 119 memset(pvt, 0, sizeof *pvt); 120 pvt->rules = accpvt->map_rules[irs_gr]; 121 pvt->rule = pvt->rules; 122 gr->private = pvt; 123 gr->close = gr_close; 124 gr->next = gr_next; 125 gr->byname = gr_byname; 126 gr->bygid = gr_bygid; 127 gr->rewind = gr_rewind; 128 gr->list = gr_list; 129 gr->minimize = gr_minimize; 130 gr->res_get = gr_res_get; 131 gr->res_set = gr_res_set; 132 return (gr); 133} 134 135/* Methods. */ 136 137static void 138gr_close(struct irs_gr *this) { 139 struct pvt *pvt = (struct pvt *)this->private; 140 141 memput(pvt, sizeof *pvt); 142 memput(this, sizeof *this); 143} 144 145static struct group * 146gr_next(struct irs_gr *this) { 147 struct pvt *pvt = (struct pvt *)this->private; 148 struct group *rval; 149 struct irs_gr *gr; 150 151 while (pvt->rule) { 152 gr = pvt->rule->inst->gr; 153 rval = (*gr->next)(gr); 154 if (rval) 155 return (rval); 156 if (!(pvt->rule->flags & IRS_CONTINUE)) 157 break; 158 pvt->rule = pvt->rule->next; 159 if (pvt->rule) { 160 gr = pvt->rule->inst->gr; 161 (*gr->rewind)(gr); 162 } 163 } 164 return (NULL); 165} 166 167static struct group * 168gr_byname(struct irs_gr *this, const char *name) { 169 struct pvt *pvt = (struct pvt *)this->private; 170 struct irs_rule *rule; 171 struct group *tval; 172 struct irs_gr *gr; 173 int dirty; 174 175 dirty = 0; 176 for (rule = pvt->rules; rule; rule = rule->next) { 177 gr = rule->inst->gr; 178 tval = (*gr->byname)(gr, name); 179 if (tval) { 180 if (!grmerge(this, tval, dirty++)) 181 return (NULL); 182 if (!(rule->flags & IRS_MERGE)) 183 break; 184 } else { 185 if (!(rule->flags & IRS_CONTINUE)) 186 break; 187 } 188 } 189 if (dirty) 190 return (&pvt->group); 191 return (NULL); 192} 193 194static struct group * 195gr_bygid(struct irs_gr *this, gid_t gid) { 196 struct pvt *pvt = (struct pvt *)this->private; 197 struct irs_rule *rule; 198 struct group *tval; 199 struct irs_gr *gr; 200 int dirty; 201 202 dirty = 0; 203 for (rule = pvt->rules; rule; rule = rule->next) { 204 gr = rule->inst->gr; 205 tval = (*gr->bygid)(gr, gid); 206 if (tval) { 207 if (!grmerge(this, tval, dirty++)) 208 return (NULL); 209 if (!(rule->flags & IRS_MERGE)) 210 break; 211 } else { 212 if (!(rule->flags & IRS_CONTINUE)) 213 break; 214 } 215 } 216 if (dirty) 217 return (&pvt->group); 218 return (NULL); 219} 220 221static void 222gr_rewind(struct irs_gr *this) { 223 struct pvt *pvt = (struct pvt *)this->private; 224 struct irs_gr *gr; 225 226 pvt->rule = pvt->rules; 227 if (pvt->rule) { 228 gr = pvt->rule->inst->gr; 229 (*gr->rewind)(gr); 230 } 231} 232 233static int 234gr_list(struct irs_gr *this, const char *name, 235 gid_t basegid, gid_t *groups, int *ngroups) 236{ 237 struct pvt *pvt = (struct pvt *)this->private; 238 struct irs_rule *rule; 239 struct irs_gr *gr; 240 int t_ngroups, maxgroups; 241 gid_t *t_groups; 242 int n, t, rval = 0; 243 244 maxgroups = *ngroups; 245 *ngroups = 0; 246 t_groups = (gid_t *)malloc(maxgroups * sizeof(gid_t)); 247 if (!t_groups) { 248 errno = ENOMEM; 249 return (-1); 250 } 251 252 for (rule = pvt->rules; rule; rule = rule->next) { 253 t_ngroups = maxgroups; 254 gr = rule->inst->gr; 255 t = (*gr->list)(gr, name, basegid, t_groups, &t_ngroups); 256 for (n = 0; n < t_ngroups; n++) { 257 if (newgid(*ngroups, groups, t_groups[n])) { 258 if (*ngroups == maxgroups) { 259 rval = -1; 260 goto done; 261 } 262 groups[(*ngroups)++] = t_groups[n]; 263 } 264 } 265 if (t == 0) { 266 if (!(rule->flags & IRS_MERGE)) 267 break; 268 } else { 269 if (!(rule->flags & IRS_CONTINUE)) 270 break; 271 } 272 } 273 done: 274 free(t_groups); 275 return (rval); 276} 277 278static void 279gr_minimize(struct irs_gr *this) { 280 struct pvt *pvt = (struct pvt *)this->private; 281 struct irs_rule *rule; 282 283 for (rule = pvt->rules; rule != NULL; rule = rule->next) { 284 struct irs_gr *gr = rule->inst->gr; 285 286 (*gr->minimize)(gr); 287 } 288} 289 290static struct __res_state * 291gr_res_get(struct irs_gr *this) { 292 struct pvt *pvt = (struct pvt *)this->private; 293 294 if (!pvt->res) { 295 struct __res_state *res; 296 res = (struct __res_state *)malloc(sizeof *res); 297 if (!res) { 298 errno = ENOMEM; 299 return (NULL); 300 } 301 memset(res, 0, sizeof *res); 302 gr_res_set(this, res, free); 303 } 304 305 return (pvt->res); 306} 307 308static void 309gr_res_set(struct irs_gr *this, struct __res_state *res, 310 void (*free_res)(void *)) { 311 struct pvt *pvt = (struct pvt *)this->private; 312 struct irs_rule *rule; 313 314 if (pvt->res && pvt->free_res) { 315 res_nclose(pvt->res); 316 (*pvt->free_res)(pvt->res); 317 } 318 319 pvt->res = res; 320 pvt->free_res = free_res; 321 322 for (rule = pvt->rules; rule != NULL; rule = rule->next) { 323 struct irs_gr *gr = rule->inst->gr; 324 325 if (gr->res_set) 326 (*gr->res_set)(gr, pvt->res, NULL); 327 } 328} 329 330/* Private. */ 331 332static int 333grmerge(struct irs_gr *this, const struct group *src, int preserve) { 334 struct pvt *pvt = (struct pvt *)this->private; 335 char *cp, **m, **p, *oldmembuf, *ep; 336 int n, ndst, nnew; 337 size_t used; 338 339 if (!preserve) { 340 pvt->group.gr_gid = src->gr_gid; 341 if (pvt->nmemb < 1) { 342 m = malloc(sizeof *m); 343 if (m == NULL) { 344 /* No harm done, no work done. */ 345 return (0); 346 } 347 pvt->group.gr_mem = m; 348 pvt->nmemb = 1; 349 } 350 pvt->group.gr_mem[0] = NULL; 351 } 352 ndst = countvec(pvt->group.gr_mem); 353 nnew = countnew(pvt->group.gr_mem, src->gr_mem); 354 355 /* 356 * Make sure destination member array is large enough. 357 * p points to new portion. 358 */ 359 n = ndst + nnew + 1; 360 if ((size_t)n > pvt->nmemb) { 361 m = realloc(pvt->group.gr_mem, n * sizeof *m); 362 if (m == NULL) { 363 /* No harm done, no work done. */ 364 return (0); 365 } 366 pvt->group.gr_mem = m; 367 pvt->nmemb = n; 368 } 369 p = pvt->group.gr_mem + ndst; 370 371 /* 372 * Enlarge destination membuf; cp points at new portion. 373 */ 374 n = sizenew(pvt->group.gr_mem, src->gr_mem); 375 INSIST((nnew == 0) == (n == 0)); 376 if (!preserve) { 377 n += strlen(src->gr_name) + 1; 378 n += strlen(src->gr_passwd) + 1; 379 } 380 if (n == 0) { 381 /* No work to do. */ 382 return (1); 383 } 384 used = preserve ? pvt->membufsize : 0; 385 cp = malloc(used + n); 386 if (cp == NULL) { 387 /* No harm done, no work done. */ 388 return (0); 389 } 390 ep = cp + used + n; 391 if (used != 0) 392 memcpy(cp, pvt->membuf, used); 393 oldmembuf = pvt->membuf; 394 pvt->membuf = cp; 395 pvt->membufsize = used + n; 396 cp += used; 397 398 /* 399 * Adjust group.gr_mem. 400 */ 401 if (pvt->membuf != oldmembuf) 402 for (m = pvt->group.gr_mem; *m; m++) 403 *m = pvt->membuf + (*m - oldmembuf); 404 405 /* 406 * Add new elements. 407 */ 408 for (m = src->gr_mem; *m; m++) 409 if (isnew(pvt->group.gr_mem, *m)) { 410 *p++ = cp; 411 *p = NULL; 412 n = strlen(*m) + 1; 413 if (n > ep - cp) { 414 FREE_IF(oldmembuf); 415 return (0); 416 } 417 strcpy(cp, *m); /* (checked) */ 418 cp += n; 419 } 420 if (preserve) { 421 pvt->group.gr_name = pvt->membuf + 422 (pvt->group.gr_name - oldmembuf); 423 pvt->group.gr_passwd = pvt->membuf + 424 (pvt->group.gr_passwd - oldmembuf); 425 } else { 426 pvt->group.gr_name = cp; 427 n = strlen(src->gr_name) + 1; 428 if (n > ep - cp) { 429 FREE_IF(oldmembuf); 430 return (0); 431 } 432 strcpy(cp, src->gr_name); /* (checked) */ 433 cp += n; 434 435 pvt->group.gr_passwd = cp; 436 n = strlen(src->gr_passwd) + 1; 437 if (n > ep - cp) { 438 FREE_IF(oldmembuf); 439 return (0); 440 } 441 strcpy(cp, src->gr_passwd); /* (checked) */ 442 cp += n; 443 } 444 FREE_IF(oldmembuf); 445 INSIST(cp >= pvt->membuf && cp <= &pvt->membuf[pvt->membufsize]); 446 return (1); 447} 448 449static int 450countvec(char **vec) { 451 int n = 0; 452 453 while (*vec++) 454 n++; 455 return (n); 456} 457 458static int 459isnew(char **old, char *new) { 460 for (; *old; old++) 461 if (strcmp(*old, new) == 0) 462 return (0); 463 return (1); 464} 465 466static int 467countnew(char **old, char **new) { 468 int n = 0; 469 470 for (; *new; new++) 471 n += isnew(old, *new); 472 return (n); 473} 474 475static size_t 476sizenew(char **old, char **new) { 477 size_t n = 0; 478 479 for (; *new; new++) 480 if (isnew(old, *new)) 481 n += strlen(*new) + 1; 482 return (n); 483} 484 485static int 486newgid(int ngroups, gid_t *groups, gid_t group) { 487 ngroups--, groups++; 488 for (; ngroups-- > 0; groups++) 489 if (*groups == group) 490 return (0); 491 return (1); 492} 493 494#endif /* WANT_IRS_GR */ 495/*! \file */ 496