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