1 /* $NetBSD: parse_netgroup.c,v 1.3 2002/07/06 01:00:15 wiz 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.3 2002/07/06 01:00:15 wiz 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(const char *); 96 static struct linelist *read_for_group(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(const char *group) 107 { 108 /* Sanity check */ 109 110 if (group == NULL || !strlen(group)) 111 return; 112 113 if (grouphead.gr == (struct netgrp *)0 || 114 strcmp(group, grouphead.grname)) { 115 rng_endnetgrent(); 116 if (parse_netgrp(group)) 117 rng_endnetgrent(); 118 else { 119 grouphead.grname = (char *) 120 malloc(strlen(group) + 1); 121 strcpy(grouphead.grname, group); 122 } 123 } 124 nextgrp = grouphead.gr; 125 } 126 127 /* 128 * Get the next netgroup off the list. 129 */ 130 int 131 rng_getnetgrent(char **hostp, char **userp, char **domp) 132 { 133 if (nextgrp) { 134 *hostp = nextgrp->ng_str[NG_HOST]; 135 *userp = nextgrp->ng_str[NG_USER]; 136 *domp = nextgrp->ng_str[NG_DOM]; 137 nextgrp = nextgrp->ng_next; 138 return (1); 139 } 140 return (0); 141 } 142 143 /* 144 * rng_endnetgrent() - cleanup 145 */ 146 void 147 rng_endnetgrent(void) 148 { 149 struct linelist *lp, *olp; 150 struct netgrp *gp, *ogp; 151 152 lp = linehead; 153 while (lp) { 154 olp = lp; 155 lp = lp->l_next; 156 free(olp->l_groupname); 157 free(olp->l_line); 158 free((char *)olp); 159 } 160 linehead = (struct linelist *)0; 161 if (grouphead.grname) { 162 free(grouphead.grname); 163 grouphead.grname = (char *)0; 164 } 165 gp = grouphead.gr; 166 while (gp) { 167 ogp = gp; 168 gp = gp->ng_next; 169 if (ogp->ng_str[NG_HOST]) 170 free(ogp->ng_str[NG_HOST]); 171 if (ogp->ng_str[NG_USER]) 172 free(ogp->ng_str[NG_USER]); 173 if (ogp->ng_str[NG_DOM]) 174 free(ogp->ng_str[NG_DOM]); 175 free((char *)ogp); 176 } 177 grouphead.gr = (struct netgrp *)0; 178 } 179 180 /* 181 * Parse the netgroup file setting up the linked lists. 182 */ 183 static int 184 parse_netgrp(const char *group) 185 { 186 char *spos, *epos; 187 int len, strpos; 188 #ifdef DEBUG 189 int fields; 190 #endif 191 char *pos, *gpos; 192 struct netgrp *grp; 193 struct linelist *lp = linehead; 194 195 /* 196 * First, see if the line has already been read in. 197 */ 198 while (lp) { 199 if (!strcmp(group, lp->l_groupname)) 200 break; 201 lp = lp->l_next; 202 } 203 if (lp == (struct linelist *)0 && 204 (lp = read_for_group(group)) == (struct linelist *)0) 205 return (1); 206 if (lp->l_parsed) { 207 #ifdef DEBUG 208 /* 209 * This error message is largely superflous since the 210 * code handles the error condition sucessfully, and 211 * spewing it out from inside libc can actually hose 212 * certain programs. 213 */ 214 warnx("Cycle in netgroup %s", lp->l_groupname); 215 #endif 216 return (1); 217 } else 218 lp->l_parsed = 1; 219 pos = lp->l_line; 220 /* Watch for null pointer dereferences, dammit! */ 221 while (pos != NULL && *pos != '\0') { 222 if (*pos == '(') { 223 grp = (struct netgrp *)malloc(sizeof (struct netgrp)); 224 memset((char *)grp, 0, sizeof (struct netgrp)); 225 grp->ng_next = grouphead.gr; 226 grouphead.gr = grp; 227 pos++; 228 gpos = strsep(&pos, ")"); 229 #ifdef DEBUG 230 fields = 0; 231 #endif 232 for (strpos = 0; strpos < 3; strpos++) { 233 if ((spos = strsep(&gpos, ","))) { 234 #ifdef DEBUG 235 fields++; 236 #endif 237 while (*spos == ' ' || *spos == '\t') 238 spos++; 239 if ((epos = strpbrk(spos, " \t"))) { 240 *epos = '\0'; 241 len = epos - spos; 242 } else 243 len = strlen(spos); 244 if (len > 0) { 245 grp->ng_str[strpos] = (char *) 246 malloc(len + 1); 247 memmove(grp->ng_str[strpos], 248 spos, len + 1); 249 } 250 } else { 251 /* 252 * All other systems I've tested 253 * return NULL for empty netgroup 254 * fields. It's up to user programs 255 * to handle the NULLs appropriately. 256 */ 257 grp->ng_str[strpos] = NULL; 258 } 259 } 260 #ifdef DEBUG 261 /* 262 * Note: on other platforms, malformed netgroup 263 * entries are not normally flagged. While we 264 * can catch bad entries and report them, we should 265 * stay silent by default for compatibility's sake. 266 */ 267 if (fields < 3) 268 warnx( 269 "Bad entry (%s%s%s%s%s) in netgroup \"%s\"", 270 grp->ng_str[NG_HOST] == NULL ? "" : 271 grp->ng_str[NG_HOST], 272 grp->ng_str[NG_USER] == NULL ? "" : ",", 273 grp->ng_str[NG_USER] == NULL ? "" : 274 grp->ng_str[NG_USER], 275 grp->ng_str[NG_DOM] == NULL ? "" : ",", 276 grp->ng_str[NG_DOM] == NULL ? "" : 277 grp->ng_str[NG_DOM], 278 lp->l_groupname); 279 #endif 280 } else { 281 spos = strsep(&pos, ", \t"); 282 if (parse_netgrp(spos)) 283 continue; 284 } 285 /* Watch for null pointer dereferences, dammit! */ 286 if (pos != NULL) 287 while (*pos == ' ' || *pos == ',' || *pos == '\t') 288 pos++; 289 } 290 return (0); 291 } 292 293 /* 294 * Read the netgroup file and save lines until the line for the netgroup 295 * is found. Return 1 if eof is encountered. 296 */ 297 static struct linelist * 298 read_for_group(const char *group) 299 { 300 char *pos, *spos, *linep = NULL, *olinep = NULL; 301 int len, olen; 302 int cont; 303 struct linelist *lp; 304 char line[LINSIZ + 1]; 305 char *data = NULL; 306 307 data = lookup (gtable, group); 308 sprintf(line, "%s %s", group, data); 309 pos = (char *)&line; 310 #ifdef CANT_HAPPEN 311 if (*pos == '#') 312 continue; 313 #endif 314 while (*pos == ' ' || *pos == '\t') 315 pos++; 316 spos = pos; 317 while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 318 *pos != '\0') 319 pos++; 320 len = pos - spos; 321 while (*pos == ' ' || *pos == '\t') 322 pos++; 323 if (*pos != '\n' && *pos != '\0') { 324 lp = (struct linelist *)malloc(sizeof (*lp)); 325 lp->l_parsed = 0; 326 lp->l_groupname = (char *)malloc(len + 1); 327 memmove(lp->l_groupname, spos, len); 328 *(lp->l_groupname + len) = '\0'; 329 len = strlen(pos); 330 olen = 0; 331 /* 332 * Loop around handling line continuations. 333 */ 334 do { 335 if (*(pos + len - 1) == '\n') 336 len--; 337 if (*(pos + len - 1) == '\\') { 338 len--; 339 cont = 1; 340 } else 341 cont = 0; 342 if (len > 0) { 343 linep = (char *)malloc(olen + len + 1); 344 if (olen > 0) { 345 memmove(linep, olinep, olen); 346 free(olinep); 347 } 348 memmove(linep + olen, pos, len); 349 olen += len; 350 *(linep + olen) = '\0'; 351 olinep = linep; 352 } 353 #ifdef CANT_HAPPEN 354 if (cont) { 355 if (fgets(line, LINSIZ, netf)) { 356 pos = line; 357 len = strlen(pos); 358 } else 359 cont = 0; 360 } 361 #endif 362 } while (cont); 363 lp->l_line = linep; 364 lp->l_next = linehead; 365 linehead = lp; 366 #ifdef CANT_HAPPEN 367 /* 368 * If this is the one we wanted, we are done. 369 */ 370 if (!strcmp(lp->l_groupname, group)) 371 #endif 372 return (lp); 373 } 374 return ((struct linelist *)0); 375 } 376