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