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