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