1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #if defined(LIBC_SCCS) && !defined(lint) 38 static char sccsid[] = "$Id$"; 39 #endif /* LIBC_SCCS and not lint */ 40 41 /* 42 * This is a specially hacked-up version of getnetgrent.c used to parse 43 * data from the stored hash table of netgroup info rather than from a 44 * file. It's used mainly for the parse_netgroup() function. All the YP 45 * stuff and file support has been stripped out since it isn't needed. 46 */ 47 48 #include <stdio.h> 49 #include <strings.h> 50 #include <stdlib.h> 51 #include <unistd.h> 52 #include "hash.h" 53 54 /* 55 * Static Variables and functions used by setnetgrent(), getnetgrent() and 56 * __endnetgrent(). 57 * There are two linked lists: 58 * - linelist is just used by setnetgrent() to parse the net group file via. 59 * parse_netgrp() 60 * - 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 netgrp { 70 struct netgrp *ng_next; /* Chain ptr */ 71 char *ng_str[3]; /* Field pointers, see below */ 72 }; 73 #define NG_HOST 0 /* Host name */ 74 #define NG_USER 1 /* User name */ 75 #define NG_DOM 2 /* and Domain name */ 76 77 static struct linelist *linehead = (struct linelist *)0; 78 static struct netgrp *nextgrp = (struct netgrp *)0; 79 static struct { 80 struct netgrp *gr; 81 char *grname; 82 } grouphead = { 83 (struct netgrp *)0, 84 (char *)0, 85 }; 86 static int parse_netgrp(); 87 static struct linelist *read_for_group(); 88 void __setnetgrent(), __endnetgrent(); 89 int __getnetgrent(); 90 extern struct group_entry *gtable[]; 91 extern char *lookup __P(( struct group_entry *[], char * )); 92 #define LINSIZ 1024 /* Length of netgroup file line */ 93 94 /* 95 * setnetgrent() 96 * Parse the netgroup file looking for the netgroup and build the list 97 * of netgrp structures. Let parse_netgrp() and read_for_group() do 98 * most of the work. 99 */ 100 void 101 __setnetgrent(group) 102 char *group; 103 { 104 /* Sanity check */ 105 106 if (group == NULL || !strlen(group)) 107 return; 108 109 if (grouphead.gr == (struct netgrp *)0 || 110 strcmp(group, grouphead.grname)) { 111 __endnetgrent(); 112 if (parse_netgrp(group)) 113 __endnetgrent(); 114 else { 115 grouphead.grname = (char *) 116 malloc(strlen(group) + 1); 117 strcpy(grouphead.grname, group); 118 } 119 } 120 nextgrp = grouphead.gr; 121 } 122 123 /* 124 * Get the next netgroup off the list. 125 */ 126 int 127 __getnetgrent(hostp, userp, domp) 128 char **hostp, **userp, **domp; 129 { 130 if (nextgrp) { 131 *hostp = nextgrp->ng_str[NG_HOST]; 132 *userp = nextgrp->ng_str[NG_USER]; 133 *domp = nextgrp->ng_str[NG_DOM]; 134 nextgrp = nextgrp->ng_next; 135 return (1); 136 } 137 return (0); 138 } 139 140 /* 141 * __endnetgrent() - cleanup 142 */ 143 void 144 __endnetgrent() 145 { 146 register struct linelist *lp, *olp; 147 register struct netgrp *gp, *ogp; 148 149 lp = linehead; 150 while (lp) { 151 olp = lp; 152 lp = lp->l_next; 153 free(olp->l_groupname); 154 free(olp->l_line); 155 free((char *)olp); 156 } 157 linehead = (struct linelist *)0; 158 if (grouphead.grname) { 159 free(grouphead.grname); 160 grouphead.grname = (char *)0; 161 } 162 gp = grouphead.gr; 163 while (gp) { 164 ogp = gp; 165 gp = gp->ng_next; 166 if (ogp->ng_str[NG_HOST]) 167 free(ogp->ng_str[NG_HOST]); 168 if (ogp->ng_str[NG_USER]) 169 free(ogp->ng_str[NG_USER]); 170 if (ogp->ng_str[NG_DOM]) 171 free(ogp->ng_str[NG_DOM]); 172 free((char *)ogp); 173 } 174 grouphead.gr = (struct netgrp *)0; 175 } 176 177 /* 178 * Parse the netgroup file setting up the linked lists. 179 */ 180 static int 181 parse_netgrp(group) 182 char *group; 183 { 184 register char *spos, *epos; 185 register int len, strpos; 186 #ifdef DEBUG 187 register int fields; 188 #endif 189 char *pos, *gpos; 190 struct netgrp *grp; 191 struct linelist *lp = linehead; 192 193 /* 194 * First, see if the line has already been read in. 195 */ 196 while (lp) { 197 if (!strcmp(group, lp->l_groupname)) 198 break; 199 lp = lp->l_next; 200 } 201 if (lp == (struct linelist *)0 && 202 (lp = read_for_group(group)) == (struct linelist *)0) 203 return (1); 204 if (lp->l_parsed) { 205 #ifdef DEBUG 206 /* 207 * This error message is largely superflous since the 208 * code handles the error condition sucessfully, and 209 * spewing it out from inside libc can actually hose 210 * certain programs. 211 */ 212 fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname); 213 #endif 214 return (1); 215 } else 216 lp->l_parsed = 1; 217 pos = lp->l_line; 218 /* Watch for null pointer dereferences, dammit! */ 219 while (pos != NULL && *pos != '\0') { 220 if (*pos == '(') { 221 grp = (struct netgrp *)malloc(sizeof (struct netgrp)); 222 bzero((char *)grp, sizeof (struct netgrp)); 223 grp->ng_next = grouphead.gr; 224 grouphead.gr = grp; 225 pos++; 226 gpos = strsep(&pos, ")"); 227 #ifdef DEBUG 228 fields = 0; 229 #endif 230 for (strpos = 0; strpos < 3; strpos++) { 231 if ((spos = strsep(&gpos, ","))) { 232 #ifdef DEBUG 233 fields++; 234 #endif 235 while (*spos == ' ' || *spos == '\t') 236 spos++; 237 if ((epos = strpbrk(spos, " \t"))) { 238 *epos = '\0'; 239 len = epos - spos; 240 } else 241 len = strlen(spos); 242 if (len > 0) { 243 grp->ng_str[strpos] = (char *) 244 malloc(len + 1); 245 bcopy(spos, grp->ng_str[strpos], 246 len + 1); 247 } 248 } else { 249 /* 250 * All other systems I've tested 251 * return NULL for empty netgroup 252 * fields. It's up to user programs 253 * to handle the NULLs appropriately. 254 */ 255 grp->ng_str[strpos] = NULL; 256 } 257 } 258 #ifdef DEBUG 259 /* 260 * Note: on other platforms, malformed netgroup 261 * entries are not normally flagged. While we 262 * can catch bad entries and report them, we should 263 * stay silent by default for compatibility's sake. 264 */ 265 if (fields < 3) 266 fprintf(stderr, "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n", 267 grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST], 268 grp->ng_str[NG_USER] == NULL ? "" : ",", 269 grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER], 270 grp->ng_str[NG_DOM] == NULL ? "" : ",", 271 grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM], 272 lp->l_groupname); 273 #endif 274 } else { 275 spos = strsep(&pos, ", \t"); 276 if (parse_netgrp(spos)) 277 continue; 278 } 279 /* Watch for null pointer dereferences, dammit! */ 280 if (pos != NULL) 281 while (*pos == ' ' || *pos == ',' || *pos == '\t') 282 pos++; 283 } 284 return (0); 285 } 286 287 /* 288 * Read the netgroup file and save lines until the line for the netgroup 289 * is found. Return 1 if eof is encountered. 290 */ 291 static struct linelist * 292 read_for_group(group) 293 char *group; 294 { 295 register char *pos, *spos, *linep, *olinep; 296 register int len, olen; 297 int cont; 298 struct linelist *lp; 299 char line[LINSIZ + 1]; 300 char *key = NULL, *data = NULL; 301 302 data = lookup (gtable, group); 303 sprintf(line, "%s %s", group, data); 304 pos = (char *)&line; 305 #ifdef CANT_HAPPEN 306 if (*pos == '#') 307 continue; 308 #endif 309 while (*pos == ' ' || *pos == '\t') 310 pos++; 311 spos = pos; 312 while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 313 *pos != '\0') 314 pos++; 315 len = pos - spos; 316 while (*pos == ' ' || *pos == '\t') 317 pos++; 318 if (*pos != '\n' && *pos != '\0') { 319 lp = (struct linelist *)malloc(sizeof (*lp)); 320 lp->l_parsed = 0; 321 lp->l_groupname = (char *)malloc(len + 1); 322 bcopy(spos, lp->l_groupname, len); 323 *(lp->l_groupname + len) = '\0'; 324 len = strlen(pos); 325 olen = 0; 326 /* 327 * Loop around handling line continuations. 328 */ 329 do { 330 if (*(pos + len - 1) == '\n') 331 len--; 332 if (*(pos + len - 1) == '\\') { 333 len--; 334 cont = 1; 335 } else 336 cont = 0; 337 if (len > 0) { 338 linep = (char *)malloc(olen + len + 1); 339 if (olen > 0) { 340 bcopy(olinep, linep, olen); 341 free(olinep); 342 } 343 bcopy(pos, linep + olen, len); 344 olen += len; 345 *(linep + olen) = '\0'; 346 olinep = linep; 347 } 348 #ifdef CANT_HAPPEN 349 if (cont) { 350 if (fgets(line, LINSIZ, netf)) { 351 pos = line; 352 len = strlen(pos); 353 } else 354 cont = 0; 355 } 356 #endif 357 } while (cont); 358 lp->l_line = linep; 359 lp->l_next = linehead; 360 linehead = lp; 361 #ifdef CANT_HAPPEN 362 /* 363 * If this is the one we wanted, we are done. 364 */ 365 if (!strcmp(lp->l_groupname, group)) 366 #endif 367 return (lp); 368 } 369 return ((struct linelist *)0); 370 } 371