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