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