getservent.c revision 2830:5228d1267a01
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 *
25 *	nis/getservent.c -- "nis" backend for nsswitch "services" database
26 */
27
28#pragma ident	"%Z%%M%	%I%	%E% SMI"
29
30#include "nis_common.h"
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <signal.h>
35#include <malloc.h>
36#include <netdb.h>
37#include <synch.h>
38#include <ctype.h>
39#include <rpcsvc/ypclnt.h>
40#include <thread.h>
41#include <sys/types.h>
42#include <netinet/in.h>
43
44static int
45check_name(args)
46	nss_XbyY_args_t		*args;
47{
48	struct servent		*serv	= (struct servent *)args->returnval;
49	const char		*name	= args->key.serv.serv.name;
50	const char		*proto	= args->key.serv.proto;
51	char			**aliasp;
52
53	if (proto != 0 && strcmp(serv->s_proto, proto) != 0) {
54		return (0);
55	}
56	if (strcmp(serv->s_name, name) == 0) {
57		return (1);
58	}
59	for (aliasp = serv->s_aliases;  *aliasp != 0;  aliasp++) {
60		if (strcmp(*aliasp, name) == 0) {
61			return (1);
62		}
63	}
64	return (0);
65}
66
67static int
68check_name2(nss_XbyY_args_t *argp)
69{
70	const char	*limit, *linep, *keyp;
71	int		name_match = 0;
72
73	linep = (const char *)argp->buf.buffer;
74	limit = linep + strlen(argp->buf.buffer);
75	keyp = argp->key.serv.serv.name;
76
77	/* compare name */
78	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
79		keyp++;
80		linep++;
81	}
82	if (*keyp == '\0' && linep < limit && isspace(*linep)) {
83		if (argp->key.serv.proto == NULL)
84			return (1);
85		else
86			name_match = 1;
87	}
88
89	/* skip remainder of the name, if any */
90	while (linep < limit && !isspace(*linep))
91		linep++;
92	/* skip the delimiting spaces */
93	while (linep < limit && isspace(*linep))
94		linep++;
95	/* skip port number */
96	while (linep < limit && !isspace(*linep) && *linep != '/')
97		linep++;
98	if (linep == limit || *linep != '/')
99		return (0);
100
101	linep++;
102	if ((keyp = argp->key.serv.proto) == NULL) {
103		/* skip protocol */
104		while (linep < limit && !isspace(*linep))
105			linep++;
106	} else {
107		/* compare protocol */
108		while (*keyp && linep < limit && !isspace(*linep) &&
109				*keyp == *linep) {
110			keyp++;
111			linep++;
112		}
113		/* no protocol match */
114		if (*keyp || (linep < limit && !isspace(*linep)))
115			return (0);
116		/* protocol and name match, return */
117		if (name_match)
118			return (1);
119		/* protocol match but name yet to be matched, so continue */
120	}
121
122	/* compare with the aliases */
123	while (linep < limit) {
124		/* skip the delimiting spaces */
125		while (linep < limit && isspace(*linep))
126			linep++;
127
128		/* compare with the alias name */
129		keyp = argp->key.serv.serv.name;
130		while (*keyp && linep < limit && !isspace(*linep) &&
131				*keyp == *linep) {
132			keyp++;
133			linep++;
134		}
135		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
136				return (1);
137
138		/* skip remainder of the alias name, if any */
139		while (linep < limit && !isspace(*linep))
140			linep++;
141	}
142	return (0);
143}
144
145static mutex_t	no_byname_lock	= DEFAULTMUTEX;
146static int	no_byname_map	= 0;
147
148static nss_status_t
149getbyname(be, a)
150	nis_backend_ptr_t	be;
151	void			*a;
152{
153	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
154	const char		*name	= argp->key.serv.serv.name;
155	const char		*proto	= argp->key.serv.proto;
156	int			no_map;
157	sigset_t		oldmask, newmask;
158
159	(void) sigfillset(&newmask);
160	(void) _thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
161	(void) _mutex_lock(&no_byname_lock);
162	no_map = no_byname_map;
163	(void) _mutex_unlock(&no_byname_lock);
164	(void) _thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
165
166	if (no_map == 0) {
167		int		yp_status;
168		nss_status_t	res;
169
170		if (proto == 0) {
171			res = _nss_nis_lookup(be, argp, 1,
172			    "services.byservicename", name, &yp_status);
173		} else {
174			int len = strlen(name) + strlen(proto) + 3;
175			char *key = malloc(len);
176
177			if (key == NULL) {
178				return (NSS_UNAVAIL);
179			}
180			(void) snprintf(key, len, "%s/%s", name, proto);
181			res = _nss_nis_lookup(be, argp, 1,
182			    "services.byservicename", key, &yp_status);
183			free(key);
184		}
185
186		if (yp_status == YPERR_MAP) {
187			(void) sigfillset(&newmask);
188			_thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
189			_mutex_lock(&no_byname_lock);
190			no_byname_map = 1;
191			_mutex_unlock(&no_byname_lock);
192			_thr_sigsetmask(SIG_SETMASK, &oldmask,
193					(sigset_t *)NULL);
194		} else /* if (res == NSS_SUCCESS) <==== */ {
195			return (res);
196		}
197	}
198
199	/*
200	 * use check_anme to compare service name if nss1 or nss2 and
201	 * request is not from nscd; otherwise use check_name2
202	 */
203	if (argp->buf.result != NULL)
204		return (_nss_nis_XY_all(be, argp, 1, name, check_name));
205	else
206		return (_nss_nis_XY_all(be, argp, 1, name, check_name2));
207}
208
209static int
210check_port(args)
211	nss_XbyY_args_t		*args;
212{
213	struct servent		*serv	= (struct servent *)args->returnval;
214
215	/*
216	 * We only resorted to _nss_nis_XY_all because proto == 0, so just...
217	 */
218	return (serv->s_port == args->key.serv.serv.port);
219}
220
221static int
222check_port2(nss_XbyY_args_t *argp)
223{
224	const char	*limit, *linep, *keyp, *numstart;
225	int		numlen, s_port;
226	char		numbuf[12], *numend;
227
228	linep = (const char *)argp->buf.buffer;
229	limit = linep + strlen(argp->buf.buffer);
230
231	/* skip name */
232	while (linep < limit && !isspace(*linep))
233		linep++;
234	/* skip the delimiting spaces */
235	while (linep < limit && isspace(*linep))
236		linep++;
237
238	/* compare port num */
239	numstart = linep;
240	while (linep < limit && !isspace(*linep) && *linep != '/')
241		linep++;
242	if (linep == limit || *linep != '/')
243		return (0);
244	numlen = linep - numstart;
245	if (numlen == 0 || numlen >= sizeof (numbuf))
246		return (0);
247	(void) memcpy(numbuf, numstart, numlen);
248	numbuf[numlen] = '\0';
249	s_port = htons((int)strtol(numbuf, &numend, 10));
250	if (*numend != '\0')
251		return (0);
252	if (s_port == argp->key.serv.serv.port) {
253		if ((keyp = argp->key.serv.proto) == NULL)
254			return (1);
255	} else
256		return (0);
257
258	/* compare protocol */
259	linep++;
260	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
261		keyp++;
262		linep++;
263	}
264	return (*keyp == '\0' && (linep == limit || isspace(*linep)));
265}
266
267
268static nss_status_t
269getbyport(be, a)
270	nis_backend_ptr_t	be;
271	void			*a;
272{
273	nss_XbyY_args_t		*argp	= (nss_XbyY_args_t *)a;
274	int			port	= ntohs(argp->key.serv.serv.port);
275	const char		*proto	= argp->key.serv.proto;
276	char			*key;
277	nss_status_t		res;
278	int			len;
279
280	if (proto == 0) {
281		char		portstr[12];
282
283		(void) snprintf(portstr, 12, "%d", port);
284		/*
285		 * use check_port to compare service port if nss1 or
286		 * nss2 and request is not from nscd; otherwise use
287		 * check_port2
288		 */
289		if (argp->buf.result != NULL)
290			return (_nss_nis_XY_all(be, argp, 1, portstr,
291				check_port));
292		else
293			return (_nss_nis_XY_all(be, argp, 1, portstr,
294				check_port2));
295	}
296
297	len = strlen(proto) + 14;
298	if ((key = malloc(len)) == 0) {
299		return (NSS_UNAVAIL);
300	}
301	(void) snprintf(key, len, "%d/%s", port, proto);
302
303	res = _nss_nis_lookup(be, argp, 1, "services.byname", key, 0);
304
305	free(key);
306	return (res);
307}
308
309static nis_backend_op_t serv_ops[] = {
310	_nss_nis_destr,
311	_nss_nis_endent,
312	_nss_nis_setent,
313	_nss_nis_getent_netdb,
314	getbyname,
315	getbyport
316};
317
318/*ARGSUSED*/
319nss_backend_t *
320_nss_nis_services_constr(dummy1, dummy2, dummy3)
321	const char	*dummy1, *dummy2, *dummy3;
322{
323	return (_nss_nis_constr(serv_ops,
324				sizeof (serv_ops) / sizeof (serv_ops[0]),
325				"services.byname"));
326}
327