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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <netdb.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <sys/systeminfo.h>
32 #include "ns_internal.h"
33 #include "ldap_common.h"
34 
35 /* host attributes filters */
36 
37 /* probably some change in the ipHostNumber field */
38 
39 #define	_H_DN			"dn"
40 #define	_H_NAME			"cn"
41 #define	_H_ADDR			"iphostnumber"
42 #define	_F_GETHOSTS6BYNAME	"(&(objectClass=ipHost)(cn=%s))"
43 #define	_F_GETHOSTS6BYNAME_SSD	"(&(%%s)(cn=%s))"
44 #define	_F_GETHOSTS6DOTTEDBYNAME \
45 				"(&(objectClass=ipHost)(|(cn=%s)(cn=%s)))"
46 #define	_F_GETHOSTS6DOTTEDBYNAME_SSD \
47 				"(&(%%s)(|(cn=%s)(cn=%s)))"
48 #define	_F_GETHOSTS6BYADDR	"(&(objectClass=ipHost)(ipHostNumber=%s))"
49 #define	_F_GETHOSTS6BYADDR_SSD	"(&(%%s)(ipHostNumber=%s))"
50 
51 static const char *ipnodes_attrs[] = {
52 	_H_NAME,
53 	_H_ADDR,
54 	(char *)NULL
55 };
56 
57 extern int
58 _nss_ldap_hosts2str_int(int af, ldap_backend_ptr be, nss_XbyY_args_t *argp);
59 
60 /*
61  * _nss_ldap_hosts2str is the data marshaling method for the ipnodes getXbyY
62  * system call gethostbyname() and gethostbyaddr.
63  * This method is called after a successful search has been performed.
64  * This method will parse the search results into the file format.
65  * e.g.
66  *
67  * fe80::a00:20ff:fec4:f2b6 ipnodes_1
68  *
69  */
70 static int
_nss_ldap_hosts2str(ldap_backend_ptr be,nss_XbyY_args_t * argp)71 _nss_ldap_hosts2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) {
72 	return (_nss_ldap_hosts2str_int(AF_INET6, be, argp));
73 }
74 
75 /*
76  * getbyname gets a struct hostent by hostname. This function constructs
77  * an ldap search filter using the name invocation parameter and the
78  * gethostbyname search filter defined. Once the filter is constructed,
79  * we search for a matching entry and marshal the data results into
80  * struct hostent for the frontend process.  Host name searches will be
81  * on fully qualified host names (foo.bar.sun.com)
82  */
83 
84 static nss_status_t
getbyname(ldap_backend_ptr be,void * a)85 getbyname(ldap_backend_ptr be, void *a)
86 {
87 	char		hostname[3 * MAXHOSTNAMELEN];
88 	char		realdomain[BUFSIZ];
89 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
90 	nss_status_t	lstat;
91 	char		searchfilter[SEARCHFILTERLEN];
92 	char		userdata[SEARCHFILTERLEN];
93 	int		rc;
94 
95 	if (_ldap_filter_name(hostname, argp->key.ipnode.name,
96 			sizeof (hostname)) != 0)
97 		return ((nss_status_t)NSS_NOTFOUND);
98 
99 	rc = snprintf(searchfilter, sizeof (searchfilter),
100 	    _F_GETHOSTS6BYNAME, hostname);
101 	if (rc >= sizeof (searchfilter) || rc < 0)
102 		return ((nss_status_t)NSS_NOTFOUND);
103 	rc = snprintf(userdata, sizeof (userdata),
104 	    _F_GETHOSTS6BYNAME_SSD, hostname);
105 	if (rc >= sizeof (userdata) || rc < 0)
106 		return ((nss_status_t)NSS_NOTFOUND);
107 
108 	/* get the domain we are in */
109 	rc = sysinfo(SI_SRPC_DOMAIN, realdomain, BUFSIZ);
110 	if (rc <= 0)
111 		return ((nss_status_t)NSS_NOTFOUND);
112 
113 	/* Is this a request for a host.domain */
114 	if (DOTTEDSUBDOMAIN(hostname)) {
115 		char	host[MAXHOSTNAMELEN];
116 		char	domain[MAXHOSTNAMELEN];
117 		char	hname[3 * MAXHOSTNAMELEN];
118 
119 		/* separate host and domain.  this function */
120 		/* will munge hname, so use argp->keyname */
121 		/* from here on for original string */
122 
123 		(void) strcpy(hname, hostname);
124 		if (chophostdomain(hname, host, domain) == -1) {
125 			return ((nss_status_t)NSS_NOTFOUND);
126 		}
127 
128 		/* if domain is a proper subset of realdomain */
129 		/* ie. domain = "foo" and realdomain */
130 		/* = "foor.bar.sun.com", we try to lookup both" */
131 		/* host.domain and host */
132 
133 		if (propersubdomain(realdomain, domain) == 1) {
134 			/* yes, it is a proper domain */
135 			rc = snprintf(searchfilter, sizeof (searchfilter),
136 			    _F_GETHOSTS6DOTTEDBYNAME, hostname, host);
137 			if (rc >= sizeof (searchfilter) || rc < 0)
138 				return ((nss_status_t)NSS_NOTFOUND);
139 
140 			rc = snprintf(userdata, sizeof (userdata),
141 			    _F_GETHOSTS6DOTTEDBYNAME_SSD, hostname, host);
142 			if (rc >= sizeof (userdata) || rc < 0)
143 				return ((nss_status_t)NSS_NOTFOUND);
144 		} else {
145 			/* it is not a proper domain, so only try to look up */
146 			/* host.domain */
147 			rc = snprintf(searchfilter, sizeof (searchfilter),
148 			    _F_GETHOSTS6BYNAME, hostname);
149 			if (rc >= sizeof (searchfilter) || rc < 0)
150 				return ((nss_status_t)NSS_NOTFOUND);
151 
152 			rc = snprintf(userdata, sizeof (userdata),
153 			    _F_GETHOSTS6BYNAME_SSD, hostname);
154 			if (rc >= sizeof (userdata) || rc < 0)
155 				return ((nss_status_t)NSS_NOTFOUND);
156 		}
157 	} else {
158 		rc = snprintf(searchfilter, sizeof (searchfilter),
159 		    _F_GETHOSTS6BYNAME, hostname);
160 		if (rc >= sizeof (searchfilter) || rc < 0)
161 			return ((nss_status_t)NSS_NOTFOUND);
162 
163 		rc = snprintf(userdata, sizeof (userdata),
164 		    _F_GETHOSTS6BYNAME_SSD, hostname);
165 		if (rc >= sizeof (userdata) || rc < 0)
166 			return ((nss_status_t)NSS_NOTFOUND);
167 	}
168 	lstat = (nss_status_t)_nss_ldap_lookup(be, argp, _HOSTS,
169 		searchfilter, NULL,
170 		_merge_SSD_filter, userdata);
171 	if (lstat == (nss_status_t)NS_LDAP_SUCCESS)
172 		return ((nss_status_t)NSS_SUCCESS);
173 
174 	argp->h_errno = __nss2herrno(lstat);
175 	return ((nss_status_t)lstat);
176 }
177 
178 
179 /*
180  * getbyaddr gets a struct hostent by host address. This function
181  * constructs an ldap search filter using the host address invocation
182  * parameter and the gethostbyaddr search filter defined. Once the
183  * filter is constructed, we search for a matching entry and marshal
184  * the data results into struct hostent for the frontend process.
185  */
186 
187 static nss_status_t
getbyaddr(ldap_backend_ptr be,void * a)188 getbyaddr(ldap_backend_ptr be, void *a)
189 {
190 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
191 	struct in6_addr	addr;
192 	char		addrbuf[INET6_ADDRSTRLEN + 1];
193 	nss_status_t	lstat;
194 	char		searchfilter[SEARCHFILTERLEN];
195 	char		userdata[SEARCHFILTERLEN];
196 	int		ret;
197 
198 	argp->h_errno = 0;
199 	if ((argp->key.hostaddr.type != AF_INET6) ||
200 	    (argp->key.hostaddr.len != sizeof (addr)))
201 		return (NSS_NOTFOUND);
202 
203 	(void) memcpy(&addr, argp->key.hostaddr.addr, sizeof (addr));
204 	if (IN6_IS_ADDR_V4MAPPED(&addr)) {
205 		if (inet_ntop(AF_INET, (void *) &addr.s6_addr[12],
206 				(void *)addrbuf, INET_ADDRSTRLEN) == NULL) {
207 			return (NSS_NOTFOUND);
208 		}
209 	} else {
210 		if (inet_ntop(AF_INET6, (void *)&addr, (void *)addrbuf,
211 				INET6_ADDRSTRLEN) == NULL)
212 			return (NSS_NOTFOUND);
213 	}
214 	ret = snprintf(searchfilter, sizeof (searchfilter),
215 	    _F_GETHOSTS6BYADDR, addrbuf);
216 	if (ret >= sizeof (searchfilter) || ret < 0)
217 		return ((nss_status_t)NSS_NOTFOUND);
218 
219 	ret = snprintf(userdata, sizeof (userdata),
220 	    _F_GETHOSTS6BYADDR_SSD, addrbuf);
221 	if (ret >= sizeof (userdata) || ret < 0)
222 		return ((nss_status_t)NSS_NOTFOUND);
223 
224 	lstat = (nss_status_t)_nss_ldap_lookup(be, argp,
225 		_HOSTS6, searchfilter, NULL,
226 		_merge_SSD_filter, userdata);
227 	if (lstat == (nss_status_t)NS_LDAP_SUCCESS)
228 		return ((nss_status_t)NSS_SUCCESS);
229 
230 	argp->h_errno = __nss2herrno(lstat);
231 	return ((nss_status_t)lstat);
232 }
233 
234 static ldap_backend_op_t ipnodes_ops[] = {
235 	_nss_ldap_destr,
236 	0,
237 	0,
238 	0,
239 	getbyname,
240 	getbyaddr
241 };
242 
243 
244 /*
245  * _nss_ldap_hosts_constr is where life begins. This function calls the generic
246  * ldap constructor function to define and build the abstract data types
247  * required to support ldap operations.
248  */
249 
250 /*ARGSUSED0*/
251 nss_backend_t *
_nss_ldap_ipnodes_constr(const char * dummy1,const char * dummy2,const char * dummy3)252 _nss_ldap_ipnodes_constr(const char *dummy1, const char *dummy2,
253 			const char *dummy3)
254 {
255 
256 	return ((nss_backend_t *)_nss_ldap_constr(ipnodes_ops,
257 		sizeof (ipnodes_ops)/sizeof (ipnodes_ops[0]), _HOSTS6,
258 		ipnodes_attrs, _nss_ldap_hosts2str));
259 }
260