xref: /titanic_50/usr/src/lib/nsswitch/ldap/common/gethostent6.c (revision 03831d35f7499c87d51205817c93e9a8d42c4bae)
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 <sys/socket.h>
32 #include <inet/ip6.h>
33 #include <syslog.h>
34 #include <sys/systeminfo.h>
35 #include "ns_internal.h"
36 #include "ldap_common.h"
37 
38 /* host attributes filters */
39 
40 /* probably some change in the ipHostNumber field */
41 
42 #define	_H_DN			"dn"
43 #define	_H_NAME			"cn"
44 #define	_H_ADDR			"iphostnumber"
45 #define	_F_GETHOSTS6BYNAME	"(&(objectClass=ipHost)(cn=%s))"
46 #define	_F_GETHOSTS6BYNAME_SSD	"(&(%%s)(cn=%s))"
47 #define	_F_GETHOSTS6DOTTEDBYNAME \
48 				"(&(objectClass=ipHost)(|(cn=%s)(cn=%s)))"
49 #define	_F_GETHOSTS6DOTTEDBYNAME_SSD \
50 				"(&(%%s)(|(cn=%s)(cn=%s)))"
51 #define	_F_GETHOSTS6BYADDR	"(&(objectClass=ipHost)(ipHostNumber=%s))"
52 #define	_F_GETHOSTS6BYADDR_SSD	"(&(%%s)(ipHostNumber=%s))"
53 
54 static const char *ipnodes_attrs[] = {
55 	_H_NAME,
56 	_H_ADDR,
57 	(char *)NULL
58 };
59 
60 extern int inet_pton(int, const char *, void *);
61 const char *inet_ntop(int af, const void *src, char *dst, size_t size);
62 
63 /*
64  * _nss_ldap_hosts2ent is the data marshaling method for the ipnodes getXbyY
65  * system call gethostbyname() and gethostbyaddr. The format of this call
66  * is a cononical name and alias (alias is cononical name too) and one or
67  * more IP addresses in support of multihomed hosts. This method is called
68  * after a successful synchronous search has been performed. This method
69  * will parse the search results into struct hostent = argp->buf.buffer
70  * which gets returned to the frontend process. One of three error
71  * conditions is also returned to nsswitch.
72  */
73 
74 static int
75 _nss_ldap_hosts2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp)
76 {
77 	int			i, j;
78 	int			nss_result;
79 	int			buflen = (int)0;
80 	int			firstimename = (int)1;
81 	int			firstimedn   = (int)1;
82 	int			firstimeaddr = (int)1;
83 	unsigned long		len = 0L;
84 	char			**hn, **ha, **dp;
85 	char			*cname = (char *)NULL;
86 	char			*buffer = (char *)NULL;
87 	char			*ceiling = (char *)NULL;
88 	struct hostent		*host = (struct hostent *)NULL;
89 	struct in6_addr		addr6;
90 	struct in_addr		addr;
91 	char			*val;
92 	ns_ldap_result_t	*result = be->result;
93 	ns_ldap_attr_t		*attrptr;
94 	int			namecount = 0;
95 	int			addrcount = 0;
96 	int			aliascount = 0;
97 	int			gluelen = 0;
98 	ns_ldap_entry_t		*entry;
99 	ns_ldap_attr_t		*attr;
100 
101 	buffer = argp->buf.buffer;
102 	buflen = (size_t)argp->buf.buflen;
103 	if (!argp->buf.result) {
104 		nss_result = (int)NSS_STR_PARSE_ERANGE;
105 		goto result_hosts2ent;
106 	}
107 	host = (struct hostent *)argp->buf.result;
108 	ceiling = buffer + buflen;
109 
110 	nss_result = (int)NSS_STR_PARSE_SUCCESS;
111 	(void) memset(argp->buf.buffer, 0, buflen);
112 
113 	attrptr = getattr(result, 0);
114 	if (attrptr == NULL) {
115 		nss_result = (int)NSS_STR_PARSE_PARSE;
116 		goto result_hosts2ent;
117 	}
118 
119 	for (entry = result->entry; entry != NULL; entry = entry->next) {
120 		for (i = 0, attr = entry->attr_pair[i];
121 				i < entry->attr_count; i++) {
122 			attr = entry->attr_pair[i];
123 			if (strcasecmp(attr->attrname, _H_NAME) == 0)
124 				namecount += attr->value_count;
125 			if (strcasecmp(attr->attrname, _H_ADDR) == 0)
126 				addrcount += attr->value_count;
127 		}
128 	}
129 
130 	for (entry = result->entry; entry != NULL; entry = entry->next) {
131 	    for (i = 0; i < entry->attr_count; i++) {
132 		attrptr = entry->attr_pair[i];
133 		if (attrptr == NULL) {
134 		    nss_result = (int)NSS_STR_PARSE_PARSE;
135 		    goto result_hosts2ent;
136 		}
137 		if (strcasecmp(attrptr->attrname, _H_DN) == 0) {
138 		    for (j = 0; j < attrptr->value_count; j++) {
139 			if (firstimedn) {
140 			    /* get domain name associated with this dn */
141 			    be->toglue = _get_domain_name(
142 					attrptr->attrvalue[j]);
143 			    firstimedn = (int)0;
144 			}
145 		    }
146 		}
147 		if (strcasecmp(attrptr->attrname, _H_NAME) == 0) {
148 		    for (j = 0; j < attrptr->value_count; j++) {
149 			if (firstimename) {
150 			    /* canonical name */
151 			    cname = __s_api_get_canonical_name(result->entry,
152 				attrptr, 1);
153 			    if (cname == NULL ||
154 				(len = strlen(cname)) < 1) {
155 				nss_result = (int)NSS_STR_PARSE_PARSE;
156 				goto result_hosts2ent;
157 			    }
158 			    if (be->toglue != NULL &&
159 				!DOTTEDSUBDOMAIN(cname))
160 				gluelen = strlen(be->toglue) + 1;
161 			    else
162 				gluelen = 0;
163 			    host->h_name = buffer;
164 			    buffer += len + gluelen + 1;
165 			    if (buffer >= ceiling) {
166 				nss_result = (int)NSS_STR_PARSE_ERANGE;
167 				goto result_hosts2ent;
168 			    }
169 			    (void) strcpy(host->h_name, cname);
170 			    if (gluelen > 0) {
171 				(void) strcat(host->h_name, ".");
172 				(void) strcat(host->h_name, be->toglue);
173 			    }
174 			    /* alias name */
175 			    aliascount = (namecount >= 1 ? (namecount - 1) : 0);
176 			    hn = host->h_aliases =
177 				(char **)ROUND_UP(buffer, sizeof (char **));
178 			    buffer = (char *)host->h_aliases +
179 				sizeof (char *) * (aliascount + 1);
180 			    buffer = (char *)ROUND_UP(buffer, sizeof (char **));
181 			    if (buffer >= ceiling) {
182 				nss_result = (int)NSS_STR_PARSE_ERANGE;
183 				goto result_hosts2ent;
184 			    }
185 			    firstimename = (int)0;
186 			}
187 			/* alias list */
188 			if (aliascount > 0) {
189 				if ((attrptr->attrvalue[j] == NULL) ||
190 				    (len = strlen(attrptr->attrvalue[j])) < 1) {
191 				    nss_result = (int)NSS_STR_PARSE_PARSE;
192 				    goto result_hosts2ent;
193 				}
194 				/* skip canonical name */
195 				if (strcmp(attrptr->attrvalue[j], cname) == 0)
196 					continue;
197 				/* check for duplicates */
198 				for (dp = host->h_aliases; *dp != NULL; dp++) {
199 				    if (strcmp(*dp, attrptr->attrvalue[j]) == 0)
200 					goto next_alias;
201 				}
202 				if (be->toglue != NULL &&
203 					!DOTTEDSUBDOMAIN(attrptr->attrvalue[j]))
204 					gluelen = strlen(be->toglue) + 1;
205 				else
206 					gluelen = 0;
207 				*hn = buffer;
208 				buffer += len + gluelen + 1;
209 				if (buffer >= ceiling) {
210 				    nss_result = (int)NSS_STR_PARSE_ERANGE;
211 				    goto result_hosts2ent;
212 				}
213 				(void) strcpy(*hn, attrptr->attrvalue[j]);
214 				if (gluelen > 0) {
215 				    (void) strcat(*hn, ".");
216 				    (void) strcat(*hn, be->toglue);
217 				}
218 				hn++;
219 			}
220 next_alias:
221 			continue;
222 		    }
223 		}
224 	    }
225 	}
226 
227 	for (entry = result->entry; entry != NULL; entry = entry->next) {
228 	    for (i = 0; i < entry->attr_count; i++) {
229 		attrptr = entry->attr_pair[i];
230 		if (attrptr == NULL) {
231 		    nss_result = (int)NSS_STR_PARSE_PARSE;
232 		    goto result_hosts2ent;
233 		}
234 
235 		if (strcasecmp(attrptr->attrname, _H_ADDR) == 0) {
236 		    for (j = 0; j < attrptr->value_count; j++) {
237 			if (firstimeaddr) {
238 			    /* allocate 1 address per entry */
239 			    ha = host->h_addr_list = (char **)ROUND_UP(buffer,
240 				sizeof (char **));
241 			    buffer = (char *)host->h_addr_list +
242 				sizeof (char *) * (addrcount + 1);
243 			    buffer = (char *)ROUND_UP(buffer, sizeof (char **));
244 			    if (buffer >= ceiling) {
245 				nss_result = (int)NSS_STR_PARSE_ERANGE;
246 				goto result_hosts2ent;
247 			    }
248 			    firstimeaddr = (int)0;
249 			}
250 			val = (char *)_strip_quotes(attrptr->attrvalue[j]);
251 			if (inet_pton(AF_INET6, val, (void *) &addr6) != 1) {
252 			    if (inet_pton(AF_INET, val, (void *) &addr) != 1) {
253 				goto next_addr;
254 			    } else {
255 				IN6_INADDR_TO_V4MAPPED(&addr, &addr6);
256 			    }
257 			}
258 
259 			/* check for duplicates */
260 			for (dp = host->h_addr_list; *dp != NULL; dp++) {
261 			    if (memcmp(*dp, &addr6, sizeof (struct in6_addr))
262 				== 0)
263 				goto next_addr;
264 			}
265 			*ha = buffer;
266 			len = (unsigned long)sizeof (struct in6_addr);
267 			buffer += len;
268 			if (buffer >= ceiling) {
269 			    nss_result = (int)NSS_STR_PARSE_ERANGE;
270 			    goto result_hosts2ent;
271 			}
272 			(void) memcpy(*ha++, (char *)&addr6, (size_t)len);
273 next_addr:
274 			continue;
275 		    }
276 		}
277 	    }
278 	}
279 
280 	host->h_addrtype = AF_INET6;
281 	host->h_length = IPV6_ADDR_LEN;
282 
283 #ifdef DEBUG
284 	(void) fprintf(stdout, "\n[gethostent.c: _nss_ldap_byname2ent]\n");
285 	(void) fprintf(stdout, "        h_name: [%s]\n", host->h_name);
286 	if (host->h_aliases != NULL) {
287 		for (hn = host->h_aliases; *hn != NULL; hn++)
288 			(void) fprintf(stdout, "     h_aliases: [%s]\n", *hn);
289 	}
290 	(void) fprintf(stdout, "    h_addrtype: [%d]\n", host->h_addrtype);
291 	(void) fprintf(stdout, "      h_length: [%d]\n", host->h_length);
292 
293 	for (hn = host->h_addr_list; *hn != NULL; hn++) {
294 		char addrbuf[INET6_ADDRSTRLEN + 1];
295 		(void) fprintf(stdout, "   haddr_list: [%s]\n",
296 			inet_ntop(AF_INET6, (void *)hn, (void *)addrbuf,
297 				INET6_ADDRSTRLEN));
298 	}
299 #endif /* DEBUG */
300 
301 result_hosts2ent:
302 
303 	(void) __ns_ldap_freeResult(&be->result);
304 	return ((int)nss_result);
305 }
306 
307 
308 /*
309  * getbyname gets a struct hostent by hostname. This function constructs
310  * an ldap search filter using the name invocation parameter and the
311  * gethostbyname search filter defined. Once the filter is constructed,
312  * we search for a matching entry and marshal the data results into
313  * struct hostent for the frontend process.  Host name searches will be
314  * on fully qualified host names (foo.bar.sun.com)
315  */
316 
317 static nss_status_t
318 getbyname(ldap_backend_ptr be, void *a)
319 {
320 	char		hostname[3 * MAXHOSTNAMELEN];
321 	char		realdomain[BUFSIZ];
322 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
323 	nss_status_t	lstat;
324 	char		searchfilter[SEARCHFILTERLEN];
325 	char		userdata[SEARCHFILTERLEN];
326 	int		rc;
327 
328 #ifdef DEBUG
329 	(void) fprintf(stdout, "\n[gethostent6.c: getbyname]\n");
330 #endif /* DEBUG */
331 
332 	if (_ldap_filter_name(hostname, argp->key.ipnode.name,
333 			sizeof (hostname)) != 0)
334 		return ((nss_status_t)NSS_NOTFOUND);
335 
336 	rc = snprintf(searchfilter, sizeof (searchfilter),
337 	    _F_GETHOSTS6BYNAME, hostname);
338 	if (rc >= sizeof (searchfilter) || rc < 0)
339 		return ((nss_status_t)NSS_NOTFOUND);
340 	rc = snprintf(userdata, sizeof (userdata),
341 	    _F_GETHOSTS6BYNAME_SSD, hostname);
342 	if (rc >= sizeof (userdata) || rc < 0)
343 		return ((nss_status_t)NSS_NOTFOUND);
344 
345 	/* get the domain we are in */
346 	rc = sysinfo(SI_SRPC_DOMAIN, realdomain, BUFSIZ);
347 	if (rc <= 0)
348 		return ((nss_status_t)NSS_NOTFOUND);
349 
350 	/* Is this a request for a host.domain */
351 	if (DOTTEDSUBDOMAIN(hostname)) {
352 		char	host[MAXHOSTNAMELEN];
353 		char	domain[MAXHOSTNAMELEN];
354 		char	hname[3 * MAXHOSTNAMELEN];
355 
356 		/* separate host and domain.  this function */
357 		/* will munge hname, so use argp->keyname */
358 		/* from here on for original string */
359 
360 		(void) strcpy(hname, hostname);
361 		if (chophostdomain(hname, host, domain) == -1) {
362 			return ((nss_status_t)NSS_NOTFOUND);
363 		}
364 
365 		/* if domain is a proper subset of realdomain */
366 		/* ie. domain = "foo" and realdomain */
367 		/* = "foor.bar.sun.com", we try to lookup both" */
368 		/* host.domain and host */
369 
370 		if (propersubdomain(realdomain, domain) == 1) {
371 			/* yes, it is a proper domain */
372 			rc = snprintf(searchfilter, sizeof (searchfilter),
373 			    _F_GETHOSTS6DOTTEDBYNAME, hostname, host);
374 			if (rc >= sizeof (searchfilter) || rc < 0)
375 				return ((nss_status_t)NSS_NOTFOUND);
376 
377 			rc = snprintf(userdata, sizeof (userdata),
378 			    _F_GETHOSTS6DOTTEDBYNAME_SSD, hostname, host);
379 			if (rc >= sizeof (userdata) || rc < 0)
380 				return ((nss_status_t)NSS_NOTFOUND);
381 		} else {
382 			/* it is not a proper domain, so only try to look up */
383 			/* host.domain */
384 			rc = snprintf(searchfilter, sizeof (searchfilter),
385 			    _F_GETHOSTS6BYNAME, hostname);
386 			if (rc >= sizeof (searchfilter) || rc < 0)
387 				return ((nss_status_t)NSS_NOTFOUND);
388 
389 			rc = snprintf(userdata, sizeof (userdata),
390 			    _F_GETHOSTS6BYNAME_SSD, hostname);
391 			if (rc >= sizeof (userdata) || rc < 0)
392 				return ((nss_status_t)NSS_NOTFOUND);
393 		}
394 	} else {
395 		rc = snprintf(searchfilter, sizeof (searchfilter),
396 		    _F_GETHOSTS6BYNAME, hostname);
397 		if (rc >= sizeof (searchfilter) || rc < 0)
398 			return ((nss_status_t)NSS_NOTFOUND);
399 
400 		rc = snprintf(userdata, sizeof (userdata),
401 		    _F_GETHOSTS6BYNAME_SSD, hostname);
402 		if (rc >= sizeof (userdata) || rc < 0)
403 			return ((nss_status_t)NSS_NOTFOUND);
404 	}
405 	lstat = (nss_status_t)_nss_ldap_lookup(be, argp, _HOSTS,
406 		searchfilter, NULL,
407 		_merge_SSD_filter, userdata);
408 	if (lstat == (nss_status_t)NS_LDAP_SUCCESS)
409 		return ((nss_status_t)NSS_SUCCESS);
410 
411 	argp->h_errno = __nss2herrno(lstat);
412 	return ((nss_status_t)lstat);
413 }
414 
415 
416 /*
417  * getbyaddr gets a struct hostent by host address. This function
418  * constructs an ldap search filter using the host address invocation
419  * parameter and the gethostbyaddr search filter defined. Once the
420  * filter is constructed, we search for a matching entry and marshal
421  * the data results into struct hostent for the frontend process.
422  */
423 
424 static nss_status_t
425 getbyaddr(ldap_backend_ptr be, void *a)
426 {
427 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
428 	struct in6_addr	addr;
429 	char		addrbuf[INET6_ADDRSTRLEN + 1];
430 	nss_status_t	lstat;
431 	char		searchfilter[SEARCHFILTERLEN];
432 	char		userdata[SEARCHFILTERLEN];
433 	int		ret;
434 
435 #ifdef DEBUG
436 	(void) fprintf(stdout, "\n[gethostent6.c: getbyaddr]\n");
437 #endif /* DEBUG */
438 	argp->h_errno = 0;
439 	if ((argp->key.hostaddr.type != AF_INET6) ||
440 	    (argp->key.hostaddr.len != sizeof (addr)))
441 		return (NSS_NOTFOUND);
442 
443 	(void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr));
444 	if (IN6_IS_ADDR_V4MAPPED(&addr)) {
445 		if (inet_ntop(AF_INET, (void *) &addr.s6_addr[12],
446 				(void *)addrbuf, INET_ADDRSTRLEN) == NULL) {
447 			return (NSS_NOTFOUND);
448 		}
449 	} else {
450 		if (inet_ntop(AF_INET6, (void *)&addr, (void *)addrbuf,
451 				INET6_ADDRSTRLEN) == NULL)
452 			return (NSS_NOTFOUND);
453 	}
454 	ret = snprintf(searchfilter, sizeof (searchfilter),
455 	    _F_GETHOSTS6BYADDR, addrbuf);
456 	if (ret >= sizeof (searchfilter) || ret < 0)
457 		return ((nss_status_t)NSS_NOTFOUND);
458 
459 	ret = snprintf(userdata, sizeof (userdata),
460 	    _F_GETHOSTS6BYADDR_SSD, addrbuf);
461 	if (ret >= sizeof (userdata) || ret < 0)
462 		return ((nss_status_t)NSS_NOTFOUND);
463 
464 	lstat = (nss_status_t)_nss_ldap_lookup(be, argp,
465 		_HOSTS6, searchfilter, NULL,
466 		_merge_SSD_filter, userdata);
467 	if (lstat == (nss_status_t)NS_LDAP_SUCCESS)
468 		return ((nss_status_t)NSS_SUCCESS);
469 
470 	argp->h_errno = __nss2herrno(lstat);
471 	return ((nss_status_t)lstat);
472 }
473 
474 static ldap_backend_op_t ipnodes_ops[] = {
475 	_nss_ldap_destr,
476 	0,
477 	0,
478 	0,
479 	getbyname,
480 	getbyaddr
481 };
482 
483 
484 /*
485  * _nss_ldap_hosts_constr is where life begins. This function calls the generic
486  * ldap constructor function to define and build the abstract data types
487  * required to support ldap operations.
488  */
489 
490 /*ARGSUSED0*/
491 nss_backend_t *
492 _nss_ldap_ipnodes_constr(const char *dummy1, const char *dummy2,
493 			const char *dummy3)
494 {
495 
496 #ifdef DEBUG
497 	(void) fprintf(stdout, "\n[gethostent6.c: _nss_ldap_host6_constr]\n");
498 #endif /* DEBUG */
499 	return ((nss_backend_t *)_nss_ldap_constr(ipnodes_ops,
500 		sizeof (ipnodes_ops)/sizeof (ipnodes_ops[0]), _HOSTS6,
501 		ipnodes_attrs, _nss_ldap_hosts2ent));
502 }
503