summaryrefslogtreecommitdiffstats
path: root/libraries/libldap/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/libldap/open.c')
-rw-r--r--libraries/libldap/open.c611
1 files changed, 611 insertions, 0 deletions
diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c
new file mode 100644
index 0000000..5882b63
--- /dev/null
+++ b/libraries/libldap/open.c
@@ -0,0 +1,611 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2021 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* Portions Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <ac/stdlib.h>
+
+#include <ac/param.h>
+#include <ac/socket.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+#include <ac/unistd.h>
+
+#include "ldap-int.h"
+#include "ldap.h"
+#include "ldap_log.h"
+
+/* Caller must hold the conn_mutex since simultaneous accesses are possible */
+int ldap_open_defconn( LDAP *ld )
+{
+ ld->ld_defconn = ldap_new_connection( ld,
+ &ld->ld_options.ldo_defludp, 1, 1, NULL, 0, 0 );
+
+ if( ld->ld_defconn == NULL ) {
+ ld->ld_errno = LDAP_SERVER_DOWN;
+ return -1;
+ }
+
+ ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */
+ return 0;
+}
+
+/*
+ * 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( LDAP_CONST char *host, int port )
+{
+ int rc;
+ LDAP *ld;
+
+ Debug( LDAP_DEBUG_TRACE, "ldap_open(%s, %d)\n",
+ host, port, 0 );
+
+ ld = ldap_init( host, port );
+ if ( ld == NULL ) {
+ return( NULL );
+ }
+
+ LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
+ rc = ldap_open_defconn( ld );
+ LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
+
+ if( rc < 0 ) {
+ ldap_ld_free( ld, 0, NULL, NULL );
+ ld = NULL;
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "ldap_open: %s\n",
+ ld != NULL ? "succeeded" : "failed", 0, 0 );
+
+ return ld;
+}
+
+
+
+int
+ldap_create( LDAP **ldp )
+{
+ LDAP *ld;
+ struct ldapoptions *gopts;
+
+ *ldp = NULL;
+ /* Get pointer to global option structure */
+ if ( (gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
+ return LDAP_NO_MEMORY;
+ }
+
+ /* Initialize the global options, if not already done. */
+ if( gopts->ldo_valid != LDAP_INITIALIZED ) {
+ ldap_int_initialize(gopts, NULL);
+ if ( gopts->ldo_valid != LDAP_INITIALIZED )
+ return LDAP_LOCAL_ERROR;
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "ldap_create\n", 0, 0, 0 );
+
+ if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
+ return( LDAP_NO_MEMORY );
+ }
+
+ if ( (ld->ldc = (struct ldap_common *) LDAP_CALLOC( 1,
+ sizeof(struct ldap_common) )) == NULL ) {
+ LDAP_FREE( (char *)ld );
+ return( LDAP_NO_MEMORY );
+ }
+ /* copy the global options */
+ LDAP_MUTEX_LOCK( &gopts->ldo_mutex );
+ AC_MEMCPY(&ld->ld_options, gopts, sizeof(ld->ld_options));
+#ifdef LDAP_R_COMPILE
+ /* Properly initialize the structs mutex */
+ ldap_pvt_thread_mutex_init( &(ld->ld_ldopts_mutex) );
+#endif
+ LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex );
+
+ ld->ld_valid = LDAP_VALID_SESSION;
+
+ /* but not pointers to malloc'ed items */
+ ld->ld_options.ldo_sctrls = NULL;
+ ld->ld_options.ldo_cctrls = NULL;
+ ld->ld_options.ldo_defludp = NULL;
+ ld->ld_options.ldo_conn_cbs = NULL;
+
+#ifdef HAVE_CYRUS_SASL
+ ld->ld_options.ldo_def_sasl_mech = gopts->ldo_def_sasl_mech
+ ? LDAP_STRDUP( gopts->ldo_def_sasl_mech ) : NULL;
+ ld->ld_options.ldo_def_sasl_realm = gopts->ldo_def_sasl_realm
+ ? LDAP_STRDUP( gopts->ldo_def_sasl_realm ) : NULL;
+ ld->ld_options.ldo_def_sasl_authcid = gopts->ldo_def_sasl_authcid
+ ? LDAP_STRDUP( gopts->ldo_def_sasl_authcid ) : NULL;
+ ld->ld_options.ldo_def_sasl_authzid = gopts->ldo_def_sasl_authzid
+ ? LDAP_STRDUP( gopts->ldo_def_sasl_authzid ) : NULL;
+#endif
+
+#ifdef HAVE_TLS
+ /* We explicitly inherit the SSL_CTX, don't need the names/paths. Leave
+ * them empty to allow new SSL_CTX's to be created from scratch.
+ */
+ memset( &ld->ld_options.ldo_tls_info, 0,
+ sizeof( ld->ld_options.ldo_tls_info ));
+ ld->ld_options.ldo_tls_ctx = NULL;
+#endif
+
+ if ( gopts->ldo_defludp ) {
+ ld->ld_options.ldo_defludp = ldap_url_duplist(gopts->ldo_defludp);
+
+ if ( ld->ld_options.ldo_defludp == NULL ) goto nomem;
+ }
+
+ if (( ld->ld_selectinfo = ldap_new_select_info()) == NULL ) goto nomem;
+
+ ld->ld_lberoptions = LBER_USE_DER;
+
+ ld->ld_sb = ber_sockbuf_alloc( );
+ if ( ld->ld_sb == NULL ) goto nomem;
+
+#ifdef LDAP_R_COMPILE
+ ldap_pvt_thread_mutex_init( &ld->ld_msgid_mutex );
+ ldap_pvt_thread_mutex_init( &ld->ld_conn_mutex );
+ ldap_pvt_thread_mutex_init( &ld->ld_req_mutex );
+ ldap_pvt_thread_mutex_init( &ld->ld_res_mutex );
+ ldap_pvt_thread_mutex_init( &ld->ld_abandon_mutex );
+ ldap_pvt_thread_mutex_init( &ld->ld_ldcmutex );
+#endif
+ ld->ld_ldcrefcnt = 1;
+ *ldp = ld;
+ return LDAP_SUCCESS;
+
+nomem:
+ ldap_free_select_info( ld->ld_selectinfo );
+ ldap_free_urllist( ld->ld_options.ldo_defludp );
+#ifdef HAVE_CYRUS_SASL
+ LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid );
+ LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid );
+ LDAP_FREE( ld->ld_options.ldo_def_sasl_realm );
+ LDAP_FREE( ld->ld_options.ldo_def_sasl_mech );
+#endif
+ LDAP_FREE( (char *)ld );
+ return LDAP_NO_MEMORY;
+}
+
+/*
+ * ldap_init - initialize the LDAP library. 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_init( host, port );
+ */
+LDAP *
+ldap_init( LDAP_CONST char *defhost, int defport )
+{
+ LDAP *ld;
+ int rc;
+
+ rc = ldap_create(&ld);
+ if ( rc != LDAP_SUCCESS )
+ return NULL;
+
+ if (defport != 0)
+ ld->ld_options.ldo_defport = defport;
+
+ if (defhost != NULL) {
+ rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, defhost);
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_ld_free(ld, 1, NULL, NULL);
+ return NULL;
+ }
+ }
+
+ return( ld );
+}
+
+
+int
+ldap_initialize( LDAP **ldp, LDAP_CONST char *url )
+{
+ int rc;
+ LDAP *ld;
+
+ *ldp = NULL;
+ rc = ldap_create(&ld);
+ if ( rc != LDAP_SUCCESS )
+ return rc;
+
+ if (url != NULL) {
+ rc = ldap_set_option(ld, LDAP_OPT_URI, url);
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_ld_free(ld, 1, NULL, NULL);
+ return rc;
+ }
+#ifdef LDAP_CONNECTIONLESS
+ if (ldap_is_ldapc_url(url))
+ LDAP_IS_UDP(ld) = 1;
+#endif
+ }
+
+ *ldp = ld;
+ return LDAP_SUCCESS;
+}
+
+int
+ldap_init_fd(
+ ber_socket_t fd,
+ int proto,
+ LDAP_CONST char *url,
+ LDAP **ldp
+)
+{
+ int rc;
+ LDAP *ld;
+ LDAPConn *conn;
+#ifdef LDAP_CONNECTIONLESS
+ ber_socklen_t len;
+#endif
+
+ *ldp = NULL;
+ rc = ldap_create( &ld );
+ if( rc != LDAP_SUCCESS )
+ return( rc );
+
+ if (url != NULL) {
+ rc = ldap_set_option(ld, LDAP_OPT_URI, url);
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_ld_free(ld, 1, NULL, NULL);
+ return rc;
+ }
+ }
+
+ LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
+ /* Attach the passed socket as the LDAP's connection */
+ conn = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 );
+ if( conn == NULL ) {
+ ldap_unbind_ext( ld, NULL, NULL );
+ return( LDAP_NO_MEMORY );
+ }
+ if( url )
+ conn->lconn_server = ldap_url_dup( ld->ld_options.ldo_defludp );
+ ber_sockbuf_ctrl( conn->lconn_sb, LBER_SB_OPT_SET_FD, &fd );
+ ld->ld_defconn = conn;
+ ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */
+ LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
+
+ switch( proto ) {
+ case LDAP_PROTO_TCP:
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" );
+#endif
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+ break;
+
+#ifdef LDAP_CONNECTIONLESS
+ case LDAP_PROTO_UDP:
+ LDAP_IS_UDP(ld) = 1;
+ if( ld->ld_options.ldo_peer )
+ ldap_memfree( ld->ld_options.ldo_peer );
+ ld->ld_options.ldo_peer = ldap_memcalloc( 1, sizeof( struct sockaddr_storage ) );
+ len = sizeof( struct sockaddr_storage );
+ if( getpeername ( fd, ld->ld_options.ldo_peer, &len ) < 0) {
+ ldap_unbind_ext( ld, NULL, NULL );
+ return( AC_SOCKET_ERROR );
+ }
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" );
+#endif
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+ break;
+#endif /* LDAP_CONNECTIONLESS */
+
+ case LDAP_PROTO_IPC:
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
+#endif
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+ break;
+
+ case LDAP_PROTO_EXT:
+ /* caller must supply sockbuf handlers */
+ break;
+
+ default:
+ ldap_unbind_ext( ld, NULL, NULL );
+ return LDAP_PARAM_ERROR;
+ }
+
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
+ INT_MAX, (void *)"ldap_" );
+#endif
+
+ /* Add the connection to the *LDAP's select pool */
+ ldap_mark_select_read( ld, conn->lconn_sb );
+
+ *ldp = ld;
+ return LDAP_SUCCESS;
+}
+
+/* Protected by ld_conn_mutex */
+int
+ldap_int_open_connection(
+ LDAP *ld,
+ LDAPConn *conn,
+ LDAPURLDesc *srv,
+ int async )
+{
+ int rc = -1;
+ int proto;
+
+ Debug( LDAP_DEBUG_TRACE, "ldap_int_open_connection\n", 0, 0, 0 );
+
+ switch ( proto = ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) {
+ case LDAP_PROTO_TCP:
+ rc = ldap_connect_to_host( ld, conn->lconn_sb,
+ proto, srv, async );
+
+ if ( rc == -1 ) return rc;
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" );
+#endif
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+
+ break;
+
+#ifdef LDAP_CONNECTIONLESS
+ case LDAP_PROTO_UDP:
+ LDAP_IS_UDP(ld) = 1;
+ rc = ldap_connect_to_host( ld, conn->lconn_sb,
+ proto, srv, async );
+
+ if ( rc == -1 ) return rc;
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" );
+#endif
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+
+ break;
+#endif
+ case LDAP_PROTO_IPC:
+#ifdef LDAP_PF_LOCAL
+ /* only IPC mechanism supported is PF_LOCAL (PF_UNIX) */
+ rc = ldap_connect_to_path( ld, conn->lconn_sb,
+ srv, async );
+ if ( rc == -1 ) return rc;
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
+#endif
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+
+ break;
+#endif /* LDAP_PF_LOCAL */
+ default:
+ return -1;
+ break;
+ }
+
+ conn->lconn_created = time( NULL );
+
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
+ INT_MAX, (void *)"ldap_" );
+#endif
+
+#ifdef LDAP_CONNECTIONLESS
+ if( proto == LDAP_PROTO_UDP ) return 0;
+#endif
+
+#ifdef HAVE_TLS
+ if ((rc == 0 || rc == -2) && ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
+ strcmp( srv->lud_scheme, "ldaps" ) == 0 ))
+ {
+ ++conn->lconn_refcnt; /* avoid premature free */
+
+ rc = ldap_int_tls_start( ld, conn, srv );
+
+ --conn->lconn_refcnt;
+
+ if (rc != LDAP_SUCCESS) {
+ /* process connection callbacks */
+ {
+ struct ldapoptions *lo;
+ ldaplist *ll;
+ ldap_conncb *cb;
+
+ lo = &ld->ld_options;
+ LDAP_MUTEX_LOCK( &lo->ldo_mutex );
+ if ( lo->ldo_conn_cbs ) {
+ for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
+ cb = ll->ll_data;
+ cb->lc_del( ld, conn->lconn_sb, cb );
+ }
+ }
+ LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
+ lo = LDAP_INT_GLOBAL_OPT();
+ LDAP_MUTEX_LOCK( &lo->ldo_mutex );
+ if ( lo->ldo_conn_cbs ) {
+ for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
+ cb = ll->ll_data;
+ cb->lc_del( ld, conn->lconn_sb, cb );
+ }
+ }
+ LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
+ }
+ ber_int_sb_close( conn->lconn_sb );
+ return -1;
+ }
+ }
+#endif
+
+ return( 0 );
+}
+
+/*
+ * ldap_open_internal_connection - open connection and set file descriptor
+ *
+ * note: ldap_init_fd() may be preferable
+ */
+
+int
+ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp )
+{
+ int rc;
+ LDAPConn *c;
+ LDAPRequest *lr;
+ LDAP *ld;
+
+ rc = ldap_create( &ld );
+ if( rc != LDAP_SUCCESS ) {
+ *ldp = NULL;
+ return( rc );
+ }
+
+ /* Make it appear that a search request, msgid 0, was sent */
+ lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ));
+ if( lr == NULL ) {
+ ldap_unbind_ext( ld, NULL, NULL );
+ *ldp = NULL;
+ return( LDAP_NO_MEMORY );
+ }
+ memset(lr, 0, sizeof( LDAPRequest ));
+ lr->lr_msgid = 0;
+ lr->lr_status = LDAP_REQST_INPROGRESS;
+ lr->lr_res_errno = LDAP_SUCCESS;
+ /* no mutex lock needed, we just created this ld here */
+ ld->ld_requests = lr;
+
+ LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
+ /* Attach the passed socket as the *LDAP's connection */
+ c = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 );
+ if( c == NULL ) {
+ ldap_unbind_ext( ld, NULL, NULL );
+ *ldp = NULL;
+ LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
+ return( LDAP_NO_MEMORY );
+ }
+ ber_sockbuf_ctrl( c->lconn_sb, LBER_SB_OPT_SET_FD, fdp );
+#ifdef LDAP_DEBUG
+ ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_debug,
+ LBER_SBIOD_LEVEL_PROVIDER, (void *)"int_" );
+#endif
+ ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_tcp,
+ LBER_SBIOD_LEVEL_PROVIDER, NULL );
+ ld->ld_defconn = c;
+ LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
+
+ /* Add the connection to the *LDAP's select pool */
+ ldap_mark_select_read( ld, c->lconn_sb );
+
+ /* Make this connection an LDAP V3 protocol connection */
+ rc = LDAP_VERSION3;
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &rc );
+ *ldp = ld;
+
+ ++ld->ld_defconn->lconn_refcnt; /* so it never gets closed/freed */
+
+ return( LDAP_SUCCESS );
+}
+
+LDAP *
+ldap_dup( LDAP *old )
+{
+ LDAP *ld;
+
+ if ( old == NULL ) {
+ return( NULL );
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "ldap_dup\n", 0, 0, 0 );
+
+ if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
+ return( NULL );
+ }
+
+ LDAP_MUTEX_LOCK( &old->ld_ldcmutex );
+ ld->ldc = old->ldc;
+ old->ld_ldcrefcnt++;
+ LDAP_MUTEX_UNLOCK( &old->ld_ldcmutex );
+ return ( ld );
+}
+
+int
+ldap_int_check_async_open( LDAP *ld, ber_socket_t sd )
+{
+ struct timeval tv = { 0 };
+ int rc;
+
+ rc = ldap_int_poll( ld, sd, &tv, 1 );
+ switch ( rc ) {
+ case 0:
+ /* now ready to start tls */
+ ld->ld_defconn->lconn_status = LDAP_CONNST_CONNECTED;
+ break;
+
+ default:
+ ld->ld_errno = LDAP_CONNECT_ERROR;
+ return -1;
+
+ case -2:
+ /* connect not completed yet */
+ ld->ld_errno = LDAP_X_CONNECTING;
+ return rc;
+ }
+
+#ifdef HAVE_TLS
+ if ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
+ !strcmp( ld->ld_defconn->lconn_server->lud_scheme, "ldaps" )) {
+
+ ++ld->ld_defconn->lconn_refcnt; /* avoid premature free */
+
+ rc = ldap_int_tls_start( ld, ld->ld_defconn, ld->ld_defconn->lconn_server );
+
+ --ld->ld_defconn->lconn_refcnt;
+ }
+#endif
+ return rc;
+}