xref: /onnv-gate/usr/src/lib/libldap4/common/open.c (revision 0:68f95e015346)
1 /*
2  * Copyright (c) 1995-2001 by Sun Microsystems, Inc.
3  * All rights reserved.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  *  Copyright (c) 1995 Regents of the University of Michigan.
10  *  All rights reserved.
11  *
12  *  open.c
13  */
14 
15 #ifndef	lint
16 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the "
17 	"University of Michigan.\nAll rights reserved.\n";
18 #endif
19 
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h> /* calloc(), free(), atoi() for Solaris */
23 #include <locale.h>
24 #include <thread.h>
25 
26 #ifdef MACOS
27 #include <stdlib.h>
28 #include "macos.h"
29 #endif /* MACOS */
30 
31 #if defined(DOS) || defined(_WIN32)
32 #include "msdos.h"
33 #include <stdlib.h>
34 #endif /* DOS */
35 
36 #if !defined(MACOS) && !defined(DOS) && !defined(_WIN32)
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #ifndef VMS
41 #include <sys/param.h>
42 #endif
43 #include <netinet/in.h>
44 #endif
45 #include "lber.h"
46 #include "ldap.h"
47 #include "ldap-private.h"
48 #include "ldap-int.h"
49 
50 #ifdef LDAP_DEBUG
51 int	ldap_debug;
52 #endif
53 
54 #ifndef INADDR_LOOPBACK
55 #define	INADDR_LOOPBACK	((unsigned int) 0x7f000001)
56 #endif
57 
58 #ifndef MAXHOSTNAMELEN
59 #define	MAXHOSTNAMELEN  64
60 #endif
61 
62 extern int thr_kill(thread_t, int);
63 
64 /*
65  * ldap_open - initialize and connect to an ldap server.  A magic cookie to
66  * be used for future communication is returned on success, NULL on failure.
67  * "host" may be a space-separated list of hosts or IP addresses
68  *
69  * Example:
70  *	LDAP	*ld;
71  *	ld = ldap_open( hostname, port );
72  */
73 
74 LDAP *
ldap_open(char * host,int port)75 ldap_open(char *host, int port)
76 {
77 	LDAP		*ld;
78 	int err;
79 
80 	if ((ld = ldap_init(host, port)) == NULL) {
81 		return (NULL);
82 	}
83 
84 	Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 113,
85 		"ldap_open (after ldap_init)\n"), 0, 0, 0);
86 
87 #ifdef _REENTRANT
88 	LOCK_LDAP(ld);
89 #endif
90 	if ((err = open_default_ldap_connection(ld)) != LDAP_SUCCESS) {
91 #ifdef _REENTRANT
92 	UNLOCK_LDAP(ld);
93 #endif
94 		ldap_ld_free(ld, 0);
95 		Debug(LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1275,
96 			"ldap_open failed, %s\n"),
97 			ldap_err2string(err), 0, 0);
98 		return (NULL);
99 	}
100 
101 	Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 194,
102 		"ldap_open successful, ld_host is %s\n"),
103 		(ld->ld_host == NULL) ? "(null)" : ld->ld_host, 0, 0);
104 #ifdef _REENTRANT
105 	UNLOCK_LDAP(ld);
106 #endif
107 	return (ld);
108 
109 }
110 
111 /*
112  * Open the default connection
113  * ld->ld_defconn MUST be null when calling this function,
114  * ie the connection was never established
115  * ld should be LOCKed before calling this function
116  */
117 int
open_default_ldap_connection(LDAP * ld)118 open_default_ldap_connection(LDAP *ld)
119 {
120 	LDAPServer	*srv;
121 	int err;
122 
123 	if ((srv = (LDAPServer *)calloc(1, sizeof (LDAPServer))) ==
124 	    NULL || (ld->ld_defhost != NULL && (srv->lsrv_host =
125 	    strdup(ld->ld_defhost)) == NULL)) {
126 		return (LDAP_NO_MEMORY);
127 	}
128 	srv->lsrv_port = ld->ld_defport;
129 
130 	if ((ld->ld_defconn = new_connection(ld, &srv, 1, 1, 0)) ==
131 		NULL) {
132 		err = ld->ld_errno;
133 		Debug(LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1276,
134 		"Default connection to ldap server %s couldn't be "
135 		"opened (%d)\n"), ld->ld_defhost, err, 0);
136 
137 		if (ld->ld_defhost != NULL)
138 			free(srv->lsrv_host);
139 		free((char *)srv);
140 		return (err);
141 	}
142 
143 	/* so it never gets closed/freed */
144 	++ld->ld_defconn->lconn_refcnt;
145 
146 	return (LDAP_SUCCESS);
147 }
148 
149 static pthread_mutex_t ldap_thr_index_mutex = {0};
150 static pthread_t ldap_thr_table[MAX_THREAD_ID] = {0};
151 
152 int
ldap_thr_index()153 ldap_thr_index()
154 {
155 	int i = 0;
156 	int free = 0;
157 	pthread_t cur = thr_self();
158 	for (i = 1; i < MAX_THREAD_ID; ++i) {
159 		if (ldap_thr_table[i] == cur) {
160 			return (i);
161 		} /* end if */
162 	} /* end for */
163 	/*
164 	 * not in the table, allocate a new entry
165 	 */
166 	pthread_mutex_lock(&ldap_thr_index_mutex);
167 	for (i = 1; i < MAX_THREAD_ID; ++i) {
168 		if (ldap_thr_table[i] == 0 ||
169 			thr_kill(ldap_thr_table[i], 0) != 0) {
170 			ldap_thr_table[i] = cur;
171 			pthread_mutex_unlock(&ldap_thr_index_mutex);
172 			return (i);
173 		} /* end if */
174 	} /* end for */
175 	pthread_mutex_unlock(&ldap_thr_index_mutex);
176 	/* if table is full, return the first entry, so that it */
177 	/* doesn't core dump */
178 	return (0);
179 }
180 
181 /*
182  * ldap_init - initialize the LDAP library.  A magic cookie to be used for
183  * future communication is returned on success, NULL on failure.
184  * "defhost" may be a space-separated list of hosts or IP addresses
185  *
186  * Example:
187  *	LDAP	*ld;
188  *	ld = ldap_init( default_hostname, default_port );
189  */
190 LDAP *
ldap_init(char * defhost,int defport)191 ldap_init(char *defhost, int defport)
192 {
193 	LDAP			*ld;
194 	char *locale;
195 
196 	locale = setlocale(LC_ALL, "");
197 	i18n_catopen("sdserver");
198 
199 	Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 195,
200 		"ldap_init\n"), 0, 0, 0);
201 
202 
203 	if ((ld = (LDAP *) calloc(1, sizeof (LDAP))) == NULL) {
204 		return (NULL);
205 	}
206 
207 #ifdef _REENTRANT
208 	pthread_mutex_init(&ld->ld_ldap_mutex, DEFAULT_TYPE);
209 	pthread_mutex_init(&ld->ld_response_mutex, DEFAULT_TYPE);
210 	pthread_mutex_init(&ld->ld_poll_mutex, DEFAULT_TYPE);
211 	ld->ld_lockthread = 0;
212 #endif
213 
214 	if ((ld->ld_selectinfo = new_select_info()) == NULL) {
215 		free((char *)ld);
216 		return (NULL);
217 	}
218 	ld->ld_follow_referral = 1;
219 
220 	/*
221 	 * default to localhost when hostname is not specified
222 	 * or if null string is passed as hostname
223 	 */
224 
225 	if ((defhost != NULL) && (*defhost != NULL) &&
226 		(ld->ld_defhost = strdup(defhost)) == NULL) {
227 		free_select_info(ld->ld_selectinfo);
228 		free((char *)ld);
229 		return (NULL);
230 	}
231 
232 	ld->ld_defport = (defport == 0) ? LDAP_PORT : defport;
233 	ld->ld_version = LDAP_VERSION;
234 	ld->ld_lberoptions = LBER_USE_DER;
235 	ld->ld_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
236 	ld->ld_connect_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
237 
238 #if defined(STR_TRANSLATION) && defined(LDAP_DEFAULT_CHARSET)
239 	ld->ld_lberoptions |= LBER_TRANSLATE_STRINGS;
240 #if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
241 	ldap_set_string_translators(ld, ldap_8859_to_t61,
242 		ldap_t61_to_8859);
243 #endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
244 #endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
245 
246 	return (ld);
247 }
248 
249 
250 /* ARGSUSED */
251 int
open_ldap_connection(LDAP * ld,Sockbuf * sb,char * host,int defport,char ** krbinstancep,int async)252 open_ldap_connection(LDAP *ld, Sockbuf *sb, char *host, int defport,
253 	char **krbinstancep, int async)
254 {
255 	int 			rc, port;
256 	char			*p, *q, *r;
257 	char			*curhost, hostname[ 2*MAXHOSTNAMELEN ];
258 	int			bindTimeout;
259 
260 	Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 196,
261 		"open_ldap_connection\n"), 0, 0, 0);
262 
263 	defport = htons(defport);
264 	bindTimeout = ld->ld_connect_timeout;
265 
266 	if (host != NULL) {
267 		for (p = host; p != NULL && *p != '\0'; p = q) {
268 			if ((q = strchr(p, ' ')) != NULL) {
269 				(void) strncpy(hostname, p, q - p);
270 				hostname[ q - p ] = '\0';
271 				curhost = hostname;
272 				while (*q == ' ') {
273 					++q;
274 				}
275 			} else {
276 				/* avoid copy if possible */
277 				curhost = p;
278 				q = NULL;
279 			}
280 
281 			if ((r = strchr(curhost, ':')) != NULL) {
282 			    if (curhost != hostname) {
283 				/* now copy */
284 				(void) strcpy(hostname, curhost);
285 				r = hostname + (r - curhost);
286 				curhost = hostname;
287 			    }
288 			    *r++ = '\0';
289 			    port = htons((short)atoi(r));
290 			} else {
291 			    port = defport;
292 			}
293 
294 			if ((rc = connect_to_host(sb, curhost, 0,
295 			    port, async, bindTimeout)) != -1) {
296 				break;
297 			}
298 		}
299 	} else {
300 		rc = connect_to_host(sb, NULL, htonl(INADDR_LOOPBACK),
301 			defport, async, bindTimeout);
302 	}
303 
304 	if (rc == -1) {
305 		return (rc);
306 	}
307 
308 	if (krbinstancep != NULL) {
309 #ifdef KERBEROS
310 		if ((*krbinstancep = host_connected_to(sb)) != NULL &&
311 			(p = strchr(*krbinstancep, '.')) != NULL) {
312 			*p = '\0';
313 		}
314 #else /* KERBEROS */
315 		krbinstancep = NULL;
316 #endif /* KERBEROS */
317 	}
318 
319 	return (0);
320 }
321 
322 /*
323  * ldap_ssl_open - initialize and connect to an ssl secured ldap
324  * server.  First ldap_open() is called and then ssl is layered on top
325  * of the socket.  A magic cookie to be used for future communication
326  * is returned on success, NULL on failure.  "host" may be a
327  * space-separated list of hosts or IP addresses.  CAfile and CApath
328  * are used first time through, subsequent calls are ignored and can
329  * be NULL.
330  *
331  * Example:
332  *	LDAP	*ld;
333  * ld = ldap_ssl_open( hostname, port, key );
334  */
335 
336 #ifdef LDAP_SSL
337 
338 #include "security/ssl.h"
339 
340 int
establish_ssl_connection(LDAP * ld)341 establish_ssl_connection(LDAP *ld)
342 {
343 	SSL *ssl = NULL;	/* The Client's SSL connection */
344 
345 	/*
346 	 * Creates a new SSL connection.  This holds information
347 	 * pertinent to this
348 	 * connection.
349 	 */
350 	if ((ssl = SSL_new()) == NULL) {
351 		Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 198,
352 			"SSL_new() failed: %s\n"),
353 			SSL_strerr(SSL_errno(ssl)), 0, 0);
354 		return (-1);
355 	}
356 
357 	/* if keyname is non-null, set ssl keypackage name from it */
358 	if (ld->ld_ssl_key != NULL) {
359 		if (SSL_set_userid(ssl, ld->ld_ssl_key, 0) == NULL) {
360 			Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1,
361 				199, "SSL_set_userid() failed: %s\n"),
362 				SSL_strerr(SSL_errno(ssl)), 0, 0);
363 			return (-1);
364 		}
365 	}
366 
367 	/* Start the SSL connection */
368 	if (SSL_connect(ssl, ld->ld_sb.sb_sd) < 1) {
369 		Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 200,
370 			"SSL_connect() failed: %s\n"),
371 			SSL_strerr(SSL_errno(ssl)), 0, 0);
372 		return (-1);
373 	}
374 
375 	ld->ld_sb.sb_ssl = ssl;
376 	return (0);
377 }
378 
379 
380 LDAP *
ldap_ssl_open(char * host,int port,char * keyname)381 ldap_ssl_open(char *host, int port, char *keyname)
382 {
383 	LDAP		*ld;
384 	int rval;
385 
386 
387 	if (port == 0)
388 		port = SSL_LDAP_PORT;
389 
390 	ld = ldap_open(host, port);
391 
392 	Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 197,
393 		"ldap_ssl_open (after ldap_open)\n"), 0, 0, 0);
394 
395 	if (ld == NULL)
396 		return (NULL);
397 
398 	ld->ld_use_ssl = 1;
399 	if (keyname)
400 		ld->ld_ssl_key = strdup(keyname);
401 
402 	if (establish_ssl_connection(ld) != 0) {
403 		ldap_ld_free(ld, 1);
404 		return (NULL);
405 	}
406 
407 	return (ld);
408 }
409 
410 LDAP *
ldap_ssl_init(char * defhost,int defport,char * keyname)411 ldap_ssl_init(char *defhost, int defport, char *keyname)
412 {
413 	LDAP		*ld;
414 	int rval;
415 
416 
417 	if (defport == 0)
418 		defport = SSL_LDAP_PORT;
419 
420 	ld = ldap_init(defhost, defport);
421 
422 	Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 197,
423 		"ldap_ssl_open (after ldap_open)\n"), 0, 0, 0);
424 
425 	if (ld == NULL)
426 		return (NULL);
427 	ld->ld_use_ssl = 1;
428 	ld->ld_ssl_key = strdup(keyname);
429 
430 	return (ld);
431 }
432 
433 #endif /* LDAP_SSL */
434