1 /* $OpenBSD: parse_netgroup.c,v 1.12 2009/10/27 23:59:58 deraadt 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 if (grouphead.grname) { 147 free(grouphead.grname); 148 grouphead.grname = NULL; 149 } 150 gp = grouphead.gr; 151 while (gp) { 152 ogp = gp; 153 gp = gp->ng_next; 154 if (ogp->ng_str[NG_HOST]) 155 free(ogp->ng_str[NG_HOST]); 156 if (ogp->ng_str[NG_USER]) 157 free(ogp->ng_str[NG_USER]); 158 if (ogp->ng_str[NG_DOM]) 159 free(ogp->ng_str[NG_DOM]); 160 free(ogp); 161 } 162 grouphead.gr = NULL; 163 } 164 165 /* 166 * Parse the netgroup file setting up the linked lists. 167 */ 168 static int 169 parse_netgrp(char *group) 170 { 171 char *spos, *epos; 172 int len, strpos; 173 #ifdef DEBUG 174 int fields; 175 #endif 176 char *pos, *gpos; 177 struct netgrp *grp; 178 struct linelist *lp = linehead; 179 180 /* 181 * First, see if the line has already been read in. 182 */ 183 while (lp) { 184 if (!strcmp(group, lp->l_groupname)) 185 break; 186 lp = lp->l_next; 187 } 188 if (lp == NULL && (lp = read_for_group(group)) == NULL) 189 return (1); 190 if (lp->l_parsed) { 191 #ifdef DEBUG 192 /* 193 * This error message is largely superflous since the 194 * code handles the error condition successfully, and 195 * spewing it out from inside libc can actually hose 196 * certain programs. 197 */ 198 fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname); 199 #endif 200 return (1); 201 } else 202 lp->l_parsed = 1; 203 pos = lp->l_line; 204 /* Watch for null pointer dereferences, dammit! */ 205 while (pos != NULL && *pos != '\0') { 206 if (*pos == '(') { 207 grp = malloc(sizeof(struct netgrp)); 208 bzero(grp, sizeof(struct netgrp)); 209 grp->ng_next = grouphead.gr; 210 grouphead.gr = grp; 211 pos++; 212 gpos = strsep(&pos, ")"); 213 #ifdef DEBUG 214 fields = 0; 215 #endif 216 for (strpos = 0; strpos < 3; strpos++) { 217 if ((spos = strsep(&gpos, ","))) { 218 #ifdef DEBUG 219 fields++; 220 #endif 221 while (*spos == ' ' || *spos == '\t') 222 spos++; 223 if ((epos = strpbrk(spos, " \t"))) { 224 *epos = '\0'; 225 len = epos - spos; 226 } else 227 len = strlen(spos); 228 if (len > 0) { 229 grp->ng_str[strpos] = malloc(len + 1); 230 bcopy(spos, grp->ng_str[strpos], 231 len + 1); 232 } 233 } else { 234 /* 235 * All other systems I've tested 236 * return NULL for empty netgroup 237 * fields. It's up to user programs 238 * to handle the NULLs appropriately. 239 */ 240 grp->ng_str[strpos] = NULL; 241 } 242 } 243 #ifdef DEBUG 244 /* 245 * Note: on other platforms, malformed netgroup 246 * entries are not normally flagged. While we 247 * can catch bad entries and report them, we should 248 * stay silent by default for compatibility's sake. 249 */ 250 if (fields < 3) 251 fprintf(stderr, "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n", 252 grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST], 253 grp->ng_str[NG_USER] == NULL ? "" : ",", 254 grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER], 255 grp->ng_str[NG_DOM] == NULL ? "" : ",", 256 grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM], 257 lp->l_groupname); 258 #endif 259 } else { 260 spos = strsep(&pos, ", \t"); 261 if (parse_netgrp(spos)) 262 continue; 263 } 264 /* Watch for null pointer dereferences, dammit! */ 265 if (pos != NULL) 266 while (*pos == ' ' || *pos == ',' || *pos == '\t') 267 pos++; 268 } 269 return (0); 270 } 271 272 /* 273 * Read the netgroup file and save lines until the line for the netgroup 274 * is found. Return 1 if eof is encountered. 275 */ 276 static struct linelist * 277 read_for_group(char *group) 278 { 279 char *pos, *spos, *linep = NULL, *olinep = NULL; 280 int len, olen; 281 int cont; 282 struct linelist *lp; 283 char line[LINSIZ + 1]; 284 char *data = NULL; 285 286 data = lookup (gtable, group); 287 snprintf(line, sizeof line, "%s %s", group, data); 288 pos = (char *)&line; 289 #ifdef CANT_HAPPEN 290 if (*pos == '#') 291 continue; 292 #endif 293 while (*pos == ' ' || *pos == '\t') 294 pos++; 295 spos = pos; 296 while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 297 *pos != '\0') 298 pos++; 299 len = pos - spos; 300 while (*pos == ' ' || *pos == '\t') 301 pos++; 302 if (*pos != '\n' && *pos != '\0') { 303 lp = malloc(sizeof(*lp)); 304 lp->l_parsed = 0; 305 lp->l_groupname = malloc(len + 1); 306 bcopy(spos, lp->l_groupname, len); 307 *(lp->l_groupname + len) = '\0'; 308 len = strlen(pos); 309 olen = 0; 310 /* 311 * Loop around handling line continuations. 312 */ 313 do { 314 if (*(pos + len - 1) == '\n') 315 len--; 316 if (*(pos + len - 1) == '\\') { 317 len--; 318 cont = 1; 319 } else 320 cont = 0; 321 if (len > 0) { 322 linep = malloc(olen + len + 1); 323 if (olen > 0) { 324 bcopy(olinep, linep, olen); 325 free(olinep); 326 } 327 bcopy(pos, linep + olen, len); 328 olen += len; 329 *(linep + olen) = '\0'; 330 olinep = linep; 331 } 332 #ifdef CANT_HAPPEN 333 if (cont) { 334 if (fgets(line, sizeof(line), netf)) { 335 pos = line; 336 len = strlen(pos); 337 } else 338 cont = 0; 339 } 340 #endif 341 } while (cont); 342 lp->l_line = linep; 343 lp->l_next = linehead; 344 linehead = lp; 345 #ifdef CANT_HAPPEN 346 /* 347 * If this is the one we wanted, we are done. 348 */ 349 if (!strcmp(lp->l_groupname, group)) 350 #endif 351 return (lp); 352 } 353 return (NULL); 354 } 355