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
5*2830Sdjl  * Common Development and Distribution License (the "License").
6*2830Sdjl  * 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 /*
22*2830Sdjl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*2830Sdjl  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  *	nis/getservent.c -- "nis" backend for nsswitch "services" database
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include "nis_common.h"
310Sstevel@tonic-gate #include <stdio.h>
32*2830Sdjl #include <stdlib.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <signal.h>
350Sstevel@tonic-gate #include <malloc.h>
360Sstevel@tonic-gate #include <netdb.h>
370Sstevel@tonic-gate #include <synch.h>
38*2830Sdjl #include <ctype.h>
390Sstevel@tonic-gate #include <rpcsvc/ypclnt.h>
400Sstevel@tonic-gate #include <thread.h>
410Sstevel@tonic-gate #include <sys/types.h>
420Sstevel@tonic-gate #include <netinet/in.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate static int
450Sstevel@tonic-gate check_name(args)
460Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
470Sstevel@tonic-gate {
48*2830Sdjl 	struct servent		*serv	= (struct servent *)args->returnval;
490Sstevel@tonic-gate 	const char		*name	= args->key.serv.serv.name;
500Sstevel@tonic-gate 	const char		*proto	= args->key.serv.proto;
510Sstevel@tonic-gate 	char			**aliasp;
520Sstevel@tonic-gate 
530Sstevel@tonic-gate 	if (proto != 0 && strcmp(serv->s_proto, proto) != 0) {
540Sstevel@tonic-gate 		return (0);
550Sstevel@tonic-gate 	}
560Sstevel@tonic-gate 	if (strcmp(serv->s_name, name) == 0) {
570Sstevel@tonic-gate 		return (1);
580Sstevel@tonic-gate 	}
590Sstevel@tonic-gate 	for (aliasp = serv->s_aliases;  *aliasp != 0;  aliasp++) {
600Sstevel@tonic-gate 		if (strcmp(*aliasp, name) == 0) {
610Sstevel@tonic-gate 			return (1);
620Sstevel@tonic-gate 		}
630Sstevel@tonic-gate 	}
640Sstevel@tonic-gate 	return (0);
650Sstevel@tonic-gate }
660Sstevel@tonic-gate 
67*2830Sdjl static int
68*2830Sdjl check_name2(nss_XbyY_args_t *argp)
69*2830Sdjl {
70*2830Sdjl 	const char	*limit, *linep, *keyp;
71*2830Sdjl 	int		name_match = 0;
72*2830Sdjl 
73*2830Sdjl 	linep = (const char *)argp->buf.buffer;
74*2830Sdjl 	limit = linep + strlen(argp->buf.buffer);
75*2830Sdjl 	keyp = argp->key.serv.serv.name;
76*2830Sdjl 
77*2830Sdjl 	/* compare name */
78*2830Sdjl 	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
79*2830Sdjl 		keyp++;
80*2830Sdjl 		linep++;
81*2830Sdjl 	}
82*2830Sdjl 	if (*keyp == '\0' && linep < limit && isspace(*linep)) {
83*2830Sdjl 		if (argp->key.serv.proto == NULL)
84*2830Sdjl 			return (1);
85*2830Sdjl 		else
86*2830Sdjl 			name_match = 1;
87*2830Sdjl 	}
88*2830Sdjl 
89*2830Sdjl 	/* skip remainder of the name, if any */
90*2830Sdjl 	while (linep < limit && !isspace(*linep))
91*2830Sdjl 		linep++;
92*2830Sdjl 	/* skip the delimiting spaces */
93*2830Sdjl 	while (linep < limit && isspace(*linep))
94*2830Sdjl 		linep++;
95*2830Sdjl 	/* skip port number */
96*2830Sdjl 	while (linep < limit && !isspace(*linep) && *linep != '/')
97*2830Sdjl 		linep++;
98*2830Sdjl 	if (linep == limit || *linep != '/')
99*2830Sdjl 		return (0);
100*2830Sdjl 
101*2830Sdjl 	linep++;
102*2830Sdjl 	if ((keyp = argp->key.serv.proto) == NULL) {
103*2830Sdjl 		/* skip protocol */
104*2830Sdjl 		while (linep < limit && !isspace(*linep))
105*2830Sdjl 			linep++;
106*2830Sdjl 	} else {
107*2830Sdjl 		/* compare protocol */
108*2830Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
109*2830Sdjl 				*keyp == *linep) {
110*2830Sdjl 			keyp++;
111*2830Sdjl 			linep++;
112*2830Sdjl 		}
113*2830Sdjl 		/* no protocol match */
114*2830Sdjl 		if (*keyp || (linep < limit && !isspace(*linep)))
115*2830Sdjl 			return (0);
116*2830Sdjl 		/* protocol and name match, return */
117*2830Sdjl 		if (name_match)
118*2830Sdjl 			return (1);
119*2830Sdjl 		/* protocol match but name yet to be matched, so continue */
120*2830Sdjl 	}
121*2830Sdjl 
122*2830Sdjl 	/* compare with the aliases */
123*2830Sdjl 	while (linep < limit) {
124*2830Sdjl 		/* skip the delimiting spaces */
125*2830Sdjl 		while (linep < limit && isspace(*linep))
126*2830Sdjl 			linep++;
127*2830Sdjl 
128*2830Sdjl 		/* compare with the alias name */
129*2830Sdjl 		keyp = argp->key.serv.serv.name;
130*2830Sdjl 		while (*keyp && linep < limit && !isspace(*linep) &&
131*2830Sdjl 				*keyp == *linep) {
132*2830Sdjl 			keyp++;
133*2830Sdjl 			linep++;
134*2830Sdjl 		}
135*2830Sdjl 		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
136*2830Sdjl 				return (1);
137*2830Sdjl 
138*2830Sdjl 		/* skip remainder of the alias name, if any */
139*2830Sdjl 		while (linep < limit && !isspace(*linep))
140*2830Sdjl 			linep++;
141*2830Sdjl 	}
142*2830Sdjl 	return (0);
143*2830Sdjl }
144*2830Sdjl 
1450Sstevel@tonic-gate static mutex_t	no_byname_lock	= DEFAULTMUTEX;
1460Sstevel@tonic-gate static int	no_byname_map	= 0;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate static nss_status_t
1490Sstevel@tonic-gate getbyname(be, a)
1500Sstevel@tonic-gate 	nis_backend_ptr_t	be;
1510Sstevel@tonic-gate 	void			*a;
1520Sstevel@tonic-gate {
153*2830Sdjl 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
1540Sstevel@tonic-gate 	const char		*name	= argp->key.serv.serv.name;
1550Sstevel@tonic-gate 	const char		*proto	= argp->key.serv.proto;
1560Sstevel@tonic-gate 	int			no_map;
1570Sstevel@tonic-gate 	sigset_t		oldmask, newmask;
1580Sstevel@tonic-gate 
159*2830Sdjl 	(void) sigfillset(&newmask);
1600Sstevel@tonic-gate 	(void) _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
1610Sstevel@tonic-gate 	(void) _mutex_lock(&no_byname_lock);
1620Sstevel@tonic-gate 	no_map = no_byname_map;
1630Sstevel@tonic-gate 	(void) _mutex_unlock(&no_byname_lock);
1640Sstevel@tonic-gate 	(void) _thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if (no_map == 0) {
1670Sstevel@tonic-gate 		int		yp_status;
1680Sstevel@tonic-gate 		nss_status_t	res;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 		if (proto == 0) {
1710Sstevel@tonic-gate 			res = _nss_nis_lookup(be, argp, 1,
1720Sstevel@tonic-gate 			    "services.byservicename", name, &yp_status);
1730Sstevel@tonic-gate 		} else {
174*2830Sdjl 			int len = strlen(name) + strlen(proto) + 3;
175*2830Sdjl 			char *key = malloc(len);
1760Sstevel@tonic-gate 
177*2830Sdjl 			if (key == NULL) {
1780Sstevel@tonic-gate 				return (NSS_UNAVAIL);
1790Sstevel@tonic-gate 			}
180*2830Sdjl 			(void) snprintf(key, len, "%s/%s", name, proto);
1810Sstevel@tonic-gate 			res = _nss_nis_lookup(be, argp, 1,
1820Sstevel@tonic-gate 			    "services.byservicename", key, &yp_status);
1830Sstevel@tonic-gate 			free(key);
1840Sstevel@tonic-gate 		}
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 		if (yp_status == YPERR_MAP) {
187*2830Sdjl 			(void) sigfillset(&newmask);
1880Sstevel@tonic-gate 			_thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
1890Sstevel@tonic-gate 			_mutex_lock(&no_byname_lock);
1900Sstevel@tonic-gate 			no_byname_map = 1;
1910Sstevel@tonic-gate 			_mutex_unlock(&no_byname_lock);
192*2830Sdjl 			_thr_sigsetmask(SIG_SETMASK, &oldmask,
193*2830Sdjl 					(sigset_t *)NULL);
1940Sstevel@tonic-gate 		} else /* if (res == NSS_SUCCESS) <==== */ {
1950Sstevel@tonic-gate 			return (res);
1960Sstevel@tonic-gate 		}
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 
199*2830Sdjl 	/*
200*2830Sdjl 	 * use check_anme to compare service name if nss1 or nss2 and
201*2830Sdjl 	 * request is not from nscd; otherwise use check_name2
202*2830Sdjl 	 */
203*2830Sdjl 	if (argp->buf.result != NULL)
204*2830Sdjl 		return (_nss_nis_XY_all(be, argp, 1, name, check_name));
205*2830Sdjl 	else
206*2830Sdjl 		return (_nss_nis_XY_all(be, argp, 1, name, check_name2));
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate static int
2100Sstevel@tonic-gate check_port(args)
2110Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
2120Sstevel@tonic-gate {
213*2830Sdjl 	struct servent		*serv	= (struct servent *)args->returnval;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/*
2160Sstevel@tonic-gate 	 * We only resorted to _nss_nis_XY_all because proto == 0, so just...
2170Sstevel@tonic-gate 	 */
2180Sstevel@tonic-gate 	return (serv->s_port == args->key.serv.serv.port);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
221*2830Sdjl static int
222*2830Sdjl check_port2(nss_XbyY_args_t *argp)
223*2830Sdjl {
224*2830Sdjl 	const char	*limit, *linep, *keyp, *numstart;
225*2830Sdjl 	int		numlen, s_port;
226*2830Sdjl 	char		numbuf[12], *numend;
227*2830Sdjl 
228*2830Sdjl 	linep = (const char *)argp->buf.buffer;
229*2830Sdjl 	limit = linep + strlen(argp->buf.buffer);
230*2830Sdjl 
231*2830Sdjl 	/* skip name */
232*2830Sdjl 	while (linep < limit && !isspace(*linep))
233*2830Sdjl 		linep++;
234*2830Sdjl 	/* skip the delimiting spaces */
235*2830Sdjl 	while (linep < limit && isspace(*linep))
236*2830Sdjl 		linep++;
237*2830Sdjl 
238*2830Sdjl 	/* compare port num */
239*2830Sdjl 	numstart = linep;
240*2830Sdjl 	while (linep < limit && !isspace(*linep) && *linep != '/')
241*2830Sdjl 		linep++;
242*2830Sdjl 	if (linep == limit || *linep != '/')
243*2830Sdjl 		return (0);
244*2830Sdjl 	numlen = linep - numstart;
245*2830Sdjl 	if (numlen == 0 || numlen >= sizeof (numbuf))
246*2830Sdjl 		return (0);
247*2830Sdjl 	(void) memcpy(numbuf, numstart, numlen);
248*2830Sdjl 	numbuf[numlen] = '\0';
249*2830Sdjl 	s_port = htons((int)strtol(numbuf, &numend, 10));
250*2830Sdjl 	if (*numend != '\0')
251*2830Sdjl 		return (0);
252*2830Sdjl 	if (s_port == argp->key.serv.serv.port) {
253*2830Sdjl 		if ((keyp = argp->key.serv.proto) == NULL)
254*2830Sdjl 			return (1);
255*2830Sdjl 	} else
256*2830Sdjl 		return (0);
257*2830Sdjl 
258*2830Sdjl 	/* compare protocol */
259*2830Sdjl 	linep++;
260*2830Sdjl 	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
261*2830Sdjl 		keyp++;
262*2830Sdjl 		linep++;
263*2830Sdjl 	}
264*2830Sdjl 	return (*keyp == '\0' && (linep == limit || isspace(*linep)));
265*2830Sdjl }
266*2830Sdjl 
267*2830Sdjl 
2680Sstevel@tonic-gate static nss_status_t
2690Sstevel@tonic-gate getbyport(be, a)
2700Sstevel@tonic-gate 	nis_backend_ptr_t	be;
2710Sstevel@tonic-gate 	void			*a;
2720Sstevel@tonic-gate {
273*2830Sdjl 	nss_XbyY_args_t		*argp	= (nss_XbyY_args_t *)a;
2740Sstevel@tonic-gate 	int			port	= ntohs(argp->key.serv.serv.port);
2750Sstevel@tonic-gate 	const char		*proto	= argp->key.serv.proto;
2760Sstevel@tonic-gate 	char			*key;
2770Sstevel@tonic-gate 	nss_status_t		res;
278*2830Sdjl 	int			len;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	if (proto == 0) {
2810Sstevel@tonic-gate 		char		portstr[12];
2820Sstevel@tonic-gate 
283*2830Sdjl 		(void) snprintf(portstr, 12, "%d", port);
284*2830Sdjl 		/*
285*2830Sdjl 		 * use check_port to compare service port if nss1 or
286*2830Sdjl 		 * nss2 and request is not from nscd; otherwise use
287*2830Sdjl 		 * check_port2
288*2830Sdjl 		 */
289*2830Sdjl 		if (argp->buf.result != NULL)
290*2830Sdjl 			return (_nss_nis_XY_all(be, argp, 1, portstr,
291*2830Sdjl 				check_port));
292*2830Sdjl 		else
293*2830Sdjl 			return (_nss_nis_XY_all(be, argp, 1, portstr,
294*2830Sdjl 				check_port2));
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
297*2830Sdjl 	len = strlen(proto) + 14;
298*2830Sdjl 	if ((key = malloc(len)) == 0) {
2990Sstevel@tonic-gate 		return (NSS_UNAVAIL);
3000Sstevel@tonic-gate 	}
301*2830Sdjl 	(void) snprintf(key, len, "%d/%s", port, proto);
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	res = _nss_nis_lookup(be, argp, 1, "services.byname", key, 0);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	free(key);
3060Sstevel@tonic-gate 	return (res);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate static nis_backend_op_t serv_ops[] = {
3100Sstevel@tonic-gate 	_nss_nis_destr,
3110Sstevel@tonic-gate 	_nss_nis_endent,
3120Sstevel@tonic-gate 	_nss_nis_setent,
3130Sstevel@tonic-gate 	_nss_nis_getent_netdb,
3140Sstevel@tonic-gate 	getbyname,
3150Sstevel@tonic-gate 	getbyport
3160Sstevel@tonic-gate };
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate /*ARGSUSED*/
3190Sstevel@tonic-gate nss_backend_t *
3200Sstevel@tonic-gate _nss_nis_services_constr(dummy1, dummy2, dummy3)
3210Sstevel@tonic-gate 	const char	*dummy1, *dummy2, *dummy3;
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 	return (_nss_nis_constr(serv_ops,
3240Sstevel@tonic-gate 				sizeof (serv_ops) / sizeof (serv_ops[0]),
3250Sstevel@tonic-gate 				"services.byname"));
3260Sstevel@tonic-gate }
327