/*
* Copyright (c) 1995-2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 1995 Regents of the University of Michigan.
* All rights reserved.
*
* open.c
*/
#ifndef lint
static char copyright[] = "@(#) Copyright (c) 1995 Regents of the "
"University of Michigan.\nAll rights reserved.\n";
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h> /* calloc(), free(), atoi() for Solaris */
#include <locale.h>
#include <thread.h>
#ifdef MACOS
#include <stdlib.h>
#include "macos.h"
#endif /* MACOS */
#if defined(DOS) || defined(_WIN32)
#include "msdos.h"
#include <stdlib.h>
#endif /* DOS */
#if !defined(MACOS) && !defined(DOS) && !defined(_WIN32)
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifndef VMS
#include <sys/param.h>
#endif
#include <netinet/in.h>
#endif
#include "lber.h"
#include "ldap.h"
#include "ldap-private.h"
#include "ldap-int.h"
#ifdef LDAP_DEBUG
int ldap_debug;
#endif
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK ((unsigned int) 0x7f000001)
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
extern int thr_kill(thread_t, int);
/*
* ldap_open - initialize and connect to an ldap server. A magic cookie to
* be used for future communication is returned on success, NULL on failure.
* "host" may be a space-separated list of hosts or IP addresses
*
* Example:
* LDAP *ld;
* ld = ldap_open( hostname, port );
*/
LDAP *
ldap_open(char *host, int port)
{
LDAP *ld;
int err;
if ((ld = ldap_init(host, port)) == NULL) {
return (NULL);
}
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 113,
"ldap_open (after ldap_init)\n"), 0, 0, 0);
#ifdef _REENTRANT
LOCK_LDAP(ld);
#endif
if ((err = open_default_ldap_connection(ld)) != LDAP_SUCCESS) {
#ifdef _REENTRANT
UNLOCK_LDAP(ld);
#endif
ldap_ld_free(ld, 0);
Debug(LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1275,
"ldap_open failed, %s\n"),
ldap_err2string(err), 0, 0);
return (NULL);
}
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 194,
"ldap_open successful, ld_host is %s\n"),
(ld->ld_host == NULL) ? "(null)" : ld->ld_host, 0, 0);
#ifdef _REENTRANT
UNLOCK_LDAP(ld);
#endif
return (ld);
}
/*
* Open the default connection
* ld->ld_defconn MUST be null when calling this function,
* ie the connection was never established
* ld should be LOCKed before calling this function
*/
int
open_default_ldap_connection(LDAP *ld)
{
LDAPServer *srv;
int err;
if ((srv = (LDAPServer *)calloc(1, sizeof (LDAPServer))) ==
NULL || (ld->ld_defhost != NULL && (srv->lsrv_host =
strdup(ld->ld_defhost)) == NULL)) {
return (LDAP_NO_MEMORY);
}
srv->lsrv_port = ld->ld_defport;
if ((ld->ld_defconn = new_connection(ld, &srv, 1, 1, 0)) ==
NULL) {
err = ld->ld_errno;
Debug(LDAP_DEBUG_ANY, catgets(slapdcat, 1, 1276,
"Default connection to ldap server %s couldn't be "
"opened (%d)\n"), ld->ld_defhost, err, 0);
if (ld->ld_defhost != NULL)
free(srv->lsrv_host);
free((char *)srv);
return (err);
}
/* so it never gets closed/freed */
++ld->ld_defconn->lconn_refcnt;
return (LDAP_SUCCESS);
}
static pthread_mutex_t ldap_thr_index_mutex = {0};
static pthread_t ldap_thr_table[MAX_THREAD_ID] = {0};
int
ldap_thr_index()
{
int i = 0;
int free = 0;
pthread_t cur = thr_self();
for (i = 1; i < MAX_THREAD_ID; ++i) {
if (ldap_thr_table[i] == cur) {
return (i);
} /* end if */
} /* end for */
/*
* not in the table, allocate a new entry
*/
pthread_mutex_lock(&ldap_thr_index_mutex);
for (i = 1; i < MAX_THREAD_ID; ++i) {
if (ldap_thr_table[i] == 0 ||
thr_kill(ldap_thr_table[i], 0) != 0) {
ldap_thr_table[i] = cur;
pthread_mutex_unlock(&ldap_thr_index_mutex);
return (i);
} /* end if */
} /* end for */
pthread_mutex_unlock(&ldap_thr_index_mutex);
/* if table is full, return the first entry, so that it */
/* doesn't core dump */
return (0);
}
/*
* ldap_init - initialize the LDAP library. A magic cookie to be used for
* future communication is returned on success, NULL on failure.
* "defhost" may be a space-separated list of hosts or IP addresses
*
* Example:
* LDAP *ld;
* ld = ldap_init( default_hostname, default_port );
*/
LDAP *
ldap_init(char *defhost, int defport)
{
LDAP *ld;
char *locale;
locale = setlocale(LC_ALL, "");
i18n_catopen("sdserver");
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 195,
"ldap_init\n"), 0, 0, 0);
if ((ld = (LDAP *) calloc(1, sizeof (LDAP))) == NULL) {
return (NULL);
}
#ifdef _REENTRANT
pthread_mutex_init(&ld->ld_ldap_mutex, DEFAULT_TYPE);
pthread_mutex_init(&ld->ld_response_mutex, DEFAULT_TYPE);
pthread_mutex_init(&ld->ld_poll_mutex, DEFAULT_TYPE);
ld->ld_lockthread = 0;
#endif
if ((ld->ld_selectinfo = new_select_info()) == NULL) {
free((char *)ld);
return (NULL);
}
ld->ld_follow_referral = 1;
/*
* default to localhost when hostname is not specified
* or if null string is passed as hostname
*/
if ((defhost != NULL) && (*defhost != NULL) &&
(ld->ld_defhost = strdup(defhost)) == NULL) {
free_select_info(ld->ld_selectinfo);
free((char *)ld);
return (NULL);
}
ld->ld_defport = (defport == 0) ? LDAP_PORT : defport;
ld->ld_version = LDAP_VERSION;
ld->ld_lberoptions = LBER_USE_DER;
ld->ld_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
ld->ld_connect_timeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
#if defined(STR_TRANSLATION) && defined(LDAP_DEFAULT_CHARSET)
ld->ld_lberoptions |= LBER_TRANSLATE_STRINGS;
#if LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET
ldap_set_string_translators(ld, ldap_8859_to_t61,
ldap_t61_to_8859);
#endif /* LDAP_CHARSET_8859 == LDAP_DEFAULT_CHARSET */
#endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
return (ld);
}
/* ARGSUSED */
int
open_ldap_connection(LDAP *ld, Sockbuf *sb, char *host, int defport,
char **krbinstancep, int async)
{
int rc, port;
char *p, *q, *r;
char *curhost, hostname[ 2*MAXHOSTNAMELEN ];
int bindTimeout;
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 196,
"open_ldap_connection\n"), 0, 0, 0);
defport = htons(defport);
bindTimeout = ld->ld_connect_timeout;
if (host != NULL) {
for (p = host; p != NULL && *p != '\0'; p = q) {
if ((q = strchr(p, ' ')) != NULL) {
(void) strncpy(hostname, p, q - p);
hostname[ q - p ] = '\0';
curhost = hostname;
while (*q == ' ') {
++q;
}
} else {
/* avoid copy if possible */
curhost = p;
q = NULL;
}
if ((r = strchr(curhost, ':')) != NULL) {
if (curhost != hostname) {
/* now copy */
(void) strcpy(hostname, curhost);
r = hostname + (r - curhost);
curhost = hostname;
}
*r++ = '\0';
port = htons((short)atoi(r));
} else {
port = defport;
}
if ((rc = connect_to_host(sb, curhost, 0,
port, async, bindTimeout)) != -1) {
break;
}
}
} else {
rc = connect_to_host(sb, NULL, htonl(INADDR_LOOPBACK),
defport, async, bindTimeout);
}
if (rc == -1) {
return (rc);
}
if (krbinstancep != NULL) {
#ifdef KERBEROS
if ((*krbinstancep = host_connected_to(sb)) != NULL &&
(p = strchr(*krbinstancep, '.')) != NULL) {
*p = '\0';
}
#else /* KERBEROS */
krbinstancep = NULL;
#endif /* KERBEROS */
}
return (0);
}
/*
* ldap_ssl_open - initialize and connect to an ssl secured ldap
* server. First ldap_open() is called and then ssl is layered on top
* of the socket. A magic cookie to be used for future communication
* is returned on success, NULL on failure. "host" may be a
* space-separated list of hosts or IP addresses. CAfile and CApath
* are used first time through, subsequent calls are ignored and can
* be NULL.
*
* Example:
* LDAP *ld;
* ld = ldap_ssl_open( hostname, port, key );
*/
#ifdef LDAP_SSL
#include "security/ssl.h"
int
establish_ssl_connection(LDAP *ld)
{
SSL *ssl = NULL; /* The Client's SSL connection */
/*
* Creates a new SSL connection. This holds information
* pertinent to this
* connection.
*/
if ((ssl = SSL_new()) == NULL) {
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 198,
"SSL_new() failed: %s\n"),
SSL_strerr(SSL_errno(ssl)), 0, 0);
return (-1);
}
/* if keyname is non-null, set ssl keypackage name from it */
if (ld->ld_ssl_key != NULL) {
if (SSL_set_userid(ssl, ld->ld_ssl_key, 0) == NULL) {
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1,
199, "SSL_set_userid() failed: %s\n"),
SSL_strerr(SSL_errno(ssl)), 0, 0);
return (-1);
}
}
/* Start the SSL connection */
if (SSL_connect(ssl, ld->ld_sb.sb_sd) < 1) {
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 200,
"SSL_connect() failed: %s\n"),
SSL_strerr(SSL_errno(ssl)), 0, 0);
return (-1);
}
ld->ld_sb.sb_ssl = ssl;
return (0);
}
LDAP *
ldap_ssl_open(char *host, int port, char *keyname)
{
LDAP *ld;
int rval;
if (port == 0)
port = SSL_LDAP_PORT;
ld = ldap_open(host, port);
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 197,
"ldap_ssl_open (after ldap_open)\n"), 0, 0, 0);
if (ld == NULL)
return (NULL);
ld->ld_use_ssl = 1;
if (keyname)
ld->ld_ssl_key = strdup(keyname);
if (establish_ssl_connection(ld) != 0) {
ldap_ld_free(ld, 1);
return (NULL);
}
return (ld);
}
LDAP *
ldap_ssl_init(char *defhost, int defport, char *keyname)
{
LDAP *ld;
int rval;
if (defport == 0)
defport = SSL_LDAP_PORT;
ld = ldap_init(defhost, defport);
Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 197,
"ldap_ssl_open (after ldap_open)\n"), 0, 0, 0);
if (ld == NULL)
return (NULL);
ld->ld_use_ssl = 1;
ld->ld_ssl_key = strdup(keyname);
return (ld);
}
#endif /* LDAP_SSL */