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