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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <netdb.h>
29 #include "ldap_common.h"
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <sys/tsol/tndb.h>
35 
36 /* tnrhdb attributes filters */
37 #define	_TNRHDB_ADDR		"ipTnetNumber"
38 #define	_TNRHDB_TNAME		"ipTnetTemplateName"
39 #define	_F_GETTNDBBYADDR	"(&(objectClass=ipTnetHost)(ipTnetNumber=%s))"
40 #define	_F_GETTNDBBYADDR_SSD	"(&(%%s)(ipTnetNumber=%s))"
41 
42 static const char *tnrhdb_attrs[] = {
43 	_TNRHDB_ADDR,
44 	_TNRHDB_TNAME,
45 	NULL
46 };
47 
48 static void
49 escape_colon(char *in, char *out) {
50 	int i, j;
51 	for (i = 0, j = 0; in[i] != '\0'; i++) {
52 		if (in[i] == ':') {
53 			out[j++] = '\\';
54 			out[j++] = in[i];
55 		} else
56 			out[j++] = in[i];
57 	}
58 	out[j] = '\0';
59 }
60 
61 /*
62  * _nss_ldap_tnrhdb2str is the data marshaling method for the tnrhdb
63  * (tsol_getrhbyaddr()/tsol_getrhent()) backend processes.
64  * This method is called after a successful ldap search has been performed.
65  * This method will parse the ldap search values into the file format.
66  *
67  * e.g.
68  *
69  * 192.168.120.6:public
70  * fec0\:\:a00\:20ff\:fea0\:21f7:cipso
71  *
72  */
73 static int
74 _nss_ldap_tnrhdb2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
75 {
76 	int			nss_result = NSS_STR_PARSE_SUCCESS;
77 	int			len = 0;
78 	char			*buffer = NULL;
79 	char			**addr, **template, *addr_out;
80 	ns_ldap_result_t	*result = be->result;
81 	char addr6[INET6_ADDRSTRLEN + 5]; /* 5 '\' for ':' at most */
82 
83 	if (result == NULL)
84 		return (NSS_STR_PARSE_PARSE);
85 
86 	addr = __ns_ldap_getAttr(result->entry, _TNRHDB_ADDR);
87 	if (addr == NULL || addr[0] == NULL || (strlen(addr[0]) < 1)) {
88 		nss_result = NSS_STR_PARSE_PARSE;
89 		goto result_tnrhdb2str;
90 	}
91 
92 	/*
93 	 * Escape ':' in IPV6.
94 	 * The value is stored in LDAP directory without escape charaters.
95 	 */
96 	if (strchr(addr[0], ':') != NULL) {
97 		escape_colon(addr[0], addr6);
98 		addr_out = addr6;
99 	} else
100 		addr_out = addr[0];
101 
102 	template = __ns_ldap_getAttr(result->entry, _TNRHDB_TNAME);
103 	if (template == NULL || template[0] == NULL ||
104 			(strlen(template[0]) < 1)) {
105 		nss_result = NSS_STR_PARSE_PARSE;
106 		goto result_tnrhdb2str;
107 	}
108 	/* "addr:template" */
109 	len = strlen(addr_out) + strlen(template[0]) + 2;
110 
111 	if (argp->buf.result != NULL) {
112 		if ((be->buffer = calloc(1, len)) == NULL) {
113 			nss_result = NSS_STR_PARSE_PARSE;
114 			goto result_tnrhdb2str;
115 		}
116 		be->buflen = len - 1;
117 		buffer = be->buffer;
118 	} else
119 		buffer = argp->buf.buffer;
120 
121 	(void) snprintf(buffer, len, "%s:%s", addr_out, template[0]);
122 
123 result_tnrhdb2str:
124 	(void) __ns_ldap_freeResult(&be->result);
125 	return (nss_result);
126 }
127 
128 
129 static nss_status_t
130 getbyaddr(ldap_backend_ptr be, void *a)
131 {
132 	char		searchfilter[SEARCHFILTERLEN];
133 	char		userdata[SEARCHFILTERLEN];
134 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
135 
136 	if (argp->key.hostaddr.addr == NULL ||
137 		(argp->key.hostaddr.type != AF_INET &&
138 		argp->key.hostaddr.type != AF_INET6))
139 			return (NSS_NOTFOUND);
140 	if (strchr(argp->key.hostaddr.addr, ':') != NULL) {
141 		/* IPV6 */
142 		if (argp->key.hostaddr.type == AF_INET)
143 			return (NSS_NOTFOUND);
144 	} else {
145 		/* IPV4 */
146 		if (argp->key.hostaddr.type == AF_INET6)
147 			return (NSS_NOTFOUND);
148 	}
149 
150 	/*
151 	 * The IPV6 addresses are saved in the directory without '\'s.
152 	 * So don't need to escape colons in IPV6 addresses.
153 	 */
154 	if (snprintf(searchfilter, sizeof (searchfilter), _F_GETTNDBBYADDR,
155 	    argp->key.hostaddr.addr) < 0)
156 		return ((nss_status_t)NSS_NOTFOUND);
157 
158 	if (snprintf(userdata, sizeof (userdata), _F_GETTNDBBYADDR_SSD,
159 	    argp->key.hostaddr.addr) < 0)
160 		return ((nss_status_t)NSS_NOTFOUND);
161 
162 	return (_nss_ldap_lookup(be, argp, _TNRHDB, searchfilter, NULL,
163 	    _merge_SSD_filter, userdata));
164 }
165 
166 
167 static ldap_backend_op_t tnrhdb_ops[] = {
168 	_nss_ldap_destr,
169 	_nss_ldap_endent,
170 	_nss_ldap_setent,
171 	_nss_ldap_getent,
172 	getbyaddr
173 };
174 
175 
176 /* ARGSUSED */
177 nss_backend_t *
178 _nss_ldap_tnrhdb_constr(const char *dummy1,
179     const char *dummy2,
180     const char *dummy3,
181     const char *dummy4,
182     const char *dummy5)
183 {
184 	return ((nss_backend_t *)_nss_ldap_constr(tnrhdb_ops,
185 		sizeof (tnrhdb_ops)/sizeof (tnrhdb_ops[0]), _TNRHDB,
186 		tnrhdb_attrs, _nss_ldap_tnrhdb2str));
187 }
188