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