1/* $NetBSD: lcl_ng.c,v 1.1.1.2 2012/09/09 16:07:54 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: lcl_ng.c,v 1.3 2005/04/27 04:56:31 sra Exp "; 22#endif 23 24/* Imports */ 25 26#include "port_before.h" 27 28#include <sys/types.h> 29#include <netinet/in.h> 30#include <arpa/nameser.h> 31#include <resolv.h> 32#include <errno.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <unistd.h> 37 38#include <irs.h> 39#include <isc/memcluster.h> 40 41#include "port_after.h" 42 43#include "irs_p.h" 44#include "lcl_p.h" 45 46/* Definitions */ 47 48#define NG_HOST 0 /*%< Host name */ 49#define NG_USER 1 /*%< User name */ 50#define NG_DOM 2 /*%< and Domain name */ 51#define LINSIZ 1024 /*%< Length of netgroup file line */ 52/* 53 * XXX Warning XXX 54 * This code is a hack-and-slash special. It realy needs to be 55 * rewritten with things like strdup, and realloc in mind. 56 * More reasonable data structures would not be a bad thing. 57 */ 58 59/*% 60 * Static Variables and functions used by setnetgrent(), getnetgrent() and 61 * endnetgrent(). 62 * 63 * There are two linked lists: 64 * \li linelist is just used by setnetgrent() to parse the net group file via. 65 * parse_netgrp() 66 * \li netgrp is the list of entries for the current netgroup 67 */ 68struct linelist { 69 struct linelist *l_next; /*%< Chain ptr. */ 70 int l_parsed; /*%< Flag for cycles */ 71 char * l_groupname; /*%< Name of netgroup */ 72 char * l_line; /*%< Netgroup entrie(s) to be parsed */ 73}; 74 75struct ng_old_struct { 76 struct ng_old_struct *ng_next; /*%< Chain ptr */ 77 char * ng_str[3]; /*%< Field pointers, see below */ 78}; 79 80struct pvt { 81 FILE *fp; 82 struct linelist *linehead; 83 struct ng_old_struct *nextgrp; 84 struct { 85 struct ng_old_struct *gr; 86 char *grname; 87 } grouphead; 88}; 89 90/* Forward */ 91 92static void ng_rewind(struct irs_ng *, const char*); 93static void ng_close(struct irs_ng *); 94static int ng_next(struct irs_ng *, const char **, 95 const char **, const char **); 96static int ng_test(struct irs_ng *, const char *, 97 const char *, const char *, 98 const char *); 99static void ng_minimize(struct irs_ng *); 100 101static int parse_netgrp(struct irs_ng *, const char*); 102static struct linelist *read_for_group(struct irs_ng *, const char *); 103static void freelists(struct irs_ng *); 104 105/* Public */ 106 107struct irs_ng * 108irs_lcl_ng(struct irs_acc *this) { 109 struct irs_ng *ng; 110 struct pvt *pvt; 111 112 UNUSED(this); 113 114 if (!(ng = memget(sizeof *ng))) { 115 errno = ENOMEM; 116 return (NULL); 117 } 118 memset(ng, 0x5e, sizeof *ng); 119 if (!(pvt = memget(sizeof *pvt))) { 120 memput(ng, sizeof *ng); 121 errno = ENOMEM; 122 return (NULL); 123 } 124 memset(pvt, 0, sizeof *pvt); 125 ng->private = pvt; 126 ng->close = ng_close; 127 ng->next = ng_next; 128 ng->test = ng_test; 129 ng->rewind = ng_rewind; 130 ng->minimize = ng_minimize; 131 return (ng); 132} 133 134/* Methods */ 135 136static void 137ng_close(struct irs_ng *this) { 138 struct pvt *pvt = (struct pvt *)this->private; 139 140 if (pvt->fp != NULL) 141 fclose(pvt->fp); 142 freelists(this); 143 memput(pvt, sizeof *pvt); 144 memput(this, sizeof *this); 145} 146 147/*% 148 * Parse the netgroup file looking for the netgroup and build the list 149 * of netgrp structures. Let parse_netgrp() and read_for_group() do 150 * most of the work. 151 */ 152static void 153ng_rewind(struct irs_ng *this, const char *group) { 154 struct pvt *pvt = (struct pvt *)this->private; 155 156 if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) { 157 fclose(pvt->fp); 158 pvt->fp = NULL; 159 } 160 161 if (pvt->fp == NULL || pvt->grouphead.gr == NULL || 162 strcmp(group, pvt->grouphead.grname)) { 163 freelists(this); 164 if (pvt->fp != NULL) 165 fclose(pvt->fp); 166 pvt->fp = fopen(_PATH_NETGROUP, "r"); 167 if (pvt->fp != NULL) { 168 if (parse_netgrp(this, group)) 169 freelists(this); 170 if (!(pvt->grouphead.grname = strdup(group))) 171 freelists(this); 172 fclose(pvt->fp); 173 pvt->fp = NULL; 174 } 175 } 176 pvt->nextgrp = pvt->grouphead.gr; 177} 178 179/*% 180 * Get the next netgroup off the list. 181 */ 182static int 183ng_next(struct irs_ng *this, const char **host, const char **user, 184 const char **domain) 185{ 186 struct pvt *pvt = (struct pvt *)this->private; 187 188 if (pvt->nextgrp) { 189 *host = pvt->nextgrp->ng_str[NG_HOST]; 190 *user = pvt->nextgrp->ng_str[NG_USER]; 191 *domain = pvt->nextgrp->ng_str[NG_DOM]; 192 pvt->nextgrp = pvt->nextgrp->ng_next; 193 return (1); 194 } 195 return (0); 196} 197 198/*% 199 * Search for a match in a netgroup. 200 */ 201static int 202ng_test(struct irs_ng *this, const char *name, 203 const char *host, const char *user, const char *domain) 204{ 205 const char *ng_host, *ng_user, *ng_domain; 206 207 ng_rewind(this, name); 208 while (ng_next(this, &ng_host, &ng_user, &ng_domain)) 209 if ((host == NULL || ng_host == NULL || 210 !strcmp(host, ng_host)) && 211 (user == NULL || ng_user == NULL || 212 !strcmp(user, ng_user)) && 213 (domain == NULL || ng_domain == NULL || 214 !strcmp(domain, ng_domain))) { 215 freelists(this); 216 return (1); 217 } 218 freelists(this); 219 return (0); 220} 221 222static void 223ng_minimize(struct irs_ng *this) { 224 struct pvt *pvt = (struct pvt *)this->private; 225 226 if (pvt->fp != NULL) { 227 (void)fclose(pvt->fp); 228 pvt->fp = NULL; 229 } 230} 231 232/* Private */ 233 234/*% 235 * endnetgrent() - cleanup 236 */ 237static void 238freelists(struct irs_ng *this) { 239 struct pvt *pvt = (struct pvt *)this->private; 240 struct linelist *lp, *olp; 241 struct ng_old_struct *gp, *ogp; 242 243 lp = pvt->linehead; 244 while (lp) { 245 olp = lp; 246 lp = lp->l_next; 247 free(olp->l_groupname); 248 free(olp->l_line); 249 free((char *)olp); 250 } 251 pvt->linehead = NULL; 252 if (pvt->grouphead.grname) { 253 free(pvt->grouphead.grname); 254 pvt->grouphead.grname = NULL; 255 } 256 gp = pvt->grouphead.gr; 257 while (gp) { 258 ogp = gp; 259 gp = gp->ng_next; 260 if (ogp->ng_str[NG_HOST]) 261 free(ogp->ng_str[NG_HOST]); 262 if (ogp->ng_str[NG_USER]) 263 free(ogp->ng_str[NG_USER]); 264 if (ogp->ng_str[NG_DOM]) 265 free(ogp->ng_str[NG_DOM]); 266 free((char *)ogp); 267 } 268 pvt->grouphead.gr = NULL; 269} 270 271/*% 272 * Parse the netgroup file setting up the linked lists. 273 */ 274static int 275parse_netgrp(struct irs_ng *this, const char *group) { 276 struct pvt *pvt = (struct pvt *)this->private; 277 char *spos, *epos; 278 int len, strpos; 279 char *pos, *gpos; 280 struct ng_old_struct *grp; 281 struct linelist *lp = pvt->linehead; 282 283 /* 284 * First, see if the line has already been read in. 285 */ 286 while (lp) { 287 if (!strcmp(group, lp->l_groupname)) 288 break; 289 lp = lp->l_next; 290 } 291 if (lp == NULL && 292 (lp = read_for_group(this, group)) == NULL) 293 return (1); 294 if (lp->l_parsed) { 295 /*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/ 296 return (1); 297 } else 298 lp->l_parsed = 1; 299 pos = lp->l_line; 300 while (*pos != '\0') { 301 if (*pos == '(') { 302 if (!(grp = malloc(sizeof (struct ng_old_struct)))) { 303 freelists(this); 304 errno = ENOMEM; 305 return (1); 306 } 307 memset(grp, 0, sizeof (struct ng_old_struct)); 308 grp->ng_next = pvt->grouphead.gr; 309 pvt->grouphead.gr = grp; 310 pos++; 311 gpos = strsep(&pos, ")"); 312 for (strpos = 0; strpos < 3; strpos++) { 313 if ((spos = strsep(&gpos, ","))) { 314 while (*spos == ' ' || *spos == '\t') 315 spos++; 316 if ((epos = strpbrk(spos, " \t"))) { 317 *epos = '\0'; 318 len = epos - spos; 319 } else 320 len = strlen(spos); 321 if (len > 0) { 322 if(!(grp->ng_str[strpos] 323 = (char *) 324 malloc(len + 1))) { 325 freelists(this); 326 return (1); 327 } 328 memcpy(grp->ng_str[strpos], 329 spos, 330 len + 1); 331 } 332 } else 333 goto errout; 334 } 335 } else { 336 spos = strsep(&pos, ", \t"); 337 if (spos != NULL && parse_netgrp(this, spos)) { 338 freelists(this); 339 return (1); 340 } 341 } 342 if (pos == NULL) 343 break; 344 while (*pos == ' ' || *pos == ',' || *pos == '\t') 345 pos++; 346 } 347 return (0); 348 errout: 349 /*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname, 350 spos);*/ 351 return (1); 352} 353 354/*% 355 * Read the netgroup file and save lines until the line for the netgroup 356 * is found. Return 1 if eof is encountered. 357 */ 358static struct linelist * 359read_for_group(struct irs_ng *this, const char *group) { 360 struct pvt *pvt = (struct pvt *)this->private; 361 char *pos, *spos, *linep = NULL, *olinep; 362 int len, olen, cont; 363 struct linelist *lp; 364 char line[LINSIZ + 1]; 365 366 while (fgets(line, LINSIZ, pvt->fp) != NULL) { 367 pos = line; 368 if (*pos == '#') 369 continue; 370 while (*pos == ' ' || *pos == '\t') 371 pos++; 372 spos = pos; 373 while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 374 *pos != '\0') 375 pos++; 376 len = pos - spos; 377 while (*pos == ' ' || *pos == '\t') 378 pos++; 379 if (*pos != '\n' && *pos != '\0') { 380 if (!(lp = malloc(sizeof (*lp)))) { 381 freelists(this); 382 return (NULL); 383 } 384 lp->l_parsed = 0; 385 if (!(lp->l_groupname = malloc(len + 1))) { 386 free(lp); 387 freelists(this); 388 return (NULL); 389 } 390 memcpy(lp->l_groupname, spos, len); 391 *(lp->l_groupname + len) = '\0'; 392 len = strlen(pos); 393 olen = 0; 394 olinep = NULL; 395 396 /* 397 * Loop around handling line continuations. 398 */ 399 do { 400 if (*(pos + len - 1) == '\n') 401 len--; 402 if (*(pos + len - 1) == '\\') { 403 len--; 404 cont = 1; 405 } else 406 cont = 0; 407 if (len > 0) { 408 if (!(linep = malloc(olen + len + 1))){ 409 if (olen > 0) 410 free(olinep); 411 free(lp->l_groupname); 412 free(lp); 413 freelists(this); 414 errno = ENOMEM; 415 return (NULL); 416 } 417 if (olen > 0) { 418 memcpy(linep, olinep, olen); 419 free(olinep); 420 } 421 memcpy(linep + olen, pos, len); 422 olen += len; 423 *(linep + olen) = '\0'; 424 olinep = linep; 425 } 426 if (cont) { 427 if (fgets(line, LINSIZ, pvt->fp)) { 428 pos = line; 429 len = strlen(pos); 430 } else 431 cont = 0; 432 } 433 } while (cont); 434 lp->l_line = linep; 435 lp->l_next = pvt->linehead; 436 pvt->linehead = lp; 437 438 /* 439 * If this is the one we wanted, we are done. 440 */ 441 if (!strcmp(lp->l_groupname, group)) 442 return (lp); 443 } 444 } 445 return (NULL); 446} 447 448/*! \file */ 449