parse_netgroup.c revision 229780
1238405Sjkim/* 2238405Sjkim * Copyright (c) 1992, 1993 3238405Sjkim * The Regents of the University of California. All rights reserved. 4238405Sjkim * 5238405Sjkim * This code is derived from software contributed to Berkeley by 6238405Sjkim * Rick Macklem at The University of Guelph. 7238405Sjkim * 8238405Sjkim * Redistribution and use in source and binary forms, with or without 9238405Sjkim * modification, are permitted provided that the following conditions 10238405Sjkim * are met: 11238405Sjkim * 1. Redistributions of source code must retain the above copyright 12238405Sjkim * notice, this list of conditions and the following disclaimer. 13238405Sjkim * 2. Redistributions in binary form must reproduce the above copyright 14238405Sjkim * notice, this list of conditions and the following disclaimer in the 15238405Sjkim * documentation and/or other materials provided with the distribution. 16238405Sjkim * 3. All advertising materials mentioning features or use of this software 17238405Sjkim * must display the following acknowledgement: 18238405Sjkim * This product includes software developed by the University of 19238405Sjkim * California, Berkeley and its contributors. 20238405Sjkim * 4. Neither the name of the University nor the names of its contributors 21238405Sjkim * may be used to endorse or promote products derived from this software 22238405Sjkim * without specific prior written permission. 23238405Sjkim * 24238405Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25238405Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26238405Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27238405Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28238405Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29238405Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30238405Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31238405Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32238405Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33238405Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34238405Sjkim * SUCH DAMAGE. 35238405Sjkim */ 36238405Sjkim 37238405Sjkim#ifndef lint 38238405Sjkimstatic const char rcsid[] = 39238405Sjkim "$FreeBSD: head/libexec/revnetgroup/parse_netgroup.c 229780 2012-01-07 16:09:54Z uqs $"; 40238405Sjkim#endif /* not lint */ 41238405Sjkim 42238405Sjkim/* 43238405Sjkim * This is a specially hacked-up version of getnetgrent.c used to parse 44238405Sjkim * data from the stored hash table of netgroup info rather than from a 45238405Sjkim * file. It's used mainly for the parse_netgroup() function. All the YP 46238405Sjkim * stuff and file support has been stripped out since it isn't needed. 47238405Sjkim */ 48238405Sjkim 49238405Sjkim#include <stdio.h> 50238405Sjkim#include <string.h> 51238405Sjkim#include <strings.h> 52238405Sjkim#include <stdlib.h> 53238405Sjkim#include <unistd.h> 54238405Sjkim#include "hash.h" 55238405Sjkim 56238405Sjkim/* 57238405Sjkim * Static Variables and functions used by setnetgrent(), getnetgrent() and 58238405Sjkim * __endnetgrent(). 59238405Sjkim * There are two linked lists: 60238405Sjkim * - linelist is just used by setnetgrent() to parse the net group file via. 61238405Sjkim * parse_netgrp() 62238405Sjkim * - netgrp is the list of entries for the current netgroup 63238405Sjkim */ 64238405Sjkimstruct linelist { 65238405Sjkim struct linelist *l_next; /* Chain ptr. */ 66238405Sjkim int l_parsed; /* Flag for cycles */ 67238405Sjkim char *l_groupname; /* Name of netgroup */ 68238405Sjkim char *l_line; /* Netgroup entrie(s) to be parsed */ 69238405Sjkim}; 70238405Sjkim 71238405Sjkimstruct netgrp { 72238405Sjkim struct netgrp *ng_next; /* Chain ptr */ 73238405Sjkim char *ng_str[3]; /* Field pointers, see below */ 74238405Sjkim}; 75238405Sjkim#define NG_HOST 0 /* Host name */ 76238405Sjkim#define NG_USER 1 /* User name */ 77238405Sjkim#define NG_DOM 2 /* and Domain name */ 78238405Sjkim 79238405Sjkimstatic struct linelist *linehead = (struct linelist *)0; 80238405Sjkimstatic struct netgrp *nextgrp = (struct netgrp *)0; 81238405Sjkimstatic struct { 82238405Sjkim struct netgrp *gr; 83238405Sjkim char *grname; 84238405Sjkim} grouphead = { 85238405Sjkim (struct netgrp *)0, 86238405Sjkim (char *)0, 87238405Sjkim}; 88238405Sjkimstatic int parse_netgrp(char *group); 89238405Sjkimstatic struct linelist *read_for_group(char *group); 90238405Sjkimextern struct group_entry *gtable[]; 91238405Sjkim 92238405Sjkim/* 93238405Sjkim * setnetgrent() 94238405Sjkim * Parse the netgroup file looking for the netgroup and build the list 95238405Sjkim * of netgrp structures. Let parse_netgrp() and read_for_group() do 96238405Sjkim * most of the work. 97238405Sjkim */ 98238405Sjkimvoid 99238405Sjkim__setnetgrent(char *group) 100238405Sjkim{ 101238405Sjkim /* Sanity check */ 102238405Sjkim 103238405Sjkim if (group == NULL || !strlen(group)) 104238405Sjkim return; 105238405Sjkim 106238405Sjkim if (grouphead.gr == (struct netgrp *)0 || 107238405Sjkim strcmp(group, grouphead.grname)) { 108238405Sjkim __endnetgrent(); 109238405Sjkim if (parse_netgrp(group)) 110238405Sjkim __endnetgrent(); 111238405Sjkim else { 112238405Sjkim grouphead.grname = (char *) 113238405Sjkim malloc(strlen(group) + 1); 114238405Sjkim strcpy(grouphead.grname, group); 115238405Sjkim } 116238405Sjkim } 117238405Sjkim nextgrp = grouphead.gr; 118238405Sjkim} 119238405Sjkim 120238405Sjkim/* 121238405Sjkim * Get the next netgroup off the list. 122238405Sjkim */ 123238405Sjkimint 124238405Sjkim__getnetgrent(char **hostp, char **userp, char **domp) 125238405Sjkim{ 126238405Sjkim if (nextgrp) { 127238405Sjkim *hostp = nextgrp->ng_str[NG_HOST]; 128238405Sjkim *userp = nextgrp->ng_str[NG_USER]; 129238405Sjkim *domp = nextgrp->ng_str[NG_DOM]; 130238405Sjkim nextgrp = nextgrp->ng_next; 131238405Sjkim return (1); 132238405Sjkim } 133238405Sjkim return (0); 134238405Sjkim} 135238405Sjkim 136238405Sjkim/* 137238405Sjkim * __endnetgrent() - cleanup 138238405Sjkim */ 139238405Sjkimvoid 140238405Sjkim__endnetgrent(void) 141238405Sjkim{ 142238405Sjkim struct linelist *lp, *olp; 143238405Sjkim struct netgrp *gp, *ogp; 144238405Sjkim 145238405Sjkim lp = linehead; 146238405Sjkim while (lp) { 147238405Sjkim olp = lp; 148238405Sjkim lp = lp->l_next; 149238405Sjkim free(olp->l_groupname); 150238405Sjkim free(olp->l_line); 151238405Sjkim free((char *)olp); 152238405Sjkim } 153238405Sjkim linehead = (struct linelist *)0; 154238405Sjkim if (grouphead.grname) { 155238405Sjkim free(grouphead.grname); 156238405Sjkim grouphead.grname = (char *)0; 157238405Sjkim } 158238405Sjkim gp = grouphead.gr; 159238405Sjkim while (gp) { 160238405Sjkim ogp = gp; 161238405Sjkim gp = gp->ng_next; 162238405Sjkim if (ogp->ng_str[NG_HOST]) 163238405Sjkim free(ogp->ng_str[NG_HOST]); 164238405Sjkim if (ogp->ng_str[NG_USER]) 165238405Sjkim free(ogp->ng_str[NG_USER]); 166238405Sjkim if (ogp->ng_str[NG_DOM]) 167238405Sjkim free(ogp->ng_str[NG_DOM]); 168238405Sjkim free((char *)ogp); 169238405Sjkim } 170238405Sjkim grouphead.gr = (struct netgrp *)0; 171238405Sjkim} 172238405Sjkim 173238405Sjkim/* 174238405Sjkim * Parse the netgroup file setting up the linked lists. 175238405Sjkim */ 176238405Sjkimstatic int 177238405Sjkimparse_netgrp(char *group) 178238405Sjkim{ 179238405Sjkim char *spos, *epos; 180238405Sjkim int len, strpos; 181238405Sjkim#ifdef DEBUG 182238405Sjkim int fields; 183238405Sjkim#endif 184238405Sjkim char *pos, *gpos; 185238405Sjkim struct netgrp *grp; 186238405Sjkim struct linelist *lp = linehead; 187238405Sjkim 188238405Sjkim /* 189238405Sjkim * First, see if the line has already been read in. 190238405Sjkim */ 191238405Sjkim while (lp) { 192238405Sjkim if (!strcmp(group, lp->l_groupname)) 193238405Sjkim break; 194238405Sjkim lp = lp->l_next; 195238405Sjkim } 196238405Sjkim if (lp == (struct linelist *)0 && 197238405Sjkim (lp = read_for_group(group)) == (struct linelist *)0) 198238405Sjkim return (1); 199238405Sjkim if (lp->l_parsed) { 200238405Sjkim#ifdef DEBUG 201238405Sjkim /* 202238405Sjkim * This error message is largely superfluous since the 203238405Sjkim * code handles the error condition successfully, and 204238405Sjkim * spewing it out from inside libc can actually hose 205238405Sjkim * certain programs. 206238405Sjkim */ 207238405Sjkim warnx("cycle in netgroup %s", lp->l_groupname); 208238405Sjkim#endif 209238405Sjkim return (1); 210238405Sjkim } else 211238405Sjkim lp->l_parsed = 1; 212238405Sjkim pos = lp->l_line; 213238405Sjkim /* Watch for null pointer dereferences, dammit! */ 214238405Sjkim while (pos != NULL && *pos != '\0') { 215238405Sjkim if (*pos == '(') { 216238405Sjkim grp = (struct netgrp *)malloc(sizeof (struct netgrp)); 217238405Sjkim bzero((char *)grp, sizeof (struct netgrp)); 218238405Sjkim grp->ng_next = grouphead.gr; 219238405Sjkim grouphead.gr = grp; 220238405Sjkim pos++; 221238405Sjkim gpos = strsep(&pos, ")"); 222238405Sjkim#ifdef DEBUG 223238405Sjkim fields = 0; 224238405Sjkim#endif 225238405Sjkim for (strpos = 0; strpos < 3; strpos++) { 226238405Sjkim if ((spos = strsep(&gpos, ","))) { 227238405Sjkim#ifdef DEBUG 228238405Sjkim fields++; 229238405Sjkim#endif 230238405Sjkim while (*spos == ' ' || *spos == '\t') 231238405Sjkim spos++; 232238405Sjkim if ((epos = strpbrk(spos, " \t"))) { 233238405Sjkim *epos = '\0'; 234238405Sjkim len = epos - spos; 235238405Sjkim } else 236238405Sjkim len = strlen(spos); 237238405Sjkim if (len > 0) { 238238405Sjkim grp->ng_str[strpos] = (char *) 239238405Sjkim malloc(len + 1); 240238405Sjkim bcopy(spos, grp->ng_str[strpos], 241238405Sjkim len + 1); 242238405Sjkim } 243238405Sjkim } else { 244238405Sjkim /* 245238405Sjkim * All other systems I've tested 246238405Sjkim * return NULL for empty netgroup 247238405Sjkim * fields. It's up to user programs 248238405Sjkim * to handle the NULLs appropriately. 249238405Sjkim */ 250238405Sjkim grp->ng_str[strpos] = NULL; 251238405Sjkim } 252238405Sjkim } 253238405Sjkim#ifdef DEBUG 254238405Sjkim /* 255238405Sjkim * Note: on other platforms, malformed netgroup 256238405Sjkim * entries are not normally flagged. While we 257238405Sjkim * can catch bad entries and report them, we should 258238405Sjkim * stay silent by default for compatibility's sake. 259238405Sjkim */ 260238405Sjkim if (fields < 3) 261238405Sjkim warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"", 262238405Sjkim grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST], 263238405Sjkim grp->ng_str[NG_USER] == NULL ? "" : ",", 264238405Sjkim grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER], 265238405Sjkim grp->ng_str[NG_DOM] == NULL ? "" : ",", 266238405Sjkim grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM], 267238405Sjkim lp->l_groupname); 268238405Sjkim#endif 269238405Sjkim } else { 270238405Sjkim spos = strsep(&pos, ", \t"); 271238405Sjkim if (parse_netgrp(spos)) 272238405Sjkim continue; 273238405Sjkim } 274238405Sjkim /* Watch for null pointer dereferences, dammit! */ 275238405Sjkim if (pos != NULL) 276238405Sjkim while (*pos == ' ' || *pos == ',' || *pos == '\t') 277238405Sjkim pos++; 278238405Sjkim } 279238405Sjkim return (0); 280238405Sjkim} 281238405Sjkim 282238405Sjkim/* 283238405Sjkim * Read the netgroup file and save lines until the line for the netgroup 284238405Sjkim * is found. Return 1 if eof is encountered. 285238405Sjkim */ 286238405Sjkimstatic struct linelist * 287238405Sjkimread_for_group(char *group) 288238405Sjkim{ 289238405Sjkim char *pos, *spos, *linep = NULL, *olinep = NULL; 290238405Sjkim int len, olen; 291238405Sjkim int cont; 292238405Sjkim struct linelist *lp; 293238405Sjkim char line[LINSIZ + 1]; 294238405Sjkim char *data = NULL; 295238405Sjkim 296238405Sjkim data = lookup (gtable, group); 297238405Sjkim sprintf(line, "%s %s", group, data); 298238405Sjkim pos = (char *)&line; 299238405Sjkim#ifdef CANT_HAPPEN 300238405Sjkim if (*pos == '#') 301238405Sjkim continue; 302238405Sjkim#endif 303238405Sjkim while (*pos == ' ' || *pos == '\t') 304238405Sjkim pos++; 305238405Sjkim spos = pos; 306238405Sjkim while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 307238405Sjkim *pos != '\0') 308238405Sjkim pos++; 309238405Sjkim len = pos - spos; 310238405Sjkim while (*pos == ' ' || *pos == '\t') 311238405Sjkim pos++; 312238405Sjkim if (*pos != '\n' && *pos != '\0') { 313238405Sjkim lp = (struct linelist *)malloc(sizeof (*lp)); 314238405Sjkim lp->l_parsed = 0; 315238405Sjkim lp->l_groupname = (char *)malloc(len + 1); 316238405Sjkim bcopy(spos, lp->l_groupname, len); 317238405Sjkim *(lp->l_groupname + len) = '\0'; 318238405Sjkim len = strlen(pos); 319238405Sjkim olen = 0; 320238405Sjkim /* 321238405Sjkim * Loop around handling line continuations. 322238405Sjkim */ 323238405Sjkim do { 324238405Sjkim if (*(pos + len - 1) == '\n') 325238405Sjkim len--; 326238405Sjkim if (*(pos + len - 1) == '\\') { 327238405Sjkim len--; 328238405Sjkim cont = 1; 329238405Sjkim } else 330238405Sjkim cont = 0; 331238405Sjkim if (len > 0) { 332238405Sjkim linep = (char *)malloc(olen + len + 1); 333238405Sjkim if (olen > 0) { 334238405Sjkim bcopy(olinep, linep, olen); 335238405Sjkim free(olinep); 336238405Sjkim } 337238405Sjkim bcopy(pos, linep + olen, len); 338238405Sjkim olen += len; 339238405Sjkim *(linep + olen) = '\0'; 340238405Sjkim olinep = linep; 341238405Sjkim } 342238405Sjkim#ifdef CANT_HAPPEN 343238405Sjkim if (cont) { 344238405Sjkim if (fgets(line, LINSIZ, netf)) { 345238405Sjkim pos = line; 346238405Sjkim len = strlen(pos); 347238405Sjkim } else 348238405Sjkim cont = 0; 349238405Sjkim } 350238405Sjkim#endif 351238405Sjkim } while (cont); 352238405Sjkim lp->l_line = linep; 353238405Sjkim lp->l_next = linehead; 354238405Sjkim linehead = lp; 355238405Sjkim#ifdef CANT_HAPPEN 356238405Sjkim /* 357238405Sjkim * If this is the one we wanted, we are done. 358238405Sjkim */ 359238405Sjkim if (!strcmp(lp->l_groupname, group)) 360238405Sjkim#endif 361238405Sjkim return (lp); 362238405Sjkim } 363238405Sjkim return ((struct linelist *)0); 364238405Sjkim} 365238405Sjkim