10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51914Scasper * Common Development and Distribution License (the "License").
61914Scasper * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
226279Sdjl * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate *
250Sstevel@tonic-gate * Common code and structures used by name-service-switch "files" backends.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * An implementation that used mmap() sensibly would be a wonderful thing,
300Sstevel@tonic-gate * but this here is just yer standard fgets() thang.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include "files_common.h"
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate #include <fcntl.h>
390Sstevel@tonic-gate #include <poll.h>
400Sstevel@tonic-gate #include <unistd.h>
410Sstevel@tonic-gate #include <sys/stat.h>
422830Sdjl #include <sys/mman.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate /*ARGSUSED*/
450Sstevel@tonic-gate nss_status_t
_nss_files_setent(be,dummy)460Sstevel@tonic-gate _nss_files_setent(be, dummy)
470Sstevel@tonic-gate files_backend_ptr_t be;
480Sstevel@tonic-gate void *dummy;
490Sstevel@tonic-gate {
500Sstevel@tonic-gate if (be->f == 0) {
510Sstevel@tonic-gate if (be->filename == 0) {
520Sstevel@tonic-gate /* Backend isn't initialized properly? */
530Sstevel@tonic-gate return (NSS_UNAVAIL);
540Sstevel@tonic-gate }
551914Scasper if ((be->f = fopen(be->filename, "rF")) == 0) {
560Sstevel@tonic-gate return (NSS_UNAVAIL);
570Sstevel@tonic-gate }
580Sstevel@tonic-gate } else {
591914Scasper rewind(be->f);
600Sstevel@tonic-gate }
610Sstevel@tonic-gate return (NSS_SUCCESS);
620Sstevel@tonic-gate }
630Sstevel@tonic-gate
640Sstevel@tonic-gate /*ARGSUSED*/
650Sstevel@tonic-gate nss_status_t
_nss_files_endent(be,dummy)660Sstevel@tonic-gate _nss_files_endent(be, dummy)
670Sstevel@tonic-gate files_backend_ptr_t be;
680Sstevel@tonic-gate void *dummy;
690Sstevel@tonic-gate {
700Sstevel@tonic-gate if (be->f != 0) {
712830Sdjl (void) fclose(be->f);
720Sstevel@tonic-gate be->f = 0;
730Sstevel@tonic-gate }
740Sstevel@tonic-gate if (be->buf != 0) {
750Sstevel@tonic-gate free(be->buf);
760Sstevel@tonic-gate be->buf = 0;
770Sstevel@tonic-gate }
780Sstevel@tonic-gate return (NSS_SUCCESS);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate * This routine reads a line, including the processing of continuation
830Sstevel@tonic-gate * characters. It always leaves (or inserts) \n\0 at the end of the line.
840Sstevel@tonic-gate * It returns the length of the line read, excluding the \n\0. Who's idea
850Sstevel@tonic-gate * was this?
860Sstevel@tonic-gate * Returns -1 on EOF.
870Sstevel@tonic-gate *
880Sstevel@tonic-gate * Note that since each concurrent call to _nss_files_read_line has
890Sstevel@tonic-gate * it's own FILE pointer, we can use getc_unlocked w/o difficulties,
900Sstevel@tonic-gate * a substantial performance win.
910Sstevel@tonic-gate */
920Sstevel@tonic-gate int
_nss_files_read_line(f,buffer,buflen)930Sstevel@tonic-gate _nss_files_read_line(f, buffer, buflen)
941914Scasper FILE *f;
950Sstevel@tonic-gate char *buffer;
960Sstevel@tonic-gate int buflen;
970Sstevel@tonic-gate {
980Sstevel@tonic-gate int linelen; /* 1st unused slot in buffer */
990Sstevel@tonic-gate int c;
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /*CONSTCOND*/
1020Sstevel@tonic-gate while (1) {
1030Sstevel@tonic-gate linelen = 0;
1040Sstevel@tonic-gate while (linelen < buflen - 1) { /* "- 1" saves room for \n\0 */
1051914Scasper switch (c = getc_unlocked(f)) {
1060Sstevel@tonic-gate case EOF:
1070Sstevel@tonic-gate if (linelen == 0 ||
1080Sstevel@tonic-gate buffer[linelen - 1] == '\\') {
1090Sstevel@tonic-gate return (-1);
1100Sstevel@tonic-gate } else {
1110Sstevel@tonic-gate buffer[linelen ] = '\n';
1120Sstevel@tonic-gate buffer[linelen + 1] = '\0';
1130Sstevel@tonic-gate return (linelen);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate case '\n':
1160Sstevel@tonic-gate if (linelen > 0 &&
1170Sstevel@tonic-gate buffer[linelen - 1] == '\\') {
1180Sstevel@tonic-gate --linelen; /* remove the '\\' */
1190Sstevel@tonic-gate } else {
1200Sstevel@tonic-gate buffer[linelen ] = '\n';
1210Sstevel@tonic-gate buffer[linelen + 1] = '\0';
1220Sstevel@tonic-gate return (linelen);
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate break;
1250Sstevel@tonic-gate default:
1260Sstevel@tonic-gate buffer[linelen++] = c;
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate /* Buffer overflow -- eat rest of line and loop again */
1300Sstevel@tonic-gate /* ===> Should syslog() */
1310Sstevel@tonic-gate do {
1321914Scasper c = getc_unlocked(f);
1330Sstevel@tonic-gate if (c == EOF) {
1340Sstevel@tonic-gate return (-1);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate } while (c != '\n');
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate /*NOTREACHED*/
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate /*
1420Sstevel@tonic-gate * used only for getgroupbymem() now.
1430Sstevel@tonic-gate */
1440Sstevel@tonic-gate nss_status_t
_nss_files_do_all(be,args,filter,func)1450Sstevel@tonic-gate _nss_files_do_all(be, args, filter, func)
1460Sstevel@tonic-gate files_backend_ptr_t be;
1470Sstevel@tonic-gate void *args;
1480Sstevel@tonic-gate const char *filter;
1490Sstevel@tonic-gate files_do_all_func_t func;
1500Sstevel@tonic-gate {
1516279Sdjl long grlen;
1520Sstevel@tonic-gate char *buffer;
1530Sstevel@tonic-gate int buflen;
1540Sstevel@tonic-gate nss_status_t res;
1550Sstevel@tonic-gate
1566279Sdjl if (be->buf == 0) {
1576279Sdjl if ((grlen = sysconf(_SC_GETGR_R_SIZE_MAX)) > 0)
1586279Sdjl be->minbuf = grlen;
1596279Sdjl if ((be->buf = malloc(be->minbuf)) == 0)
1606279Sdjl return (NSS_UNAVAIL);
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate buffer = be->buf;
1630Sstevel@tonic-gate buflen = be->minbuf;
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS) {
1660Sstevel@tonic-gate return (res);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate res = NSS_NOTFOUND;
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate do {
1720Sstevel@tonic-gate int linelen;
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate if ((linelen = _nss_files_read_line(be->f, buffer,
1750Sstevel@tonic-gate buflen)) < 0) {
1760Sstevel@tonic-gate /* End of file */
1770Sstevel@tonic-gate break;
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate if (filter != 0 && strstr(buffer, filter) == 0) {
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate * Optimization: if the entry doesn't contain the
1820Sstevel@tonic-gate * filter string then it can't be the entry we want,
1830Sstevel@tonic-gate * so don't bother looking more closely at it.
1840Sstevel@tonic-gate */
1850Sstevel@tonic-gate continue;
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate res = (*func)(buffer, linelen, args);
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate } while (res == NSS_NOTFOUND);
1900Sstevel@tonic-gate
1912830Sdjl (void) _nss_files_endent(be, 0);
1920Sstevel@tonic-gate return (res);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /*
1960Sstevel@tonic-gate * Could implement this as an iterator function on top of _nss_files_do_all(),
1970Sstevel@tonic-gate * but the shared code is small enough that it'd be pretty silly.
1980Sstevel@tonic-gate */
1990Sstevel@tonic-gate nss_status_t
_nss_files_XY_all(be,args,netdb,filter,check)2000Sstevel@tonic-gate _nss_files_XY_all(be, args, netdb, filter, check)
2010Sstevel@tonic-gate files_backend_ptr_t be;
2020Sstevel@tonic-gate nss_XbyY_args_t *args;
2030Sstevel@tonic-gate int netdb; /* whether it uses netdb */
2040Sstevel@tonic-gate /* format or not */
2050Sstevel@tonic-gate const char *filter; /* advisory, to speed up */
2060Sstevel@tonic-gate /* string search */
2070Sstevel@tonic-gate files_XY_check_func check; /* NULL means one-shot, for getXXent */
2080Sstevel@tonic-gate {
2096279Sdjl char *r;
2100Sstevel@tonic-gate nss_status_t res;
2110Sstevel@tonic-gate int parsestat;
2120Sstevel@tonic-gate int (*func)();
2130Sstevel@tonic-gate
2142830Sdjl if (filter != NULL && *filter == '\0')
2152830Sdjl return (NSS_NOTFOUND);
2166279Sdjl if (be->buf == 0 || (be->minbuf < args->buf.buflen)) {
2176279Sdjl if (be->minbuf < args->buf.buflen) {
2186279Sdjl if (be->buf == 0) {
2196279Sdjl be->minbuf = args->buf.buflen;
2206279Sdjl } else if (
2216279Sdjl (r = realloc(be->buf, args->buf.buflen)) != NULL) {
2226279Sdjl be->buf = r;
2236279Sdjl be->minbuf = args->buf.buflen;
2246279Sdjl }
2256279Sdjl }
2266279Sdjl if (be->buf == 0 &&
2276279Sdjl (be->buf = malloc(be->minbuf)) == 0)
2286279Sdjl return (NSS_UNAVAIL);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate if (check != 0 || be->f == 0) {
2320Sstevel@tonic-gate if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS) {
2330Sstevel@tonic-gate return (res);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate res = NSS_NOTFOUND;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate /*CONSTCOND*/
2400Sstevel@tonic-gate while (1) {
2410Sstevel@tonic-gate char *instr = be->buf;
2420Sstevel@tonic-gate int linelen;
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate if ((linelen = _nss_files_read_line(be->f, instr,
2450Sstevel@tonic-gate be->minbuf)) < 0) {
2460Sstevel@tonic-gate /* End of file */
2470Sstevel@tonic-gate args->returnval = 0;
2482830Sdjl args->returnlen = 0;
2490Sstevel@tonic-gate break;
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate if (filter != 0 && strstr(instr, filter) == 0) {
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate * Optimization: if the entry doesn't contain the
2540Sstevel@tonic-gate * filter string then it can't be the entry we want,
2550Sstevel@tonic-gate * so don't bother looking more closely at it.
2560Sstevel@tonic-gate */
2570Sstevel@tonic-gate continue;
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate if (netdb) {
2600Sstevel@tonic-gate char *first;
2610Sstevel@tonic-gate char *last;
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate if ((last = strchr(instr, '#')) == 0) {
2640Sstevel@tonic-gate last = instr + linelen;
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate *last-- = '\0'; /* Nuke '\n' or #comment */
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate * Skip leading whitespace. Normally there isn't
2700Sstevel@tonic-gate * any, so it's not worth calling strspn().
2710Sstevel@tonic-gate */
2720Sstevel@tonic-gate for (first = instr; isspace(*first); first++) {
2730Sstevel@tonic-gate ;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate if (*first == '\0') {
2760Sstevel@tonic-gate continue;
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate * Found something non-blank on the line. Skip back
2800Sstevel@tonic-gate * over any trailing whitespace; since we know
2810Sstevel@tonic-gate * there's non-whitespace earlier in the line,
2820Sstevel@tonic-gate * checking for termination is easy.
2830Sstevel@tonic-gate */
2840Sstevel@tonic-gate while (isspace(*last)) {
2850Sstevel@tonic-gate --last;
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate linelen = last - first + 1;
2890Sstevel@tonic-gate if (first != instr) {
2900Sstevel@tonic-gate instr = first;
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate args->returnval = 0;
2952830Sdjl args->returnlen = 0;
2962830Sdjl
2972830Sdjl if (check != NULL && (*check)(args, instr, linelen) == 0)
2982830Sdjl continue;
2990Sstevel@tonic-gate
300*8040SBaban.Kenkre@Sun.COM parsestat = NSS_STR_PARSE_SUCCESS;
301*8040SBaban.Kenkre@Sun.COM if (be->filename != NULL) {
302*8040SBaban.Kenkre@Sun.COM /*
303*8040SBaban.Kenkre@Sun.COM * Special case for passwd and group wherein we
304*8040SBaban.Kenkre@Sun.COM * replace uids/gids > MAXUID by ID_NOBODY
305*8040SBaban.Kenkre@Sun.COM * because files backend does not support
306*8040SBaban.Kenkre@Sun.COM * ephemeral ids.
307*8040SBaban.Kenkre@Sun.COM */
308*8040SBaban.Kenkre@Sun.COM if (strcmp(be->filename, PF_PATH) == 0)
309*8040SBaban.Kenkre@Sun.COM parsestat = validate_passwd_ids(instr,
310*8040SBaban.Kenkre@Sun.COM &linelen, be->minbuf, 2);
311*8040SBaban.Kenkre@Sun.COM else if (strcmp(be->filename, GF_PATH) == 0)
312*8040SBaban.Kenkre@Sun.COM parsestat = validate_group_ids(instr,
313*8040SBaban.Kenkre@Sun.COM &linelen, be->minbuf, 2, check);
314*8040SBaban.Kenkre@Sun.COM }
315*8040SBaban.Kenkre@Sun.COM
316*8040SBaban.Kenkre@Sun.COM if (parsestat == NSS_STR_PARSE_SUCCESS) {
317*8040SBaban.Kenkre@Sun.COM func = args->str2ent;
318*8040SBaban.Kenkre@Sun.COM parsestat = (*func)(instr, linelen, args->buf.result,
319*8040SBaban.Kenkre@Sun.COM args->buf.buffer, args->buf.buflen);
320*8040SBaban.Kenkre@Sun.COM }
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate if (parsestat == NSS_STR_PARSE_SUCCESS) {
3232830Sdjl args->returnval = (args->buf.result != NULL)?
3242830Sdjl args->buf.result : args->buf.buffer;
3252830Sdjl args->returnlen = linelen;
3262830Sdjl res = NSS_SUCCESS;
3272830Sdjl break;
3280Sstevel@tonic-gate } else if (parsestat == NSS_STR_PARSE_ERANGE) {
3290Sstevel@tonic-gate args->erange = 1;
3300Sstevel@tonic-gate break;
3310Sstevel@tonic-gate } /* else if (parsestat == NSS_STR_PARSE_PARSE) don't care ! */
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate /*
3350Sstevel@tonic-gate * stayopen is set to 0 by default in order to close the opened
3360Sstevel@tonic-gate * file. Some applications may break if it is set to 1.
3370Sstevel@tonic-gate */
3380Sstevel@tonic-gate if (check != 0 && !args->stayopen) {
3390Sstevel@tonic-gate (void) _nss_files_endent(be, 0);
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate return (res);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate /*
3460Sstevel@tonic-gate * File hashing support. Critical for sites with large (e.g. 1000+ lines)
3470Sstevel@tonic-gate * /etc/passwd or /etc/group files. Currently only used by getpw*() and
3480Sstevel@tonic-gate * getgr*() routines, but any files backend can use this stuff.
3490Sstevel@tonic-gate */
3500Sstevel@tonic-gate static void
_nss_files_hash_destroy(files_hash_t * fhp)3510Sstevel@tonic-gate _nss_files_hash_destroy(files_hash_t *fhp)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate free(fhp->fh_table);
3540Sstevel@tonic-gate fhp->fh_table = NULL;
3550Sstevel@tonic-gate free(fhp->fh_line);
3560Sstevel@tonic-gate fhp->fh_line = NULL;
3570Sstevel@tonic-gate free(fhp->fh_file_start);
3580Sstevel@tonic-gate fhp->fh_file_start = NULL;
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate #ifdef PIC
3610Sstevel@tonic-gate /*
3620Sstevel@tonic-gate * It turns out the hashing stuff really needs to be disabled for processes
3630Sstevel@tonic-gate * other than the nscd; the consumption of swap space and memory is otherwise
3640Sstevel@tonic-gate * unacceptable when the nscd is killed w/ a large passwd file (4M) active.
3650Sstevel@tonic-gate * See 4031930 for details.
3660Sstevel@tonic-gate * So we just use this psuedo function to enable the hashing feature. Since
3670Sstevel@tonic-gate * this function name is private, we just create a function w/ the name
3680Sstevel@tonic-gate * __nss_use_files_hash in the nscd itself and everyone else uses the old
3690Sstevel@tonic-gate * interface.
3700Sstevel@tonic-gate * We also disable hashing for .a executables to avoid problems with large
3710Sstevel@tonic-gate * files....
3720Sstevel@tonic-gate */
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate #pragma weak __nss_use_files_hash
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate extern void __nss_use_files_hash(void);
3770Sstevel@tonic-gate #endif /* pic */
3780Sstevel@tonic-gate
3792830Sdjl /*ARGSUSED*/
3800Sstevel@tonic-gate nss_status_t
_nss_files_XY_hash(files_backend_ptr_t be,nss_XbyY_args_t * args,int netdb,files_hash_t * fhp,int hashop,files_XY_check_func check)3810Sstevel@tonic-gate _nss_files_XY_hash(files_backend_ptr_t be, nss_XbyY_args_t *args,
3820Sstevel@tonic-gate int netdb, files_hash_t *fhp, int hashop, files_XY_check_func check)
3830Sstevel@tonic-gate {
3842830Sdjl /* LINTED E_FUNC_VAR_UNUSED */
385*8040SBaban.Kenkre@Sun.COM int fd, retries, ht, stat;
3862830Sdjl /* LINTED E_FUNC_VAR_UNUSED */
3870Sstevel@tonic-gate uint_t hash, line, f;
3882830Sdjl /* LINTED E_FUNC_VAR_UNUSED */
3890Sstevel@tonic-gate files_hashent_t *hp, *htab;
3902830Sdjl /* LINTED E_FUNC_VAR_UNUSED */
3910Sstevel@tonic-gate char *cp, *first, *last;
3922830Sdjl /* LINTED E_FUNC_VAR_UNUSED */
3930Sstevel@tonic-gate nss_XbyY_args_t xargs;
3942830Sdjl /* LINTED E_FUNC_VAR_UNUSED */
3950Sstevel@tonic-gate struct stat64 st;
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate #ifndef PIC
3980Sstevel@tonic-gate return (_nss_files_XY_all(be, args, netdb, 0, check));
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate #else
4010Sstevel@tonic-gate if (__nss_use_files_hash == 0)
4020Sstevel@tonic-gate return (_nss_files_XY_all(be, args, netdb, 0, check));
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate mutex_lock(&fhp->fh_lock);
4050Sstevel@tonic-gate retry:
4060Sstevel@tonic-gate retries = 100;
4070Sstevel@tonic-gate while (stat64(be->filename, &st) < 0) {
4080Sstevel@tonic-gate /*
4090Sstevel@tonic-gate * On a healthy system this can't happen except during brief
4100Sstevel@tonic-gate * periods when the file is being modified/renamed. Keep
4110Sstevel@tonic-gate * trying until things settle down, but eventually give up.
4120Sstevel@tonic-gate */
4130Sstevel@tonic-gate if (--retries == 0)
4140Sstevel@tonic-gate goto unavail;
4150Sstevel@tonic-gate poll(0, 0, 100);
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate if (st.st_mtim.tv_sec == fhp->fh_mtime.tv_sec &&
4190Sstevel@tonic-gate st.st_mtim.tv_nsec == fhp->fh_mtime.tv_nsec &&
4200Sstevel@tonic-gate fhp->fh_table != NULL) {
4210Sstevel@tonic-gate htab = &fhp->fh_table[hashop * fhp->fh_size];
4222830Sdjl hash = fhp->fh_hash_func[hashop](args, 1, NULL, 0);
4230Sstevel@tonic-gate for (hp = htab[hash % fhp->fh_size].h_first; hp != NULL;
4240Sstevel@tonic-gate hp = hp->h_next) {
4250Sstevel@tonic-gate if (hp->h_hash != hash)
4260Sstevel@tonic-gate continue;
4270Sstevel@tonic-gate line = hp - htab;
4282830Sdjl if ((*check)(args, fhp->fh_line[line].l_start,
4292830Sdjl fhp->fh_line[line].l_len) == 0)
4302830Sdjl continue;
431*8040SBaban.Kenkre@Sun.COM
432*8040SBaban.Kenkre@Sun.COM if (be->filename != NULL) {
433*8040SBaban.Kenkre@Sun.COM stat = NSS_STR_PARSE_SUCCESS;
434*8040SBaban.Kenkre@Sun.COM if (strcmp(be->filename, PF_PATH) == 0)
435*8040SBaban.Kenkre@Sun.COM stat = validate_passwd_ids(
436*8040SBaban.Kenkre@Sun.COM fhp->fh_line[line].l_start,
437*8040SBaban.Kenkre@Sun.COM &fhp->fh_line[line].l_len,
438*8040SBaban.Kenkre@Sun.COM fhp->fh_line[line].l_len + 1,
439*8040SBaban.Kenkre@Sun.COM 1);
440*8040SBaban.Kenkre@Sun.COM else if (strcmp(be->filename, GF_PATH) == 0)
441*8040SBaban.Kenkre@Sun.COM stat = validate_group_ids(
442*8040SBaban.Kenkre@Sun.COM fhp->fh_line[line].l_start,
443*8040SBaban.Kenkre@Sun.COM &fhp->fh_line[line].l_len,
444*8040SBaban.Kenkre@Sun.COM fhp->fh_line[line].l_len + 1,
445*8040SBaban.Kenkre@Sun.COM 1, check);
446*8040SBaban.Kenkre@Sun.COM if (stat != NSS_STR_PARSE_SUCCESS) {
447*8040SBaban.Kenkre@Sun.COM if (stat == NSS_STR_PARSE_ERANGE)
448*8040SBaban.Kenkre@Sun.COM args->erange = 1;
449*8040SBaban.Kenkre@Sun.COM continue;
450*8040SBaban.Kenkre@Sun.COM }
451*8040SBaban.Kenkre@Sun.COM }
452*8040SBaban.Kenkre@Sun.COM
4530Sstevel@tonic-gate if ((*args->str2ent)(fhp->fh_line[line].l_start,
4540Sstevel@tonic-gate fhp->fh_line[line].l_len, args->buf.result,
4550Sstevel@tonic-gate args->buf.buffer, args->buf.buflen) ==
4560Sstevel@tonic-gate NSS_STR_PARSE_SUCCESS) {
4572830Sdjl args->returnval = (args->buf.result)?
4582830Sdjl args->buf.result:args->buf.buffer;
4592830Sdjl args->returnlen = fhp->fh_line[line].l_len;
4602830Sdjl mutex_unlock(&fhp->fh_lock);
4612830Sdjl return (NSS_SUCCESS);
4620Sstevel@tonic-gate } else {
4630Sstevel@tonic-gate args->erange = 1;
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate args->returnval = 0;
4672830Sdjl args->returnlen = 0;
4680Sstevel@tonic-gate mutex_unlock(&fhp->fh_lock);
4690Sstevel@tonic-gate return (NSS_NOTFOUND);
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate _nss_files_hash_destroy(fhp);
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate if (st.st_size > SSIZE_MAX)
4750Sstevel@tonic-gate goto unavail;
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate if ((fhp->fh_file_start = malloc((ssize_t)st.st_size + 1)) == NULL)
4780Sstevel@tonic-gate goto unavail;
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate if ((fd = open(be->filename, O_RDONLY)) < 0)
4810Sstevel@tonic-gate goto unavail;
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate if (read(fd, fhp->fh_file_start, (ssize_t)st.st_size) !=
4840Sstevel@tonic-gate (ssize_t)st.st_size) {
4850Sstevel@tonic-gate close(fd);
4860Sstevel@tonic-gate goto retry;
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate close(fd);
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate fhp->fh_file_end = fhp->fh_file_start + (off_t)st.st_size;
4920Sstevel@tonic-gate *fhp->fh_file_end = '\n';
4930Sstevel@tonic-gate fhp->fh_mtime = st.st_mtim;
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate /*
4960Sstevel@tonic-gate * If the file changed since we read it, or if it's less than
4970Sstevel@tonic-gate * 1-2 seconds old, don't trust it; its modification may still
4980Sstevel@tonic-gate * be in progress. The latter is a heuristic hack to minimize
4990Sstevel@tonic-gate * the likelihood of damage if someone modifies /etc/mumble
5000Sstevel@tonic-gate * directly (as opposed to editing and renaming a temp file).
5010Sstevel@tonic-gate *
5020Sstevel@tonic-gate * Note: the cast to u_int is there in case (1) someone rdated
5030Sstevel@tonic-gate * the system backwards since the last modification of /etc/mumble
5040Sstevel@tonic-gate * or (2) this is a diskless client whose time is badly out of sync
5050Sstevel@tonic-gate * with its server. The 1-2 second age hack doesn't cover these
5060Sstevel@tonic-gate * cases -- oh well.
5070Sstevel@tonic-gate */
5080Sstevel@tonic-gate if (stat64(be->filename, &st) < 0 ||
5090Sstevel@tonic-gate st.st_mtim.tv_sec != fhp->fh_mtime.tv_sec ||
5100Sstevel@tonic-gate st.st_mtim.tv_nsec != fhp->fh_mtime.tv_nsec ||
5110Sstevel@tonic-gate (uint_t)(time(0) - st.st_mtim.tv_sec + 2) < 4) {
5120Sstevel@tonic-gate poll(0, 0, 1000);
5130Sstevel@tonic-gate goto retry;
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate line = 1;
5170Sstevel@tonic-gate for (cp = fhp->fh_file_start; cp < fhp->fh_file_end; cp++)
5180Sstevel@tonic-gate if (*cp == '\n')
5190Sstevel@tonic-gate line++;
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate for (f = 2; f * f <= line; f++) { /* find next largest prime */
5220Sstevel@tonic-gate if (line % f == 0) {
5230Sstevel@tonic-gate f = 1;
5240Sstevel@tonic-gate line++;
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate fhp->fh_size = line;
5290Sstevel@tonic-gate fhp->fh_line = malloc(line * sizeof (files_linetab_t));
5300Sstevel@tonic-gate fhp->fh_table = calloc(line * fhp->fh_nhtab, sizeof (files_hashent_t));
5310Sstevel@tonic-gate if (fhp->fh_line == NULL || fhp->fh_table == NULL)
5320Sstevel@tonic-gate goto unavail;
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate line = 0;
5350Sstevel@tonic-gate cp = fhp->fh_file_start;
5360Sstevel@tonic-gate while (cp < fhp->fh_file_end) {
5370Sstevel@tonic-gate first = cp;
5380Sstevel@tonic-gate while (*cp != '\n')
5390Sstevel@tonic-gate cp++;
5400Sstevel@tonic-gate if (cp > first && *(cp - 1) == '\\') {
5410Sstevel@tonic-gate memmove(first + 2, first, cp - first - 1);
5420Sstevel@tonic-gate cp = first + 2;
5430Sstevel@tonic-gate continue;
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate last = cp;
5460Sstevel@tonic-gate *cp++ = '\0';
5470Sstevel@tonic-gate if (netdb) {
5480Sstevel@tonic-gate if ((last = strchr(first, '#')) == 0)
5490Sstevel@tonic-gate last = cp - 1;
5500Sstevel@tonic-gate *last-- = '\0'; /* nuke '\n' or #comment */
5510Sstevel@tonic-gate while (isspace(*first)) /* nuke leading whitespace */
5520Sstevel@tonic-gate first++;
5530Sstevel@tonic-gate if (*first == '\0') /* skip content-free lines */
5540Sstevel@tonic-gate continue;
5550Sstevel@tonic-gate while (isspace(*last)) /* nuke trailing whitespace */
5560Sstevel@tonic-gate --last;
5570Sstevel@tonic-gate *++last = '\0';
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate for (ht = 0; ht < fhp->fh_nhtab; ht++) {
5600Sstevel@tonic-gate hp = &fhp->fh_table[ht * fhp->fh_size + line];
5612830Sdjl hp->h_hash = fhp->fh_hash_func[ht](&xargs, 0, first,
5622830Sdjl last - first);
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate fhp->fh_line[line].l_start = first;
5650Sstevel@tonic-gate fhp->fh_line[line++].l_len = last - first;
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate /*
5690Sstevel@tonic-gate * Populate the hash tables in reverse order so that the hash chains
5700Sstevel@tonic-gate * end up in forward order. This ensures that hashed lookups find
5710Sstevel@tonic-gate * things in the same order that a linear search of the file would.
5720Sstevel@tonic-gate * This is essential in cases where there could be multiple matches.
5730Sstevel@tonic-gate * For example: until 2.7, root and smtp both had uid 0; but we
5740Sstevel@tonic-gate * certainly wouldn't want getpwuid(0) to return smtp.
5750Sstevel@tonic-gate */
5760Sstevel@tonic-gate for (ht = 0; ht < fhp->fh_nhtab; ht++) {
5770Sstevel@tonic-gate htab = &fhp->fh_table[ht * fhp->fh_size];
5780Sstevel@tonic-gate for (hp = &htab[line - 1]; hp >= htab; hp--) {
5790Sstevel@tonic-gate uint_t bucket = hp->h_hash % fhp->fh_size;
5800Sstevel@tonic-gate hp->h_next = htab[bucket].h_first;
5810Sstevel@tonic-gate htab[bucket].h_first = hp;
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate goto retry;
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate unavail:
5880Sstevel@tonic-gate _nss_files_hash_destroy(fhp);
5890Sstevel@tonic-gate mutex_unlock(&fhp->fh_lock);
5900Sstevel@tonic-gate return (NSS_UNAVAIL);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate #endif /* PIC */
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate nss_status_t
_nss_files_getent_rigid(be,a)5950Sstevel@tonic-gate _nss_files_getent_rigid(be, a)
5960Sstevel@tonic-gate files_backend_ptr_t be;
5970Sstevel@tonic-gate void *a;
5980Sstevel@tonic-gate {
5990Sstevel@tonic-gate nss_XbyY_args_t *args = (nss_XbyY_args_t *)a;
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate return (_nss_files_XY_all(be, args, 0, 0, 0));
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate nss_status_t
_nss_files_getent_netdb(be,a)6050Sstevel@tonic-gate _nss_files_getent_netdb(be, a)
6060Sstevel@tonic-gate files_backend_ptr_t be;
6070Sstevel@tonic-gate void *a;
6080Sstevel@tonic-gate {
6090Sstevel@tonic-gate nss_XbyY_args_t *args = (nss_XbyY_args_t *)a;
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate return (_nss_files_XY_all(be, args, 1, 0, 0));
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate /*ARGSUSED*/
6150Sstevel@tonic-gate nss_status_t
_nss_files_destr(be,dummy)6160Sstevel@tonic-gate _nss_files_destr(be, dummy)
6170Sstevel@tonic-gate files_backend_ptr_t be;
6180Sstevel@tonic-gate void *dummy;
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate if (be != 0) {
6210Sstevel@tonic-gate if (be->f != 0) {
6222830Sdjl (void) _nss_files_endent(be, 0);
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate if (be->hashinfo != NULL) {
6252830Sdjl (void) mutex_lock(&be->hashinfo->fh_lock);
6260Sstevel@tonic-gate if (--be->hashinfo->fh_refcnt == 0)
6270Sstevel@tonic-gate _nss_files_hash_destroy(be->hashinfo);
6282830Sdjl (void) mutex_unlock(&be->hashinfo->fh_lock);
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate free(be);
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate return (NSS_SUCCESS); /* In case anyone is dumb enough to check */
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate nss_backend_t *
_nss_files_constr(ops,n_ops,filename,min_bufsize,fhp)6360Sstevel@tonic-gate _nss_files_constr(ops, n_ops, filename, min_bufsize, fhp)
6370Sstevel@tonic-gate files_backend_op_t ops[];
6380Sstevel@tonic-gate int n_ops;
6390Sstevel@tonic-gate const char *filename;
6400Sstevel@tonic-gate int min_bufsize;
6410Sstevel@tonic-gate files_hash_t *fhp;
6420Sstevel@tonic-gate {
6430Sstevel@tonic-gate files_backend_ptr_t be;
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate if ((be = (files_backend_ptr_t)malloc(sizeof (*be))) == 0) {
6460Sstevel@tonic-gate return (0);
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate be->ops = ops;
6490Sstevel@tonic-gate be->n_ops = n_ops;
6500Sstevel@tonic-gate be->filename = filename;
6510Sstevel@tonic-gate be->minbuf = min_bufsize;
6520Sstevel@tonic-gate be->f = 0;
6530Sstevel@tonic-gate be->buf = 0;
6540Sstevel@tonic-gate be->hashinfo = fhp;
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate if (fhp != NULL) {
6572830Sdjl (void) mutex_lock(&fhp->fh_lock);
6580Sstevel@tonic-gate fhp->fh_refcnt++;
6592830Sdjl (void) mutex_unlock(&fhp->fh_lock);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate return ((nss_backend_t *)be);
6630Sstevel@tonic-gate }
6642830Sdjl
6652830Sdjl int
_nss_files_check_name_colon(nss_XbyY_args_t * argp,const char * line,int linelen)6662830Sdjl _nss_files_check_name_colon(nss_XbyY_args_t *argp, const char *line,
6672830Sdjl int linelen)
6682830Sdjl {
6692830Sdjl const char *linep, *limit;
6702830Sdjl const char *keyp = argp->key.name;
6712830Sdjl
6722830Sdjl linep = line;
6732830Sdjl limit = line + linelen;
6742830Sdjl while (*keyp && linep < limit && *keyp == *linep) {
6752830Sdjl keyp++;
6762830Sdjl linep++;
6772830Sdjl }
6782830Sdjl return (linep < limit && *keyp == '\0' && *linep == ':');
6792830Sdjl }
6802830Sdjl
6812830Sdjl /*
6822830Sdjl * This routine is used to parse lines of the form:
6832830Sdjl * name number aliases
6842830Sdjl * It returns 1 if the key in argp matches any one of the
6852830Sdjl * names in the line, otherwise 0
6862830Sdjl * Used by rpc, networks, protocols
6872830Sdjl */
6882830Sdjl int
_nss_files_check_name_aliases(nss_XbyY_args_t * argp,const char * line,int linelen)6892830Sdjl _nss_files_check_name_aliases(nss_XbyY_args_t *argp, const char *line,
6902830Sdjl int linelen)
6912830Sdjl {
6922830Sdjl const char *limit, *linep, *keyp;
6932830Sdjl
6942830Sdjl linep = line;
6952830Sdjl limit = line + linelen;
6962830Sdjl keyp = argp->key.name;
6972830Sdjl
6982830Sdjl /* compare name */
6992830Sdjl while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
7002830Sdjl keyp++;
7012830Sdjl linep++;
7022830Sdjl }
7032830Sdjl if (*keyp == '\0' && linep < limit && isspace(*linep))
7042830Sdjl return (1);
7052830Sdjl /* skip remainder of the name, if any */
7062830Sdjl while (linep < limit && !isspace(*linep))
7072830Sdjl linep++;
7082830Sdjl /* skip the delimiting spaces */
7092830Sdjl while (linep < limit && isspace(*linep))
7102830Sdjl linep++;
7112830Sdjl /* compare with the aliases */
7122830Sdjl while (linep < limit) {
7132830Sdjl /*
7142830Sdjl * 1st pass: skip number
7152830Sdjl * Other passes: skip remainder of the alias name, if any
7162830Sdjl */
7172830Sdjl while (linep < limit && !isspace(*linep))
7182830Sdjl linep++;
7192830Sdjl /* skip the delimiting spaces */
7202830Sdjl while (linep < limit && isspace(*linep))
7212830Sdjl linep++;
7222830Sdjl /* compare with the alias name */
7232830Sdjl keyp = argp->key.name;
7242830Sdjl while (*keyp && linep < limit && !isspace(*linep) &&
7256279Sdjl *keyp == *linep) {
7262830Sdjl keyp++;
7272830Sdjl linep++;
7282830Sdjl }
7292830Sdjl if (*keyp == '\0' && (linep == limit || isspace(*linep)))
7302830Sdjl return (1);
7312830Sdjl }
7322830Sdjl return (0);
7332830Sdjl }
734