xref: /illumos-gate/usr/src/lib/nsswitch/ldap/common/ldap_utils.c (revision 2aeafac3612e19716bf8164f89c3c9196342979c)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26  */
27 
28 #include <sys/systeminfo.h>
29 #include "ldap_common.h"
30 
31 
32 #ifdef DEBUG
33 /*
34  * Debugging routine for printing the value of a result
35  * structure
36  */
37 int
38 printresult(ns_ldap_result_t *result)
39 {
40 	int		i, j, k;
41 	ns_ldap_entry_t	*curEntry;
42 
43 	printf("--------------------------------------\n");
44 	printf("entries_count %d\n", result->entries_count);
45 	curEntry = result->entry;
46 	for (i = 0; i < result->entries_count; i++) {
47 		printf("entry %d has attr_count = %d \n",
48 		    i, curEntry->attr_count);
49 		for (j = 0; j < curEntry->attr_count; j++) {
50 			printf("entry %d has attr_pair[%d] = %s \n",
51 			    i, j, curEntry->attr_pair[j]->attrname);
52 			for (k = 0;
53 			    (k < curEntry->attr_pair[j]->value_count) &&
54 			    (curEntry->attr_pair[j]->attrvalue[k]);
55 			    k++)
56 				printf("entry %d has "
57 				    "attr_pair[%d]->attrvalue[%d] = %s \n",
58 				    i, j, k,
59 				    curEntry->attr_pair[j]->attrvalue[k]);
60 		}
61 		printf("\n--------------------------------------\n");
62 		curEntry = curEntry->next;
63 	}
64 	return (1);
65 }
66 #endif
67 
68 
69 /*
70  *
71  */
72 
73 ns_ldap_attr_t *
74 getattr(ns_ldap_result_t *result, int i)
75 {
76 	ns_ldap_entry_t	*entry;
77 
78 #ifdef DEBUG
79 	(void) fprintf(stdout, "\n[ldap_utils.c: getattr]\n");
80 #endif /* DEBUG */
81 
82 	if (result != NULL) {
83 		entry = result->entry;
84 	} else {
85 		return (NULL);
86 	}
87 	if (result->entries_count == 0) {
88 		return (NULL);
89 	} else {
90 		return (entry->attr_pair[i]);
91 	}
92 }
93 
94 /*
95  * _get_domain_name() passes the dn one level up from cdn, e.g.,
96  * a pointer pointing to "ou= ..." for the cdn's listed below:
97  * 	dn: cn=hostname+ipHostNumber="109.34.54.76", ou= ...
98  *	dn: echo+IpServiceProtocol=udp, ou= ...
99  * to __ns_ldap_dn2domain() to retrieve the domain name associated
100  * with cdn.
101  */
102 
103 char *
104 _get_domain_name(char *cdn)
105 {
106 	char			**rdns;
107 	char			*pdn, *domain = NULL;
108 	int			nrdns;
109 	int			len = 0;
110 	const ns_cred_t		*cred = NULL;
111 	ns_ldap_error_t		*error;
112 
113 	/* break the cdn into its components */
114 	rdns = ldap_explode_dn(cdn, 0);
115 	if (rdns == NULL || *rdns == NULL)
116 		return (NULL);
117 
118 	/* construct parent dn */
119 	for (nrdns = 1; rdns[nrdns]; nrdns++)
120 		len += strlen(rdns[nrdns]) + 1;
121 	if (len == 0)
122 		len = strlen(rdns[0]);
123 	pdn = (char *)malloc(len + 1);
124 	if (pdn == NULL) {
125 		ldap_value_free(rdns);
126 		return (NULL);
127 	}
128 
129 	*pdn = '\0';
130 	if (nrdns == 1)
131 		(void) strcat(pdn, rdns[0]);
132 	else {
133 		for (nrdns = 1; rdns[nrdns]; nrdns++) {
134 			(void) strcat(pdn, rdns[nrdns]);
135 			(void) strcat(pdn, ",");
136 		}
137 		/* remove the last ',' */
138 		pdn[strlen(pdn) - 1] = '\0';
139 	}
140 	/* get domain name */
141 	(void) __ns_ldap_dn2domain(pdn, &domain, cred, &error);
142 
143 	ldap_value_free(rdns);
144 	free(pdn);
145 	return (domain);
146 }
147 
148 
149 /*
150  * 	"109.34.54.76" -> 109.34.54.76
151  */
152 
153 const char *
154 _strip_quotes(char *ipaddress)
155 {
156 	char	*cp = (char *)NULL;
157 
158 	/* look for first " */
159 	if ((cp = strchr(ipaddress, '"')) == NULL)
160 		return ((char *)ipaddress);
161 	ipaddress++;
162 	/* look for last " */
163 	if ((cp = strchr(ipaddress, '"')) == NULL)
164 		return ((char *)ipaddress);
165 	*cp++ = '\0';
166 
167 	return (ipaddress);
168 }
169 
170 
171 /*
172  * This is a copy of a routine in libnsl/nss/netdir_inet.c.  It is
173  * here because /etc/lib/nss_ldap.so.1 cannot call routines in
174  * libnsl.  Care should be taken to keep the two copies in sync.
175  */
176 
177 int
178 __nss2herrno(nss_status_t nsstat)
179 {
180 	switch (nsstat) {
181 		case NSS_SUCCESS:
182 			return (0);
183 		case NSS_NOTFOUND:
184 			return (HOST_NOT_FOUND);
185 		case NSS_TRYAGAIN:
186 			return (TRY_AGAIN);
187 		case NSS_UNAVAIL:
188 		default:	/* keep gcc happy */
189 			return (NO_RECOVERY);
190 	}
191 	/* NOTREACHED */
192 }
193 
194 /*
195  * This is a generic filter call back function for
196  * merging the filter from service search descriptor with
197  * an existing search filter. This routine expects userdata
198  * contain a format string with a single %s in it, and will
199  * use the format string with sprintf() to insert the SSD filter.
200  *
201  * This routine is passed to the __ns_ldap_list() or
202  * __ns_ldap_firstEntry() APIs as the filter call back
203  * together with the userdata. For example,
204  * the gethostbyname processing may call __ns_ldap_list() with
205  * "(&(objectClass=ipHost)(cn=sys1))" as filter, this function
206  * as the filter call back, and "(&(%s)(cn=sys1))" as the
207  * userdata, this routine will in turn gets call to produce
208  * "(&(department=sds)(cn=sys1))" as the real search
209  * filter, if the input SSD contains a filter "department=sds".
210  */
211 int
212 _merge_SSD_filter(const ns_ldap_search_desc_t *desc,
213 			char **realfilter,
214 			const void *userdata)
215 {
216 	int	len;
217 	char *checker;
218 
219 #ifdef DEBUG
220 	(void) fprintf(stdout, "\n[ldap_utils.c: _merge_SSD_filter]\n");
221 #endif /* DEBUG */
222 
223 	/* sanity check */
224 	if (realfilter == NULL)
225 		return (NS_LDAP_INVALID_PARAM);
226 	*realfilter = NULL;
227 
228 	if (desc == NULL || desc->filter == NULL || userdata == NULL)
229 		return (NS_LDAP_INVALID_PARAM);
230 
231 	/* Parameter check.  We only want one %s here, otherwise bail. */
232 	len = 0;	/* Reuse 'len' as "Number of %s hits"... */
233 	checker = (char *)userdata;
234 	do {
235 		checker = strchr(checker, '%');
236 		if (checker != NULL) {
237 			if (len > 0 || *(checker + 1) != 's')
238 				return (NS_LDAP_INVALID_PARAM);
239 			len++;	/* Got our %s. */
240 			checker += 2;
241 		} else if (len != 1)
242 			return (NS_LDAP_INVALID_PARAM);
243 	} while (checker != NULL);
244 
245 #ifdef DEBUG
246 	(void) fprintf(stdout, "\n[userdata: %s]\n", (char *)userdata);
247 	(void) fprintf(stdout, "\n[SSD filter: %s]\n", desc->filter);
248 #endif /* DEBUG */
249 
250 	len = strlen(userdata) + strlen(desc->filter) + 1;
251 
252 	*realfilter = (char *)malloc(len);
253 	if (*realfilter == NULL)
254 		return (NS_LDAP_MEMORY);
255 
256 	(void) sprintf(*realfilter, (char *)userdata, desc->filter);
257 
258 #ifdef DEBUG
259 	(void) fprintf(stdout, "\n[new filter: %s]\n", *realfilter);
260 #endif /* DEBUG */
261 
262 	return (NS_LDAP_SUCCESS);
263 }
264 
265 static char
266 hex_char(int n)
267 {
268 	return ("0123456789abcdef"[n & 0xf]);
269 }
270 
271 int
272 _ldap_filter_name(char *filter_name, const char *name, int filter_name_size)
273 {
274 	char *end = filter_name + filter_name_size;
275 	char c;
276 
277 	for (; *name; name++) {
278 		c = *name;
279 		switch (c) {
280 			case '*':
281 			case '(':
282 			case ')':
283 			case '\\':
284 				if (end <= filter_name + 3)
285 					return (-1);
286 				*filter_name++ = '\\';
287 				*filter_name++ = hex_char(c >> 4);
288 				*filter_name++ = hex_char(c & 0xf);
289 				break;
290 			default:
291 				if (end <= filter_name + 1)
292 					return (-1);
293 				*filter_name++ = c;
294 				break;
295 		}
296 	}
297 	if (end <= filter_name)
298 		return (-1);
299 	*filter_name = '\0';
300 	return (0);
301 }
302