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
5cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6cb5caa98Sdjl  * 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  */
21*7257d1b4Sraf 
227c478bd9Sstevel@tonic-gate /*
23*7257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24cb5caa98Sdjl  * Use is subject to license terms.
25*7257d1b4Sraf  */
26*7257d1b4Sraf 
27*7257d1b4Sraf /*
287c478bd9Sstevel@tonic-gate  *	nis/getservent.c -- "nis" backend for nsswitch "services" database
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include "nis_common.h"
327c478bd9Sstevel@tonic-gate #include <stdio.h>
33cb5caa98Sdjl #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <signal.h>
367c478bd9Sstevel@tonic-gate #include <malloc.h>
377c478bd9Sstevel@tonic-gate #include <netdb.h>
387c478bd9Sstevel@tonic-gate #include <synch.h>
39cb5caa98Sdjl #include <ctype.h>
407c478bd9Sstevel@tonic-gate #include <rpcsvc/ypclnt.h>
417c478bd9Sstevel@tonic-gate #include <thread.h>
427c478bd9Sstevel@tonic-gate #include <sys/types.h>
437c478bd9Sstevel@tonic-gate #include <netinet/in.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate static int
check_name(args)467c478bd9Sstevel@tonic-gate check_name(args)
477c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
487c478bd9Sstevel@tonic-gate {
49cb5caa98Sdjl 	struct servent		*serv	= (struct servent *)args->returnval;
507c478bd9Sstevel@tonic-gate 	const char		*name	= args->key.serv.serv.name;
517c478bd9Sstevel@tonic-gate 	const char		*proto	= args->key.serv.proto;
527c478bd9Sstevel@tonic-gate 	char			**aliasp;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 	if (proto != 0 && strcmp(serv->s_proto, proto) != 0) {
557c478bd9Sstevel@tonic-gate 		return (0);
567c478bd9Sstevel@tonic-gate 	}
577c478bd9Sstevel@tonic-gate 	if (strcmp(serv->s_name, name) == 0) {
587c478bd9Sstevel@tonic-gate 		return (1);
597c478bd9Sstevel@tonic-gate 	}
607c478bd9Sstevel@tonic-gate 	for (aliasp = serv->s_aliases;  *aliasp != 0;  aliasp++) {
617c478bd9Sstevel@tonic-gate 		if (strcmp(*aliasp, name) == 0) {
627c478bd9Sstevel@tonic-gate 			return (1);
637c478bd9Sstevel@tonic-gate 		}
647c478bd9Sstevel@tonic-gate 	}
657c478bd9Sstevel@tonic-gate 	return (0);
667c478bd9Sstevel@tonic-gate }
677c478bd9Sstevel@tonic-gate 
68cb5caa98Sdjl static int
check_name2(nss_XbyY_args_t * argp)69cb5caa98Sdjl check_name2(nss_XbyY_args_t *argp)
70cb5caa98Sdjl {
71cb5caa98Sdjl 	const char	*limit, *linep, *keyp;
72cb5caa98Sdjl 	int		name_match = 0;
73cb5caa98Sdjl 
74cb5caa98Sdjl 	linep = (const char *)argp->buf.buffer;
75cb5caa98Sdjl 	limit = linep + strlen(argp->buf.buffer);
76cb5caa98Sdjl 	keyp = argp->key.serv.serv.name;
77cb5caa98Sdjl 
78cb5caa98Sdjl 	/* compare name */
79cb5caa98Sdjl 	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
80cb5caa98Sdjl 		keyp++;
81cb5caa98Sdjl 		linep++;
82cb5caa98Sdjl 	}
83cb5caa98Sdjl 	if (*keyp == '\0' && linep < limit && isspace(*linep)) {
84cb5caa98Sdjl 		if (argp->key.serv.proto == NULL)
85cb5caa98Sdjl 			return (1);
86cb5caa98Sdjl 		else
87cb5caa98Sdjl 			name_match = 1;
88cb5caa98Sdjl 	}
89cb5caa98Sdjl 
90cb5caa98Sdjl 	/* skip remainder of the name, if any */
91cb5caa98Sdjl 	while (linep < limit && !isspace(*linep))
92cb5caa98Sdjl 		linep++;
93cb5caa98Sdjl 	/* skip the delimiting spaces */
94cb5caa98Sdjl 	while (linep < limit && isspace(*linep))
95cb5caa98Sdjl 		linep++;
96cb5caa98Sdjl 	/* skip port number */
97cb5caa98Sdjl 	while (linep < limit && !isspace(*linep) && *linep != '/')
98cb5caa98Sdjl 		linep++;
99cb5caa98Sdjl 	if (linep == limit || *linep != '/')
100cb5caa98Sdjl 		return (0);
101cb5caa98Sdjl 
102cb5caa98Sdjl 	linep++;
103cb5caa98Sdjl 	if ((keyp = argp->key.serv.proto) == NULL) {
104cb5caa98Sdjl 		/* skip protocol */
105cb5caa98Sdjl 		while (linep < limit && !isspace(*linep))
106cb5caa98Sdjl 			linep++;
107cb5caa98Sdjl 	} else {
108cb5caa98Sdjl 		/* compare protocol */
109cb5caa98Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
110*7257d1b4Sraf 		    *keyp == *linep) {
111cb5caa98Sdjl 			keyp++;
112cb5caa98Sdjl 			linep++;
113cb5caa98Sdjl 		}
114cb5caa98Sdjl 		/* no protocol match */
115cb5caa98Sdjl 		if (*keyp || (linep < limit && !isspace(*linep)))
116cb5caa98Sdjl 			return (0);
117cb5caa98Sdjl 		/* protocol and name match, return */
118cb5caa98Sdjl 		if (name_match)
119cb5caa98Sdjl 			return (1);
120cb5caa98Sdjl 		/* protocol match but name yet to be matched, so continue */
121cb5caa98Sdjl 	}
122cb5caa98Sdjl 
123cb5caa98Sdjl 	/* compare with the aliases */
124cb5caa98Sdjl 	while (linep < limit) {
125cb5caa98Sdjl 		/* skip the delimiting spaces */
126cb5caa98Sdjl 		while (linep < limit && isspace(*linep))
127cb5caa98Sdjl 			linep++;
128cb5caa98Sdjl 
129cb5caa98Sdjl 		/* compare with the alias name */
130cb5caa98Sdjl 		keyp = argp->key.serv.serv.name;
131cb5caa98Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
132*7257d1b4Sraf 		    *keyp == *linep) {
133cb5caa98Sdjl 			keyp++;
134cb5caa98Sdjl 			linep++;
135cb5caa98Sdjl 		}
136cb5caa98Sdjl 		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
137cb5caa98Sdjl 				return (1);
138cb5caa98Sdjl 
139cb5caa98Sdjl 		/* skip remainder of the alias name, if any */
140cb5caa98Sdjl 		while (linep < limit && !isspace(*linep))
141cb5caa98Sdjl 			linep++;
142cb5caa98Sdjl 	}
143cb5caa98Sdjl 	return (0);
144cb5caa98Sdjl }
145cb5caa98Sdjl 
1467c478bd9Sstevel@tonic-gate static mutex_t	no_byname_lock	= DEFAULTMUTEX;
1477c478bd9Sstevel@tonic-gate static int	no_byname_map	= 0;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static nss_status_t
getbyname(be,a)1507c478bd9Sstevel@tonic-gate getbyname(be, a)
1517c478bd9Sstevel@tonic-gate 	nis_backend_ptr_t	be;
1527c478bd9Sstevel@tonic-gate 	void			*a;
1537c478bd9Sstevel@tonic-gate {
154cb5caa98Sdjl 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
1557c478bd9Sstevel@tonic-gate 	const char		*name	= argp->key.serv.serv.name;
1567c478bd9Sstevel@tonic-gate 	const char		*proto	= argp->key.serv.proto;
1577c478bd9Sstevel@tonic-gate 	int			no_map;
1587c478bd9Sstevel@tonic-gate 	sigset_t		oldmask, newmask;
1597c478bd9Sstevel@tonic-gate 
160cb5caa98Sdjl 	(void) sigfillset(&newmask);
161*7257d1b4Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
162*7257d1b4Sraf 	(void) mutex_lock(&no_byname_lock);
1637c478bd9Sstevel@tonic-gate 	no_map = no_byname_map;
164*7257d1b4Sraf 	(void) mutex_unlock(&no_byname_lock);
165*7257d1b4Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if (no_map == 0) {
1687c478bd9Sstevel@tonic-gate 		int		yp_status;
1697c478bd9Sstevel@tonic-gate 		nss_status_t	res;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		if (proto == 0) {
1727c478bd9Sstevel@tonic-gate 			res = _nss_nis_lookup(be, argp, 1,
1737c478bd9Sstevel@tonic-gate 			    "services.byservicename", name, &yp_status);
1747c478bd9Sstevel@tonic-gate 		} else {
175cb5caa98Sdjl 			int len = strlen(name) + strlen(proto) + 3;
176cb5caa98Sdjl 			char *key = malloc(len);
1777c478bd9Sstevel@tonic-gate 
178cb5caa98Sdjl 			if (key == NULL) {
1797c478bd9Sstevel@tonic-gate 				return (NSS_UNAVAIL);
1807c478bd9Sstevel@tonic-gate 			}
181cb5caa98Sdjl 			(void) snprintf(key, len, "%s/%s", name, proto);
1827c478bd9Sstevel@tonic-gate 			res = _nss_nis_lookup(be, argp, 1,
1837c478bd9Sstevel@tonic-gate 			    "services.byservicename", key, &yp_status);
1847c478bd9Sstevel@tonic-gate 			free(key);
1857c478bd9Sstevel@tonic-gate 		}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 		if (yp_status == YPERR_MAP) {
188cb5caa98Sdjl 			(void) sigfillset(&newmask);
189*7257d1b4Sraf 			(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
190*7257d1b4Sraf 			(void) mutex_lock(&no_byname_lock);
1917c478bd9Sstevel@tonic-gate 			no_byname_map = 1;
192*7257d1b4Sraf 			(void) mutex_unlock(&no_byname_lock);
193*7257d1b4Sraf 			(void) thr_sigsetmask(SIG_SETMASK, &oldmask,
194cb5caa98Sdjl 					(sigset_t *)NULL);
1957c478bd9Sstevel@tonic-gate 		} else /* if (res == NSS_SUCCESS) <==== */ {
1967c478bd9Sstevel@tonic-gate 			return (res);
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
200cb5caa98Sdjl 	/*
201cb5caa98Sdjl 	 * use check_anme to compare service name if nss1 or nss2 and
202cb5caa98Sdjl 	 * request is not from nscd; otherwise use check_name2
203cb5caa98Sdjl 	 */
204cb5caa98Sdjl 	if (argp->buf.result != NULL)
205cb5caa98Sdjl 		return (_nss_nis_XY_all(be, argp, 1, name, check_name));
206cb5caa98Sdjl 	else
207cb5caa98Sdjl 		return (_nss_nis_XY_all(be, argp, 1, name, check_name2));
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static int
check_port(args)2117c478bd9Sstevel@tonic-gate check_port(args)
2127c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
2137c478bd9Sstevel@tonic-gate {
214cb5caa98Sdjl 	struct servent		*serv	= (struct servent *)args->returnval;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * We only resorted to _nss_nis_XY_all because proto == 0, so just...
2187c478bd9Sstevel@tonic-gate 	 */
2197c478bd9Sstevel@tonic-gate 	return (serv->s_port == args->key.serv.serv.port);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
222cb5caa98Sdjl static int
check_port2(nss_XbyY_args_t * argp)223cb5caa98Sdjl check_port2(nss_XbyY_args_t *argp)
224cb5caa98Sdjl {
225cb5caa98Sdjl 	const char	*limit, *linep, *keyp, *numstart;
226cb5caa98Sdjl 	int		numlen, s_port;
227cb5caa98Sdjl 	char		numbuf[12], *numend;
228cb5caa98Sdjl 
229cb5caa98Sdjl 	linep = (const char *)argp->buf.buffer;
230cb5caa98Sdjl 	limit = linep + strlen(argp->buf.buffer);
231cb5caa98Sdjl 
232cb5caa98Sdjl 	/* skip name */
233cb5caa98Sdjl 	while (linep < limit && !isspace(*linep))
234cb5caa98Sdjl 		linep++;
235cb5caa98Sdjl 	/* skip the delimiting spaces */
236cb5caa98Sdjl 	while (linep < limit && isspace(*linep))
237cb5caa98Sdjl 		linep++;
238cb5caa98Sdjl 
239cb5caa98Sdjl 	/* compare port num */
240cb5caa98Sdjl 	numstart = linep;
241cb5caa98Sdjl 	while (linep < limit && !isspace(*linep) && *linep != '/')
242cb5caa98Sdjl 		linep++;
243cb5caa98Sdjl 	if (linep == limit || *linep != '/')
244cb5caa98Sdjl 		return (0);
245cb5caa98Sdjl 	numlen = linep - numstart;
246cb5caa98Sdjl 	if (numlen == 0 || numlen >= sizeof (numbuf))
247cb5caa98Sdjl 		return (0);
248cb5caa98Sdjl 	(void) memcpy(numbuf, numstart, numlen);
249cb5caa98Sdjl 	numbuf[numlen] = '\0';
250cb5caa98Sdjl 	s_port = htons((int)strtol(numbuf, &numend, 10));
251cb5caa98Sdjl 	if (*numend != '\0')
252cb5caa98Sdjl 		return (0);
253cb5caa98Sdjl 	if (s_port == argp->key.serv.serv.port) {
254cb5caa98Sdjl 		if ((keyp = argp->key.serv.proto) == NULL)
255cb5caa98Sdjl 			return (1);
256cb5caa98Sdjl 	} else
257cb5caa98Sdjl 		return (0);
258cb5caa98Sdjl 
259cb5caa98Sdjl 	/* compare protocol */
260cb5caa98Sdjl 	linep++;
261cb5caa98Sdjl 	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
262cb5caa98Sdjl 		keyp++;
263cb5caa98Sdjl 		linep++;
264cb5caa98Sdjl 	}
265cb5caa98Sdjl 	return (*keyp == '\0' && (linep == limit || isspace(*linep)));
266cb5caa98Sdjl }
267cb5caa98Sdjl 
268cb5caa98Sdjl 
2697c478bd9Sstevel@tonic-gate static nss_status_t
getbyport(be,a)2707c478bd9Sstevel@tonic-gate getbyport(be, a)
2717c478bd9Sstevel@tonic-gate 	nis_backend_ptr_t	be;
2727c478bd9Sstevel@tonic-gate 	void			*a;
2737c478bd9Sstevel@tonic-gate {
274cb5caa98Sdjl 	nss_XbyY_args_t		*argp	= (nss_XbyY_args_t *)a;
2757c478bd9Sstevel@tonic-gate 	int			port	= ntohs(argp->key.serv.serv.port);
2767c478bd9Sstevel@tonic-gate 	const char		*proto	= argp->key.serv.proto;
2777c478bd9Sstevel@tonic-gate 	char			*key;
2787c478bd9Sstevel@tonic-gate 	nss_status_t		res;
279cb5caa98Sdjl 	int			len;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	if (proto == 0) {
2827c478bd9Sstevel@tonic-gate 		char		portstr[12];
2837c478bd9Sstevel@tonic-gate 
284cb5caa98Sdjl 		(void) snprintf(portstr, 12, "%d", port);
285cb5caa98Sdjl 		/*
286cb5caa98Sdjl 		 * use check_port to compare service port if nss1 or
287cb5caa98Sdjl 		 * nss2 and request is not from nscd; otherwise use
288cb5caa98Sdjl 		 * check_port2
289cb5caa98Sdjl 		 */
290cb5caa98Sdjl 		if (argp->buf.result != NULL)
291cb5caa98Sdjl 			return (_nss_nis_XY_all(be, argp, 1, portstr,
292cb5caa98Sdjl 				check_port));
293cb5caa98Sdjl 		else
294cb5caa98Sdjl 			return (_nss_nis_XY_all(be, argp, 1, portstr,
295cb5caa98Sdjl 				check_port2));
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
298cb5caa98Sdjl 	len = strlen(proto) + 14;
299cb5caa98Sdjl 	if ((key = malloc(len)) == 0) {
3007c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
3017c478bd9Sstevel@tonic-gate 	}
302cb5caa98Sdjl 	(void) snprintf(key, len, "%d/%s", port, proto);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	res = _nss_nis_lookup(be, argp, 1, "services.byname", key, 0);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	free(key);
3077c478bd9Sstevel@tonic-gate 	return (res);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate static nis_backend_op_t serv_ops[] = {
3117c478bd9Sstevel@tonic-gate 	_nss_nis_destr,
3127c478bd9Sstevel@tonic-gate 	_nss_nis_endent,
3137c478bd9Sstevel@tonic-gate 	_nss_nis_setent,
3147c478bd9Sstevel@tonic-gate 	_nss_nis_getent_netdb,
3157c478bd9Sstevel@tonic-gate 	getbyname,
3167c478bd9Sstevel@tonic-gate 	getbyport
3177c478bd9Sstevel@tonic-gate };
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3207c478bd9Sstevel@tonic-gate nss_backend_t *
_nss_nis_services_constr(dummy1,dummy2,dummy3)3217c478bd9Sstevel@tonic-gate _nss_nis_services_constr(dummy1, dummy2, dummy3)
3227c478bd9Sstevel@tonic-gate 	const char	*dummy1, *dummy2, *dummy3;
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	return (_nss_nis_constr(serv_ops,
3257c478bd9Sstevel@tonic-gate 				sizeof (serv_ops) / sizeof (serv_ops[0]),
3267c478bd9Sstevel@tonic-gate 				"services.byname"));
3277c478bd9Sstevel@tonic-gate }
328