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