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 #ifndef lint 55 static const char rcsid[] = "$Id$"; 56 #endif 57 58 /* 59 * Static Variables and functions used by setnetgrent(), getnetgrent() and 60 * __endnetgrent(). 61 * There are two linked lists: 62 * - linelist is just used by setnetgrent() to parse the net group file via. 63 * parse_netgrp() 64 * - 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 netgrp { 74 struct netgrp *ng_next; /* Chain ptr */ 75 char *ng_str[3]; /* Field pointers, see below */ 76 }; 77 #define NG_HOST 0 /* Host name */ 78 #define NG_USER 1 /* User name */ 79 #define NG_DOM 2 /* and Domain name */ 80 81 static struct linelist *linehead = (struct linelist *)0; 82 static struct netgrp *nextgrp = (struct netgrp *)0; 83 static struct { 84 struct netgrp *gr; 85 char *grname; 86 } grouphead = { 87 (struct netgrp *)0, 88 (char *)0, 89 }; 90 static int parse_netgrp(); 91 static struct linelist *read_for_group(); 92 void __setnetgrent(), __endnetgrent(); 93 int __getnetgrent(); 94 extern struct group_entry *gtable[]; 95 96 /* 97 * setnetgrent() 98 * Parse the netgroup file looking for the netgroup and build the list 99 * of netgrp structures. Let parse_netgrp() and read_for_group() do 100 * most of the work. 101 */ 102 void 103 __setnetgrent(group) 104 char *group; 105 { 106 /* Sanity check */ 107 108 if (group == NULL || !strlen(group)) 109 return; 110 111 if (grouphead.gr == (struct netgrp *)0 || 112 strcmp(group, grouphead.grname)) { 113 __endnetgrent(); 114 if (parse_netgrp(group)) 115 __endnetgrent(); 116 else { 117 grouphead.grname = (char *) 118 malloc(strlen(group) + 1); 119 strcpy(grouphead.grname, group); 120 } 121 } 122 nextgrp = grouphead.gr; 123 } 124 125 /* 126 * Get the next netgroup off the list. 127 */ 128 int 129 __getnetgrent(hostp, userp, domp) 130 char **hostp, **userp, **domp; 131 { 132 if (nextgrp) { 133 *hostp = nextgrp->ng_str[NG_HOST]; 134 *userp = nextgrp->ng_str[NG_USER]; 135 *domp = nextgrp->ng_str[NG_DOM]; 136 nextgrp = nextgrp->ng_next; 137 return (1); 138 } 139 return (0); 140 } 141 142 /* 143 * __endnetgrent() - cleanup 144 */ 145 void 146 __endnetgrent() 147 { 148 register struct linelist *lp, *olp; 149 register struct netgrp *gp, *ogp; 150 151 lp = linehead; 152 while (lp) { 153 olp = lp; 154 lp = lp->l_next; 155 free(olp->l_groupname); 156 free(olp->l_line); 157 free((char *)olp); 158 } 159 linehead = (struct linelist *)0; 160 if (grouphead.grname) { 161 free(grouphead.grname); 162 grouphead.grname = (char *)0; 163 } 164 gp = grouphead.gr; 165 while (gp) { 166 ogp = gp; 167 gp = gp->ng_next; 168 if (ogp->ng_str[NG_HOST]) 169 free(ogp->ng_str[NG_HOST]); 170 if (ogp->ng_str[NG_USER]) 171 free(ogp->ng_str[NG_USER]); 172 if (ogp->ng_str[NG_DOM]) 173 free(ogp->ng_str[NG_DOM]); 174 free((char *)ogp); 175 } 176 grouphead.gr = (struct netgrp *)0; 177 } 178 179 /* 180 * Parse the netgroup file setting up the linked lists. 181 */ 182 static int 183 parse_netgrp(group) 184 char *group; 185 { 186 register char *spos, *epos; 187 register int len, strpos; 188 #ifdef DEBUG 189 register int fields; 190 #endif 191 char *pos, *gpos; 192 struct netgrp *grp; 193 struct linelist *lp = linehead; 194 195 /* 196 * First, see if the line has already been read in. 197 */ 198 while (lp) { 199 if (!strcmp(group, lp->l_groupname)) 200 break; 201 lp = lp->l_next; 202 } 203 if (lp == (struct linelist *)0 && 204 (lp = read_for_group(group)) == (struct linelist *)0) 205 return (1); 206 if (lp->l_parsed) { 207 #ifdef DEBUG 208 /* 209 * This error message is largely superflous since the 210 * code handles the error condition sucessfully, and 211 * spewing it out from inside libc can actually hose 212 * certain programs. 213 */ 214 fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname); 215 #endif 216 return (1); 217 } else 218 lp->l_parsed = 1; 219 pos = lp->l_line; 220 /* Watch for null pointer dereferences, dammit! */ 221 while (pos != NULL && *pos != '\0') { 222 if (*pos == '(') { 223 grp = (struct netgrp *)malloc(sizeof (struct netgrp)); 224 bzero((char *)grp, sizeof (struct netgrp)); 225 grp->ng_next = grouphead.gr; 226 grouphead.gr = grp; 227 pos++; 228 gpos = strsep(&pos, ")"); 229 #ifdef DEBUG 230 fields = 0; 231 #endif 232 for (strpos = 0; strpos < 3; strpos++) { 233 if ((spos = strsep(&gpos, ","))) { 234 #ifdef DEBUG 235 fields++; 236 #endif 237 while (*spos == ' ' || *spos == '\t') 238 spos++; 239 if ((epos = strpbrk(spos, " \t"))) { 240 *epos = '\0'; 241 len = epos - spos; 242 } else 243 len = strlen(spos); 244 if (len > 0) { 245 grp->ng_str[strpos] = (char *) 246 malloc(len + 1); 247 bcopy(spos, grp->ng_str[strpos], 248 len + 1); 249 } 250 } else { 251 /* 252 * All other systems I've tested 253 * return NULL for empty netgroup 254 * fields. It's up to user programs 255 * to handle the NULLs appropriately. 256 */ 257 grp->ng_str[strpos] = NULL; 258 } 259 } 260 #ifdef DEBUG 261 /* 262 * Note: on other platforms, malformed netgroup 263 * entries are not normally flagged. While we 264 * can catch bad entries and report them, we should 265 * stay silent by default for compatibility's sake. 266 */ 267 if (fields < 3) 268 fprintf(stderr, "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n", 269 grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST], 270 grp->ng_str[NG_USER] == NULL ? "" : ",", 271 grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER], 272 grp->ng_str[NG_DOM] == NULL ? "" : ",", 273 grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM], 274 lp->l_groupname); 275 #endif 276 } else { 277 spos = strsep(&pos, ", \t"); 278 if (parse_netgrp(spos)) 279 continue; 280 } 281 /* Watch for null pointer dereferences, dammit! */ 282 if (pos != NULL) 283 while (*pos == ' ' || *pos == ',' || *pos == '\t') 284 pos++; 285 } 286 return (0); 287 } 288 289 /* 290 * Read the netgroup file and save lines until the line for the netgroup 291 * is found. Return 1 if eof is encountered. 292 */ 293 static struct linelist * 294 read_for_group(group) 295 char *group; 296 { 297 register char *pos, *spos, *linep = NULL, *olinep = NULL; 298 register int len, olen; 299 int cont; 300 struct linelist *lp; 301 char line[LINSIZ + 1]; 302 char *data = NULL; 303 304 data = lookup (gtable, group); 305 sprintf(line, "%s %s", group, data); 306 pos = (char *)&line; 307 #ifdef CANT_HAPPEN 308 if (*pos == '#') 309 continue; 310 #endif 311 while (*pos == ' ' || *pos == '\t') 312 pos++; 313 spos = pos; 314 while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 315 *pos != '\0') 316 pos++; 317 len = pos - spos; 318 while (*pos == ' ' || *pos == '\t') 319 pos++; 320 if (*pos != '\n' && *pos != '\0') { 321 lp = (struct linelist *)malloc(sizeof (*lp)); 322 lp->l_parsed = 0; 323 lp->l_groupname = (char *)malloc(len + 1); 324 bcopy(spos, lp->l_groupname, len); 325 *(lp->l_groupname + len) = '\0'; 326 len = strlen(pos); 327 olen = 0; 328 /* 329 * Loop around handling line continuations. 330 */ 331 do { 332 if (*(pos + len - 1) == '\n') 333 len--; 334 if (*(pos + len - 1) == '\\') { 335 len--; 336 cont = 1; 337 } else 338 cont = 0; 339 if (len > 0) { 340 linep = (char *)malloc(olen + len + 1); 341 if (olen > 0) { 342 bcopy(olinep, linep, olen); 343 free(olinep); 344 } 345 bcopy(pos, linep + olen, len); 346 olen += len; 347 *(linep + olen) = '\0'; 348 olinep = linep; 349 } 350 #ifdef CANT_HAPPEN 351 if (cont) { 352 if (fgets(line, LINSIZ, netf)) { 353 pos = line; 354 len = strlen(pos); 355 } else 356 cont = 0; 357 } 358 #endif 359 } while (cont); 360 lp->l_line = linep; 361 lp->l_next = linehead; 362 linehead = lp; 363 #ifdef CANT_HAPPEN 364 /* 365 * If this is the one we wanted, we are done. 366 */ 367 if (!strcmp(lp->l_groupname, group)) 368 #endif 369 return (lp); 370 } 371 return ((struct linelist *)0); 372 } 373