xref: /titanic_52/usr/src/lib/nsswitch/ldap/common/getether.c (revision 9512fe850e98fdd448c638ca63fdd92a8a510255)
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 <sys/types.h>
30 #include <sys/socket.h>
31 #include <net/if.h>
32 #include <netinet/in.h>
33 #include <net/if_arp.h>
34 #include <netinet/if_ether.h>
35 #include "ldap_common.h"
36 
37 /* ether attributes filters */
38 #define	_E_HOSTNAME		"cn"
39 #define	_E_MACADDRESS		"macaddress"
40 #define	_F_GETETHERBYHOST	"(&(objectClass=ieee802Device)(cn=%s))"
41 #define	_F_GETETHERBYHOST_SSD	"(&(%%s)(cn=%s))"
42 #define	_F_GETETHERBYETHER	"(&(objectClass=ieee802Device)(macAddress=%s))"
43 #define	_F_GETETHERBYETHER_SSD	"(&(%%s)(macAddress=%s))"
44 
45 static const char *ethers_attrs[] = {
46 	_E_HOSTNAME,
47 	_E_MACADDRESS,
48 	(char *)NULL
49 };
50 
51 
52 /*
53  * _nss_ldap_ethers2ent is the data marshaling method for the ethers
54  * getXbyY * (e.g., getbyhost(), getbyether()) backend processes. This
55  * method is called after a successful ldap search has been performed.
56  * This method will parse the ldap search values into uchar_t *ether
57  * = argp->buf.buffer which the frontend process expects. Three error
58  * conditions are expected and returned to nsswitch.
59  *
60  * Place the resulting struct ether_addr from the ldap query into
61  * argp->buf.result only if argp->buf.result is initialized (not NULL).
62  * e.g., it happens for the call ether_hostton.
63  *
64  * Place the resulting hostname into argp->buf.buffer only if
65  * argp->buf.buffer is initialized. I.e. it happens for the call
66  * ether_ntohost.
67  *
68  * argp->buf.buflen does not make sense for ethers. It is always set
69  * to 0 by the frontend. The caller only passes a hostname pointer in
70  * case of ether_ntohost, that is assumed to be big enough. For
71  * ether_hostton, the struct ether_addr passed is a fixed size.
72  *
73  * The interface does not let the caller specify how long is the buffer
74  * pointed by host. We make a safe assumption that the callers will
75  * always give MAXHOSTNAMELEN. In any case, it is the only finite number
76  * we can lay our hands on in case of runaway strings, memory corruption etc.
77  */
78 
79 static int
80 _nss_ldap_ethers2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp)
81 {
82 	int			i, ip;
83 	int			nss_result;
84 	int			buflen = (int)0;
85 	unsigned int		t[ETHERADDRL];
86 	unsigned long		len = 0L;
87 	char			*host = NULL;
88 	struct ether_addr	*ether = NULL;
89 	ns_ldap_result_t	*result = be->result;
90 	ns_ldap_attr_t	*attrptr;
91 	int etherflag = 0, hostflag = 0;
92 
93 	if (argp->buf.buffer) {
94 		hostflag = 1;
95 		host = argp->buf.buffer;
96 	}
97 
98 	buflen = (size_t)argp->buf.buflen;
99 
100 	if (argp->buf.result) {
101 		etherflag = 1;
102 		ether = (struct ether_addr *)argp->buf.result;
103 	}
104 
105 	nss_result = (int)NSS_STR_PARSE_SUCCESS;
106 	(void) memset(argp->buf.buffer, 0, buflen);
107 
108 	attrptr = getattr(result, 0);
109 	if (attrptr == NULL) {
110 		nss_result = (int)NSS_STR_PARSE_PARSE;
111 		goto result_ea2ent;
112 	}
113 
114 	for (i = 0; i < result->entry->attr_count; i++) {
115 		attrptr = getattr(result, i);
116 		if (attrptr == NULL) {
117 			nss_result = (int)NSS_STR_PARSE_PARSE;
118 			goto result_ea2ent;
119 		}
120 		if (hostflag) {
121 			if (strcasecmp(attrptr->attrname, _E_HOSTNAME) == 0) {
122 				if ((attrptr->attrvalue[0] == NULL) ||
123 				    (len = strlen(attrptr->attrvalue[0])) < 1) {
124 					nss_result = (int)NSS_STR_PARSE_PARSE;
125 					goto result_ea2ent;
126 				}
127 				if (len > MAXHOSTNAMELEN) {
128 					nss_result = (int)NSS_STR_PARSE_ERANGE;
129 					goto result_ea2ent;
130 				}
131 				(void) strcpy(host, attrptr->attrvalue[0]);
132 				continue;
133 			}
134 		}
135 		if (etherflag) {
136 			if (strcasecmp(attrptr->attrname, _E_MACADDRESS) == 0) {
137 				if ((attrptr->attrvalue[0] == NULL) ||
138 				    (len = strlen(attrptr->attrvalue[0])) < 1) {
139 					nss_result = (int)NSS_STR_PARSE_PARSE;
140 					goto result_ea2ent;
141 				}
142 				ip = (int)sscanf(attrptr->attrvalue[0],
143 					"%x:%x:%x:%x:%x:%x", &t[0], &t[1],
144 					&t[2], &t[3], &t[4], &t[5]);
145 				if (ip != ETHERADDRL) {
146 					nss_result = (int)NSS_STR_PARSE_PARSE;
147 					goto result_ea2ent;
148 				}
149 				for (ip = 0; ip < ETHERADDRL; ip++)
150 					ether->ether_addr_octet[ip] =
151 						(uchar_t)t[ip];
152 				continue;
153 			}
154 		}
155 	}
156 
157 #ifdef DEBUG
158 	(void) fprintf(stdout, "\n[ether_addr.c: _nss_ldap_ethers2ent]\n");
159 	if (host != NULL)
160 		(void) fprintf(stdout, "      hostname: [%s]\n", host);
161 	if (ether != NULL)
162 		(void) fprintf(stdout,
163 		    "    ether_addr: [%x:%x:%x:%x:%x:%x]\n",
164 		    ether->ether_addr_octet[0],
165 		    ether->ether_addr_octet[1],
166 		    ether->ether_addr_octet[2],
167 		    ether->ether_addr_octet[3],
168 		    ether->ether_addr_octet[4],
169 		    ether->ether_addr_octet[5]);
170 #endif /* DEBUG */
171 
172 result_ea2ent:
173 
174 	(void) __ns_ldap_freeResult(&be->result);
175 	return ((int)nss_result);
176 }
177 
178 /*
179  * getbyhost gets an ethernet address by hostname. This function
180  * constructs an ldap search filter using the hostname invocation
181  * parameter and the getetherbyhost search filter defined. Once
182  * the filter is constructed, we search for a matching entry and
183  * marshal the data results into uchar_t *ether for the frontend
184  * process. The function _nss_ldap_ethers2ent performs the data
185  * marshaling.
186  *
187  * RFC 2307, An Approach for Using LDAP as a Network Information Service,
188  * indicates that dn's be fully qualified. Host name searches will be on
189  * fully qualified host names (e.g., foo.bar.sun.com).
190  */
191 
192 static nss_status_t
193 getbyhost(ldap_backend_ptr be, void *a)
194 {
195 	char		hostname[3 * MAXHOSTNAMELEN];
196 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
197 	char		searchfilter[SEARCHFILTERLEN];
198 	char		userdata[SEARCHFILTERLEN];
199 	int		ret;
200 
201 	if (_ldap_filter_name(hostname, argp->key.name, sizeof (hostname)) != 0)
202 		return ((nss_status_t)NSS_NOTFOUND);
203 
204 	ret = snprintf(searchfilter, sizeof (searchfilter),
205 	    _F_GETETHERBYHOST, hostname);
206 	if (ret >= sizeof (searchfilter) || ret < 0)
207 		return ((nss_status_t)NSS_NOTFOUND);
208 
209 	ret = snprintf(userdata, sizeof (userdata),
210 	    _F_GETETHERBYHOST_SSD, hostname);
211 	if (ret >= sizeof (userdata) || ret < 0)
212 		return ((nss_status_t)NSS_NOTFOUND);
213 
214 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
215 		_ETHERS, searchfilter, NULL,
216 		_merge_SSD_filter, userdata));
217 }
218 
219 
220 /*
221  * getbyether gets an ethernet address by ethernet address. This
222  * function constructs an ldap search filter using the ASCII
223  * ethernet address invocation parameter and the getetherbyether
224  * search filter defined. Once the filter is constructed, we
225  * search for a matching entry and  marshal the data results into
226  * uchar_t *ether for the frontend process. The function
227  * _nss_ldap_ethers2ent performs the data marshaling.
228  */
229 
230 static nss_status_t
231 getbyether(ldap_backend_ptr be, void *a)
232 {
233 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
234 	char		etherstr[18];
235 	uchar_t	*e = argp->key.ether;
236 	char		searchfilter[SEARCHFILTERLEN];
237 	char		userdata[SEARCHFILTERLEN];
238 	int		ret;
239 
240 	ret = snprintf(etherstr, sizeof (etherstr), "%x:%x:%x:%x:%x:%x",
241 	    *e, *(e + 1), *(e + 2), *(e + 3), *(e + 4), *(e + 5));
242 	if (ret >= sizeof (etherstr) || ret < 0)
243 		return ((nss_status_t)NSS_NOTFOUND);
244 
245 	ret = snprintf(searchfilter, sizeof (searchfilter),
246 	    _F_GETETHERBYETHER, etherstr);
247 	if (ret >= sizeof (searchfilter) || ret < 0)
248 		return ((nss_status_t)NSS_NOTFOUND);
249 
250 	ret = snprintf(userdata, sizeof (userdata),
251 	    _F_GETETHERBYETHER_SSD, etherstr);
252 	if (ret >= sizeof (userdata) || ret < 0)
253 		return ((nss_status_t)NSS_NOTFOUND);
254 
255 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
256 		_ETHERS, searchfilter, NULL,
257 		_merge_SSD_filter, userdata));
258 }
259 
260 
261 static ldap_backend_op_t ethers_ops[] = {
262 	_nss_ldap_destr,
263 	getbyhost,
264 	getbyether
265 };
266 
267 
268 /*
269  * _nss_ldap_ethers_constr is where life begins. This function calls the
270  * generic ldap constructor function to define and build the abstract
271  * data types required to support ldap operations.
272  */
273 
274 /*ARGSUSED0*/
275 nss_backend_t *
276 _nss_ldap_ethers_constr(const char *dummy1, const char *dummy2,
277 			const char *dummy3)
278 {
279 
280 	return ((nss_backend_t *)_nss_ldap_constr(ethers_ops,
281 		sizeof (ethers_ops)/sizeof (ethers_ops[0]), _ETHERS,
282 		ethers_attrs, _nss_ldap_ethers2ent));
283 }
284