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