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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <ctype.h>
30 #include <netdb.h>
31 #include "ns_internal.h"
32 #include "ldap_common.h"
33 
34 /* protocols attributes filters */
35 #define	_P_NAME			"cn"
36 #define	_P_PROTO		"ipprotocolnumber"
37 #define	_F_GETPROTOBYNAME	"(&(objectClass=ipProtocol)(cn=%s))"
38 #define	_F_GETPROTOBYNAME_SSD	"(&(%%s)(cn=%s))"
39 #define	_F_GETPROTOBYNUMBER	\
40 	"(&(objectClass=ipProtocol)(ipProtocolNumber=%d))"
41 #define	_F_GETPROTOBYNUMBER_SSD	\
42 	"(&(%%s)(ipProtocolNumber=%d))"
43 
44 static const char *protocols_attrs[] = {
45 	_P_NAME,
46 	_P_PROTO,
47 	(char *)NULL
48 };
49 
50 
51 /*
52  * _nss_ldap_protocols2ent is the data marshaling method for the protocols
53  * getXbyY * (e.g., getbyname(), getbynumber(), getent()) backend processes.
54  * This method is called after a successful ldap search has been performed.
55  * This method will parse the ldap search values into *proto = (struct
56  * protoent *)argp->buf.result which the frontend process expects. Three error
57  * conditions are expected and returned to nsswitch.
58  */
59 
60 static int
61 _nss_ldap_protocols2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp)
62 {
63 	int		i, j;
64 	int		nss_result;
65 	int		buflen = (int)0;
66 	int		firstime = (int)1;
67 	unsigned long	len = 0L;
68 	char		*cp, **mp, *cname = NULL;
69 	char		*buffer = (char *)NULL;
70 	char		*ceiling = (char *)NULL;
71 	struct protoent	*proto = (struct protoent *)NULL;
72 	ns_ldap_result_t	*result = be->result;
73 	ns_ldap_attr_t	*attrptr;
74 
75 	buffer = (char *)argp->buf.buffer;
76 	buflen = (size_t)argp->buf.buflen;
77 	if (!argp->buf.result) {
78 		nss_result = (int)NSS_STR_PARSE_ERANGE;
79 		goto result_pls2ent;
80 	}
81 	proto = (struct protoent *)argp->buf.result;
82 	ceiling = buffer + buflen;
83 
84 	nss_result = (int)NSS_STR_PARSE_SUCCESS;
85 	(void) memset(argp->buf.buffer, 0, buflen);
86 
87 	attrptr = getattr(result, 0);
88 	if (attrptr == NULL) {
89 		nss_result = (int)NSS_STR_PARSE_PARSE;
90 		goto result_pls2ent;
91 	}
92 	for (i = 0; i < result->entry->attr_count; i++) {
93 		attrptr = getattr(result, i);
94 		if (attrptr == NULL) {
95 			nss_result = (int)NSS_STR_PARSE_PARSE;
96 			goto result_pls2ent;
97 		}
98 		if (strcasecmp(attrptr->attrname, _P_NAME) == 0) {
99 			for (j = 0; j < attrptr->value_count; j++) {
100 				if (firstime) {
101 					/* protocol name */
102 					cname = __s_api_get_canonical_name(
103 						result->entry, attrptr, 1);
104 					if (cname == NULL ||
105 						(len = strlen(cname)) < 1) {
106 						nss_result =
107 							NSS_STR_PARSE_PARSE;
108 						goto result_pls2ent;
109 					}
110 					proto->p_name = buffer;
111 					buffer += len + 1;
112 					if (buffer >= ceiling) {
113 						nss_result =
114 						    (int)NSS_STR_PARSE_ERANGE;
115 						goto result_pls2ent;
116 					}
117 					(void) strcpy(proto->p_name, cname);
118 					mp = proto->p_aliases =
119 						(char **)ROUND_UP(buffer,
120 						sizeof (char **));
121 					buffer = (char *)proto->p_aliases +
122 						sizeof (char *) *
123 						(attrptr->value_count + 1);
124 					buffer = (char *)ROUND_UP(buffer,
125 						sizeof (char **));
126 					if (buffer >= ceiling) {
127 						nss_result =
128 						    (int)NSS_STR_PARSE_ERANGE;
129 						goto result_pls2ent;
130 					}
131 					firstime = (int)0;
132 				}
133 				/* alias list */
134 				if ((attrptr->attrvalue[j] == NULL) ||
135 				    (len = strlen(attrptr->attrvalue[j])) < 1) {
136 					nss_result = NSS_STR_PARSE_PARSE;
137 					goto result_pls2ent;
138 				}
139 				/*
140 				 * When the data is imported by ldapaddent,
141 				 * it does not save the aliase in the "cn"
142 				 * that is same as the canonical name but only
143 				 * differnt in case.
144 				 * e.g.
145 				 * icmp		1	ICMP
146 				 *
147 				 * is saved as
148 				 *
149 				 * dn: cn=icmp, ...
150 				 * ...
151 				 * cn: icmp
152 				 * ...
153 				 * So it needs to replicate the canonical name
154 				 * as an aliase of upper case.
155 				 *
156 				 * But in the case of
157 				 * ospf		89 OSPFIGP
158 				 * it creates a redundant aliase.
159 				 * e.g.
160 				 * dn: cn=icmp, ...
161 				 * ...
162 				 * cn: ospf
163 				 * cn: OSPFIGP
164 				 * ...
165 				 *
166 				 * getent services ospf
167 				 * ==> ospf	89 ospf OSPFIGP
168 				 *
169 				 * Some condition check is added to handle this
170 				 * scenario. Such check also works with
171 				 * following scenario.
172 				 * dn: cn=icmp, ...
173 				 * ...
174 				 * cn: icmp
175 				 * cn: ICMP
176 				 * ...
177 				 */
178 				if (strcmp(proto->p_name,
179 				    attrptr->attrvalue[j]) == 0) {
180 					if (attrptr->value_count > 1)
181 						/* Do not replicate */
182 						continue;
183 					for (cp = attrptr->attrvalue[j];
184 					    *cp; cp++)
185 						*cp = toupper(*cp);
186 				}
187 				*mp = buffer;
188 				buffer += len + 1;
189 				if (buffer >= ceiling) {
190 					nss_result = (int)NSS_STR_PARSE_ERANGE;
191 					goto result_pls2ent;
192 				}
193 				(void) strcpy(*mp++, attrptr->attrvalue[j]);
194 				continue;
195 			}
196 		}
197 		if (strcasecmp(attrptr->attrname, _P_PROTO) == 0) {
198 			if ((attrptr->attrvalue[0] == NULL) ||
199 			    (len = strlen(attrptr->attrvalue[0])) < 1) {
200 				nss_result = (int)NSS_STR_PARSE_PARSE;
201 				goto result_pls2ent;
202 			}
203 			errno = 0;
204 			proto->p_proto = (int)strtol(attrptr->attrvalue[0],
205 					    (char **)NULL, 10);
206 			if (errno != 0) {
207 				nss_result = (int)NSS_STR_PARSE_PARSE;
208 				goto result_pls2ent;
209 			}
210 			continue;
211 		}
212 	}
213 
214 #ifdef DEBUG
215 	(void) fprintf(stdout, "\n[getprotoent.c: _nss_ldap_protocols2ent]\n");
216 	(void) fprintf(stdout, "        p_name: [%s]\n", proto->p_name);
217 	if (mp != NULL) {
218 		for (mp = proto->p_aliases; *mp != NULL; mp++)
219 			(void) fprintf(stdout, "     p_aliases: [%s]\n", *mp);
220 	}
221 	(void) fprintf(stdout, "       p_proto: [%d]\n", proto->p_proto);
222 #endif /* DEBUG */
223 
224 result_pls2ent:
225 
226 	(void) __ns_ldap_freeResult(&be->result);
227 	return ((int)nss_result);
228 }
229 
230 
231 /*
232  * getbyname gets struct protoent values by protocol name. This
233  * function constructs an ldap search filter using the protocol
234  * name invocation parameter and the getprotobyname search filter
235  * defined. Once the filter is constructed, we search for a matching
236  * entry and marshal the data results into *proto = (struct *
237  * protoent *)argp->buf.result. The function _nss_ldap_protocols2ent
238  * performs the data marshaling.
239  */
240 
241 static nss_status_t
242 getbyname(ldap_backend_ptr be, void *a)
243 {
244 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
245 	char		searchfilter[SEARCHFILTERLEN];
246 	char		userdata[SEARCHFILTERLEN];
247 	char		name[SEARCHFILTERLEN];
248 	int		ret;
249 
250 	if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
251 		return ((nss_status_t)NSS_NOTFOUND);
252 
253 	ret = snprintf(searchfilter, sizeof (searchfilter),
254 	    _F_GETPROTOBYNAME, name);
255 	if (ret >= sizeof (searchfilter) || ret < 0)
256 		return ((nss_status_t)NSS_NOTFOUND);
257 
258 	ret = snprintf(userdata, sizeof (userdata),
259 	    _F_GETPROTOBYNAME_SSD, name);
260 	if (ret >= sizeof (userdata) || ret < 0)
261 		return ((nss_status_t)NSS_NOTFOUND);
262 
263 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
264 		_PROTOCOLS, searchfilter, NULL,
265 		_merge_SSD_filter, userdata));
266 }
267 
268 
269 /*
270  * getbynumber gets struct protoent values by protocol number. This
271  * function constructs an ldap search filter using the protocol
272  * name invocation parameter and the getprotobynumber search filter
273  * defined. Once the filter is constructed, we search for a matching
274  * entry and marshal the data results into *proto = (struct *
275  * protoent *)argp->buf.result. The function _nss_ldap_protocols2ent
276  * performs the data marshaling.
277  */
278 
279 static nss_status_t
280 getbynumber(ldap_backend_ptr be, void *a)
281 {
282 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
283 	char		searchfilter[SEARCHFILTERLEN];
284 	char		userdata[SEARCHFILTERLEN];
285 	int		ret;
286 
287 	ret = snprintf(searchfilter, sizeof (searchfilter),
288 	    _F_GETPROTOBYNUMBER, argp->key.number);
289 	if (ret >= sizeof (searchfilter) || ret < 0)
290 		return ((nss_status_t)NSS_NOTFOUND);
291 
292 	ret = snprintf(userdata, sizeof (userdata),
293 	    _F_GETPROTOBYNUMBER_SSD, argp->key.number);
294 	if (ret >= sizeof (userdata) || ret < 0)
295 		return ((nss_status_t)NSS_NOTFOUND);
296 
297 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
298 		_PROTOCOLS, searchfilter, NULL,
299 		_merge_SSD_filter, userdata));
300 }
301 
302 static ldap_backend_op_t proto_ops[] = {
303 	_nss_ldap_destr,
304 	_nss_ldap_endent,
305 	_nss_ldap_setent,
306 	_nss_ldap_getent,
307 	getbyname,
308 	getbynumber
309 };
310 
311 
312 /*
313  * _nss_ldap_protocols_constr is where life begins. This function calls
314  * the generic ldap constructor function to define and build the abstract
315  * data types required to support ldap operations.
316  */
317 
318 /*ARGSUSED0*/
319 nss_backend_t *
320 _nss_ldap_protocols_constr(const char *dummy1, const char *dummy2,
321 			const char *dummy3)
322 {
323 
324 	return ((nss_backend_t *)_nss_ldap_constr(proto_ops,
325 		sizeof (proto_ops)/sizeof (proto_ops[0]), _PROTOCOLS,
326 		protocols_attrs, _nss_ldap_protocols2ent));
327 }
328