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