xref: /titanic_51/usr/src/lib/nsswitch/ldap/common/getnetent.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
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 <netdb.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <sys/socket.h>
33 #include "ns_internal.h"
34 #include "ldap_common.h"
35 
36 /* networks attributes filters */
37 #define	_N_NAME		"cn"
38 #define	_N_NETWORK	"ipnetworknumber"
39 #define	_F_GETNETBYNAME	"(&(objectClass=ipNetwork)(cn=%s))"
40 #define	_F_GETNETBYNAME_SSD	"(&(%%s)(cn=%s))"
41 #define	_F_GETNETBYADDR	"(&(objectClass=ipNetwork)(ipNetworkNumber=%s))"
42 #define	_F_GETNETBYADDR_SSD	"(&(%%s)(ipNetworkNumber=%s))"
43 
44 static const char *networks_attrs[] = {
45 	_N_NAME,
46 	_N_NETWORK,
47 	(char *)NULL
48 };
49 
50 /*
51  * _nss_ldap_networks2ent is the data marshaling method for the networks
52  * getXbyY * (e.g., getbyname(), getbyaddr(), getnetent() backend processes.
53  * This method is called after a successful ldap search has been performed.
54  * This method will parse the ldap search values into struct netent =
55  * argp->buf.buffer which the frontend process expects. Three error conditions
56  * are expected and returned to nsswitch.
57  */
58 
59 static int
60 _nss_ldap_networks2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp)
61 {
62 	int		i, j;
63 	int		nss_result;
64 	int		buflen = (int)0;
65 	int		firstime = (int)1;
66 	unsigned long	len = 0L;
67 	char		**mp, *cname = NULL;
68 #ifdef DEBUG
69 	char		addrstr[16];
70 #endif /* DEBUG */
71 	char		*buffer = (char *)NULL;
72 	char		*ceiling = (char *)NULL;
73 	struct netent	*ntk = (struct netent *)NULL;
74 	ns_ldap_result_t	*result = be->result;
75 	ns_ldap_attr_t	*attrptr;
76 
77 	buffer = argp->buf.buffer;
78 	buflen = (size_t)argp->buf.buflen;
79 	if (!argp->buf.result) {
80 		nss_result = (int)NSS_STR_PARSE_ERANGE;
81 		goto result_net2ent;
82 	}
83 	ntk = (struct netent *)argp->buf.result;
84 	ceiling = buffer + buflen;
85 
86 	nss_result = (int)NSS_STR_PARSE_SUCCESS;
87 	(void) memset(argp->buf.buffer, 0, buflen);
88 
89 	attrptr = getattr(result, 0);
90 	if (attrptr == NULL) {
91 		nss_result = (int)NSS_STR_PARSE_PARSE;
92 		goto result_net2ent;
93 	}
94 
95 	for (i = 0; i < result->entry->attr_count; i++) {
96 		attrptr = getattr(result, i);
97 		if (attrptr == NULL) {
98 			nss_result = (int)NSS_STR_PARSE_PARSE;
99 			goto result_net2ent;
100 		}
101 		if (strcasecmp(attrptr->attrname, _N_NAME) == 0) {
102 			for (j = 0; j < attrptr->value_count; j++) {
103 				if (firstime) {
104 					/*
105 					 * The definition of the object class
106 					 * "ipNetwork" has a descripency between
107 					 * RFC 2307 and 2307bis.
108 					 * In 2307, "cn" is a MUST attribute.
109 					 * In 2307bis, "cn" is a MAY attribute.
110 					 * If "cn" is a MAY attribute,
111 					 * it does not  appear in RDN and can't
112 					 * be derived from RDN as a canonical
113 					 * "cn" name. In that case, use 1st
114 					 * "cn" value as the official name.
115 					 */
116 					cname = __s_api_get_canonical_name(
117 						result->entry, attrptr, 1);
118 					if (cname == NULL)
119 						/* 2307bis case */
120 						cname = attrptr->attrvalue[j];
121 
122 					if (cname == NULL ||
123 					    (len = strlen(cname)) < 1) {
124 						nss_result =
125 							NSS_STR_PARSE_PARSE;
126 						goto result_net2ent;
127 					}
128 					ntk->n_name = buffer;
129 					buffer += len + 1;
130 					if (buffer >= ceiling) {
131 						nss_result =
132 						    (int)NSS_STR_PARSE_ERANGE;
133 						goto result_net2ent;
134 					}
135 					(void) strcpy(ntk->n_name, cname);
136 					/* alias list */
137 					mp = ntk->n_aliases =
138 						(char **)ROUND_UP(buffer,
139 						sizeof (char **));
140 					buffer = (char *)ntk->n_aliases +
141 						sizeof (char *) *
142 						(attrptr->value_count + 1);
143 					buffer = (char *)ROUND_UP(buffer,
144 						sizeof (char **));
145 					if (buffer >= ceiling) {
146 						nss_result =
147 						    (int)NSS_STR_PARSE_ERANGE;
148 						goto result_net2ent;
149 					}
150 					firstime = (int)0;
151 				}
152 				/* alias list */
153 				if ((attrptr->attrvalue[j] == NULL) ||
154 				    (len = strlen(attrptr->attrvalue[j])) < 1) {
155 					nss_result = (int)NSS_STR_PARSE_PARSE;
156 					goto result_net2ent;
157 				}
158 				/* skip canonical name(official name) */
159 				if (strcmp(attrptr->attrvalue[j], cname) == 0)
160 					continue;
161 				*mp = buffer;
162 				buffer += len + 1;
163 				if (buffer >= ceiling) {
164 					nss_result = (int)NSS_STR_PARSE_ERANGE;
165 					goto result_net2ent;
166 				}
167 				(void) strcpy(*mp++, attrptr->attrvalue[j]);
168 				continue;
169 			}
170 		}
171 		if (strcasecmp(attrptr->attrname, _N_NETWORK) == 0) {
172 			if ((attrptr->attrvalue[0] == NULL) ||
173 			    (len = strlen(attrptr->attrvalue[0])) < 1) {
174 				nss_result = (int)NSS_STR_PARSE_PARSE;
175 				goto result_net2ent;
176 			}
177 			if ((ntk->n_net = (in_addr_t)
178 			    inet_network(attrptr->attrvalue[0])) ==
179 			    (in_addr_t)-1) {
180 				nss_result = (int)NSS_STR_PARSE_PARSE;
181 				goto result_net2ent;
182 			}
183 #ifdef DEBUG
184 			strlcpy(addrstr, attrptr->attrvalue[0],
185 						sizeof (addrstr));
186 #endif /* DEBUG */
187 			continue;
188 		}
189 	}
190 	ntk->n_addrtype = AF_INET;
191 
192 #ifdef DEBUG
193 	(void) fprintf(stdout, "\n[getnetent.c: _nss_ldap_networks2ent]\n");
194 	(void) fprintf(stdout, "        n_name: [%s]\n", ntk->n_name);
195 	if (mp != NULL) {
196 		for (mp = ntk->n_aliases; *mp != NULL; mp++)
197 			(void) fprintf(stdout, "     n_aliases: [%s]\n", *mp);
198 	}
199 	if (ntk->n_addrtype == AF_INET)
200 		(void) fprintf(stdout, "    n_addrtype: [AF_INET]\n");
201 	else
202 		(void) fprintf(stdout, "    n_addrtype: [%d]\n",
203 			    ntk->n_addrtype);
204 	(void) fprintf(stdout, "         n_net: [%s]\n", addrstr);
205 #endif /* DEBUG */
206 
207 result_net2ent:
208 
209 	(void) __ns_ldap_freeResult(&be->result);
210 	return ((int)nss_result);
211 }
212 
213 
214 /*
215  * Takes an unsigned integer in host order, and returns a printable
216  * string for it as a network number.  To allow for the possibility of
217  * naming subnets, only trailing dot-zeros are truncated.
218  */
219 
220 static int nettoa(int anet, char *buf, int buflen)
221 {
222 	int		addr;
223 	char		*p;
224 	struct in_addr	in;
225 
226 	if (buf == 0)
227 		return ((int)1);
228 
229 	in = inet_makeaddr(anet, INADDR_ANY);
230 	addr = in.s_addr;
231 	if (strlcpy(buf, inet_ntoa(in), buflen) >= buflen)
232 		return ((int)1);
233 	if ((IN_CLASSA_HOST & htonl(addr)) == 0) {
234 		p = strchr(buf, '.');
235 		if (p == NULL)
236 			return ((int)1);
237 		*p = 0;
238 	} else if ((IN_CLASSB_HOST & htonl(addr)) == 0) {
239 		p = strchr(buf, '.');
240 		if (p == NULL)
241 			return ((int)1);
242 		p = strchr(p + 1, '.');
243 		if (p == NULL)
244 			return ((int)1);
245 		*p = 0;
246 	} else if ((IN_CLASSC_HOST & htonl(addr)) == 0) {
247 		p = strrchr(buf, '.');
248 		if (p == NULL)
249 			return ((int)1);
250 		*p = 0;
251 	}
252 
253 	return ((int)0);
254 }
255 
256 
257 /*
258  * getbyname gets a network entry by name. This function constructs an
259  * ldap search filter using the network name invocation parameter and the
260  * getnetbyname search filter defined. Once the filter is constructed, we
261  * search for a matching entry and marshal the data results into struct
262  * netent for the frontend process. The function _nss_ldap_networks2ent
263  * performs the data marshaling.
264  */
265 
266 static nss_status_t
267 getbyname(ldap_backend_ptr be, void *a)
268 {
269 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
270 	char		searchfilter[SEARCHFILTERLEN];
271 	char		userdata[SEARCHFILTERLEN];
272 	char		netname[SEARCHFILTERLEN];
273 	int		ret;
274 
275 	if (_ldap_filter_name(netname, argp->key.name, sizeof (netname)) != 0)
276 		return ((nss_status_t)NSS_NOTFOUND);
277 
278 	ret = snprintf(searchfilter, sizeof (searchfilter),
279 	    _F_GETNETBYNAME, netname);
280 	if (ret >= sizeof (searchfilter) || ret < 0)
281 		return ((nss_status_t)NSS_NOTFOUND);
282 
283 	ret = snprintf(userdata, sizeof (userdata),
284 	    _F_GETNETBYNAME_SSD, netname);
285 	if (ret >= sizeof (userdata) || ret < 0)
286 		return ((nss_status_t)NSS_NOTFOUND);
287 
288 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
289 		_NETWORKS, searchfilter, NULL,
290 		_merge_SSD_filter, userdata));
291 }
292 
293 
294 /*
295  * getbyaddr gets a network entry by ip address. This function constructs an
296  * ldap search filter using the name invocation parameter and the getnetbyaddr
297  * search filter defined. Once the filter is constructed, we search for a
298  * matching entry and marshal the data results into struct netent for the
299  * frontend process. The function _nss_ldap_networks2ent performs the data
300  * marshaling.
301  */
302 
303 static nss_status_t
304 getbyaddr(ldap_backend_ptr be, void *a)
305 {
306 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
307 	char		addrstr[16];
308 	char		searchfilter[SEARCHFILTERLEN];
309 	char		userdata[SEARCHFILTERLEN];
310 	int		ret;
311 
312 	if (nettoa((int)argp->key.netaddr.net, addrstr, 16) != 0)
313 		return ((nss_status_t)NSS_UNAVAIL);
314 
315 	ret = snprintf(searchfilter, sizeof (searchfilter),
316 	    _F_GETNETBYADDR, addrstr);
317 	if (ret >= sizeof (searchfilter) || ret < 0)
318 		return ((nss_status_t)NSS_NOTFOUND);
319 
320 	ret = snprintf(userdata, sizeof (userdata),
321 	    _F_GETNETBYADDR_SSD, addrstr);
322 	if (ret >= sizeof (userdata) || ret < 0)
323 		return ((nss_status_t)NSS_NOTFOUND);
324 
325 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
326 		_NETWORKS, searchfilter, NULL,
327 		_merge_SSD_filter, userdata));
328 }
329 
330 static ldap_backend_op_t net_ops[] = {
331 	_nss_ldap_destr,
332 	_nss_ldap_endent,
333 	_nss_ldap_setent,
334 	_nss_ldap_getent,
335 	getbyname,
336 	getbyaddr
337 };
338 
339 
340 /*
341  * _nss_ldap_networks_constr is where life begins. This function calls the
342  * generic ldap constructor function to define and build the abstract data
343  * types required to support ldap operations.
344  */
345 
346 /*ARGSUSED0*/
347 nss_backend_t *
348 _nss_ldap_networks_constr(const char *dummy1, const char *dummy2,
349 			const char *dummy3)
350 {
351 
352 	return ((nss_backend_t *)_nss_ldap_constr(net_ops,
353 		sizeof (net_ops)/sizeof (net_ops[0]), _NETWORKS,
354 		networks_attrs, _nss_ldap_networks2ent));
355 }
356