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