1158115Sume/*-
2158115Sume * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3158115Sume * All rights reserved.
4158115Sume *
5158115Sume * Redistribution and use in source and binary forms, with or without
6158115Sume * modification, are permitted provided that the following conditions
7158115Sume * are met:
8158115Sume * 1. Redistributions of source code must retain the above copyright
9158115Sume *    notice, this list of conditions and the following disclaimer.
10158115Sume * 2. Redistributions in binary form must reproduce the above copyright
11158115Sume *    notice, this list of conditions and the following disclaimer in the
12158115Sume *    documentation and/or other materials provided with the distribution.
13158115Sume *
14158115Sume * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15158115Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16158115Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17158115Sume * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18158115Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19158115Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20158115Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21158115Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22158115Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23158115Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24158115Sume * SUCH DAMAGE.
25158115Sume *
26158115Sume */
27158115Sume
28158115Sume#include <sys/cdefs.h>
29158115Sume__FBSDID("$FreeBSD$");
30158115Sume
31158115Sume#include <sys/param.h>
32194093Sdes
33158115Sume#include <assert.h>
34194093Sdes#include <netdb.h>
35158115Sume#include <nsswitch.h>
36194093Sdes#include <stdlib.h>
37158115Sume#include <string.h>
38194093Sdes
39158115Sume#include "../debug.h"
40158115Sume#include "services.h"
41158115Sume
42158115Sumestatic int services_marshal_func(struct servent *, char *, size_t *);
43158115Sumestatic int services_lookup_func(const char *, size_t, char **, size_t *);
44194087Sdesstatic void *services_mp_init_func(void);
45158115Sumestatic int services_mp_lookup_func(char **, size_t *, void *);
46158115Sumestatic void services_mp_destroy_func(void *);
47158115Sume
48158115Sumestatic int
49158115Sumeservices_marshal_func(struct servent *serv, char *buffer, size_t *buffer_size)
50158115Sume{
51158115Sume	struct servent	new_serv;
52158115Sume	size_t	desired_size;
53158115Sume	char	**alias;
54158115Sume	char	*p;
55158115Sume	size_t	size;
56158115Sume	size_t	aliases_size;
57158115Sume
58158115Sume	TRACE_IN(services_marshal_func);
59158115Sume	desired_size = ALIGNBYTES + sizeof(struct servent) + sizeof(char *);
60158115Sume	if (serv->s_name != NULL)
61158115Sume		desired_size += strlen(serv->s_name) + 1;
62158115Sume	if (serv->s_proto != NULL)
63158115Sume		desired_size += strlen(serv->s_proto) + 1;
64158115Sume
65158115Sume	aliases_size = 0;
66158115Sume	if (serv->s_aliases != NULL) {
67158115Sume		for (alias = serv->s_aliases; *alias; ++alias) {
68158115Sume			desired_size += strlen(*alias) + 1;
69158115Sume			++aliases_size;
70158115Sume		}
71158115Sume
72158115Sume		desired_size += ALIGNBYTES + sizeof(char *) *
73158115Sume		    (aliases_size + 1);
74158115Sume	}
75158115Sume
76158115Sume	if ((*buffer_size < desired_size) || (buffer == NULL)) {
77158115Sume		*buffer_size = desired_size;
78158115Sume		TRACE_OUT(services_marshal_func);
79158115Sume		return (NS_RETURN);
80158115Sume	}
81158115Sume
82158115Sume	memcpy(&new_serv, serv, sizeof(struct servent));
83158115Sume	memset(buffer, 0, desired_size);
84158115Sume
85158115Sume	*buffer_size = desired_size;
86158115Sume	p = buffer + sizeof(struct servent) + sizeof(char *);
87158115Sume	memcpy(buffer + sizeof(struct servent), &p, sizeof(char *));
88158115Sume	p = (char *)ALIGN(p);
89158115Sume
90158115Sume	if (new_serv.s_name != NULL) {
91158115Sume		size = strlen(new_serv.s_name);
92158115Sume		memcpy(p, new_serv.s_name, size);
93158115Sume		new_serv.s_name = p;
94158115Sume		p += size + 1;
95158115Sume	}
96158115Sume
97158115Sume	if (new_serv.s_proto != NULL) {
98158115Sume		size = strlen(new_serv.s_proto);
99158115Sume		memcpy(p, new_serv.s_proto, size);
100158115Sume		new_serv.s_proto = p;
101158115Sume		p += size + 1;
102158115Sume	}
103158115Sume
104158115Sume	if (new_serv.s_aliases != NULL) {
105158115Sume		p = (char *)ALIGN(p);
106158115Sume		memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size);
107158115Sume		new_serv.s_aliases = (char **)p;
108158115Sume		p += sizeof(char *) * (aliases_size + 1);
109158115Sume
110158115Sume		for (alias = new_serv.s_aliases; *alias; ++alias) {
111158115Sume			size = strlen(*alias);
112158115Sume			memcpy(p, *alias, size);
113158115Sume			*alias = p;
114158115Sume			p += size + 1;
115158115Sume		}
116158115Sume	}
117158115Sume
118158115Sume	memcpy(buffer, &new_serv, sizeof(struct servent));
119158115Sume	TRACE_OUT(services_marshal_func);
120158115Sume	return (NS_SUCCESS);
121158115Sume}
122158115Sume
123158115Sumestatic int
124158115Sumeservices_lookup_func(const char *key, size_t key_size, char **buffer,
125158115Sume	size_t *buffer_size)
126158115Sume{
127158115Sume	enum nss_lookup_type lookup_type;
128158115Sume	char	*name = NULL;
129158115Sume	char	*proto = NULL;
130158115Sume	size_t	size, size2;
131158115Sume	int	port;
132158115Sume
133158115Sume	struct servent *result;
134158115Sume
135158115Sume	TRACE_IN(services_lookup_func);
136158115Sume
137158115Sume	assert(buffer != NULL);
138158115Sume	assert(buffer_size != NULL);
139158115Sume
140158115Sume	if (key_size < sizeof(enum nss_lookup_type)) {
141158115Sume		TRACE_OUT(passwd_lookup_func);
142158115Sume		return (NS_UNAVAIL);
143158115Sume	}
144158115Sume	memcpy(&lookup_type, key, sizeof(enum nss_lookup_type));
145158115Sume
146158115Sume	switch (lookup_type) {
147158115Sume	case nss_lt_name:
148158310Sume		size = key_size - sizeof(enum nss_lookup_type);
149194104Sdes		name = calloc(1, size + 1);
150158115Sume		assert(name != NULL);
151158310Sume		memcpy(name, key + sizeof(enum nss_lookup_type), size);
152158115Sume
153158115Sume		size2 = strlen(name) + 1;
154158310Sume
155158310Sume		if (size2 < size)
156158310Sume			proto = name + size2;
157158310Sume		else
158158310Sume			proto = NULL;
159158115Sume		break;
160158115Sume	case nss_lt_id:
161158115Sume		if (key_size < sizeof(enum nss_lookup_type) +
162158115Sume			sizeof(int)) {
163158115Sume			TRACE_OUT(passwd_lookup_func);
164158115Sume			return (NS_UNAVAIL);
165158115Sume		}
166158115Sume
167158115Sume		memcpy(&port, key + sizeof(enum nss_lookup_type),
168158115Sume			sizeof(int));
169158115Sume
170158310Sume		size = key_size - sizeof(enum nss_lookup_type) - sizeof(int);
171158115Sume		if (size > 0) {
172194104Sdes			proto = calloc(1, size + 1);
173158115Sume			assert(proto != NULL);
174158115Sume			memcpy(proto, key + sizeof(enum nss_lookup_type) +
175158115Sume				sizeof(int), size);
176158115Sume		}
177158115Sume		break;
178158115Sume	default:
179158115Sume		TRACE_OUT(passwd_lookup_func);
180158115Sume		return (NS_UNAVAIL);
181158115Sume	}
182158115Sume
183158115Sume	switch (lookup_type) {
184158115Sume	case nss_lt_name:
185158115Sume		result = getservbyname(name, proto);
186158115Sume		free(name);
187158115Sume		break;
188158115Sume	case nss_lt_id:
189158115Sume		result = getservbyport(port, proto);
190158115Sume		free(proto);
191158115Sume		break;
192158115Sume	default:
193158115Sume		/* SHOULD NOT BE REACHED */
194158115Sume		break;
195158115Sume	}
196158115Sume
197158115Sume	if (result != NULL) {
198158115Sume		services_marshal_func(result, NULL, buffer_size);
199194104Sdes		*buffer = malloc(*buffer_size);
200158115Sume		assert(*buffer != NULL);
201158115Sume		services_marshal_func(result, *buffer, buffer_size);
202158115Sume	}
203158115Sume
204158115Sume	TRACE_OUT(services_lookup_func);
205158115Sume	return (result == NULL ? NS_NOTFOUND : NS_SUCCESS);
206158115Sume}
207158115Sume
208158115Sumestatic void *
209194087Sdesservices_mp_init_func(void)
210158115Sume{
211158115Sume	TRACE_IN(services_mp_init_func);
212158115Sume	setservent(0);
213158115Sume	TRACE_OUT(services_mp_init_func);
214158115Sume
215158115Sume	return (NULL);
216158115Sume}
217158115Sume
218158115Sumestatic int
219158115Sumeservices_mp_lookup_func(char **buffer, size_t *buffer_size, void *mdata)
220158115Sume{
221158115Sume	struct servent *result;
222158115Sume
223158115Sume	TRACE_IN(services_mp_lookup_func);
224158115Sume	result = getservent();
225158115Sume	if (result != NULL) {
226158115Sume		services_marshal_func(result, NULL, buffer_size);
227194104Sdes		*buffer = malloc(*buffer_size);
228158115Sume		assert(*buffer != NULL);
229158115Sume		services_marshal_func(result, *buffer, buffer_size);
230158115Sume	}
231158115Sume
232158115Sume	TRACE_OUT(services_mp_lookup_func);
233158115Sume	return (result == NULL ? NS_NOTFOUND : NS_SUCCESS);
234158115Sume}
235158115Sume
236158115Sumestatic void
237158115Sumeservices_mp_destroy_func(void *mdata)
238158115Sume{
239158115Sume	TRACE_IN(services_mp_destroy_func);
240158115Sume	TRACE_OUT(services_mp_destroy_func);
241158115Sume}
242158115Sume
243158115Sumestruct agent *
244194087Sdesinit_services_agent(void)
245158115Sume{
246158115Sume	struct common_agent	*retval;
247158115Sume	TRACE_IN(init_services_agent);
248158115Sume
249194104Sdes	retval = calloc(1, sizeof(*retval));
250158115Sume	assert(retval != NULL);
251158115Sume
252158115Sume	retval->parent.name = strdup("services");
253158115Sume	assert(retval->parent.name != NULL);
254158115Sume
255158115Sume	retval->parent.type = COMMON_AGENT;
256158115Sume	retval->lookup_func = services_lookup_func;
257158115Sume
258158115Sume	TRACE_OUT(init_services_agent);
259158115Sume	return ((struct agent *)retval);
260158115Sume}
261158115Sume
262158115Sumestruct agent *
263194087Sdesinit_services_mp_agent(void)
264158115Sume{
265158115Sume	struct multipart_agent	*retval;
266158115Sume
267158115Sume	TRACE_IN(init_services_mp_agent);
268194104Sdes	retval = calloc(1,
269194104Sdes		sizeof(*retval));
270158115Sume	assert(retval != NULL);
271158115Sume
272158115Sume	retval->parent.name = strdup("services");
273158115Sume	retval->parent.type = MULTIPART_AGENT;
274158115Sume	retval->mp_init_func = services_mp_init_func;
275158115Sume	retval->mp_lookup_func = services_mp_lookup_func;
276158115Sume	retval->mp_destroy_func = services_mp_destroy_func;
277158115Sume	assert(retval->parent.name != NULL);
278158115Sume
279158115Sume	TRACE_OUT(init_services_mp_agent);
280158115Sume	return ((struct agent *)retval);
281158115Sume}
282