xref: /titanic_44/usr/src/lib/nsswitch/ldap/common/ldap_utils.c (revision 7d14b8f218dc86a431d15e352b4bf15fbb1b3596)
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