1 /* $OpenBSD: parse_netgroup.c,v 1.13 2015/12/08 07:16:33 mmcc Exp $ */ 2 /* 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Rick Macklem at The University of Guelph. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: parse_netgroup.c,v 1.5 1997/02/22 14:22:02 peter Exp $ 34 */ 35 36 /* 37 * This is a specially hacked-up version of getnetgrent.c used to parse 38 * data from the stored hash table of netgroup info rather than from a 39 * file. It's used mainly for the parse_netgroup() function. All the YP 40 * stuff and file support has been stripped out since it isn't needed. 41 */ 42 43 #include <stdio.h> 44 #include <string.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 = NULL; 73 static struct netgrp *nextgrp = NULL; 74 static struct { 75 struct netgrp *gr; 76 char *grname; 77 } grouphead = { 78 NULL, 79 NULL, 80 }; 81 82 static int parse_netgrp(char *); 83 static struct linelist *read_for_group(char *); 84 void __setnetgrent(char *), __endnetgrent(void); 85 int __getnetgrent(char **, char **, char **); 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 == NULL || strcmp(group, grouphead.grname)) { 103 __endnetgrent(); 104 if (parse_netgrp(group)) 105 __endnetgrent(); 106 else 107 grouphead.grname = strdup(group); 108 } 109 nextgrp = grouphead.gr; 110 } 111 112 /* 113 * Get the next netgroup off the list. 114 */ 115 int 116 __getnetgrent(char **hostp, char **userp, char **domp) 117 { 118 if (nextgrp) { 119 *hostp = nextgrp->ng_str[NG_HOST]; 120 *userp = nextgrp->ng_str[NG_USER]; 121 *domp = nextgrp->ng_str[NG_DOM]; 122 nextgrp = nextgrp->ng_next; 123 return (1); 124 } 125 return (0); 126 } 127 128 /* 129 * __endnetgrent() - cleanup 130 */ 131 void 132 __endnetgrent(void) 133 { 134 struct linelist *lp, *olp; 135 struct netgrp *gp, *ogp; 136 137 lp = linehead; 138 while (lp) { 139 olp = lp; 140 lp = lp->l_next; 141 free(olp->l_groupname); 142 free(olp->l_line); 143 free(olp); 144 } 145 linehead = NULL; 146 free(grouphead.grname); 147 grouphead.grname = NULL; 148 gp = grouphead.gr; 149 while (gp) { 150 ogp = gp; 151 gp = gp->ng_next; 152 free(ogp->ng_str[NG_HOST]); 153 free(ogp->ng_str[NG_USER]); 154 free(ogp->ng_str[NG_DOM]); 155 free(ogp); 156 } 157 grouphead.gr = NULL; 158 } 159 160 /* 161 * Parse the netgroup file setting up the linked lists. 162 */ 163 static int 164 parse_netgrp(char *group) 165 { 166 char *spos, *epos; 167 int len, strpos; 168 #ifdef DEBUG 169 int fields; 170 #endif 171 char *pos, *gpos; 172 struct netgrp *grp; 173 struct linelist *lp = linehead; 174 175 /* 176 * First, see if the line has already been read in. 177 */ 178 while (lp) { 179 if (!strcmp(group, lp->l_groupname)) 180 break; 181 lp = lp->l_next; 182 } 183 if (lp == NULL && (lp = read_for_group(group)) == NULL) 184 return (1); 185 if (lp->l_parsed) { 186 #ifdef DEBUG 187 /* 188 * This error message is largely superflous since the 189 * code handles the error condition successfully, and 190 * spewing it out from inside libc can actually hose 191 * certain programs. 192 */ 193 fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname); 194 #endif 195 return (1); 196 } else 197 lp->l_parsed = 1; 198 pos = lp->l_line; 199 /* Watch for null pointer dereferences, dammit! */ 200 while (pos != NULL && *pos != '\0') { 201 if (*pos == '(') { 202 grp = malloc(sizeof(struct netgrp)); 203 bzero(grp, sizeof(struct netgrp)); 204 grp->ng_next = grouphead.gr; 205 grouphead.gr = grp; 206 pos++; 207 gpos = strsep(&pos, ")"); 208 #ifdef DEBUG 209 fields = 0; 210 #endif 211 for (strpos = 0; strpos < 3; strpos++) { 212 if ((spos = strsep(&gpos, ","))) { 213 #ifdef DEBUG 214 fields++; 215 #endif 216 while (*spos == ' ' || *spos == '\t') 217 spos++; 218 if ((epos = strpbrk(spos, " \t"))) { 219 *epos = '\0'; 220 len = epos - spos; 221 } else 222 len = strlen(spos); 223 if (len > 0) { 224 grp->ng_str[strpos] = malloc(len + 1); 225 bcopy(spos, grp->ng_str[strpos], 226 len + 1); 227 } 228 } else { 229 /* 230 * All other systems I've tested 231 * return NULL for empty netgroup 232 * fields. It's up to user programs 233 * to handle the NULLs appropriately. 234 */ 235 grp->ng_str[strpos] = NULL; 236 } 237 } 238 #ifdef DEBUG 239 /* 240 * Note: on other platforms, malformed netgroup 241 * entries are not normally flagged. While we 242 * can catch bad entries and report them, we should 243 * stay silent by default for compatibility's sake. 244 */ 245 if (fields < 3) 246 fprintf(stderr, "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n", 247 grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST], 248 grp->ng_str[NG_USER] == NULL ? "" : ",", 249 grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER], 250 grp->ng_str[NG_DOM] == NULL ? "" : ",", 251 grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM], 252 lp->l_groupname); 253 #endif 254 } else { 255 spos = strsep(&pos, ", \t"); 256 if (parse_netgrp(spos)) 257 continue; 258 } 259 /* Watch for null pointer dereferences, dammit! */ 260 if (pos != NULL) 261 while (*pos == ' ' || *pos == ',' || *pos == '\t') 262 pos++; 263 } 264 return (0); 265 } 266 267 /* 268 * Read the netgroup file and save lines until the line for the netgroup 269 * is found. Return 1 if eof is encountered. 270 */ 271 static struct linelist * 272 read_for_group(char *group) 273 { 274 char *pos, *spos, *linep = NULL, *olinep = NULL; 275 int len, olen; 276 int cont; 277 struct linelist *lp; 278 char line[LINSIZ + 1]; 279 char *data = NULL; 280 281 data = lookup (gtable, group); 282 snprintf(line, sizeof line, "%s %s", group, data); 283 pos = (char *)&line; 284 #ifdef CANT_HAPPEN 285 if (*pos == '#') 286 continue; 287 #endif 288 while (*pos == ' ' || *pos == '\t') 289 pos++; 290 spos = pos; 291 while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 292 *pos != '\0') 293 pos++; 294 len = pos - spos; 295 while (*pos == ' ' || *pos == '\t') 296 pos++; 297 if (*pos != '\n' && *pos != '\0') { 298 lp = malloc(sizeof(*lp)); 299 lp->l_parsed = 0; 300 lp->l_groupname = malloc(len + 1); 301 bcopy(spos, lp->l_groupname, len); 302 *(lp->l_groupname + len) = '\0'; 303 len = strlen(pos); 304 olen = 0; 305 /* 306 * Loop around handling line continuations. 307 */ 308 do { 309 if (*(pos + len - 1) == '\n') 310 len--; 311 if (*(pos + len - 1) == '\\') { 312 len--; 313 cont = 1; 314 } else 315 cont = 0; 316 if (len > 0) { 317 linep = malloc(olen + len + 1); 318 if (olen > 0) { 319 bcopy(olinep, linep, olen); 320 free(olinep); 321 } 322 bcopy(pos, linep + olen, len); 323 olen += len; 324 *(linep + olen) = '\0'; 325 olinep = linep; 326 } 327 #ifdef CANT_HAPPEN 328 if (cont) { 329 if (fgets(line, sizeof(line), netf)) { 330 pos = line; 331 len = strlen(pos); 332 } else 333 cont = 0; 334 } 335 #endif 336 } while (cont); 337 lp->l_line = linep; 338 lp->l_next = linehead; 339 linehead = lp; 340 #ifdef CANT_HAPPEN 341 /* 342 * If this is the one we wanted, we are done. 343 */ 344 if (!strcmp(lp->l_groupname, group)) 345 #endif 346 return (lp); 347 } 348 return (NULL); 349 } 350