xref: /titanic_50/usr/src/lib/nsswitch/files/common/files_common.c (revision 655967ab7780f789dd00eece4464be60cd9aff5e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
226dd84139Sdjl  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*655967abSMarcel Telka  */
25*655967abSMarcel Telka /*
26*655967abSMarcel Telka  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
27*655967abSMarcel Telka  */
28*655967abSMarcel Telka 
29*655967abSMarcel Telka /*
307c478bd9Sstevel@tonic-gate  * Common code and structures used by name-service-switch "files" backends.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * An implementation that used mmap() sensibly would be a wonderful thing,
357c478bd9Sstevel@tonic-gate  *   but this here is just yer standard fgets() thang.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include "files_common.h"
397c478bd9Sstevel@tonic-gate #include <stdio.h>
407c478bd9Sstevel@tonic-gate #include <stdlib.h>
417c478bd9Sstevel@tonic-gate #include <string.h>
427c478bd9Sstevel@tonic-gate #include <ctype.h>
437c478bd9Sstevel@tonic-gate #include <fcntl.h>
447c478bd9Sstevel@tonic-gate #include <poll.h>
457c478bd9Sstevel@tonic-gate #include <unistd.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
47cb5caa98Sdjl #include <sys/mman.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*ARGSUSED*/
507c478bd9Sstevel@tonic-gate nss_status_t
_nss_files_setent(be,dummy)517c478bd9Sstevel@tonic-gate _nss_files_setent(be, dummy)
527c478bd9Sstevel@tonic-gate 	files_backend_ptr_t	be;
537c478bd9Sstevel@tonic-gate 	void			*dummy;
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate 	if (be->f == 0) {
567c478bd9Sstevel@tonic-gate 		if (be->filename == 0) {
577c478bd9Sstevel@tonic-gate 			/* Backend isn't initialized properly? */
587c478bd9Sstevel@tonic-gate 			return (NSS_UNAVAIL);
597c478bd9Sstevel@tonic-gate 		}
60004388ebScasper 		if ((be->f = fopen(be->filename, "rF")) == 0) {
617c478bd9Sstevel@tonic-gate 			return (NSS_UNAVAIL);
627c478bd9Sstevel@tonic-gate 		}
637c478bd9Sstevel@tonic-gate 	} else {
64004388ebScasper 		rewind(be->f);
657c478bd9Sstevel@tonic-gate 	}
667c478bd9Sstevel@tonic-gate 	return (NSS_SUCCESS);
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*ARGSUSED*/
707c478bd9Sstevel@tonic-gate nss_status_t
_nss_files_endent(be,dummy)717c478bd9Sstevel@tonic-gate _nss_files_endent(be, dummy)
727c478bd9Sstevel@tonic-gate 	files_backend_ptr_t	be;
737c478bd9Sstevel@tonic-gate 	void			*dummy;
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	if (be->f != 0) {
76cb5caa98Sdjl 		(void) fclose(be->f);
777c478bd9Sstevel@tonic-gate 		be->f = 0;
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 	if (be->buf != 0) {
807c478bd9Sstevel@tonic-gate 		free(be->buf);
817c478bd9Sstevel@tonic-gate 		be->buf = 0;
827c478bd9Sstevel@tonic-gate 	}
837c478bd9Sstevel@tonic-gate 	return (NSS_SUCCESS);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate  * This routine reads a line, including the processing of continuation
887c478bd9Sstevel@tonic-gate  * characters.  It always leaves (or inserts) \n\0 at the end of the line.
897c478bd9Sstevel@tonic-gate  * It returns the length of the line read, excluding the \n\0.  Who's idea
907c478bd9Sstevel@tonic-gate  * was this?
917c478bd9Sstevel@tonic-gate  * Returns -1 on EOF.
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  * Note that since each concurrent call to _nss_files_read_line has
947c478bd9Sstevel@tonic-gate  * it's own FILE pointer, we can use getc_unlocked w/o difficulties,
957c478bd9Sstevel@tonic-gate  * a substantial performance win.
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate int
_nss_files_read_line(f,buffer,buflen)987c478bd9Sstevel@tonic-gate _nss_files_read_line(f, buffer, buflen)
99004388ebScasper 	FILE			*f;
1007c478bd9Sstevel@tonic-gate 	char			*buffer;
1017c478bd9Sstevel@tonic-gate 	int			buflen;
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate 	int			linelen;	/* 1st unused slot in buffer */
1047c478bd9Sstevel@tonic-gate 	int			c;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
1077c478bd9Sstevel@tonic-gate 	while (1) {
1087c478bd9Sstevel@tonic-gate 		linelen = 0;
1097c478bd9Sstevel@tonic-gate 		while (linelen < buflen - 1) {	/* "- 1" saves room for \n\0 */
110004388ebScasper 			switch (c = getc_unlocked(f)) {
1117c478bd9Sstevel@tonic-gate 			case EOF:
1127c478bd9Sstevel@tonic-gate 				if (linelen == 0 ||
1137c478bd9Sstevel@tonic-gate 				    buffer[linelen - 1] == '\\') {
1147c478bd9Sstevel@tonic-gate 					return (-1);
1157c478bd9Sstevel@tonic-gate 				} else {
1167c478bd9Sstevel@tonic-gate 					buffer[linelen    ] = '\n';
1177c478bd9Sstevel@tonic-gate 					buffer[linelen + 1] = '\0';
1187c478bd9Sstevel@tonic-gate 					return (linelen);
1197c478bd9Sstevel@tonic-gate 				}
1207c478bd9Sstevel@tonic-gate 			case '\n':
1217c478bd9Sstevel@tonic-gate 				if (linelen > 0 &&
1227c478bd9Sstevel@tonic-gate 				    buffer[linelen - 1] == '\\') {
1237c478bd9Sstevel@tonic-gate 					--linelen;  /* remove the '\\' */
1247c478bd9Sstevel@tonic-gate 				} else {
1257c478bd9Sstevel@tonic-gate 					buffer[linelen    ] = '\n';
1267c478bd9Sstevel@tonic-gate 					buffer[linelen + 1] = '\0';
1277c478bd9Sstevel@tonic-gate 					return (linelen);
1287c478bd9Sstevel@tonic-gate 				}
1297c478bd9Sstevel@tonic-gate 				break;
1307c478bd9Sstevel@tonic-gate 			default:
1317c478bd9Sstevel@tonic-gate 				buffer[linelen++] = c;
1327c478bd9Sstevel@tonic-gate 			}
1337c478bd9Sstevel@tonic-gate 		}
1347c478bd9Sstevel@tonic-gate 		/* Buffer overflow -- eat rest of line and loop again */
1357c478bd9Sstevel@tonic-gate 		/* ===> Should syslog() */
1367c478bd9Sstevel@tonic-gate 		do {
137004388ebScasper 			c = getc_unlocked(f);
1387c478bd9Sstevel@tonic-gate 			if (c == EOF) {
1397c478bd9Sstevel@tonic-gate 				return (-1);
1407c478bd9Sstevel@tonic-gate 			}
1417c478bd9Sstevel@tonic-gate 		} while (c != '\n');
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate  * used only for getgroupbymem() now.
1487c478bd9Sstevel@tonic-gate  */
1497c478bd9Sstevel@tonic-gate nss_status_t
_nss_files_do_all(be,args,filter,func)1507c478bd9Sstevel@tonic-gate _nss_files_do_all(be, args, filter, func)
1517c478bd9Sstevel@tonic-gate 	files_backend_ptr_t	be;
1527c478bd9Sstevel@tonic-gate 	void			*args;
1537c478bd9Sstevel@tonic-gate 	const char		*filter;
1547c478bd9Sstevel@tonic-gate 	files_do_all_func_t	func;
1557c478bd9Sstevel@tonic-gate {
1566dd84139Sdjl 	long			grlen;
1577c478bd9Sstevel@tonic-gate 	char			*buffer;
1587c478bd9Sstevel@tonic-gate 	int			buflen;
1597c478bd9Sstevel@tonic-gate 	nss_status_t		res;
1607c478bd9Sstevel@tonic-gate 
1616dd84139Sdjl 	if (be->buf == 0) {
1626dd84139Sdjl 		if ((grlen = sysconf(_SC_GETGR_R_SIZE_MAX)) > 0)
1636dd84139Sdjl 			be->minbuf = grlen;
1646dd84139Sdjl 		if ((be->buf = malloc(be->minbuf)) == 0)
1657c478bd9Sstevel@tonic-gate 			return (NSS_UNAVAIL);
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 	buffer = be->buf;
1687c478bd9Sstevel@tonic-gate 	buflen = be->minbuf;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS) {
1717c478bd9Sstevel@tonic-gate 		return (res);
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	res = NSS_NOTFOUND;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	do {
1777c478bd9Sstevel@tonic-gate 		int		linelen;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		if ((linelen = _nss_files_read_line(be->f, buffer,
1807c478bd9Sstevel@tonic-gate 		    buflen)) < 0) {
1817c478bd9Sstevel@tonic-gate 			/* End of file */
1827c478bd9Sstevel@tonic-gate 			break;
1837c478bd9Sstevel@tonic-gate 		}
1847c478bd9Sstevel@tonic-gate 		if (filter != 0 && strstr(buffer, filter) == 0) {
1857c478bd9Sstevel@tonic-gate 			/*
1867c478bd9Sstevel@tonic-gate 			 * Optimization:  if the entry doesn't contain the
1877c478bd9Sstevel@tonic-gate 			 *   filter string then it can't be the entry we want,
1887c478bd9Sstevel@tonic-gate 			 *   so don't bother looking more closely at it.
1897c478bd9Sstevel@tonic-gate 			 */
1907c478bd9Sstevel@tonic-gate 			continue;
1917c478bd9Sstevel@tonic-gate 		}
1927c478bd9Sstevel@tonic-gate 		res = (*func)(buffer, linelen, args);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	} while (res == NSS_NOTFOUND);
1957c478bd9Sstevel@tonic-gate 
196cb5caa98Sdjl 	(void) _nss_files_endent(be, 0);
1977c478bd9Sstevel@tonic-gate 	return (res);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  * Could implement this as an iterator function on top of _nss_files_do_all(),
2027c478bd9Sstevel@tonic-gate  *   but the shared code is small enough that it'd be pretty silly.
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate nss_status_t
_nss_files_XY_all(be,args,netdb,filter,check)2057c478bd9Sstevel@tonic-gate _nss_files_XY_all(be, args, netdb, filter, check)
2067c478bd9Sstevel@tonic-gate 	files_backend_ptr_t	be;
2077c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
2087c478bd9Sstevel@tonic-gate 	int			netdb;		/* whether it uses netdb */
2097c478bd9Sstevel@tonic-gate 						/* format or not */
2107c478bd9Sstevel@tonic-gate 	const char		*filter;	/* advisory, to speed up */
2117c478bd9Sstevel@tonic-gate 						/* string search */
2127c478bd9Sstevel@tonic-gate 	files_XY_check_func	check;	/* NULL means one-shot, for getXXent */
2137c478bd9Sstevel@tonic-gate {
2146dd84139Sdjl 	char			*r;
2157c478bd9Sstevel@tonic-gate 	nss_status_t		res;
2167c478bd9Sstevel@tonic-gate 	int	parsestat;
2177c478bd9Sstevel@tonic-gate 	int (*func)();
2187c478bd9Sstevel@tonic-gate 
219cb5caa98Sdjl 	if (filter != NULL && *filter == '\0')
220cb5caa98Sdjl 		return (NSS_NOTFOUND);
2216dd84139Sdjl 	if (be->buf == 0 || (be->minbuf < args->buf.buflen)) {
2226dd84139Sdjl 		if (be->minbuf < args->buf.buflen) {
2236dd84139Sdjl 			if (be->buf == 0) {
2246dd84139Sdjl 				be->minbuf = args->buf.buflen;
2256dd84139Sdjl 			} else if (
2266dd84139Sdjl 			    (r = realloc(be->buf, args->buf.buflen)) != NULL) {
2276dd84139Sdjl 				be->buf = r;
2286dd84139Sdjl 				be->minbuf = args->buf.buflen;
2296dd84139Sdjl 			}
2306dd84139Sdjl 		}
2317c478bd9Sstevel@tonic-gate 		if (be->buf == 0 &&
2326dd84139Sdjl 			(be->buf = malloc(be->minbuf)) == 0)
2336dd84139Sdjl 				return (NSS_UNAVAIL);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	if (check != 0 || be->f == 0) {
2377c478bd9Sstevel@tonic-gate 		if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS) {
2387c478bd9Sstevel@tonic-gate 			return (res);
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	res = NSS_NOTFOUND;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
2457c478bd9Sstevel@tonic-gate 	while (1) {
2467c478bd9Sstevel@tonic-gate 		char		*instr	= be->buf;
2477c478bd9Sstevel@tonic-gate 		int		linelen;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		if ((linelen = _nss_files_read_line(be->f, instr,
2507c478bd9Sstevel@tonic-gate 		    be->minbuf)) < 0) {
2517c478bd9Sstevel@tonic-gate 			/* End of file */
2527c478bd9Sstevel@tonic-gate 			args->returnval = 0;
253cb5caa98Sdjl 			args->returnlen = 0;
2547c478bd9Sstevel@tonic-gate 			break;
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 		if (filter != 0 && strstr(instr, filter) == 0) {
2577c478bd9Sstevel@tonic-gate 			/*
2587c478bd9Sstevel@tonic-gate 			 * Optimization:  if the entry doesn't contain the
2597c478bd9Sstevel@tonic-gate 			 *   filter string then it can't be the entry we want,
2607c478bd9Sstevel@tonic-gate 			 *   so don't bother looking more closely at it.
2617c478bd9Sstevel@tonic-gate 			 */
2627c478bd9Sstevel@tonic-gate 			continue;
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 		if (netdb) {
2657c478bd9Sstevel@tonic-gate 			char		*first;
2667c478bd9Sstevel@tonic-gate 			char		*last;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 			if ((last = strchr(instr, '#')) == 0) {
2697c478bd9Sstevel@tonic-gate 				last = instr + linelen;
2707c478bd9Sstevel@tonic-gate 			}
2717c478bd9Sstevel@tonic-gate 			*last-- = '\0';		/* Nuke '\n' or #comment */
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 			/*
2747c478bd9Sstevel@tonic-gate 			 * Skip leading whitespace.  Normally there isn't
2757c478bd9Sstevel@tonic-gate 			 *   any, so it's not worth calling strspn().
2767c478bd9Sstevel@tonic-gate 			 */
2777c478bd9Sstevel@tonic-gate 			for (first = instr;  isspace(*first);  first++) {
2787c478bd9Sstevel@tonic-gate 				;
2797c478bd9Sstevel@tonic-gate 			}
2807c478bd9Sstevel@tonic-gate 			if (*first == '\0') {
2817c478bd9Sstevel@tonic-gate 				continue;
2827c478bd9Sstevel@tonic-gate 			}
2837c478bd9Sstevel@tonic-gate 			/*
2847c478bd9Sstevel@tonic-gate 			 * Found something non-blank on the line.  Skip back
2857c478bd9Sstevel@tonic-gate 			 * over any trailing whitespace;  since we know
2867c478bd9Sstevel@tonic-gate 			 * there's non-whitespace earlier in the line,
2877c478bd9Sstevel@tonic-gate 			 * checking for termination is easy.
2887c478bd9Sstevel@tonic-gate 			 */
2897c478bd9Sstevel@tonic-gate 			while (isspace(*last)) {
2907c478bd9Sstevel@tonic-gate 				--last;
2917c478bd9Sstevel@tonic-gate 			}
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 			linelen = last - first + 1;
2947c478bd9Sstevel@tonic-gate 			if (first != instr) {
2957c478bd9Sstevel@tonic-gate 					instr = first;
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 		args->returnval = 0;
300cb5caa98Sdjl 		args->returnlen = 0;
301cb5caa98Sdjl 
302cb5caa98Sdjl 		if (check != NULL && (*check)(args, instr, linelen) == 0)
303cb5caa98Sdjl 			continue;
3047c478bd9Sstevel@tonic-gate 
3052b4a7802SBaban Kenkre 		parsestat = NSS_STR_PARSE_SUCCESS;
3062b4a7802SBaban Kenkre 		if (be->filename != NULL) {
3072b4a7802SBaban Kenkre 			/*
3082b4a7802SBaban Kenkre 			 * Special case for passwd and group wherein we
3092b4a7802SBaban Kenkre 			 * replace uids/gids > MAXUID by ID_NOBODY
3102b4a7802SBaban Kenkre 			 * because files backend does not support
3112b4a7802SBaban Kenkre 			 * ephemeral ids.
3122b4a7802SBaban Kenkre 			 */
3132b4a7802SBaban Kenkre 			if (strcmp(be->filename, PF_PATH) == 0)
3142b4a7802SBaban Kenkre 				parsestat = validate_passwd_ids(instr,
3152b4a7802SBaban Kenkre 				    &linelen, be->minbuf, 2);
3162b4a7802SBaban Kenkre 			else if (strcmp(be->filename, GF_PATH) == 0)
3172b4a7802SBaban Kenkre 				parsestat = validate_group_ids(instr,
3182b4a7802SBaban Kenkre 				    &linelen, be->minbuf, 2, check);
3192b4a7802SBaban Kenkre 		}
3202b4a7802SBaban Kenkre 
3212b4a7802SBaban Kenkre 		if (parsestat == NSS_STR_PARSE_SUCCESS) {
3227c478bd9Sstevel@tonic-gate 			func = args->str2ent;
3237c478bd9Sstevel@tonic-gate 			parsestat = (*func)(instr, linelen, args->buf.result,
3247c478bd9Sstevel@tonic-gate 			    args->buf.buffer, args->buf.buflen);
3252b4a7802SBaban Kenkre 		}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 		if (parsestat == NSS_STR_PARSE_SUCCESS) {
328cb5caa98Sdjl 			args->returnval = (args->buf.result != NULL)?
329cb5caa98Sdjl 					args->buf.result : args->buf.buffer;
330cb5caa98Sdjl 			args->returnlen = linelen;
3317c478bd9Sstevel@tonic-gate 			res = NSS_SUCCESS;
3327c478bd9Sstevel@tonic-gate 			break;
3337c478bd9Sstevel@tonic-gate 		} else if (parsestat == NSS_STR_PARSE_ERANGE) {
3347c478bd9Sstevel@tonic-gate 			args->erange = 1;
3357c478bd9Sstevel@tonic-gate 			break;
3367c478bd9Sstevel@tonic-gate 		} /* else if (parsestat == NSS_STR_PARSE_PARSE) don't care ! */
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * stayopen is set to 0 by default in order to close the opened
3417c478bd9Sstevel@tonic-gate 	 * file.  Some applications may break if it is set to 1.
3427c478bd9Sstevel@tonic-gate 	 */
3437c478bd9Sstevel@tonic-gate 	if (check != 0 && !args->stayopen) {
3447c478bd9Sstevel@tonic-gate 		(void) _nss_files_endent(be, 0);
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	return (res);
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate /*
3517c478bd9Sstevel@tonic-gate  * File hashing support.  Critical for sites with large (e.g. 1000+ lines)
3527c478bd9Sstevel@tonic-gate  * /etc/passwd or /etc/group files.  Currently only used by getpw*() and
3537c478bd9Sstevel@tonic-gate  * getgr*() routines, but any files backend can use this stuff.
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate static void
_nss_files_hash_destroy(files_hash_t * fhp)3567c478bd9Sstevel@tonic-gate _nss_files_hash_destroy(files_hash_t *fhp)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate 	free(fhp->fh_table);
3597c478bd9Sstevel@tonic-gate 	fhp->fh_table = NULL;
3607c478bd9Sstevel@tonic-gate 	free(fhp->fh_line);
3617c478bd9Sstevel@tonic-gate 	fhp->fh_line = NULL;
3627c478bd9Sstevel@tonic-gate 	free(fhp->fh_file_start);
3637c478bd9Sstevel@tonic-gate 	fhp->fh_file_start = NULL;
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate #ifdef PIC
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * It turns out the hashing stuff really needs to be disabled for processes
3687c478bd9Sstevel@tonic-gate  * other than the nscd; the consumption of swap space and memory is otherwise
3697c478bd9Sstevel@tonic-gate  * unacceptable when the nscd is killed w/ a large passwd file (4M) active.
3707c478bd9Sstevel@tonic-gate  * See 4031930 for details.
3717c478bd9Sstevel@tonic-gate  * So we just use this psuedo function to enable the hashing feature.  Since
3727c478bd9Sstevel@tonic-gate  * this function name is private, we just create a function w/ the name
3737c478bd9Sstevel@tonic-gate  *  __nss_use_files_hash in the nscd itself and everyone else uses the old
3747c478bd9Sstevel@tonic-gate  * interface.
3757c478bd9Sstevel@tonic-gate  * We also disable hashing for .a executables to avoid problems with large
3767c478bd9Sstevel@tonic-gate  * files....
3777c478bd9Sstevel@tonic-gate  */
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate #pragma weak __nss_use_files_hash
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate extern void  __nss_use_files_hash(void);
3827c478bd9Sstevel@tonic-gate #endif /* pic */
3837c478bd9Sstevel@tonic-gate 
384cb5caa98Sdjl /*ARGSUSED*/
3857c478bd9Sstevel@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)3867c478bd9Sstevel@tonic-gate _nss_files_XY_hash(files_backend_ptr_t be, nss_XbyY_args_t *args,
3877c478bd9Sstevel@tonic-gate 	int netdb, files_hash_t *fhp, int hashop, files_XY_check_func check)
3887c478bd9Sstevel@tonic-gate {
389cb5caa98Sdjl 	/* LINTED E_FUNC_VAR_UNUSED */
3902b4a7802SBaban Kenkre 	int fd, retries, ht, stat;
391cb5caa98Sdjl 	/* LINTED E_FUNC_VAR_UNUSED */
3927c478bd9Sstevel@tonic-gate 	uint_t hash, line, f;
393cb5caa98Sdjl 	/* LINTED E_FUNC_VAR_UNUSED */
3947c478bd9Sstevel@tonic-gate 	files_hashent_t *hp, *htab;
395cb5caa98Sdjl 	/* LINTED E_FUNC_VAR_UNUSED */
3967c478bd9Sstevel@tonic-gate 	char *cp, *first, *last;
397cb5caa98Sdjl 	/* LINTED E_FUNC_VAR_UNUSED */
3987c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t xargs;
399cb5caa98Sdjl 	/* LINTED E_FUNC_VAR_UNUSED */
4007c478bd9Sstevel@tonic-gate 	struct stat64 st;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate #ifndef PIC
4037c478bd9Sstevel@tonic-gate 	return (_nss_files_XY_all(be, args, netdb, 0, check));
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate #else
4067c478bd9Sstevel@tonic-gate 	if (__nss_use_files_hash == 0)
4077c478bd9Sstevel@tonic-gate 		return (_nss_files_XY_all(be, args, netdb, 0, check));
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	mutex_lock(&fhp->fh_lock);
4107c478bd9Sstevel@tonic-gate retry:
4117c478bd9Sstevel@tonic-gate 	retries = 100;
4127c478bd9Sstevel@tonic-gate 	while (stat64(be->filename, &st) < 0) {
4137c478bd9Sstevel@tonic-gate 		/*
414*655967abSMarcel Telka 		 * This can happen only in two cases: Either the file is
415*655967abSMarcel Telka 		 * completely missing and we were not able to read it yet
416*655967abSMarcel Telka 		 * (fh_table is NULL), or there is some brief period when the
417*655967abSMarcel Telka 		 * file is being modified/renamed.  Keep trying until things
418*655967abSMarcel Telka 		 * settle down, but eventually give up.
4197c478bd9Sstevel@tonic-gate 		 */
420*655967abSMarcel Telka 		if (fhp->fh_table == NULL || --retries == 0)
4217c478bd9Sstevel@tonic-gate 			goto unavail;
4227c478bd9Sstevel@tonic-gate 		poll(0, 0, 100);
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	if (st.st_mtim.tv_sec == fhp->fh_mtime.tv_sec &&
4267c478bd9Sstevel@tonic-gate 	    st.st_mtim.tv_nsec == fhp->fh_mtime.tv_nsec &&
4277c478bd9Sstevel@tonic-gate 	    fhp->fh_table != NULL) {
4287c478bd9Sstevel@tonic-gate 		htab = &fhp->fh_table[hashop * fhp->fh_size];
429cb5caa98Sdjl 		hash = fhp->fh_hash_func[hashop](args, 1, NULL, 0);
4307c478bd9Sstevel@tonic-gate 		for (hp = htab[hash % fhp->fh_size].h_first; hp != NULL;
4317c478bd9Sstevel@tonic-gate 		    hp = hp->h_next) {
4327c478bd9Sstevel@tonic-gate 			if (hp->h_hash != hash)
4337c478bd9Sstevel@tonic-gate 				continue;
4347c478bd9Sstevel@tonic-gate 			line = hp - htab;
435cb5caa98Sdjl 			if ((*check)(args, fhp->fh_line[line].l_start,
436cb5caa98Sdjl 					fhp->fh_line[line].l_len) == 0)
437cb5caa98Sdjl 				continue;
4382b4a7802SBaban Kenkre 
4392b4a7802SBaban Kenkre 			if (be->filename != NULL) {
4402b4a7802SBaban Kenkre 				stat = NSS_STR_PARSE_SUCCESS;
4412b4a7802SBaban Kenkre 				if (strcmp(be->filename, PF_PATH) == 0)
4422b4a7802SBaban Kenkre 					stat = validate_passwd_ids(
4432b4a7802SBaban Kenkre 					    fhp->fh_line[line].l_start,
4442b4a7802SBaban Kenkre 					    &fhp->fh_line[line].l_len,
4452b4a7802SBaban Kenkre 					    fhp->fh_line[line].l_len + 1,
4462b4a7802SBaban Kenkre 					    1);
4472b4a7802SBaban Kenkre 				else if (strcmp(be->filename, GF_PATH) == 0)
4482b4a7802SBaban Kenkre 					stat = validate_group_ids(
4492b4a7802SBaban Kenkre 					    fhp->fh_line[line].l_start,
4502b4a7802SBaban Kenkre 					    &fhp->fh_line[line].l_len,
4512b4a7802SBaban Kenkre 					    fhp->fh_line[line].l_len + 1,
4522b4a7802SBaban Kenkre 					    1, check);
4532b4a7802SBaban Kenkre 				if (stat != NSS_STR_PARSE_SUCCESS) {
4542b4a7802SBaban Kenkre 					if (stat == NSS_STR_PARSE_ERANGE)
4552b4a7802SBaban Kenkre 						args->erange = 1;
4562b4a7802SBaban Kenkre 					continue;
4572b4a7802SBaban Kenkre 				}
4582b4a7802SBaban Kenkre 			}
4592b4a7802SBaban Kenkre 
4607c478bd9Sstevel@tonic-gate 			if ((*args->str2ent)(fhp->fh_line[line].l_start,
4617c478bd9Sstevel@tonic-gate 			    fhp->fh_line[line].l_len, args->buf.result,
4627c478bd9Sstevel@tonic-gate 			    args->buf.buffer, args->buf.buflen) ==
4637c478bd9Sstevel@tonic-gate 			    NSS_STR_PARSE_SUCCESS) {
464cb5caa98Sdjl 				args->returnval = (args->buf.result)?
465cb5caa98Sdjl 					args->buf.result:args->buf.buffer;
466cb5caa98Sdjl 				args->returnlen = fhp->fh_line[line].l_len;
4677c478bd9Sstevel@tonic-gate 				mutex_unlock(&fhp->fh_lock);
4687c478bd9Sstevel@tonic-gate 				return (NSS_SUCCESS);
4697c478bd9Sstevel@tonic-gate 			} else {
4707c478bd9Sstevel@tonic-gate 				args->erange = 1;
4717c478bd9Sstevel@tonic-gate 			}
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 		args->returnval = 0;
474cb5caa98Sdjl 		args->returnlen = 0;
4757c478bd9Sstevel@tonic-gate 		mutex_unlock(&fhp->fh_lock);
4767c478bd9Sstevel@tonic-gate 		return (NSS_NOTFOUND);
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	_nss_files_hash_destroy(fhp);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (st.st_size > SSIZE_MAX)
4827c478bd9Sstevel@tonic-gate 		goto unavail;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if ((fhp->fh_file_start = malloc((ssize_t)st.st_size + 1)) == NULL)
4857c478bd9Sstevel@tonic-gate 		goto unavail;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if ((fd = open(be->filename, O_RDONLY)) < 0)
4887c478bd9Sstevel@tonic-gate 		goto unavail;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (read(fd, fhp->fh_file_start, (ssize_t)st.st_size) !=
4917c478bd9Sstevel@tonic-gate 	    (ssize_t)st.st_size) {
4927c478bd9Sstevel@tonic-gate 		close(fd);
4937c478bd9Sstevel@tonic-gate 		goto retry;
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	close(fd);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	fhp->fh_file_end = fhp->fh_file_start + (off_t)st.st_size;
4997c478bd9Sstevel@tonic-gate 	*fhp->fh_file_end = '\n';
5007c478bd9Sstevel@tonic-gate 	fhp->fh_mtime = st.st_mtim;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/*
5037c478bd9Sstevel@tonic-gate 	 * If the file changed since we read it, or if it's less than
5047c478bd9Sstevel@tonic-gate 	 * 1-2 seconds old, don't trust it; its modification may still
5057c478bd9Sstevel@tonic-gate 	 * be in progress.  The latter is a heuristic hack to minimize
5067c478bd9Sstevel@tonic-gate 	 * the likelihood of damage if someone modifies /etc/mumble
5077c478bd9Sstevel@tonic-gate 	 * directly (as opposed to editing and renaming a temp file).
5087c478bd9Sstevel@tonic-gate 	 *
5097c478bd9Sstevel@tonic-gate 	 * Note: the cast to u_int is there in case (1) someone rdated
5107c478bd9Sstevel@tonic-gate 	 * the system backwards since the last modification of /etc/mumble
5117c478bd9Sstevel@tonic-gate 	 * or (2) this is a diskless client whose time is badly out of sync
5127c478bd9Sstevel@tonic-gate 	 * with its server.  The 1-2 second age hack doesn't cover these
5137c478bd9Sstevel@tonic-gate 	 * cases -- oh well.
5147c478bd9Sstevel@tonic-gate 	 */
5157c478bd9Sstevel@tonic-gate 	if (stat64(be->filename, &st) < 0 ||
5167c478bd9Sstevel@tonic-gate 	    st.st_mtim.tv_sec != fhp->fh_mtime.tv_sec ||
5177c478bd9Sstevel@tonic-gate 	    st.st_mtim.tv_nsec != fhp->fh_mtime.tv_nsec ||
5187c478bd9Sstevel@tonic-gate 	    (uint_t)(time(0) - st.st_mtim.tv_sec + 2) < 4) {
5197c478bd9Sstevel@tonic-gate 		poll(0, 0, 1000);
5207c478bd9Sstevel@tonic-gate 		goto retry;
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	line = 1;
5247c478bd9Sstevel@tonic-gate 	for (cp = fhp->fh_file_start; cp < fhp->fh_file_end; cp++)
5257c478bd9Sstevel@tonic-gate 		if (*cp == '\n')
5267c478bd9Sstevel@tonic-gate 			line++;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	for (f = 2; f * f <= line; f++) {	/* find next largest prime */
5297c478bd9Sstevel@tonic-gate 		if (line % f == 0) {
5307c478bd9Sstevel@tonic-gate 			f = 1;
5317c478bd9Sstevel@tonic-gate 			line++;
5327c478bd9Sstevel@tonic-gate 		}
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	fhp->fh_size = line;
5367c478bd9Sstevel@tonic-gate 	fhp->fh_line = malloc(line * sizeof (files_linetab_t));
5377c478bd9Sstevel@tonic-gate 	fhp->fh_table = calloc(line * fhp->fh_nhtab, sizeof (files_hashent_t));
5387c478bd9Sstevel@tonic-gate 	if (fhp->fh_line == NULL || fhp->fh_table == NULL)
5397c478bd9Sstevel@tonic-gate 		goto unavail;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	line = 0;
5427c478bd9Sstevel@tonic-gate 	cp = fhp->fh_file_start;
5437c478bd9Sstevel@tonic-gate 	while (cp < fhp->fh_file_end) {
5447c478bd9Sstevel@tonic-gate 		first = cp;
5457c478bd9Sstevel@tonic-gate 		while (*cp != '\n')
5467c478bd9Sstevel@tonic-gate 			cp++;
5477c478bd9Sstevel@tonic-gate 		if (cp > first && *(cp - 1) == '\\') {
5487c478bd9Sstevel@tonic-gate 			memmove(first + 2, first, cp - first - 1);
5497c478bd9Sstevel@tonic-gate 			cp = first + 2;
5507c478bd9Sstevel@tonic-gate 			continue;
5517c478bd9Sstevel@tonic-gate 		}
5527c478bd9Sstevel@tonic-gate 		last = cp;
5537c478bd9Sstevel@tonic-gate 		*cp++ = '\0';
5547c478bd9Sstevel@tonic-gate 		if (netdb) {
5557c478bd9Sstevel@tonic-gate 			if ((last = strchr(first, '#')) == 0)
5567c478bd9Sstevel@tonic-gate 				last = cp - 1;
5577c478bd9Sstevel@tonic-gate 			*last-- = '\0';		/* nuke '\n' or #comment */
5587c478bd9Sstevel@tonic-gate 			while (isspace(*first))	/* nuke leading whitespace */
5597c478bd9Sstevel@tonic-gate 				first++;
5607c478bd9Sstevel@tonic-gate 			if (*first == '\0')	/* skip content-free lines */
5617c478bd9Sstevel@tonic-gate 				continue;
5627c478bd9Sstevel@tonic-gate 			while (isspace(*last))	/* nuke trailing whitespace */
5637c478bd9Sstevel@tonic-gate 				--last;
5647c478bd9Sstevel@tonic-gate 			*++last = '\0';
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 		for (ht = 0; ht < fhp->fh_nhtab; ht++) {
5677c478bd9Sstevel@tonic-gate 			hp = &fhp->fh_table[ht * fhp->fh_size + line];
568cb5caa98Sdjl 			hp->h_hash = fhp->fh_hash_func[ht](&xargs, 0, first,
569cb5caa98Sdjl 					last - first);
5707c478bd9Sstevel@tonic-gate 		}
5717c478bd9Sstevel@tonic-gate 		fhp->fh_line[line].l_start = first;
5727c478bd9Sstevel@tonic-gate 		fhp->fh_line[line++].l_len = last - first;
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	/*
5767c478bd9Sstevel@tonic-gate 	 * Populate the hash tables in reverse order so that the hash chains
5777c478bd9Sstevel@tonic-gate 	 * end up in forward order.  This ensures that hashed lookups find
5787c478bd9Sstevel@tonic-gate 	 * things in the same order that a linear search of the file would.
5797c478bd9Sstevel@tonic-gate 	 * This is essential in cases where there could be multiple matches.
5807c478bd9Sstevel@tonic-gate 	 * For example: until 2.7, root and smtp both had uid 0; but we
5817c478bd9Sstevel@tonic-gate 	 * certainly wouldn't want getpwuid(0) to return smtp.
5827c478bd9Sstevel@tonic-gate 	 */
5837c478bd9Sstevel@tonic-gate 	for (ht = 0; ht < fhp->fh_nhtab; ht++) {
5847c478bd9Sstevel@tonic-gate 		htab = &fhp->fh_table[ht * fhp->fh_size];
5857c478bd9Sstevel@tonic-gate 		for (hp = &htab[line - 1]; hp >= htab; hp--) {
5867c478bd9Sstevel@tonic-gate 			uint_t bucket = hp->h_hash % fhp->fh_size;
5877c478bd9Sstevel@tonic-gate 			hp->h_next = htab[bucket].h_first;
5887c478bd9Sstevel@tonic-gate 			htab[bucket].h_first = hp;
5897c478bd9Sstevel@tonic-gate 		}
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	goto retry;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate unavail:
5957c478bd9Sstevel@tonic-gate 	_nss_files_hash_destroy(fhp);
5967c478bd9Sstevel@tonic-gate 	mutex_unlock(&fhp->fh_lock);
5977c478bd9Sstevel@tonic-gate 	return (NSS_UNAVAIL);
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate #endif /* PIC */
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate nss_status_t
_nss_files_getent_rigid(be,a)6027c478bd9Sstevel@tonic-gate _nss_files_getent_rigid(be, a)
6037c478bd9Sstevel@tonic-gate 	files_backend_ptr_t	be;
6047c478bd9Sstevel@tonic-gate 	void			*a;
6057c478bd9Sstevel@tonic-gate {
6067c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args = (nss_XbyY_args_t *)a;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	return (_nss_files_XY_all(be, args, 0, 0, 0));
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate nss_status_t
_nss_files_getent_netdb(be,a)6127c478bd9Sstevel@tonic-gate _nss_files_getent_netdb(be, a)
6137c478bd9Sstevel@tonic-gate 	files_backend_ptr_t	be;
6147c478bd9Sstevel@tonic-gate 	void			*a;
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args = (nss_XbyY_args_t *)a;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	return (_nss_files_XY_all(be, args, 1, 0, 0));
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6227c478bd9Sstevel@tonic-gate nss_status_t
_nss_files_destr(be,dummy)6237c478bd9Sstevel@tonic-gate _nss_files_destr(be, dummy)
6247c478bd9Sstevel@tonic-gate 	files_backend_ptr_t	be;
6257c478bd9Sstevel@tonic-gate 	void			*dummy;
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	if (be != 0) {
6287c478bd9Sstevel@tonic-gate 		if (be->f != 0) {
629cb5caa98Sdjl 			(void) _nss_files_endent(be, 0);
6307c478bd9Sstevel@tonic-gate 		}
6317c478bd9Sstevel@tonic-gate 		if (be->hashinfo != NULL) {
632cb5caa98Sdjl 			(void) mutex_lock(&be->hashinfo->fh_lock);
6337c478bd9Sstevel@tonic-gate 			if (--be->hashinfo->fh_refcnt == 0)
6347c478bd9Sstevel@tonic-gate 				_nss_files_hash_destroy(be->hashinfo);
635cb5caa98Sdjl 			(void) mutex_unlock(&be->hashinfo->fh_lock);
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 		free(be);
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 	return (NSS_SUCCESS);	/* In case anyone is dumb enough to check */
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate nss_backend_t *
_nss_files_constr(ops,n_ops,filename,min_bufsize,fhp)6437c478bd9Sstevel@tonic-gate _nss_files_constr(ops, n_ops, filename, min_bufsize, fhp)
6447c478bd9Sstevel@tonic-gate 	files_backend_op_t	ops[];
6457c478bd9Sstevel@tonic-gate 	int			n_ops;
6467c478bd9Sstevel@tonic-gate 	const char		*filename;
6477c478bd9Sstevel@tonic-gate 	int			min_bufsize;
6487c478bd9Sstevel@tonic-gate 	files_hash_t		*fhp;
6497c478bd9Sstevel@tonic-gate {
6507c478bd9Sstevel@tonic-gate 	files_backend_ptr_t	be;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	if ((be = (files_backend_ptr_t)malloc(sizeof (*be))) == 0) {
6537c478bd9Sstevel@tonic-gate 		return (0);
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 	be->ops		= ops;
6567c478bd9Sstevel@tonic-gate 	be->n_ops	= n_ops;
6577c478bd9Sstevel@tonic-gate 	be->filename	= filename;
6587c478bd9Sstevel@tonic-gate 	be->minbuf	= min_bufsize;
6597c478bd9Sstevel@tonic-gate 	be->f		= 0;
6607c478bd9Sstevel@tonic-gate 	be->buf		= 0;
6617c478bd9Sstevel@tonic-gate 	be->hashinfo	= fhp;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if (fhp != NULL) {
664cb5caa98Sdjl 		(void) mutex_lock(&fhp->fh_lock);
6657c478bd9Sstevel@tonic-gate 		fhp->fh_refcnt++;
666cb5caa98Sdjl 		(void) mutex_unlock(&fhp->fh_lock);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	return ((nss_backend_t *)be);
6707c478bd9Sstevel@tonic-gate }
671cb5caa98Sdjl 
672cb5caa98Sdjl int
_nss_files_check_name_colon(nss_XbyY_args_t * argp,const char * line,int linelen)673cb5caa98Sdjl _nss_files_check_name_colon(nss_XbyY_args_t *argp, const char *line,
674cb5caa98Sdjl 	int linelen)
675cb5caa98Sdjl {
676cb5caa98Sdjl 	const char	*linep, *limit;
677cb5caa98Sdjl 	const char	*keyp = argp->key.name;
678cb5caa98Sdjl 
679cb5caa98Sdjl 	linep = line;
680cb5caa98Sdjl 	limit = line + linelen;
681cb5caa98Sdjl 	while (*keyp && linep < limit && *keyp == *linep) {
682cb5caa98Sdjl 		keyp++;
683cb5caa98Sdjl 		linep++;
684cb5caa98Sdjl 	}
685cb5caa98Sdjl 	return (linep < limit && *keyp == '\0' && *linep == ':');
686cb5caa98Sdjl }
687cb5caa98Sdjl 
688cb5caa98Sdjl /*
689cb5caa98Sdjl  * This routine is used to parse lines of the form:
690cb5caa98Sdjl  * 	name number aliases
691cb5caa98Sdjl  * It returns 1 if the key in argp matches any one of the
692cb5caa98Sdjl  * names in the line, otherwise 0
693cb5caa98Sdjl  * Used by rpc, networks, protocols
694cb5caa98Sdjl  */
695cb5caa98Sdjl int
_nss_files_check_name_aliases(nss_XbyY_args_t * argp,const char * line,int linelen)696cb5caa98Sdjl _nss_files_check_name_aliases(nss_XbyY_args_t *argp, const char *line,
697cb5caa98Sdjl 	int linelen)
698cb5caa98Sdjl {
699cb5caa98Sdjl 	const char	*limit, *linep, *keyp;
700cb5caa98Sdjl 
701cb5caa98Sdjl 	linep = line;
702cb5caa98Sdjl 	limit = line + linelen;
703cb5caa98Sdjl 	keyp = argp->key.name;
704cb5caa98Sdjl 
705cb5caa98Sdjl 	/* compare name */
706cb5caa98Sdjl 	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
707cb5caa98Sdjl 		keyp++;
708cb5caa98Sdjl 		linep++;
709cb5caa98Sdjl 	}
710cb5caa98Sdjl 	if (*keyp == '\0' && linep < limit && isspace(*linep))
711cb5caa98Sdjl 		return (1);
712cb5caa98Sdjl 	/* skip remainder of the name, if any */
713cb5caa98Sdjl 	while (linep < limit && !isspace(*linep))
714cb5caa98Sdjl 		linep++;
715cb5caa98Sdjl 	/* skip the delimiting spaces */
716cb5caa98Sdjl 	while (linep < limit && isspace(*linep))
717cb5caa98Sdjl 		linep++;
718cb5caa98Sdjl 	/* compare with the aliases */
719cb5caa98Sdjl 	while (linep < limit) {
720cb5caa98Sdjl 		/*
721cb5caa98Sdjl 		 * 1st pass: skip number
722cb5caa98Sdjl 		 * Other passes: skip remainder of the alias name, if any
723cb5caa98Sdjl 		 */
724cb5caa98Sdjl 		while (linep < limit && !isspace(*linep))
725cb5caa98Sdjl 			linep++;
726cb5caa98Sdjl 		/* skip the delimiting spaces */
727cb5caa98Sdjl 		while (linep < limit && isspace(*linep))
728cb5caa98Sdjl 			linep++;
729cb5caa98Sdjl 		/* compare with the alias name */
730cb5caa98Sdjl 		keyp = argp->key.name;
731cb5caa98Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
732cb5caa98Sdjl 		    *keyp == *linep) {
733cb5caa98Sdjl 			keyp++;
734cb5caa98Sdjl 			linep++;
735cb5caa98Sdjl 		}
736cb5caa98Sdjl 		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
737cb5caa98Sdjl 			return (1);
738cb5caa98Sdjl 	}
739cb5caa98Sdjl 	return (0);
740cb5caa98Sdjl }
741