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
16static 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
51int	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
62extern 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
74LDAP *
75ldap_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 */
117int
118open_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
149static pthread_mutex_t ldap_thr_index_mutex = {0};
150static pthread_t ldap_thr_table[MAX_THREAD_ID] = {0};
151
152int
153ldap_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 */
190LDAP *
191ldap_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 */
251int
252open_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
340int
341establish_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
380LDAP *
381ldap_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
410LDAP *
411ldap_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