getprotoent.c revision 2830:5228d1267a01
1235368Sgnn/*
2235368Sgnn * CDDL HEADER START
3235368Sgnn *
4235368Sgnn * The contents of this file are subject to the terms of the
5235368Sgnn * Common Development and Distribution License (the "License").
6235368Sgnn * You may not use this file except in compliance with the License.
7235368Sgnn *
8235368Sgnn * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9235368Sgnn * or http://www.opensolaris.org/os/licensing.
10235368Sgnn * See the License for the specific language governing permissions
11235368Sgnn * and limitations under the License.
12235368Sgnn *
13235368Sgnn * When distributing Covered Code, include this CDDL HEADER in each
14235368Sgnn * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15235368Sgnn * If applicable, add the following below this CDDL HEADER, with the
16235368Sgnn * fields enclosed by brackets "[]" replaced with your own identifying
17235368Sgnn * information: Portions Copyright [yyyy] [name of copyright owner]
18235368Sgnn *
19235368Sgnn * CDDL HEADER END
20235368Sgnn */
21235368Sgnn/*
22235368Sgnn * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23235368Sgnn * Use is subject to license terms.
24235368Sgnn */
25235368Sgnn
26235368Sgnn#pragma ident	"%Z%%M%	%I%	%E% SMI"
27235368Sgnn
28235368Sgnn#include <ctype.h>
29235368Sgnn#include <netdb.h>
30235368Sgnn#include "ns_internal.h"
31235368Sgnn#include "ldap_common.h"
32235368Sgnn
33235368Sgnn/* protocols attributes filters */
34235368Sgnn#define	_P_NAME			"cn"
35235368Sgnn#define	_P_PROTO		"ipprotocolnumber"
36235368Sgnn#define	_F_GETPROTOBYNAME	"(&(objectClass=ipProtocol)(cn=%s))"
37235368Sgnn#define	_F_GETPROTOBYNAME_SSD	"(&(%%s)(cn=%s))"
38235368Sgnn#define	_F_GETPROTOBYNUMBER	\
39235368Sgnn	"(&(objectClass=ipProtocol)(ipProtocolNumber=%d))"
40235368Sgnn#define	_F_GETPROTOBYNUMBER_SSD	\
41235368Sgnn	"(&(%%s)(ipProtocolNumber=%d))"
42235368Sgnn
43235368Sgnnstatic const char *protocols_attrs[] = {
44235368Sgnn	_P_NAME,
45235368Sgnn	_P_PROTO,
46235368Sgnn	(char *)NULL
47235368Sgnn};
48235368Sgnn
49235368Sgnntypedef struct protocol_alias {
50235368Sgnn	char	*protocol;
51235368Sgnn	char	*alias;
52235368Sgnn} protocol_alias_t;
53235368Sgnn
54235368Sgnnstatic const protocol_alias_t ip_aliases[10] = {
55235368Sgnn	{ "ip", "IP" },
56235368Sgnn	{ "ipip", "IP-IP" },
57235368Sgnn	{ "ipcomp", "IPComp" },
58235368Sgnn	{ "ipv6", "IPv6" },
59235368Sgnn	{ "ipv6-route", "IPv6-Route" },
60235368Sgnn	{ "ipv6-frag", "IPv6-Frag" },
61235368Sgnn	{ "ipv6-icmp", "IPv6-ICMP" },
62235368Sgnn	{ "ipv6-nonxt", "IPv6-NoNxt" },
63235368Sgnn	{ "ipv6-opts", "IPv6-Opts" },
64235368Sgnn	{ NULL, NULL }
65235368Sgnn};
66235368Sgnn
67235368Sgnn/*
68235368Sgnn * When the data is imported by ldapaddent, it does not save the aliase in the
69235368Sgnn * "cn" that is same as the canonical name but only different in case.
70235368Sgnn * e.g.
71235368Sgnn * icmp		1	ICMP
72235368Sgnn *
73235368Sgnn * is saved as
74235368Sgnn *
75235368Sgnn * dn: cn=icmp, ...
76235368Sgnn * ...
77235368Sgnn * cn: icmp
78235368Sgnn * ...
79235368Sgnn *
80235368Sgnn * So it needs to replicate the canonical name as an alias of upper case.
81235368Sgnn * But some protocol does have different aliases.
82235368Sgnn *
83235368Sgnn * e.g.
84235368Sgnn * dn: cn=ospf, ...
85235368Sgnn * ...
86235368Sgnn * cn: ospf
87235368Sgnn * cn: OSPFIGP
88235368Sgnn * ...
89235368Sgnn *
90235368Sgnn * For many ip* protocols, the aliases are mixed cased. Maybe it's case
91235368Sgnn * insensitive. But this fucntion tries to restore the aliases to the original
92235368Sgnn * form as much as possible. If the alias can't be found in the aliases table,
93235368Sgnn * it assumes the alias is all upper case.
94235368Sgnn *
95235368Sgnn */
96235368Sgnnstatic char *
97235368Sgnnget_alias(char *protocol) {
98235368Sgnn	int	i;
99235368Sgnn	char	*cp;
100235368Sgnn
101235368Sgnn	if (strncmp(protocol, "ip", 2) == 0) {
102235368Sgnn		for (i = 0; ip_aliases[i].protocol != NULL; i++) {
103235368Sgnn			if (strcmp(protocol, ip_aliases[i].protocol) == 0)
104235368Sgnn				return (ip_aliases[i].alias);
105235368Sgnn		}
106235368Sgnn		/*
107235368Sgnn		 * No aliase in the table. Return an all upper case aliase
108235368Sgnn		 */
109235368Sgnn		for (cp = protocol; *cp; cp++)
110235368Sgnn			*cp = toupper(*cp);
111235368Sgnn
112235368Sgnn		return (protocol);
113235368Sgnn	} else {
114235368Sgnn		/* Return an all upper case aliase */
115235368Sgnn		for (cp = protocol; *cp; cp++)
116235368Sgnn			*cp = toupper(*cp);
117235368Sgnn
118235368Sgnn		return (protocol);
119235368Sgnn	}
120235368Sgnn
121235368Sgnn}
122235368Sgnn/*
123235368Sgnn * _nss_ldap_protocols2str is the data marshaling method for the protocols
124235368Sgnn * getXbyY * (e.g., getbyname(), getbynumber(), getent()) backend processes.
125235368Sgnn * This method is called after a successful ldap search has been performed.
126235368Sgnn * This method will parse the ldap search values into a file format.
127235368Sgnn * e.g.
128235368Sgnn * idrp 45 IDRP
129235368Sgnn * or
130235368Sgnn * ospf 89 OSPFIGP
131235368Sgnn */
132235368Sgnn
133235368Sgnnstatic int
134235368Sgnn_nss_ldap_protocols2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
135235368Sgnn{
136235368Sgnn	uint_t		i;
137235368Sgnn	int		nss_result;
138235368Sgnn	int		buflen = 0, len;
139235368Sgnn	char		*cname = NULL;
140235368Sgnn	char		*buffer = NULL, **number, *alias;
141235368Sgnn	ns_ldap_result_t	*result = be->result;
142235368Sgnn	ns_ldap_attr_t	*names;
143235368Sgnn
144235368Sgnn	if (result == NULL)
145235368Sgnn		return (NSS_STR_PARSE_PARSE);
146235368Sgnn
147235368Sgnn	buflen = argp->buf.buflen;
148235368Sgnn	if (argp->buf.result != NULL) {
149235368Sgnn		if ((be->buffer = calloc(1, buflen)) == NULL) {
150235368Sgnn			nss_result = NSS_STR_PARSE_PARSE;
151235368Sgnn			goto result_pls2str;
152235368Sgnn		}
153235368Sgnn		buffer = be->buffer;
154235368Sgnn	} else
155235368Sgnn		buffer = argp->buf.buffer;
156235368Sgnn
157235368Sgnn	nss_result = NSS_STR_PARSE_SUCCESS;
158235368Sgnn	(void) memset(argp->buf.buffer, 0, buflen);
159235368Sgnn
160235368Sgnn	names = __ns_ldap_getAttrStruct(result->entry, _P_NAME);
161235368Sgnn	if (names == NULL || names->attrvalue == NULL) {
162235368Sgnn		nss_result = NSS_STR_PARSE_PARSE;
163235368Sgnn		goto result_pls2str;
164235368Sgnn	}
165235368Sgnn	/* Get the canonical name */
166235368Sgnn	cname = __s_api_get_canonical_name(result->entry, names, 1);
167235368Sgnn	if (cname == NULL || (len = strlen(cname)) < 1) {
168235368Sgnn		nss_result = NSS_STR_PARSE_PARSE;
169235368Sgnn		goto result_pls2str;
170235368Sgnn	}
171235368Sgnn	number = __ns_ldap_getAttr(result->entry, _P_PROTO);
172235368Sgnn	if (number == NULL || number[0] == NULL ||
173235368Sgnn			(len = strlen(number[0])) < 1) {
174235368Sgnn		nss_result = NSS_STR_PARSE_PARSE;
175235368Sgnn		goto result_pls2str;
176235368Sgnn	}
177235368Sgnn	len = snprintf(buffer, buflen,  "%s %s", cname, number[0]);
178235368Sgnn	TEST_AND_ADJUST(len, buffer, buflen, result_pls2str);
179235368Sgnn	/* Append aliases */
180235368Sgnn	if (names->value_count == 1) {
181235368Sgnn		/* create an aliase from protocol name */
182235368Sgnn		alias = get_alias(cname);
183235368Sgnn		len = snprintf(buffer, buflen,  " %s", alias);
184235368Sgnn		TEST_AND_ADJUST(len, buffer, buflen, result_pls2str);
185235368Sgnn
186235368Sgnn	} else {
187235368Sgnn		for (i = 0; i < names->value_count; i++) {
188235368Sgnn			if (names->attrvalue[i] == NULL) {
189235368Sgnn				nss_result = NSS_STR_PARSE_PARSE;
190235368Sgnn				goto result_pls2str;
191235368Sgnn			}
192235368Sgnn			/* Skip the canonical name */
193235368Sgnn			if (strcasecmp(names->attrvalue[i], cname) != 0) {
194235368Sgnn				len = snprintf(buffer, buflen,  " %s",
195235368Sgnn						names->attrvalue[i]);
196235368Sgnn				TEST_AND_ADJUST(len, buffer, buflen,
197235368Sgnn						result_pls2str);
198235368Sgnn			}
199235368Sgnn		}
200235368Sgnn	}
201235368Sgnn
202235368Sgnn	/* The front end marshaller doesn't need to copy trailing nulls */
203235368Sgnn	if (argp->buf.result != NULL)
204235368Sgnn		be->buflen = strlen(be->buffer);
205235368Sgnn
206235368Sgnnresult_pls2str:
207235368Sgnn
208235368Sgnn	(void) __ns_ldap_freeResult(&be->result);
209235368Sgnn	return ((int)nss_result);
210235368Sgnn}
211235368Sgnn
212235368Sgnn
213235368Sgnn/*
214235368Sgnn * getbyname gets struct protoent values by protocol name. This
215235368Sgnn * function constructs an ldap search filter using the protocol
216235368Sgnn * name invocation parameter and the getprotobyname search filter
217235368Sgnn * defined. Once the filter is constructed, we search for a matching
218235368Sgnn * entry and marshal the data results into *proto = (struct *
219235368Sgnn * protoent *)argp->buf.result. The function _nss_ldap_protocols2ent
220235368Sgnn * performs the data marshaling.
221235368Sgnn */
222235368Sgnn
223235368Sgnnstatic nss_status_t
224235368Sgnngetbyname(ldap_backend_ptr be, void *a)
225235368Sgnn{
226235368Sgnn	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
227235368Sgnn	char		searchfilter[SEARCHFILTERLEN];
228235368Sgnn	char		userdata[SEARCHFILTERLEN];
229235368Sgnn	char		name[SEARCHFILTERLEN];
230235368Sgnn	int		ret;
231235368Sgnn
232235368Sgnn	if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
233235368Sgnn		return ((nss_status_t)NSS_NOTFOUND);
234235368Sgnn
235235368Sgnn	ret = snprintf(searchfilter, sizeof (searchfilter),
236235368Sgnn	    _F_GETPROTOBYNAME, name);
237235368Sgnn	if (ret >= sizeof (searchfilter) || ret < 0)
238235368Sgnn		return ((nss_status_t)NSS_NOTFOUND);
239235368Sgnn
240235368Sgnn	ret = snprintf(userdata, sizeof (userdata),
241235368Sgnn	    _F_GETPROTOBYNAME_SSD, name);
242235368Sgnn	if (ret >= sizeof (userdata) || ret < 0)
243235368Sgnn		return ((nss_status_t)NSS_NOTFOUND);
244235368Sgnn
245235368Sgnn	return ((nss_status_t)_nss_ldap_lookup(be, argp,
246235368Sgnn		_PROTOCOLS, searchfilter, NULL,
247235368Sgnn		_merge_SSD_filter, userdata));
248235368Sgnn}
249235368Sgnn
250235368Sgnn
251235368Sgnn/*
252235368Sgnn * getbynumber gets struct protoent values by protocol number. This
253235368Sgnn * function constructs an ldap search filter using the protocol
254235368Sgnn * name invocation parameter and the getprotobynumber search filter
255235368Sgnn * defined. Once the filter is constructed, we search for a matching
256235368Sgnn * entry and marshal the data results into *proto = (struct *
257235368Sgnn * protoent *)argp->buf.result. The function _nss_ldap_protocols2ent
258235368Sgnn * performs the data marshaling.
259235368Sgnn */
260235368Sgnn
261235368Sgnnstatic nss_status_t
262235368Sgnngetbynumber(ldap_backend_ptr be, void *a)
263235368Sgnn{
264235368Sgnn	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
265235368Sgnn	char		searchfilter[SEARCHFILTERLEN];
266235368Sgnn	char		userdata[SEARCHFILTERLEN];
267235368Sgnn	int		ret;
268235368Sgnn
269235368Sgnn	ret = snprintf(searchfilter, sizeof (searchfilter),
270235368Sgnn	    _F_GETPROTOBYNUMBER, argp->key.number);
271235368Sgnn	if (ret >= sizeof (searchfilter) || ret < 0)
272235368Sgnn		return ((nss_status_t)NSS_NOTFOUND);
273235368Sgnn
274235368Sgnn	ret = snprintf(userdata, sizeof (userdata),
275235368Sgnn	    _F_GETPROTOBYNUMBER_SSD, argp->key.number);
276235368Sgnn	if (ret >= sizeof (userdata) || ret < 0)
277235368Sgnn		return ((nss_status_t)NSS_NOTFOUND);
278235368Sgnn
279235368Sgnn	return ((nss_status_t)_nss_ldap_lookup(be, argp,
280235368Sgnn		_PROTOCOLS, searchfilter, NULL,
281235368Sgnn		_merge_SSD_filter, userdata));
282235368Sgnn}
283235368Sgnn
284235368Sgnnstatic ldap_backend_op_t proto_ops[] = {
285235368Sgnn	_nss_ldap_destr,
286235368Sgnn	_nss_ldap_endent,
287235368Sgnn	_nss_ldap_setent,
288235368Sgnn	_nss_ldap_getent,
289235368Sgnn	getbyname,
290235368Sgnn	getbynumber
291235368Sgnn};
292235368Sgnn
293235368Sgnn
294235368Sgnn/*
295235368Sgnn * _nss_ldap_protocols_constr is where life begins. This function calls
296235368Sgnn * the generic ldap constructor function to define and build the abstract
297235368Sgnn * data types required to support ldap operations.
298235368Sgnn */
299235368Sgnn
300235368Sgnn/*ARGSUSED0*/
301235368Sgnnnss_backend_t *
302235368Sgnn_nss_ldap_protocols_constr(const char *dummy1, const char *dummy2,
303235368Sgnn			const char *dummy3)
304235368Sgnn{
305235368Sgnn
306235368Sgnn	return ((nss_backend_t *)_nss_ldap_constr(proto_ops,
307235368Sgnn		sizeof (proto_ops)/sizeof (proto_ops[0]), _PROTOCOLS,
308235368Sgnn		protocols_attrs, _nss_ldap_protocols2str));
309235368Sgnn}
310235368Sgnn