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 * files/getservent.c -- "files" backend for nsswitch "services" database
26 */
27
28#pragma ident	"%Z%%M%	%I%	%E% SMI"
29
30#include <netdb.h>
31#include "files_common.h"
32#include <sys/types.h>
33#include <netinet/in.h>
34#include <inttypes.h>
35#include <strings.h>
36#include <ctype.h>
37#include <stdlib.h>
38
39static int
40check_name(nss_XbyY_args_t *argp, const char *line, int linelen)
41{
42	const char	*limit, *linep, *keyp;
43	int		name_match = 0;
44
45	linep = line;
46	limit = line + linelen;
47	keyp = argp->key.serv.serv.name;
48
49	/* compare name */
50	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
51		keyp++;
52		linep++;
53	}
54	if (*keyp == '\0' && linep < limit && isspace(*linep)) {
55		if (argp->key.serv.proto == NULL)
56			return (1);
57		else
58			name_match = 1;
59	}
60
61	/* skip remainder of the name, if any */
62	while (linep < limit && !isspace(*linep))
63		linep++;
64	/* skip the delimiting spaces */
65	while (linep < limit && isspace(*linep))
66		linep++;
67	/* skip port number */
68	while (linep < limit && !isspace(*linep) && *linep != '/')
69		linep++;
70	if (linep == limit || *linep != '/')
71		return (0);
72
73	linep++;
74	if ((keyp = argp->key.serv.proto) == NULL) {
75		/* skip protocol */
76		while (linep < limit && !isspace(*linep))
77			linep++;
78	} else {
79		/* compare protocol */
80		while (*keyp && linep < limit && !isspace(*linep) &&
81				*keyp == *linep) {
82			keyp++;
83			linep++;
84		}
85		/* no protocol match */
86		if (*keyp || (linep < limit && !isspace(*linep)))
87			return (0);
88		/* protocol and name match, return */
89		if (name_match)
90			return (1);
91		/* protocol match but name yet to be matched, so continue */
92	}
93
94	/* compare with the aliases */
95	while (linep < limit) {
96		/* skip the delimiting spaces */
97		while (linep < limit && isspace(*linep))
98			linep++;
99
100		/* compare with the alias name */
101		keyp = argp->key.serv.serv.name;
102		while (*keyp && linep < limit && !isspace(*linep) &&
103				*keyp == *linep) {
104			keyp++;
105			linep++;
106		}
107		if (*keyp == '\0' && (linep == limit || isspace(*linep)))
108				return (1);
109
110		/* skip remainder of the alias name, if any */
111		while (linep < limit && !isspace(*linep))
112			linep++;
113	}
114	return (0);
115}
116
117static nss_status_t
118getbyname(be, a)
119	files_backend_ptr_t	be;
120	void			*a;
121{
122	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
123
124	return (_nss_files_XY_all(be, argp, 1,
125				argp->key.serv.serv.name, check_name));
126}
127
128static int
129check_port(nss_XbyY_args_t *argp, const char *line, int linelen)
130{
131	const char	*limit, *linep, *keyp, *numstart;
132	int		numlen, s_port;
133	char		numbuf[12], *numend;
134
135	linep = line;
136	limit = line + linelen;
137
138	/* skip name */
139	while (linep < limit && !isspace(*linep))
140		linep++;
141	/* skip the delimiting spaces */
142	while (linep < limit && isspace(*linep))
143		linep++;
144
145	/* compare port num */
146	numstart = linep;
147	while (linep < limit && !isspace(*linep) && *linep != '/')
148		linep++;
149	if (linep == limit || *linep != '/')
150		return (0);
151	numlen = linep - numstart;
152	if (numlen == 0 || numlen >= sizeof (numbuf))
153		return (0);
154	(void) memcpy(numbuf, numstart, numlen);
155	numbuf[numlen] = '\0';
156	s_port = htons((int)strtol(numbuf, &numend, 10));
157	if (*numend != '\0')
158		return (0);
159	if (s_port == argp->key.serv.serv.port) {
160		if ((keyp = argp->key.serv.proto) == NULL)
161			return (1);
162	} else
163		return (0);
164
165	/* compare protocol */
166	linep++;
167	while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
168		keyp++;
169		linep++;
170	}
171	return (*keyp == '\0' && (linep == limit || isspace(*linep)));
172}
173
174static nss_status_t
175getbyport(be, a)
176	files_backend_ptr_t	be;
177	void			*a;
178{
179	nss_XbyY_args_t		*argp	= (nss_XbyY_args_t *)a;
180	char			portstr[12];
181
182	(void) snprintf(portstr, 12, "%d", ntohs(argp->key.serv.serv.port));
183	return (_nss_files_XY_all(be, argp, 1, portstr, check_port));
184}
185
186static files_backend_op_t serv_ops[] = {
187	_nss_files_destr,
188	_nss_files_endent,
189	_nss_files_setent,
190	_nss_files_getent_netdb,
191	getbyname,
192	getbyport
193};
194
195/*ARGSUSED*/
196nss_backend_t *
197_nss_files_services_constr(dummy1, dummy2, dummy3)
198	const char	*dummy1, *dummy2, *dummy3;
199{
200	return (_nss_files_constr(serv_ops,
201				sizeof (serv_ops) / sizeof (serv_ops[0]),
202				_PATH_SERVICES,
203				NSS_LINELEN_SERVICES,
204				NULL));
205}
206