1 /* $NetBSD: parse_netgroup.c,v 1.2 1997/10/06 06:54:13 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 */ 39 40 #include <sys/cdefs.h> 41 #ifndef lint 42 __RCSID("$NetBSD: parse_netgroup.c,v 1.2 1997/10/06 06:54:13 lukem Exp $"); 43 #endif 44 45 /* 46 * This is a specially hacked-up version of getnetgrent.c used to parse 47 * data from the stored hash table of netgroup info rather than from a 48 * file. It's used mainly for the parse_netgroup() function. All the YP 49 * stuff and file support has been stripped out since it isn't needed. 50 */ 51 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 57 #include "hash.h" 58 59 /* 60 * Static Variables and functions used by rng_setnetgrent(), rng_getnetgrent() 61 * and rng_endnetgrent(). 62 * 63 * There are two linked lists: 64 * - linelist is just used by setnetgrent() to parse the net group file via. 65 * parse_netgrp() 66 * - netgrp is the list of entries for the current netgroup 67 */ 68 struct linelist { 69 struct linelist *l_next; /* Chain ptr. */ 70 int l_parsed; /* Flag for cycles */ 71 char *l_groupname; /* Name of netgroup */ 72 char *l_line; /* Netgroup entrie(s) to be parsed */ 73 }; 74 75 struct netgrp { 76 struct netgrp *ng_next; /* Chain ptr */ 77 char *ng_str[3]; /* Field pointers, see below */ 78 }; 79 #define NG_HOST 0 /* Host name */ 80 #define NG_USER 1 /* User name */ 81 #define NG_DOM 2 /* and Domain name */ 82 83 static struct linelist *linehead = (struct linelist *)0; 84 static struct netgrp *nextgrp = (struct netgrp *)0; 85 static struct { 86 struct netgrp *gr; 87 char *grname; 88 } grouphead = { 89 (struct netgrp *)0, 90 (char *)0, 91 }; 92 93 extern struct group_entry *gtable[]; 94 95 static int parse_netgrp __P((const char *)); 96 static struct linelist *read_for_group __P((const char *)); 97 98 99 /* 100 * rng_setnetgrent() 101 * Parse the netgroup file looking for the netgroup and build the list 102 * of netgrp structures. Let parse_netgrp() and read_for_group() do 103 * most of the work. 104 */ 105 void 106 rng_setnetgrent(group) 107 const char *group; 108 { 109 /* Sanity check */ 110 111 if (group == NULL || !strlen(group)) 112 return; 113 114 if (grouphead.gr == (struct netgrp *)0 || 115 strcmp(group, grouphead.grname)) { 116 rng_endnetgrent(); 117 if (parse_netgrp(group)) 118 rng_endnetgrent(); 119 else { 120 grouphead.grname = (char *) 121 malloc(strlen(group) + 1); 122 strcpy(grouphead.grname, group); 123 } 124 } 125 nextgrp = grouphead.gr; 126 } 127 128 /* 129 * Get the next netgroup off the list. 130 */ 131 int 132 rng_getnetgrent(hostp, userp, domp) 133 char **hostp, **userp, **domp; 134 { 135 if (nextgrp) { 136 *hostp = nextgrp->ng_str[NG_HOST]; 137 *userp = nextgrp->ng_str[NG_USER]; 138 *domp = nextgrp->ng_str[NG_DOM]; 139 nextgrp = nextgrp->ng_next; 140 return (1); 141 } 142 return (0); 143 } 144 145 /* 146 * rng_endnetgrent() - cleanup 147 */ 148 void 149 rng_endnetgrent() 150 { 151 struct linelist *lp, *olp; 152 struct netgrp *gp, *ogp; 153 154 lp = linehead; 155 while (lp) { 156 olp = lp; 157 lp = lp->l_next; 158 free(olp->l_groupname); 159 free(olp->l_line); 160 free((char *)olp); 161 } 162 linehead = (struct linelist *)0; 163 if (grouphead.grname) { 164 free(grouphead.grname); 165 grouphead.grname = (char *)0; 166 } 167 gp = grouphead.gr; 168 while (gp) { 169 ogp = gp; 170 gp = gp->ng_next; 171 if (ogp->ng_str[NG_HOST]) 172 free(ogp->ng_str[NG_HOST]); 173 if (ogp->ng_str[NG_USER]) 174 free(ogp->ng_str[NG_USER]); 175 if (ogp->ng_str[NG_DOM]) 176 free(ogp->ng_str[NG_DOM]); 177 free((char *)ogp); 178 } 179 grouphead.gr = (struct netgrp *)0; 180 } 181 182 /* 183 * Parse the netgroup file setting up the linked lists. 184 */ 185 static int 186 parse_netgrp(group) 187 const char *group; 188 { 189 char *spos, *epos; 190 int len, strpos; 191 #ifdef DEBUG 192 int fields; 193 #endif 194 char *pos, *gpos; 195 struct netgrp *grp; 196 struct linelist *lp = linehead; 197 198 /* 199 * First, see if the line has already been read in. 200 */ 201 while (lp) { 202 if (!strcmp(group, lp->l_groupname)) 203 break; 204 lp = lp->l_next; 205 } 206 if (lp == (struct linelist *)0 && 207 (lp = read_for_group(group)) == (struct linelist *)0) 208 return (1); 209 if (lp->l_parsed) { 210 #ifdef DEBUG 211 /* 212 * This error message is largely superflous since the 213 * code handles the error condition sucessfully, and 214 * spewing it out from inside libc can actually hose 215 * certain programs. 216 */ 217 warnx("Cycle in netgroup %s", lp->l_groupname); 218 #endif 219 return (1); 220 } else 221 lp->l_parsed = 1; 222 pos = lp->l_line; 223 /* Watch for null pointer dereferences, dammit! */ 224 while (pos != NULL && *pos != '\0') { 225 if (*pos == '(') { 226 grp = (struct netgrp *)malloc(sizeof (struct netgrp)); 227 memset((char *)grp, 0, sizeof (struct netgrp)); 228 grp->ng_next = grouphead.gr; 229 grouphead.gr = grp; 230 pos++; 231 gpos = strsep(&pos, ")"); 232 #ifdef DEBUG 233 fields = 0; 234 #endif 235 for (strpos = 0; strpos < 3; strpos++) { 236 if ((spos = strsep(&gpos, ","))) { 237 #ifdef DEBUG 238 fields++; 239 #endif 240 while (*spos == ' ' || *spos == '\t') 241 spos++; 242 if ((epos = strpbrk(spos, " \t"))) { 243 *epos = '\0'; 244 len = epos - spos; 245 } else 246 len = strlen(spos); 247 if (len > 0) { 248 grp->ng_str[strpos] = (char *) 249 malloc(len + 1); 250 memmove(grp->ng_str[strpos], 251 spos, len + 1); 252 } 253 } else { 254 /* 255 * All other systems I've tested 256 * return NULL for empty netgroup 257 * fields. It's up to user programs 258 * to handle the NULLs appropriately. 259 */ 260 grp->ng_str[strpos] = NULL; 261 } 262 } 263 #ifdef DEBUG 264 /* 265 * Note: on other platforms, malformed netgroup 266 * entries are not normally flagged. While we 267 * can catch bad entries and report them, we should 268 * stay silent by default for compatibility's sake. 269 */ 270 if (fields < 3) 271 warnx( 272 "Bad entry (%s%s%s%s%s) in netgroup \"%s\"", 273 grp->ng_str[NG_HOST] == NULL ? "" : 274 grp->ng_str[NG_HOST], 275 grp->ng_str[NG_USER] == NULL ? "" : ",", 276 grp->ng_str[NG_USER] == NULL ? "" : 277 grp->ng_str[NG_USER], 278 grp->ng_str[NG_DOM] == NULL ? "" : ",", 279 grp->ng_str[NG_DOM] == NULL ? "" : 280 grp->ng_str[NG_DOM], 281 lp->l_groupname); 282 #endif 283 } else { 284 spos = strsep(&pos, ", \t"); 285 if (parse_netgrp(spos)) 286 continue; 287 } 288 /* Watch for null pointer dereferences, dammit! */ 289 if (pos != NULL) 290 while (*pos == ' ' || *pos == ',' || *pos == '\t') 291 pos++; 292 } 293 return (0); 294 } 295 296 /* 297 * Read the netgroup file and save lines until the line for the netgroup 298 * is found. Return 1 if eof is encountered. 299 */ 300 static struct linelist * 301 read_for_group(group) 302 const char *group; 303 { 304 char *pos, *spos, *linep = NULL, *olinep = NULL; 305 int len, olen; 306 int cont; 307 struct linelist *lp; 308 char line[LINSIZ + 1]; 309 char *data = NULL; 310 311 data = lookup (gtable, group); 312 sprintf(line, "%s %s", group, data); 313 pos = (char *)&line; 314 #ifdef CANT_HAPPEN 315 if (*pos == '#') 316 continue; 317 #endif 318 while (*pos == ' ' || *pos == '\t') 319 pos++; 320 spos = pos; 321 while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 322 *pos != '\0') 323 pos++; 324 len = pos - spos; 325 while (*pos == ' ' || *pos == '\t') 326 pos++; 327 if (*pos != '\n' && *pos != '\0') { 328 lp = (struct linelist *)malloc(sizeof (*lp)); 329 lp->l_parsed = 0; 330 lp->l_groupname = (char *)malloc(len + 1); 331 memmove(lp->l_groupname, spos, len); 332 *(lp->l_groupname + len) = '\0'; 333 len = strlen(pos); 334 olen = 0; 335 /* 336 * Loop around handling line continuations. 337 */ 338 do { 339 if (*(pos + len - 1) == '\n') 340 len--; 341 if (*(pos + len - 1) == '\\') { 342 len--; 343 cont = 1; 344 } else 345 cont = 0; 346 if (len > 0) { 347 linep = (char *)malloc(olen + len + 1); 348 if (olen > 0) { 349 memmove(linep, olinep, olen); 350 free(olinep); 351 } 352 memmove(linep + olen, pos, len); 353 olen += len; 354 *(linep + olen) = '\0'; 355 olinep = linep; 356 } 357 #ifdef CANT_HAPPEN 358 if (cont) { 359 if (fgets(line, LINSIZ, netf)) { 360 pos = line; 361 len = strlen(pos); 362 } else 363 cont = 0; 364 } 365 #endif 366 } while (cont); 367 lp->l_line = linep; 368 lp->l_next = linehead; 369 linehead = lp; 370 #ifdef CANT_HAPPEN 371 /* 372 * If this is the one we wanted, we are done. 373 */ 374 if (!strcmp(lp->l_groupname, group)) 375 #endif 376 return (lp); 377 } 378 return ((struct linelist *)0); 379 } 380