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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include "nis_common.h"
347c478bd9Sstevel@tonic-gate #include <stdio.h>
35cb5caa98Sdjl #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <signal.h>
387c478bd9Sstevel@tonic-gate #include <malloc.h>
397c478bd9Sstevel@tonic-gate #include <netdb.h>
407c478bd9Sstevel@tonic-gate #include <synch.h>
41cb5caa98Sdjl #include <ctype.h>
427c478bd9Sstevel@tonic-gate #include <rpcsvc/ypclnt.h>
437c478bd9Sstevel@tonic-gate #include <thread.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <netinet/in.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate static int
487c478bd9Sstevel@tonic-gate check_name(args)
497c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
507c478bd9Sstevel@tonic-gate {
51cb5caa98Sdjl 	struct servent		*serv	= (struct servent *)args->returnval;
527c478bd9Sstevel@tonic-gate 	const char		*name	= args->key.serv.serv.name;
537c478bd9Sstevel@tonic-gate 	const char		*proto	= args->key.serv.proto;
547c478bd9Sstevel@tonic-gate 	char			**aliasp;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	if (proto != 0 && strcmp(serv->s_proto, proto) != 0) {
577c478bd9Sstevel@tonic-gate 		return (0);
587c478bd9Sstevel@tonic-gate 	}
597c478bd9Sstevel@tonic-gate 	if (strcmp(serv->s_name, name) == 0) {
607c478bd9Sstevel@tonic-gate 		return (1);
617c478bd9Sstevel@tonic-gate 	}
627c478bd9Sstevel@tonic-gate 	for (aliasp = serv->s_aliases;  *aliasp != 0;  aliasp++) {
637c478bd9Sstevel@tonic-gate 		if (strcmp(*aliasp, name) == 0) {
647c478bd9Sstevel@tonic-gate 			return (1);
657c478bd9Sstevel@tonic-gate 		}
667c478bd9Sstevel@tonic-gate 	}
677c478bd9Sstevel@tonic-gate 	return (0);
687c478bd9Sstevel@tonic-gate }
697c478bd9Sstevel@tonic-gate 
70cb5caa98Sdjl static int
71cb5caa98Sdjl check_name2(nss_XbyY_args_t *argp)
72cb5caa98Sdjl {
73cb5caa98Sdjl 	const char	*limit, *linep, *keyp;
74cb5caa98Sdjl 	int		name_match = 0;
75cb5caa98Sdjl 
76cb5caa98Sdjl 	linep = (const char *)argp->buf.buffer;
77cb5caa98Sdjl 	limit = linep + strlen(argp->buf.buffer);
78cb5caa98Sdjl 	keyp = argp->key.serv.serv.name;
79cb5caa98Sdjl 
80cb5caa98Sdjl 	/* compare name */
81cb5caa98Sdjl 	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
82cb5caa98Sdjl 		keyp++;
83cb5caa98Sdjl 		linep++;
84cb5caa98Sdjl 	}
85cb5caa98Sdjl 	if (*keyp == '\0' && linep < limit && isspace(*linep)) {
86cb5caa98Sdjl 		if (argp->key.serv.proto == NULL)
87cb5caa98Sdjl 			return (1);
88cb5caa98Sdjl 		else
89cb5caa98Sdjl 			name_match = 1;
90cb5caa98Sdjl 	}
91cb5caa98Sdjl 
92cb5caa98Sdjl 	/* skip remainder of the name, if any */
93cb5caa98Sdjl 	while (linep < limit && !isspace(*linep))
94cb5caa98Sdjl 		linep++;
95cb5caa98Sdjl 	/* skip the delimiting spaces */
96cb5caa98Sdjl 	while (linep < limit && isspace(*linep))
97cb5caa98Sdjl 		linep++;
98cb5caa98Sdjl 	/* skip port number */
99cb5caa98Sdjl 	while (linep < limit && !isspace(*linep) && *linep != '/')
100cb5caa98Sdjl 		linep++;
101cb5caa98Sdjl 	if (linep == limit || *linep != '/')
102cb5caa98Sdjl 		return (0);
103cb5caa98Sdjl 
104cb5caa98Sdjl 	linep++;
105cb5caa98Sdjl 	if ((keyp = argp->key.serv.proto) == NULL) {
106cb5caa98Sdjl 		/* skip protocol */
107cb5caa98Sdjl 		while (linep < limit && !isspace(*linep))
108cb5caa98Sdjl 			linep++;
109cb5caa98Sdjl 	} else {
110cb5caa98Sdjl 		/* compare protocol */
111cb5caa98Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
112*7257d1b4Sraf 		    *keyp == *linep) {
113cb5caa98Sdjl 			keyp++;
114cb5caa98Sdjl 			linep++;
115cb5caa98Sdjl 		}
116cb5caa98Sdjl 		/* no protocol match */
117cb5caa98Sdjl 		if (*keyp || (linep < limit && !isspace(*linep)))
118cb5caa98Sdjl 			return (0);
119cb5caa98Sdjl 		/* protocol and name match, return */
120cb5caa98Sdjl 		if (name_match)
121cb5caa98Sdjl 			return (1);
122cb5caa98Sdjl 		/* protocol match but name yet to be matched, so continue */
123cb5caa98Sdjl 	}
124cb5caa98Sdjl 
125cb5caa98Sdjl 	/* compare with the aliases */
126cb5caa98Sdjl 	while (linep < limit) {
127cb5caa98Sdjl 		/* skip the delimiting spaces */
128cb5caa98Sdjl 		while (linep < limit && isspace(*linep))
129cb5caa98Sdjl 			linep++;
130cb5caa98Sdjl 
131cb5caa98Sdjl 		/* compare with the alias name */
132cb5caa98Sdjl 		keyp = argp->key.serv.serv.name;
133cb5caa98Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
134*7257d1b4Sraf 		    *keyp == *linep) {
135cb5caa98Sdjl 			keyp++;
136cb5caa98Sdjl 			linep++;
137cb5caa98Sdjl 		}
138cb5caa98Sdjl 		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
139cb5caa98Sdjl 				return (1);
140cb5caa98Sdjl 
141cb5caa98Sdjl 		/* skip remainder of the alias name, if any */
142cb5caa98Sdjl 		while (linep < limit && !isspace(*linep))
143cb5caa98Sdjl 			linep++;
144cb5caa98Sdjl 	}
145cb5caa98Sdjl 	return (0);
146cb5caa98Sdjl }
147cb5caa98Sdjl 
1487c478bd9Sstevel@tonic-gate static mutex_t	no_byname_lock	= DEFAULTMUTEX;
1497c478bd9Sstevel@tonic-gate static int	no_byname_map	= 0;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate static nss_status_t
1527c478bd9Sstevel@tonic-gate getbyname(be, a)
1537c478bd9Sstevel@tonic-gate 	nis_backend_ptr_t	be;
1547c478bd9Sstevel@tonic-gate 	void			*a;
1557c478bd9Sstevel@tonic-gate {
156cb5caa98Sdjl 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
1577c478bd9Sstevel@tonic-gate 	const char		*name	= argp->key.serv.serv.name;
1587c478bd9Sstevel@tonic-gate 	const char		*proto	= argp->key.serv.proto;
1597c478bd9Sstevel@tonic-gate 	int			no_map;
1607c478bd9Sstevel@tonic-gate 	sigset_t		oldmask, newmask;
1617c478bd9Sstevel@tonic-gate 
162cb5caa98Sdjl 	(void) sigfillset(&newmask);
163*7257d1b4Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
164*7257d1b4Sraf 	(void) mutex_lock(&no_byname_lock);
1657c478bd9Sstevel@tonic-gate 	no_map = no_byname_map;
166*7257d1b4Sraf 	(void) mutex_unlock(&no_byname_lock);
167*7257d1b4Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	if (no_map == 0) {
1707c478bd9Sstevel@tonic-gate 		int		yp_status;
1717c478bd9Sstevel@tonic-gate 		nss_status_t	res;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		if (proto == 0) {
1747c478bd9Sstevel@tonic-gate 			res = _nss_nis_lookup(be, argp, 1,
1757c478bd9Sstevel@tonic-gate 			    "services.byservicename", name, &yp_status);
1767c478bd9Sstevel@tonic-gate 		} else {
177cb5caa98Sdjl 			int len = strlen(name) + strlen(proto) + 3;
178cb5caa98Sdjl 			char *key = malloc(len);
1797c478bd9Sstevel@tonic-gate 
180cb5caa98Sdjl 			if (key == NULL) {
1817c478bd9Sstevel@tonic-gate 				return (NSS_UNAVAIL);
1827c478bd9Sstevel@tonic-gate 			}
183cb5caa98Sdjl 			(void) snprintf(key, len, "%s/%s", name, proto);
1847c478bd9Sstevel@tonic-gate 			res = _nss_nis_lookup(be, argp, 1,
1857c478bd9Sstevel@tonic-gate 			    "services.byservicename", key, &yp_status);
1867c478bd9Sstevel@tonic-gate 			free(key);
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 		if (yp_status == YPERR_MAP) {
190cb5caa98Sdjl 			(void) sigfillset(&newmask);
191*7257d1b4Sraf 			(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
192*7257d1b4Sraf 			(void) mutex_lock(&no_byname_lock);
1937c478bd9Sstevel@tonic-gate 			no_byname_map = 1;
194*7257d1b4Sraf 			(void) mutex_unlock(&no_byname_lock);
195*7257d1b4Sraf 			(void) thr_sigsetmask(SIG_SETMASK, &oldmask,
196cb5caa98Sdjl 					(sigset_t *)NULL);
1977c478bd9Sstevel@tonic-gate 		} else /* if (res == NSS_SUCCESS) <==== */ {
1987c478bd9Sstevel@tonic-gate 			return (res);
1997c478bd9Sstevel@tonic-gate 		}
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
202cb5caa98Sdjl 	/*
203cb5caa98Sdjl 	 * use check_anme to compare service name if nss1 or nss2 and
204cb5caa98Sdjl 	 * request is not from nscd; otherwise use check_name2
205cb5caa98Sdjl 	 */
206cb5caa98Sdjl 	if (argp->buf.result != NULL)
207cb5caa98Sdjl 		return (_nss_nis_XY_all(be, argp, 1, name, check_name));
208cb5caa98Sdjl 	else
209cb5caa98Sdjl 		return (_nss_nis_XY_all(be, argp, 1, name, check_name2));
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate static int
2137c478bd9Sstevel@tonic-gate check_port(args)
2147c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
2157c478bd9Sstevel@tonic-gate {
216cb5caa98Sdjl 	struct servent		*serv	= (struct servent *)args->returnval;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	/*
2197c478bd9Sstevel@tonic-gate 	 * We only resorted to _nss_nis_XY_all because proto == 0, so just...
2207c478bd9Sstevel@tonic-gate 	 */
2217c478bd9Sstevel@tonic-gate 	return (serv->s_port == args->key.serv.serv.port);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
224cb5caa98Sdjl static int
225cb5caa98Sdjl check_port2(nss_XbyY_args_t *argp)
226cb5caa98Sdjl {
227cb5caa98Sdjl 	const char	*limit, *linep, *keyp, *numstart;
228cb5caa98Sdjl 	int		numlen, s_port;
229cb5caa98Sdjl 	char		numbuf[12], *numend;
230cb5caa98Sdjl 
231cb5caa98Sdjl 	linep = (const char *)argp->buf.buffer;
232cb5caa98Sdjl 	limit = linep + strlen(argp->buf.buffer);
233cb5caa98Sdjl 
234cb5caa98Sdjl 	/* skip name */
235cb5caa98Sdjl 	while (linep < limit && !isspace(*linep))
236cb5caa98Sdjl 		linep++;
237cb5caa98Sdjl 	/* skip the delimiting spaces */
238cb5caa98Sdjl 	while (linep < limit && isspace(*linep))
239cb5caa98Sdjl 		linep++;
240cb5caa98Sdjl 
241cb5caa98Sdjl 	/* compare port num */
242cb5caa98Sdjl 	numstart = linep;
243cb5caa98Sdjl 	while (linep < limit && !isspace(*linep) && *linep != '/')
244cb5caa98Sdjl 		linep++;
245cb5caa98Sdjl 	if (linep == limit || *linep != '/')
246cb5caa98Sdjl 		return (0);
247cb5caa98Sdjl 	numlen = linep - numstart;
248cb5caa98Sdjl 	if (numlen == 0 || numlen >= sizeof (numbuf))
249cb5caa98Sdjl 		return (0);
250cb5caa98Sdjl 	(void) memcpy(numbuf, numstart, numlen);
251cb5caa98Sdjl 	numbuf[numlen] = '\0';
252cb5caa98Sdjl 	s_port = htons((int)strtol(numbuf, &numend, 10));
253cb5caa98Sdjl 	if (*numend != '\0')
254cb5caa98Sdjl 		return (0);
255cb5caa98Sdjl 	if (s_port == argp->key.serv.serv.port) {
256cb5caa98Sdjl 		if ((keyp = argp->key.serv.proto) == NULL)
257cb5caa98Sdjl 			return (1);
258cb5caa98Sdjl 	} else
259cb5caa98Sdjl 		return (0);
260cb5caa98Sdjl 
261cb5caa98Sdjl 	/* compare protocol */
262cb5caa98Sdjl 	linep++;
263cb5caa98Sdjl 	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
264cb5caa98Sdjl 		keyp++;
265cb5caa98Sdjl 		linep++;
266cb5caa98Sdjl 	}
267cb5caa98Sdjl 	return (*keyp == '\0' && (linep == limit || isspace(*linep)));
268cb5caa98Sdjl }
269cb5caa98Sdjl 
270cb5caa98Sdjl 
2717c478bd9Sstevel@tonic-gate static nss_status_t
2727c478bd9Sstevel@tonic-gate getbyport(be, a)
2737c478bd9Sstevel@tonic-gate 	nis_backend_ptr_t	be;
2747c478bd9Sstevel@tonic-gate 	void			*a;
2757c478bd9Sstevel@tonic-gate {
276cb5caa98Sdjl 	nss_XbyY_args_t		*argp	= (nss_XbyY_args_t *)a;
2777c478bd9Sstevel@tonic-gate 	int			port	= ntohs(argp->key.serv.serv.port);
2787c478bd9Sstevel@tonic-gate 	const char		*proto	= argp->key.serv.proto;
2797c478bd9Sstevel@tonic-gate 	char			*key;
2807c478bd9Sstevel@tonic-gate 	nss_status_t		res;
281cb5caa98Sdjl 	int			len;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if (proto == 0) {
2847c478bd9Sstevel@tonic-gate 		char		portstr[12];
2857c478bd9Sstevel@tonic-gate 
286cb5caa98Sdjl 		(void) snprintf(portstr, 12, "%d", port);
287cb5caa98Sdjl 		/*
288cb5caa98Sdjl 		 * use check_port to compare service port if nss1 or
289cb5caa98Sdjl 		 * nss2 and request is not from nscd; otherwise use
290cb5caa98Sdjl 		 * check_port2
291cb5caa98Sdjl 		 */
292cb5caa98Sdjl 		if (argp->buf.result != NULL)
293cb5caa98Sdjl 			return (_nss_nis_XY_all(be, argp, 1, portstr,
294cb5caa98Sdjl 				check_port));
295cb5caa98Sdjl 		else
296cb5caa98Sdjl 			return (_nss_nis_XY_all(be, argp, 1, portstr,
297cb5caa98Sdjl 				check_port2));
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
300cb5caa98Sdjl 	len = strlen(proto) + 14;
301cb5caa98Sdjl 	if ((key = malloc(len)) == 0) {
3027c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
3037c478bd9Sstevel@tonic-gate 	}
304cb5caa98Sdjl 	(void) snprintf(key, len, "%d/%s", port, proto);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	res = _nss_nis_lookup(be, argp, 1, "services.byname", key, 0);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	free(key);
3097c478bd9Sstevel@tonic-gate 	return (res);
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate static nis_backend_op_t serv_ops[] = {
3137c478bd9Sstevel@tonic-gate 	_nss_nis_destr,
3147c478bd9Sstevel@tonic-gate 	_nss_nis_endent,
3157c478bd9Sstevel@tonic-gate 	_nss_nis_setent,
3167c478bd9Sstevel@tonic-gate 	_nss_nis_getent_netdb,
3177c478bd9Sstevel@tonic-gate 	getbyname,
3187c478bd9Sstevel@tonic-gate 	getbyport
3197c478bd9Sstevel@tonic-gate };
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3227c478bd9Sstevel@tonic-gate nss_backend_t *
3237c478bd9Sstevel@tonic-gate _nss_nis_services_constr(dummy1, dummy2, dummy3)
3247c478bd9Sstevel@tonic-gate 	const char	*dummy1, *dummy2, *dummy3;
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	return (_nss_nis_constr(serv_ops,
3277c478bd9Sstevel@tonic-gate 				sizeof (serv_ops) / sizeof (serv_ops[0]),
3287c478bd9Sstevel@tonic-gate 				"services.byname"));
3297c478bd9Sstevel@tonic-gate }
330