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