1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * ns_files.c 24*0Sstevel@tonic-gate * 25*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <stdio.h> 32*0Sstevel@tonic-gate #include <stdlib.h> 33*0Sstevel@tonic-gate #include <syslog.h> 34*0Sstevel@tonic-gate #include <string.h> 35*0Sstevel@tonic-gate #include <ctype.h> 36*0Sstevel@tonic-gate #include <nsswitch.h> 37*0Sstevel@tonic-gate #include <sys/stat.h> 38*0Sstevel@tonic-gate #include <sys/param.h> 39*0Sstevel@tonic-gate #include <rpc/rpc.h> 40*0Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h> 41*0Sstevel@tonic-gate #include <thread.h> 42*0Sstevel@tonic-gate #include <assert.h> 43*0Sstevel@tonic-gate #include <errno.h> 44*0Sstevel@tonic-gate #include <fcntl.h> 45*0Sstevel@tonic-gate #include <unistd.h> 46*0Sstevel@tonic-gate #include <synch.h> 47*0Sstevel@tonic-gate #include <sys/types.h> 48*0Sstevel@tonic-gate #include <sys/wait.h> 49*0Sstevel@tonic-gate #include "automount.h" 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate static int read_execout(char *key, char **lp, char *fname, char *line, 52*0Sstevel@tonic-gate int linesz); 53*0Sstevel@tonic-gate static FILE *file_open(char *, char *, char **, char ***); 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate /* 56*0Sstevel@tonic-gate * Initialize the stack 57*0Sstevel@tonic-gate */ 58*0Sstevel@tonic-gate void 59*0Sstevel@tonic-gate init_files(char **stack, char ***stkptr) 60*0Sstevel@tonic-gate { 61*0Sstevel@tonic-gate /* 62*0Sstevel@tonic-gate * The call is bogus for automountd since the stack is 63*0Sstevel@tonic-gate * is more appropriately initialized in the thread-private 64*0Sstevel@tonic-gate * routines 65*0Sstevel@tonic-gate */ 66*0Sstevel@tonic-gate if (stack == NULL && stkptr == NULL) 67*0Sstevel@tonic-gate return; 68*0Sstevel@tonic-gate (void) stack_op(INIT, NULL, stack, stkptr); 69*0Sstevel@tonic-gate } 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate int 72*0Sstevel@tonic-gate getmapent_files(key, mapname, ml, stack, stkptr, iswildcard, isrestricted) 73*0Sstevel@tonic-gate char *key; 74*0Sstevel@tonic-gate char *mapname; 75*0Sstevel@tonic-gate struct mapline *ml; 76*0Sstevel@tonic-gate char **stack, ***stkptr; 77*0Sstevel@tonic-gate bool_t *iswildcard; 78*0Sstevel@tonic-gate bool_t isrestricted; 79*0Sstevel@tonic-gate { 80*0Sstevel@tonic-gate int nserr; 81*0Sstevel@tonic-gate FILE *fp; 82*0Sstevel@tonic-gate char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1]; 83*0Sstevel@tonic-gate char linebuf[LINESZ], lineqbuf[LINESZ]; 84*0Sstevel@tonic-gate char *lp, *lq; 85*0Sstevel@tonic-gate struct stat stbuf; 86*0Sstevel@tonic-gate char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */ 87*0Sstevel@tonic-gate int syntaxok = 1; 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate if (iswildcard) 90*0Sstevel@tonic-gate *iswildcard = FALSE; 91*0Sstevel@tonic-gate if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) { 92*0Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 93*0Sstevel@tonic-gate goto done; 94*0Sstevel@tonic-gate } 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate if (stat(fname, &stbuf) < 0) { 97*0Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 98*0Sstevel@tonic-gate goto done; 99*0Sstevel@tonic-gate } 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate /* 102*0Sstevel@tonic-gate * If the file has its execute bit on then 103*0Sstevel@tonic-gate * assume it's an executable map. 104*0Sstevel@tonic-gate * Execute it and pass the key as an argument. 105*0Sstevel@tonic-gate * Expect to get a map entry on the stdout. 106*0Sstevel@tonic-gate * Ignore the "x" bit on restricted maps. 107*0Sstevel@tonic-gate */ 108*0Sstevel@tonic-gate if (!isrestricted && (stbuf.st_mode & S_IXUSR)) { 109*0Sstevel@tonic-gate int rc; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate if (trace > 1) { 112*0Sstevel@tonic-gate trace_prt(1, 113*0Sstevel@tonic-gate "\tExecutable map: map=%s key=%s\n", 114*0Sstevel@tonic-gate fname, key); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate rc = read_execout(key, &lp, fname, ml->linebuf, LINESZ); 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate if (rc != 0) { 120*0Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 121*0Sstevel@tonic-gate goto done; 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate if (lp == NULL || strlen(ml->linebuf) == 0) { 125*0Sstevel@tonic-gate nserr = __NSW_NOTFOUND; 126*0Sstevel@tonic-gate goto done; 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate unquote(ml->linebuf, ml->lineqbuf); 130*0Sstevel@tonic-gate nserr = __NSW_SUCCESS; 131*0Sstevel@tonic-gate goto done; 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * It's just a normal map file. 137*0Sstevel@tonic-gate * Search for the entry with the required key. 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate for (;;) { 140*0Sstevel@tonic-gate lp = get_line(fp, fname, linebuf, sizeof (linebuf)); 141*0Sstevel@tonic-gate if (lp == NULL) { 142*0Sstevel@tonic-gate nserr = __NSW_NOTFOUND; 143*0Sstevel@tonic-gate goto done; 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate if (verbose && syntaxok && isspace(*(uchar_t *)lp)) { 146*0Sstevel@tonic-gate syntaxok = 0; 147*0Sstevel@tonic-gate syslog(LOG_ERR, 148*0Sstevel@tonic-gate "leading space in map entry \"%s\" in %s", 149*0Sstevel@tonic-gate lp, mapname); 150*0Sstevel@tonic-gate } 151*0Sstevel@tonic-gate lq = lineqbuf; 152*0Sstevel@tonic-gate unquote(lp, lq); 153*0Sstevel@tonic-gate if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word)) 154*0Sstevel@tonic-gate == -1) || (word[0] == '\0')) 155*0Sstevel@tonic-gate continue; 156*0Sstevel@tonic-gate if (strcmp(word, key) == 0) 157*0Sstevel@tonic-gate break; 158*0Sstevel@tonic-gate if (word[0] == '*' && word[1] == '\0') { 159*0Sstevel@tonic-gate if (iswildcard) 160*0Sstevel@tonic-gate *iswildcard = TRUE; 161*0Sstevel@tonic-gate break; 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate if (word[0] == '+') { 164*0Sstevel@tonic-gate nserr = getmapent(key, word+1, ml, stack, stkptr, 165*0Sstevel@tonic-gate iswildcard, isrestricted); 166*0Sstevel@tonic-gate if (nserr == __NSW_SUCCESS) 167*0Sstevel@tonic-gate goto done; 168*0Sstevel@tonic-gate continue; 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /* 172*0Sstevel@tonic-gate * sanity check each map entry key against 173*0Sstevel@tonic-gate * the lookup key as the map is searched. 174*0Sstevel@tonic-gate */ 175*0Sstevel@tonic-gate if (verbose && syntaxok) { /* sanity check entry */ 176*0Sstevel@tonic-gate if (*key == '/') { 177*0Sstevel@tonic-gate if (*word != '/') { 178*0Sstevel@tonic-gate syntaxok = 0; 179*0Sstevel@tonic-gate syslog(LOG_ERR, 180*0Sstevel@tonic-gate "bad key \"%s\" in direct map %s\n", 181*0Sstevel@tonic-gate word, mapname); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate } else { 184*0Sstevel@tonic-gate if (strchr(word, '/')) { 185*0Sstevel@tonic-gate syntaxok = 0; 186*0Sstevel@tonic-gate syslog(LOG_ERR, 187*0Sstevel@tonic-gate "bad key \"%s\" in indirect map %s\n", 188*0Sstevel@tonic-gate word, mapname); 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate (void) strcpy(ml->linebuf, lp); 195*0Sstevel@tonic-gate (void) strcpy(ml->lineqbuf, lq); 196*0Sstevel@tonic-gate nserr = __NSW_SUCCESS; 197*0Sstevel@tonic-gate done: 198*0Sstevel@tonic-gate if (fp) { 199*0Sstevel@tonic-gate (void) stack_op(POP, (char *)NULL, stack, stkptr); 200*0Sstevel@tonic-gate (void) fclose(fp); 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate return (nserr); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate int 208*0Sstevel@tonic-gate getmapkeys_files(mapname, list, error, cache_time, stack, stkptr) 209*0Sstevel@tonic-gate char *mapname; 210*0Sstevel@tonic-gate struct dir_entry **list; 211*0Sstevel@tonic-gate int *error; 212*0Sstevel@tonic-gate int *cache_time; 213*0Sstevel@tonic-gate char **stack, ***stkptr; 214*0Sstevel@tonic-gate { 215*0Sstevel@tonic-gate FILE *fp = NULL; 216*0Sstevel@tonic-gate char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1]; 217*0Sstevel@tonic-gate char linebuf[LINESZ], lineqbuf[LINESZ]; 218*0Sstevel@tonic-gate char *lp, *lq; 219*0Sstevel@tonic-gate struct stat stbuf; 220*0Sstevel@tonic-gate char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */ 221*0Sstevel@tonic-gate int syntaxok = 1; 222*0Sstevel@tonic-gate int nserr; 223*0Sstevel@tonic-gate struct dir_entry *last = NULL; 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if (trace > 1) 226*0Sstevel@tonic-gate trace_prt(1, "getmapkeys_files %s\n", mapname); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate *cache_time = RDDIR_CACHE_TIME; 229*0Sstevel@tonic-gate if ((fp = file_open(mapname, fname, stack, stkptr)) == NULL) { 230*0Sstevel@tonic-gate *error = ENOENT; 231*0Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 232*0Sstevel@tonic-gate goto done; 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate if (fseek(fp, 0L, SEEK_SET) == -1) { 235*0Sstevel@tonic-gate *error = ENOENT; 236*0Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 237*0Sstevel@tonic-gate goto done; 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate if (stat(fname, &stbuf) < 0) { 241*0Sstevel@tonic-gate *error = ENOENT; 242*0Sstevel@tonic-gate nserr = __NSW_UNAVAIL; 243*0Sstevel@tonic-gate goto done; 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * If the file has its execute bit on then 248*0Sstevel@tonic-gate * assume it's an executable map. 249*0Sstevel@tonic-gate * I don't know how to list executable maps, return 250*0Sstevel@tonic-gate * an empty map. 251*0Sstevel@tonic-gate */ 252*0Sstevel@tonic-gate if (stbuf.st_mode & S_IXUSR) { 253*0Sstevel@tonic-gate *error = 0; 254*0Sstevel@tonic-gate nserr = __NSW_SUCCESS; 255*0Sstevel@tonic-gate goto done; 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * It's just a normal map file. 259*0Sstevel@tonic-gate * List entries one line at a time. 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate for (;;) { 262*0Sstevel@tonic-gate lp = get_line(fp, fname, linebuf, sizeof (linebuf)); 263*0Sstevel@tonic-gate if (lp == NULL) { 264*0Sstevel@tonic-gate nserr = __NSW_SUCCESS; 265*0Sstevel@tonic-gate goto done; 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate if (syntaxok && isspace(*(uchar_t *)lp)) { 268*0Sstevel@tonic-gate syntaxok = 0; 269*0Sstevel@tonic-gate syslog(LOG_ERR, 270*0Sstevel@tonic-gate "leading space in map entry \"%s\" in %s", 271*0Sstevel@tonic-gate lp, mapname); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate lq = lineqbuf; 274*0Sstevel@tonic-gate unquote(lp, lq); 275*0Sstevel@tonic-gate if ((getword(word, wordq, &lp, &lq, ' ', MAXFILENAMELEN) 276*0Sstevel@tonic-gate == -1) || (word[0] == '\0')) 277*0Sstevel@tonic-gate continue; 278*0Sstevel@tonic-gate /* 279*0Sstevel@tonic-gate * Wildcard entries should be ignored and this should be 280*0Sstevel@tonic-gate * the last entry read to corroborate the search through 281*0Sstevel@tonic-gate * files, i.e., search for key until a wildcard is reached. 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate if (word[0] == '*' && word[1] == '\0') 284*0Sstevel@tonic-gate break; 285*0Sstevel@tonic-gate if (word[0] == '+') { 286*0Sstevel@tonic-gate /* 287*0Sstevel@tonic-gate * Name switch here 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate getmapkeys(word+1, list, error, cache_time, 290*0Sstevel@tonic-gate stack, stkptr, 0); 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * the list may have been updated, therefore 293*0Sstevel@tonic-gate * our 'last' may no longer be valid 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate last = NULL; 296*0Sstevel@tonic-gate continue; 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate if (add_dir_entry(word, list, &last) != 0) { 300*0Sstevel@tonic-gate *error = ENOMEM; 301*0Sstevel@tonic-gate goto done; 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate assert(last != NULL); 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate nserr = __NSW_SUCCESS; 307*0Sstevel@tonic-gate done: 308*0Sstevel@tonic-gate if (fp) { 309*0Sstevel@tonic-gate (void) stack_op(POP, (char *)NULL, stack, stkptr); 310*0Sstevel@tonic-gate (void) fclose(fp); 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate if (*list != NULL) { 314*0Sstevel@tonic-gate /* 315*0Sstevel@tonic-gate * list of entries found 316*0Sstevel@tonic-gate */ 317*0Sstevel@tonic-gate *error = 0; 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate return (nserr); 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate loadmaster_files(mastermap, defopts, stack, stkptr) 323*0Sstevel@tonic-gate char *mastermap; 324*0Sstevel@tonic-gate char *defopts; 325*0Sstevel@tonic-gate char **stack, ***stkptr; 326*0Sstevel@tonic-gate { 327*0Sstevel@tonic-gate FILE *fp; 328*0Sstevel@tonic-gate int done = 0; 329*0Sstevel@tonic-gate char *line, *dir, *map, *opts; 330*0Sstevel@tonic-gate char linebuf[LINESZ]; 331*0Sstevel@tonic-gate char lineq[LINESZ]; 332*0Sstevel@tonic-gate char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */ 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate if ((fp = file_open(mastermap, fname, stack, stkptr)) == NULL) 336*0Sstevel@tonic-gate return (__NSW_UNAVAIL); 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate while ((line = get_line(fp, fname, linebuf, 339*0Sstevel@tonic-gate sizeof (linebuf))) != NULL) { 340*0Sstevel@tonic-gate unquote(line, lineq); 341*0Sstevel@tonic-gate if (macro_expand("", line, lineq, LINESZ)) { 342*0Sstevel@tonic-gate syslog(LOG_ERR, 343*0Sstevel@tonic-gate "map %s: line too long (max %d chars)", 344*0Sstevel@tonic-gate mastermap, LINESZ - 1); 345*0Sstevel@tonic-gate continue; 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate dir = line; 348*0Sstevel@tonic-gate while (*dir && isspace(*dir)) 349*0Sstevel@tonic-gate dir++; 350*0Sstevel@tonic-gate if (*dir == '\0') 351*0Sstevel@tonic-gate continue; 352*0Sstevel@tonic-gate map = dir; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate while (*map && !isspace(*map)) map++; 355*0Sstevel@tonic-gate if (*map) 356*0Sstevel@tonic-gate *map++ = '\0'; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate if (*dir == '+') { 359*0Sstevel@tonic-gate opts = map; 360*0Sstevel@tonic-gate while (*opts && isspace(*opts)) 361*0Sstevel@tonic-gate opts++; 362*0Sstevel@tonic-gate if (*opts != '-') 363*0Sstevel@tonic-gate opts = defopts; 364*0Sstevel@tonic-gate else 365*0Sstevel@tonic-gate opts++; 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * Check for no embedded blanks. 368*0Sstevel@tonic-gate */ 369*0Sstevel@tonic-gate if (strcspn(opts, " ") == strlen(opts)) { 370*0Sstevel@tonic-gate dir++; 371*0Sstevel@tonic-gate (void) loadmaster_map(dir, opts, stack, stkptr); 372*0Sstevel@tonic-gate } else { 373*0Sstevel@tonic-gate pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname); 374*0Sstevel@tonic-gate continue; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate } else { 378*0Sstevel@tonic-gate while (*map && isspace(*map)) 379*0Sstevel@tonic-gate map++; 380*0Sstevel@tonic-gate if (*map == '\0') 381*0Sstevel@tonic-gate continue; 382*0Sstevel@tonic-gate opts = map; 383*0Sstevel@tonic-gate while (*opts && !isspace(*opts)) 384*0Sstevel@tonic-gate opts++; 385*0Sstevel@tonic-gate if (*opts) { 386*0Sstevel@tonic-gate *opts++ = '\0'; 387*0Sstevel@tonic-gate while (*opts && isspace(*opts)) 388*0Sstevel@tonic-gate opts++; 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate if (*opts != '-') 391*0Sstevel@tonic-gate opts = defopts; 392*0Sstevel@tonic-gate else 393*0Sstevel@tonic-gate opts++; 394*0Sstevel@tonic-gate /* 395*0Sstevel@tonic-gate * Check for no embedded blanks. 396*0Sstevel@tonic-gate */ 397*0Sstevel@tonic-gate if (strcspn(opts, " ") == strlen(opts)) { 398*0Sstevel@tonic-gate dirinit(dir, map, opts, 0, stack, stkptr); 399*0Sstevel@tonic-gate } else { 400*0Sstevel@tonic-gate pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir, fname); 401*0Sstevel@tonic-gate continue; 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate done++; 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate (void) stack_op(POP, (char *)NULL, stack, stkptr); 408*0Sstevel@tonic-gate (void) fclose(fp); 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate return (done ? __NSW_SUCCESS : __NSW_NOTFOUND); 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate loaddirect_files(map, local_map, opts, stack, stkptr) 414*0Sstevel@tonic-gate char *map, *local_map, *opts; 415*0Sstevel@tonic-gate char **stack, ***stkptr; 416*0Sstevel@tonic-gate { 417*0Sstevel@tonic-gate FILE *fp; 418*0Sstevel@tonic-gate int done = 0; 419*0Sstevel@tonic-gate char *line, *p1, *p2; 420*0Sstevel@tonic-gate char linebuf[LINESZ]; 421*0Sstevel@tonic-gate char fname[MAXFILENAMELEN]; /* /etc prepended to mapname if reqd */ 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate if ((fp = file_open(map, fname, stack, stkptr)) == NULL) 424*0Sstevel@tonic-gate return (__NSW_UNAVAIL); 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate while ((line = get_line(fp, fname, linebuf, 427*0Sstevel@tonic-gate sizeof (linebuf))) != NULL) { 428*0Sstevel@tonic-gate p1 = line; 429*0Sstevel@tonic-gate while (*p1 && isspace(*p1)) 430*0Sstevel@tonic-gate p1++; 431*0Sstevel@tonic-gate if (*p1 == '\0') 432*0Sstevel@tonic-gate continue; 433*0Sstevel@tonic-gate p2 = p1; 434*0Sstevel@tonic-gate while (*p2 && !isspace(*p2)) 435*0Sstevel@tonic-gate p2++; 436*0Sstevel@tonic-gate *p2 = '\0'; 437*0Sstevel@tonic-gate if (*p1 == '+') { 438*0Sstevel@tonic-gate p1++; 439*0Sstevel@tonic-gate (void) loaddirect_map(p1, local_map, opts, stack, 440*0Sstevel@tonic-gate stkptr); 441*0Sstevel@tonic-gate } else { 442*0Sstevel@tonic-gate dirinit(p1, local_map, opts, 1, stack, stkptr); 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate done++; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate (void) stack_op(POP, (char *)NULL, stack, stkptr); 448*0Sstevel@tonic-gate (void) fclose(fp); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate return (done ? __NSW_SUCCESS : __NSW_NOTFOUND); 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate /* 454*0Sstevel@tonic-gate * This procedure opens the file and pushes it onto the 455*0Sstevel@tonic-gate * the stack. Only if a file is opened successfully, is 456*0Sstevel@tonic-gate * it pushed onto the stack 457*0Sstevel@tonic-gate */ 458*0Sstevel@tonic-gate static FILE * 459*0Sstevel@tonic-gate file_open(map, fname, stack, stkptr) 460*0Sstevel@tonic-gate char *map, *fname; 461*0Sstevel@tonic-gate char **stack, ***stkptr; 462*0Sstevel@tonic-gate { 463*0Sstevel@tonic-gate FILE *fp; 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate if (*map != '/') { 466*0Sstevel@tonic-gate /* prepend an "/etc" */ 467*0Sstevel@tonic-gate (void) strcpy(fname, "/etc/"); 468*0Sstevel@tonic-gate (void) strcat(fname, map); 469*0Sstevel@tonic-gate } else 470*0Sstevel@tonic-gate (void) strcpy(fname, map); 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate fp = fopen(fname, "r"); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate if (fp != NULL) { 475*0Sstevel@tonic-gate if (!stack_op(PUSH, fname, stack, stkptr)) { 476*0Sstevel@tonic-gate (void) fclose(fp); 477*0Sstevel@tonic-gate return (NULL); 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate return (fp); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate /* 484*0Sstevel@tonic-gate * reimplemnted to be MT-HOT. 485*0Sstevel@tonic-gate */ 486*0Sstevel@tonic-gate int 487*0Sstevel@tonic-gate stack_op(op, name, stack, stkptr) 488*0Sstevel@tonic-gate int op; 489*0Sstevel@tonic-gate char *name; 490*0Sstevel@tonic-gate char **stack, ***stkptr; 491*0Sstevel@tonic-gate { 492*0Sstevel@tonic-gate char **ptr = NULL; 493*0Sstevel@tonic-gate char **stk_top = &stack[STACKSIZ - 1]; 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate /* 496*0Sstevel@tonic-gate * the stackptr points to the next empty slot 497*0Sstevel@tonic-gate * for PUSH: put the element and increment stkptr 498*0Sstevel@tonic-gate * for POP: decrement stkptr and free 499*0Sstevel@tonic-gate */ 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate switch (op) { 502*0Sstevel@tonic-gate case INIT: 503*0Sstevel@tonic-gate for (ptr = stack; ptr != stk_top; ptr++) 504*0Sstevel@tonic-gate *ptr = (char *)NULL; 505*0Sstevel@tonic-gate *stkptr = stack; 506*0Sstevel@tonic-gate return (1); 507*0Sstevel@tonic-gate case ERASE: 508*0Sstevel@tonic-gate for (ptr = stack; ptr != stk_top; ptr++) 509*0Sstevel@tonic-gate if (*ptr) { 510*0Sstevel@tonic-gate if (trace > 1) 511*0Sstevel@tonic-gate trace_prt(1, " ERASE %s\n", *ptr); 512*0Sstevel@tonic-gate free (*ptr); 513*0Sstevel@tonic-gate *ptr = (char *)NULL; 514*0Sstevel@tonic-gate } 515*0Sstevel@tonic-gate *stkptr = stack; 516*0Sstevel@tonic-gate return (1); 517*0Sstevel@tonic-gate case PUSH: 518*0Sstevel@tonic-gate if (*stkptr == stk_top) 519*0Sstevel@tonic-gate return (0); 520*0Sstevel@tonic-gate for (ptr = stack; ptr != *stkptr; ptr++) 521*0Sstevel@tonic-gate if (*ptr && (strcmp(*ptr, name) == 0)) { 522*0Sstevel@tonic-gate return (0); 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate if (trace > 1) 525*0Sstevel@tonic-gate trace_prt(1, " PUSH %s\n", name); 526*0Sstevel@tonic-gate if ((**stkptr = strdup(name)) == NULL) { 527*0Sstevel@tonic-gate syslog(LOG_ERR, "stack_op: Memory alloc failed : %m"); 528*0Sstevel@tonic-gate return (0); 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate (*stkptr)++; 531*0Sstevel@tonic-gate return (1); 532*0Sstevel@tonic-gate case POP: 533*0Sstevel@tonic-gate if (*stkptr != stack) 534*0Sstevel@tonic-gate (*stkptr)--; 535*0Sstevel@tonic-gate else 536*0Sstevel@tonic-gate syslog(LOG_ERR, "Attempt to pop empty stack\n"); 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate if (*stkptr && **stkptr) { 539*0Sstevel@tonic-gate if (trace > 1) 540*0Sstevel@tonic-gate trace_prt(1, " POP %s\n", **stkptr); 541*0Sstevel@tonic-gate free (**stkptr); 542*0Sstevel@tonic-gate **stkptr = (char *)NULL; 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate return (1); 545*0Sstevel@tonic-gate default: 546*0Sstevel@tonic-gate return (0); 547*0Sstevel@tonic-gate } 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate #define READ_EXECOUT_ARGS 3 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate /* 553*0Sstevel@tonic-gate * read_execout(char *key, char **lp, char *fname, char *line, int linesz) 554*0Sstevel@tonic-gate * A simpler, multithreaded implementation of popen(). Used due to 555*0Sstevel@tonic-gate * non multithreaded implementation of popen() (it calls vfork()) and a 556*0Sstevel@tonic-gate * significant bug in execl(). 557*0Sstevel@tonic-gate * Returns 0 on OK or -1 on error. 558*0Sstevel@tonic-gate */ 559*0Sstevel@tonic-gate static int 560*0Sstevel@tonic-gate read_execout(char *key, char **lp, char *fname, char *line, int linesz) 561*0Sstevel@tonic-gate { 562*0Sstevel@tonic-gate int p[2]; 563*0Sstevel@tonic-gate int status = 0; 564*0Sstevel@tonic-gate int child_pid; 565*0Sstevel@tonic-gate char *args[READ_EXECOUT_ARGS]; 566*0Sstevel@tonic-gate FILE *fp0; 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate if (pipe(p) < 0) { 569*0Sstevel@tonic-gate syslog(LOG_ERR, "read_execout: Cannot create pipe"); 570*0Sstevel@tonic-gate return (-1); 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate /* setup args for execv */ 574*0Sstevel@tonic-gate if (((args[0] = strdup(fname)) == NULL) || 575*0Sstevel@tonic-gate ((args[1] = strdup(key)) == NULL)) { 576*0Sstevel@tonic-gate if (args[0] != NULL) 577*0Sstevel@tonic-gate free(args[0]); 578*0Sstevel@tonic-gate syslog(LOG_ERR, "read_execout: Memory allocation failed"); 579*0Sstevel@tonic-gate return (-1); 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate args[2] = NULL; 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate if (trace > 3) 584*0Sstevel@tonic-gate trace_prt(1, "\tread_execout: forking .....\n"); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate switch ((child_pid = fork1())) { 587*0Sstevel@tonic-gate case -1: 588*0Sstevel@tonic-gate syslog(LOG_ERR, "read_execout: Cannot fork"); 589*0Sstevel@tonic-gate return (-1); 590*0Sstevel@tonic-gate case 0: 591*0Sstevel@tonic-gate /* 592*0Sstevel@tonic-gate * Child 593*0Sstevel@tonic-gate */ 594*0Sstevel@tonic-gate close(p[0]); 595*0Sstevel@tonic-gate close(1); 596*0Sstevel@tonic-gate if (fcntl(p[1], F_DUPFD, 1) != 1) { 597*0Sstevel@tonic-gate syslog(LOG_ERR, 598*0Sstevel@tonic-gate "read_execout: dup of stdout failed"); 599*0Sstevel@tonic-gate _exit(-1); 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate close(p[1]); 602*0Sstevel@tonic-gate execv(fname, &args[0]); 603*0Sstevel@tonic-gate _exit(-1); 604*0Sstevel@tonic-gate default: 605*0Sstevel@tonic-gate /* 606*0Sstevel@tonic-gate * Parent 607*0Sstevel@tonic-gate */ 608*0Sstevel@tonic-gate close(p[1]); 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate /* 611*0Sstevel@tonic-gate * wait for child to complete. Note we read after the 612*0Sstevel@tonic-gate * child exits to guarantee a full pipe. 613*0Sstevel@tonic-gate */ 614*0Sstevel@tonic-gate while (waitpid(child_pid, &status, 0) < 0) { 615*0Sstevel@tonic-gate /* if waitpid fails with EINTR, restart */ 616*0Sstevel@tonic-gate if (errno != EINTR) { 617*0Sstevel@tonic-gate status = -1; 618*0Sstevel@tonic-gate break; 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate if (status != -1) { 622*0Sstevel@tonic-gate if ((fp0 = fdopen(p[0], "r")) != NULL) { 623*0Sstevel@tonic-gate *lp = get_line(fp0, fname, line, linesz); 624*0Sstevel@tonic-gate fclose(fp0); 625*0Sstevel@tonic-gate } else { 626*0Sstevel@tonic-gate close(p[0]); 627*0Sstevel@tonic-gate status = -1; 628*0Sstevel@tonic-gate } 629*0Sstevel@tonic-gate } else { 630*0Sstevel@tonic-gate close(p[0]); 631*0Sstevel@tonic-gate } 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* free args */ 634*0Sstevel@tonic-gate free(args[0]); 635*0Sstevel@tonic-gate free(args[1]); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate if (trace > 3) 638*0Sstevel@tonic-gate trace_prt(1, "\tread_execout: map=%s key=%s line=%s\n", 639*0Sstevel@tonic-gate fname, key, line); 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate return (status); 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate } 644