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