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 * Copyright 1995-2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * Common code and structures used by name-service-switch "files" backends. 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 /* 32*0Sstevel@tonic-gate * An implementation that used mmap() sensibly would be a wonderful thing, 33*0Sstevel@tonic-gate * but this here is just yer standard fgets() thang. 34*0Sstevel@tonic-gate */ 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #include "files_common.h" 37*0Sstevel@tonic-gate #include <stdio.h> 38*0Sstevel@tonic-gate #include <stdlib.h> 39*0Sstevel@tonic-gate #include <string.h> 40*0Sstevel@tonic-gate #include <ctype.h> 41*0Sstevel@tonic-gate #include <fcntl.h> 42*0Sstevel@tonic-gate #include <poll.h> 43*0Sstevel@tonic-gate #include <unistd.h> 44*0Sstevel@tonic-gate #include <sys/stat.h> 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate /*ARGSUSED*/ 47*0Sstevel@tonic-gate nss_status_t 48*0Sstevel@tonic-gate _nss_files_setent(be, dummy) 49*0Sstevel@tonic-gate files_backend_ptr_t be; 50*0Sstevel@tonic-gate void *dummy; 51*0Sstevel@tonic-gate { 52*0Sstevel@tonic-gate if (be->f == 0) { 53*0Sstevel@tonic-gate if (be->filename == 0) { 54*0Sstevel@tonic-gate /* Backend isn't initialized properly? */ 55*0Sstevel@tonic-gate return (NSS_UNAVAIL); 56*0Sstevel@tonic-gate } 57*0Sstevel@tonic-gate if ((be->f = __nsl_fopen(be->filename, "r")) == 0) { 58*0Sstevel@tonic-gate return (NSS_UNAVAIL); 59*0Sstevel@tonic-gate } 60*0Sstevel@tonic-gate } else { 61*0Sstevel@tonic-gate __nsl_rewind(be->f); 62*0Sstevel@tonic-gate } 63*0Sstevel@tonic-gate return (NSS_SUCCESS); 64*0Sstevel@tonic-gate } 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /*ARGSUSED*/ 67*0Sstevel@tonic-gate nss_status_t 68*0Sstevel@tonic-gate _nss_files_endent(be, dummy) 69*0Sstevel@tonic-gate files_backend_ptr_t be; 70*0Sstevel@tonic-gate void *dummy; 71*0Sstevel@tonic-gate { 72*0Sstevel@tonic-gate if (be->f != 0) { 73*0Sstevel@tonic-gate __nsl_fclose(be->f); 74*0Sstevel@tonic-gate be->f = 0; 75*0Sstevel@tonic-gate } 76*0Sstevel@tonic-gate if (be->buf != 0) { 77*0Sstevel@tonic-gate free(be->buf); 78*0Sstevel@tonic-gate be->buf = 0; 79*0Sstevel@tonic-gate } 80*0Sstevel@tonic-gate return (NSS_SUCCESS); 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* 84*0Sstevel@tonic-gate * This routine reads a line, including the processing of continuation 85*0Sstevel@tonic-gate * characters. It always leaves (or inserts) \n\0 at the end of the line. 86*0Sstevel@tonic-gate * It returns the length of the line read, excluding the \n\0. Who's idea 87*0Sstevel@tonic-gate * was this? 88*0Sstevel@tonic-gate * Returns -1 on EOF. 89*0Sstevel@tonic-gate * 90*0Sstevel@tonic-gate * Note that since each concurrent call to _nss_files_read_line has 91*0Sstevel@tonic-gate * it's own FILE pointer, we can use getc_unlocked w/o difficulties, 92*0Sstevel@tonic-gate * a substantial performance win. 93*0Sstevel@tonic-gate */ 94*0Sstevel@tonic-gate int 95*0Sstevel@tonic-gate _nss_files_read_line(f, buffer, buflen) 96*0Sstevel@tonic-gate __NSL_FILE *f; 97*0Sstevel@tonic-gate char *buffer; 98*0Sstevel@tonic-gate int buflen; 99*0Sstevel@tonic-gate { 100*0Sstevel@tonic-gate int linelen; /* 1st unused slot in buffer */ 101*0Sstevel@tonic-gate int c; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate /*CONSTCOND*/ 104*0Sstevel@tonic-gate while (1) { 105*0Sstevel@tonic-gate linelen = 0; 106*0Sstevel@tonic-gate while (linelen < buflen - 1) { /* "- 1" saves room for \n\0 */ 107*0Sstevel@tonic-gate switch (c = __nsl_getc_unlocked(f)) { 108*0Sstevel@tonic-gate case EOF: 109*0Sstevel@tonic-gate if (linelen == 0 || 110*0Sstevel@tonic-gate buffer[linelen - 1] == '\\') { 111*0Sstevel@tonic-gate return (-1); 112*0Sstevel@tonic-gate } else { 113*0Sstevel@tonic-gate buffer[linelen ] = '\n'; 114*0Sstevel@tonic-gate buffer[linelen + 1] = '\0'; 115*0Sstevel@tonic-gate return (linelen); 116*0Sstevel@tonic-gate } 117*0Sstevel@tonic-gate case '\n': 118*0Sstevel@tonic-gate if (linelen > 0 && 119*0Sstevel@tonic-gate buffer[linelen - 1] == '\\') { 120*0Sstevel@tonic-gate --linelen; /* remove the '\\' */ 121*0Sstevel@tonic-gate } else { 122*0Sstevel@tonic-gate buffer[linelen ] = '\n'; 123*0Sstevel@tonic-gate buffer[linelen + 1] = '\0'; 124*0Sstevel@tonic-gate return (linelen); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate break; 127*0Sstevel@tonic-gate default: 128*0Sstevel@tonic-gate buffer[linelen++] = c; 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate /* Buffer overflow -- eat rest of line and loop again */ 132*0Sstevel@tonic-gate /* ===> Should syslog() */ 133*0Sstevel@tonic-gate do { 134*0Sstevel@tonic-gate c = __nsl_getc_unlocked(f); 135*0Sstevel@tonic-gate if (c == EOF) { 136*0Sstevel@tonic-gate return (-1); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate } while (c != '\n'); 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate /*NOTREACHED*/ 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate /* 144*0Sstevel@tonic-gate * used only for getgroupbymem() now. 145*0Sstevel@tonic-gate */ 146*0Sstevel@tonic-gate nss_status_t 147*0Sstevel@tonic-gate _nss_files_do_all(be, args, filter, func) 148*0Sstevel@tonic-gate files_backend_ptr_t be; 149*0Sstevel@tonic-gate void *args; 150*0Sstevel@tonic-gate const char *filter; 151*0Sstevel@tonic-gate files_do_all_func_t func; 152*0Sstevel@tonic-gate { 153*0Sstevel@tonic-gate char *buffer; 154*0Sstevel@tonic-gate int buflen; 155*0Sstevel@tonic-gate nss_status_t res; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate if (be->buf == 0 && 158*0Sstevel@tonic-gate (be->buf = malloc(be->minbuf)) == 0) { 159*0Sstevel@tonic-gate return (NSS_UNAVAIL); 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate buffer = be->buf; 162*0Sstevel@tonic-gate buflen = be->minbuf; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS) { 165*0Sstevel@tonic-gate return (res); 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate res = NSS_NOTFOUND; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate do { 171*0Sstevel@tonic-gate int linelen; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate if ((linelen = _nss_files_read_line(be->f, buffer, 174*0Sstevel@tonic-gate buflen)) < 0) { 175*0Sstevel@tonic-gate /* End of file */ 176*0Sstevel@tonic-gate break; 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate if (filter != 0 && strstr(buffer, filter) == 0) { 179*0Sstevel@tonic-gate /* 180*0Sstevel@tonic-gate * Optimization: if the entry doesn't contain the 181*0Sstevel@tonic-gate * filter string then it can't be the entry we want, 182*0Sstevel@tonic-gate * so don't bother looking more closely at it. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate continue; 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate res = (*func)(buffer, linelen, args); 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate } while (res == NSS_NOTFOUND); 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate _nss_files_endent(be, 0); 191*0Sstevel@tonic-gate return (res); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate * Could implement this as an iterator function on top of _nss_files_do_all(), 196*0Sstevel@tonic-gate * but the shared code is small enough that it'd be pretty silly. 197*0Sstevel@tonic-gate */ 198*0Sstevel@tonic-gate nss_status_t 199*0Sstevel@tonic-gate _nss_files_XY_all(be, args, netdb, filter, check) 200*0Sstevel@tonic-gate files_backend_ptr_t be; 201*0Sstevel@tonic-gate nss_XbyY_args_t *args; 202*0Sstevel@tonic-gate int netdb; /* whether it uses netdb */ 203*0Sstevel@tonic-gate /* format or not */ 204*0Sstevel@tonic-gate const char *filter; /* advisory, to speed up */ 205*0Sstevel@tonic-gate /* string search */ 206*0Sstevel@tonic-gate files_XY_check_func check; /* NULL means one-shot, for getXXent */ 207*0Sstevel@tonic-gate { 208*0Sstevel@tonic-gate nss_status_t res; 209*0Sstevel@tonic-gate int parsestat; 210*0Sstevel@tonic-gate int (*func)(); 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate if (be->buf == 0 && 213*0Sstevel@tonic-gate (be->buf = malloc(be->minbuf)) == 0) { 214*0Sstevel@tonic-gate return (NSS_UNAVAIL); /* really panic, malloc failed */ 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate if (check != 0 || be->f == 0) { 218*0Sstevel@tonic-gate if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS) { 219*0Sstevel@tonic-gate return (res); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate res = NSS_NOTFOUND; 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate /*CONSTCOND*/ 226*0Sstevel@tonic-gate while (1) { 227*0Sstevel@tonic-gate char *instr = be->buf; 228*0Sstevel@tonic-gate int linelen; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate if ((linelen = _nss_files_read_line(be->f, instr, 231*0Sstevel@tonic-gate be->minbuf)) < 0) { 232*0Sstevel@tonic-gate /* End of file */ 233*0Sstevel@tonic-gate args->returnval = 0; 234*0Sstevel@tonic-gate args->erange = 0; 235*0Sstevel@tonic-gate break; 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate if (filter != 0 && strstr(instr, filter) == 0) { 238*0Sstevel@tonic-gate /* 239*0Sstevel@tonic-gate * Optimization: if the entry doesn't contain the 240*0Sstevel@tonic-gate * filter string then it can't be the entry we want, 241*0Sstevel@tonic-gate * so don't bother looking more closely at it. 242*0Sstevel@tonic-gate */ 243*0Sstevel@tonic-gate continue; 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate if (netdb) { 246*0Sstevel@tonic-gate char *first; 247*0Sstevel@tonic-gate char *last; 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate if ((last = strchr(instr, '#')) == 0) { 250*0Sstevel@tonic-gate last = instr + linelen; 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate *last-- = '\0'; /* Nuke '\n' or #comment */ 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /* 255*0Sstevel@tonic-gate * Skip leading whitespace. Normally there isn't 256*0Sstevel@tonic-gate * any, so it's not worth calling strspn(). 257*0Sstevel@tonic-gate */ 258*0Sstevel@tonic-gate for (first = instr; isspace(*first); first++) { 259*0Sstevel@tonic-gate ; 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate if (*first == '\0') { 262*0Sstevel@tonic-gate continue; 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate /* 265*0Sstevel@tonic-gate * Found something non-blank on the line. Skip back 266*0Sstevel@tonic-gate * over any trailing whitespace; since we know 267*0Sstevel@tonic-gate * there's non-whitespace earlier in the line, 268*0Sstevel@tonic-gate * checking for termination is easy. 269*0Sstevel@tonic-gate */ 270*0Sstevel@tonic-gate while (isspace(*last)) { 271*0Sstevel@tonic-gate --last; 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate linelen = last - first + 1; 275*0Sstevel@tonic-gate if (first != instr) { 276*0Sstevel@tonic-gate instr = first; 277*0Sstevel@tonic-gate } 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate args->returnval = 0; 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate func = args->str2ent; 283*0Sstevel@tonic-gate parsestat = (*func)(instr, linelen, args->buf.result, 284*0Sstevel@tonic-gate args->buf.buffer, args->buf.buflen); 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate if (parsestat == NSS_STR_PARSE_SUCCESS) { 287*0Sstevel@tonic-gate args->returnval = args->buf.result; 288*0Sstevel@tonic-gate if (check == 0 || (*check)(args)) { 289*0Sstevel@tonic-gate res = NSS_SUCCESS; 290*0Sstevel@tonic-gate break; 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate } else if (parsestat == NSS_STR_PARSE_ERANGE) { 293*0Sstevel@tonic-gate args->erange = 1; 294*0Sstevel@tonic-gate break; 295*0Sstevel@tonic-gate } /* else if (parsestat == NSS_STR_PARSE_PARSE) don't care ! */ 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * stayopen is set to 0 by default in order to close the opened 300*0Sstevel@tonic-gate * file. Some applications may break if it is set to 1. 301*0Sstevel@tonic-gate */ 302*0Sstevel@tonic-gate if (check != 0 && !args->stayopen) { 303*0Sstevel@tonic-gate (void) _nss_files_endent(be, 0); 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate return (res); 307*0Sstevel@tonic-gate } 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* 310*0Sstevel@tonic-gate * File hashing support. Critical for sites with large (e.g. 1000+ lines) 311*0Sstevel@tonic-gate * /etc/passwd or /etc/group files. Currently only used by getpw*() and 312*0Sstevel@tonic-gate * getgr*() routines, but any files backend can use this stuff. 313*0Sstevel@tonic-gate */ 314*0Sstevel@tonic-gate static void 315*0Sstevel@tonic-gate _nss_files_hash_destroy(files_hash_t *fhp) 316*0Sstevel@tonic-gate { 317*0Sstevel@tonic-gate free(fhp->fh_table); 318*0Sstevel@tonic-gate fhp->fh_table = NULL; 319*0Sstevel@tonic-gate free(fhp->fh_line); 320*0Sstevel@tonic-gate fhp->fh_line = NULL; 321*0Sstevel@tonic-gate free(fhp->fh_file_start); 322*0Sstevel@tonic-gate fhp->fh_file_start = NULL; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate #ifdef PIC 325*0Sstevel@tonic-gate /* 326*0Sstevel@tonic-gate * It turns out the hashing stuff really needs to be disabled for processes 327*0Sstevel@tonic-gate * other than the nscd; the consumption of swap space and memory is otherwise 328*0Sstevel@tonic-gate * unacceptable when the nscd is killed w/ a large passwd file (4M) active. 329*0Sstevel@tonic-gate * See 4031930 for details. 330*0Sstevel@tonic-gate * So we just use this psuedo function to enable the hashing feature. Since 331*0Sstevel@tonic-gate * this function name is private, we just create a function w/ the name 332*0Sstevel@tonic-gate * __nss_use_files_hash in the nscd itself and everyone else uses the old 333*0Sstevel@tonic-gate * interface. 334*0Sstevel@tonic-gate * We also disable hashing for .a executables to avoid problems with large 335*0Sstevel@tonic-gate * files.... 336*0Sstevel@tonic-gate */ 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate #pragma weak __nss_use_files_hash 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate extern void __nss_use_files_hash(void); 341*0Sstevel@tonic-gate #endif /* pic */ 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate nss_status_t 344*0Sstevel@tonic-gate _nss_files_XY_hash(files_backend_ptr_t be, nss_XbyY_args_t *args, 345*0Sstevel@tonic-gate int netdb, files_hash_t *fhp, int hashop, files_XY_check_func check) 346*0Sstevel@tonic-gate { 347*0Sstevel@tonic-gate int fd, retries, ht; 348*0Sstevel@tonic-gate uint_t hash, line, f; 349*0Sstevel@tonic-gate files_hashent_t *hp, *htab; 350*0Sstevel@tonic-gate char *cp, *first, *last; 351*0Sstevel@tonic-gate nss_XbyY_args_t xargs; 352*0Sstevel@tonic-gate struct stat64 st; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate #ifndef PIC 355*0Sstevel@tonic-gate return (_nss_files_XY_all(be, args, netdb, 0, check)); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate #else 358*0Sstevel@tonic-gate if (__nss_use_files_hash == 0) 359*0Sstevel@tonic-gate return (_nss_files_XY_all(be, args, netdb, 0, check)); 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate mutex_lock(&fhp->fh_lock); 362*0Sstevel@tonic-gate retry: 363*0Sstevel@tonic-gate retries = 100; 364*0Sstevel@tonic-gate while (stat64(be->filename, &st) < 0) { 365*0Sstevel@tonic-gate /* 366*0Sstevel@tonic-gate * On a healthy system this can't happen except during brief 367*0Sstevel@tonic-gate * periods when the file is being modified/renamed. Keep 368*0Sstevel@tonic-gate * trying until things settle down, but eventually give up. 369*0Sstevel@tonic-gate */ 370*0Sstevel@tonic-gate if (--retries == 0) 371*0Sstevel@tonic-gate goto unavail; 372*0Sstevel@tonic-gate poll(0, 0, 100); 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate if (st.st_mtim.tv_sec == fhp->fh_mtime.tv_sec && 376*0Sstevel@tonic-gate st.st_mtim.tv_nsec == fhp->fh_mtime.tv_nsec && 377*0Sstevel@tonic-gate fhp->fh_table != NULL) { 378*0Sstevel@tonic-gate htab = &fhp->fh_table[hashop * fhp->fh_size]; 379*0Sstevel@tonic-gate hash = fhp->fh_hash_func[hashop](args, 1); 380*0Sstevel@tonic-gate for (hp = htab[hash % fhp->fh_size].h_first; hp != NULL; 381*0Sstevel@tonic-gate hp = hp->h_next) { 382*0Sstevel@tonic-gate if (hp->h_hash != hash) 383*0Sstevel@tonic-gate continue; 384*0Sstevel@tonic-gate line = hp - htab; 385*0Sstevel@tonic-gate if ((*args->str2ent)(fhp->fh_line[line].l_start, 386*0Sstevel@tonic-gate fhp->fh_line[line].l_len, args->buf.result, 387*0Sstevel@tonic-gate args->buf.buffer, args->buf.buflen) == 388*0Sstevel@tonic-gate NSS_STR_PARSE_SUCCESS) { 389*0Sstevel@tonic-gate args->returnval = args->buf.result; 390*0Sstevel@tonic-gate if ((*check)(args)) { 391*0Sstevel@tonic-gate mutex_unlock(&fhp->fh_lock); 392*0Sstevel@tonic-gate return (NSS_SUCCESS); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate } else { 395*0Sstevel@tonic-gate args->erange = 1; 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate args->returnval = 0; 399*0Sstevel@tonic-gate mutex_unlock(&fhp->fh_lock); 400*0Sstevel@tonic-gate return (NSS_NOTFOUND); 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate _nss_files_hash_destroy(fhp); 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate if (st.st_size > SSIZE_MAX) 406*0Sstevel@tonic-gate goto unavail; 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate if ((fhp->fh_file_start = malloc((ssize_t)st.st_size + 1)) == NULL) 409*0Sstevel@tonic-gate goto unavail; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate if ((fd = open(be->filename, O_RDONLY)) < 0) 412*0Sstevel@tonic-gate goto unavail; 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate if (read(fd, fhp->fh_file_start, (ssize_t)st.st_size) != 415*0Sstevel@tonic-gate (ssize_t)st.st_size) { 416*0Sstevel@tonic-gate close(fd); 417*0Sstevel@tonic-gate goto retry; 418*0Sstevel@tonic-gate } 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate close(fd); 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate fhp->fh_file_end = fhp->fh_file_start + (off_t)st.st_size; 423*0Sstevel@tonic-gate *fhp->fh_file_end = '\n'; 424*0Sstevel@tonic-gate fhp->fh_mtime = st.st_mtim; 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate /* 427*0Sstevel@tonic-gate * If the file changed since we read it, or if it's less than 428*0Sstevel@tonic-gate * 1-2 seconds old, don't trust it; its modification may still 429*0Sstevel@tonic-gate * be in progress. The latter is a heuristic hack to minimize 430*0Sstevel@tonic-gate * the likelihood of damage if someone modifies /etc/mumble 431*0Sstevel@tonic-gate * directly (as opposed to editing and renaming a temp file). 432*0Sstevel@tonic-gate * 433*0Sstevel@tonic-gate * Note: the cast to u_int is there in case (1) someone rdated 434*0Sstevel@tonic-gate * the system backwards since the last modification of /etc/mumble 435*0Sstevel@tonic-gate * or (2) this is a diskless client whose time is badly out of sync 436*0Sstevel@tonic-gate * with its server. The 1-2 second age hack doesn't cover these 437*0Sstevel@tonic-gate * cases -- oh well. 438*0Sstevel@tonic-gate */ 439*0Sstevel@tonic-gate if (stat64(be->filename, &st) < 0 || 440*0Sstevel@tonic-gate st.st_mtim.tv_sec != fhp->fh_mtime.tv_sec || 441*0Sstevel@tonic-gate st.st_mtim.tv_nsec != fhp->fh_mtime.tv_nsec || 442*0Sstevel@tonic-gate (uint_t)(time(0) - st.st_mtim.tv_sec + 2) < 4) { 443*0Sstevel@tonic-gate poll(0, 0, 1000); 444*0Sstevel@tonic-gate goto retry; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate line = 1; 448*0Sstevel@tonic-gate for (cp = fhp->fh_file_start; cp < fhp->fh_file_end; cp++) 449*0Sstevel@tonic-gate if (*cp == '\n') 450*0Sstevel@tonic-gate line++; 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate for (f = 2; f * f <= line; f++) { /* find next largest prime */ 453*0Sstevel@tonic-gate if (line % f == 0) { 454*0Sstevel@tonic-gate f = 1; 455*0Sstevel@tonic-gate line++; 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate fhp->fh_size = line; 460*0Sstevel@tonic-gate fhp->fh_line = malloc(line * sizeof (files_linetab_t)); 461*0Sstevel@tonic-gate fhp->fh_table = calloc(line * fhp->fh_nhtab, sizeof (files_hashent_t)); 462*0Sstevel@tonic-gate if (fhp->fh_line == NULL || fhp->fh_table == NULL) 463*0Sstevel@tonic-gate goto unavail; 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate xargs = *args; 466*0Sstevel@tonic-gate xargs.buf.result = malloc(fhp->fh_resultsize + fhp->fh_bufsize); 467*0Sstevel@tonic-gate if (xargs.buf.result == NULL) 468*0Sstevel@tonic-gate goto unavail; 469*0Sstevel@tonic-gate xargs.buf.buffer = (char *)xargs.buf.result + fhp->fh_resultsize; 470*0Sstevel@tonic-gate xargs.buf.buflen = fhp->fh_bufsize; 471*0Sstevel@tonic-gate xargs.returnval = xargs.buf.result; 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate line = 0; 474*0Sstevel@tonic-gate cp = fhp->fh_file_start; 475*0Sstevel@tonic-gate while (cp < fhp->fh_file_end) { 476*0Sstevel@tonic-gate first = cp; 477*0Sstevel@tonic-gate while (*cp != '\n') 478*0Sstevel@tonic-gate cp++; 479*0Sstevel@tonic-gate if (cp > first && *(cp - 1) == '\\') { 480*0Sstevel@tonic-gate memmove(first + 2, first, cp - first - 1); 481*0Sstevel@tonic-gate cp = first + 2; 482*0Sstevel@tonic-gate continue; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate last = cp; 485*0Sstevel@tonic-gate *cp++ = '\0'; 486*0Sstevel@tonic-gate if (netdb) { 487*0Sstevel@tonic-gate if ((last = strchr(first, '#')) == 0) 488*0Sstevel@tonic-gate last = cp - 1; 489*0Sstevel@tonic-gate *last-- = '\0'; /* nuke '\n' or #comment */ 490*0Sstevel@tonic-gate while (isspace(*first)) /* nuke leading whitespace */ 491*0Sstevel@tonic-gate first++; 492*0Sstevel@tonic-gate if (*first == '\0') /* skip content-free lines */ 493*0Sstevel@tonic-gate continue; 494*0Sstevel@tonic-gate while (isspace(*last)) /* nuke trailing whitespace */ 495*0Sstevel@tonic-gate --last; 496*0Sstevel@tonic-gate *++last = '\0'; 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate if ((*xargs.str2ent)(first, last - first, 499*0Sstevel@tonic-gate xargs.buf.result, xargs.buf.buffer, xargs.buf.buflen) != 500*0Sstevel@tonic-gate NSS_STR_PARSE_SUCCESS) 501*0Sstevel@tonic-gate continue; 502*0Sstevel@tonic-gate for (ht = 0; ht < fhp->fh_nhtab; ht++) { 503*0Sstevel@tonic-gate hp = &fhp->fh_table[ht * fhp->fh_size + line]; 504*0Sstevel@tonic-gate hp->h_hash = fhp->fh_hash_func[ht](&xargs, 0); 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate fhp->fh_line[line].l_start = first; 507*0Sstevel@tonic-gate fhp->fh_line[line++].l_len = last - first; 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate free(xargs.buf.result); 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate /* 512*0Sstevel@tonic-gate * Populate the hash tables in reverse order so that the hash chains 513*0Sstevel@tonic-gate * end up in forward order. This ensures that hashed lookups find 514*0Sstevel@tonic-gate * things in the same order that a linear search of the file would. 515*0Sstevel@tonic-gate * This is essential in cases where there could be multiple matches. 516*0Sstevel@tonic-gate * For example: until 2.7, root and smtp both had uid 0; but we 517*0Sstevel@tonic-gate * certainly wouldn't want getpwuid(0) to return smtp. 518*0Sstevel@tonic-gate */ 519*0Sstevel@tonic-gate for (ht = 0; ht < fhp->fh_nhtab; ht++) { 520*0Sstevel@tonic-gate htab = &fhp->fh_table[ht * fhp->fh_size]; 521*0Sstevel@tonic-gate for (hp = &htab[line - 1]; hp >= htab; hp--) { 522*0Sstevel@tonic-gate uint_t bucket = hp->h_hash % fhp->fh_size; 523*0Sstevel@tonic-gate hp->h_next = htab[bucket].h_first; 524*0Sstevel@tonic-gate htab[bucket].h_first = hp; 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate goto retry; 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate unavail: 531*0Sstevel@tonic-gate _nss_files_hash_destroy(fhp); 532*0Sstevel@tonic-gate mutex_unlock(&fhp->fh_lock); 533*0Sstevel@tonic-gate return (NSS_UNAVAIL); 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate #endif /* PIC */ 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate nss_status_t 538*0Sstevel@tonic-gate _nss_files_getent_rigid(be, a) 539*0Sstevel@tonic-gate files_backend_ptr_t be; 540*0Sstevel@tonic-gate void *a; 541*0Sstevel@tonic-gate { 542*0Sstevel@tonic-gate nss_XbyY_args_t *args = (nss_XbyY_args_t *)a; 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate return (_nss_files_XY_all(be, args, 0, 0, 0)); 545*0Sstevel@tonic-gate } 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate nss_status_t 548*0Sstevel@tonic-gate _nss_files_getent_netdb(be, a) 549*0Sstevel@tonic-gate files_backend_ptr_t be; 550*0Sstevel@tonic-gate void *a; 551*0Sstevel@tonic-gate { 552*0Sstevel@tonic-gate nss_XbyY_args_t *args = (nss_XbyY_args_t *)a; 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate return (_nss_files_XY_all(be, args, 1, 0, 0)); 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate /*ARGSUSED*/ 558*0Sstevel@tonic-gate nss_status_t 559*0Sstevel@tonic-gate _nss_files_destr(be, dummy) 560*0Sstevel@tonic-gate files_backend_ptr_t be; 561*0Sstevel@tonic-gate void *dummy; 562*0Sstevel@tonic-gate { 563*0Sstevel@tonic-gate if (be != 0) { 564*0Sstevel@tonic-gate if (be->f != 0) { 565*0Sstevel@tonic-gate _nss_files_endent(be, 0); 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate if (be->hashinfo != NULL) { 568*0Sstevel@tonic-gate mutex_lock(&be->hashinfo->fh_lock); 569*0Sstevel@tonic-gate if (--be->hashinfo->fh_refcnt == 0) 570*0Sstevel@tonic-gate _nss_files_hash_destroy(be->hashinfo); 571*0Sstevel@tonic-gate mutex_unlock(&be->hashinfo->fh_lock); 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate free(be); 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate return (NSS_SUCCESS); /* In case anyone is dumb enough to check */ 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate nss_backend_t * 579*0Sstevel@tonic-gate _nss_files_constr(ops, n_ops, filename, min_bufsize, fhp) 580*0Sstevel@tonic-gate files_backend_op_t ops[]; 581*0Sstevel@tonic-gate int n_ops; 582*0Sstevel@tonic-gate const char *filename; 583*0Sstevel@tonic-gate int min_bufsize; 584*0Sstevel@tonic-gate files_hash_t *fhp; 585*0Sstevel@tonic-gate { 586*0Sstevel@tonic-gate files_backend_ptr_t be; 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate if ((be = (files_backend_ptr_t)malloc(sizeof (*be))) == 0) { 589*0Sstevel@tonic-gate return (0); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate be->ops = ops; 592*0Sstevel@tonic-gate be->n_ops = n_ops; 593*0Sstevel@tonic-gate be->filename = filename; 594*0Sstevel@tonic-gate be->minbuf = min_bufsize; 595*0Sstevel@tonic-gate be->f = 0; 596*0Sstevel@tonic-gate be->buf = 0; 597*0Sstevel@tonic-gate be->hashinfo = fhp; 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate if (fhp != NULL) { 600*0Sstevel@tonic-gate mutex_lock(&fhp->fh_lock); 601*0Sstevel@tonic-gate fhp->fh_refcnt++; 602*0Sstevel@tonic-gate mutex_unlock(&fhp->fh_lock); 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate return ((nss_backend_t *)be); 606*0Sstevel@tonic-gate } 607