+void
+bindconf_tls_defaults( slap_bindconf *bc )
+{
+#ifdef HAVE_TLS
+ if ( bc->sb_tls_do_init ) {
+ if ( !bc->sb_tls_cacert )
+ ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CACERTFILE,
+ &bc->sb_tls_cacert );
+ if ( !bc->sb_tls_cacertdir )
+ ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CACERTDIR,
+ &bc->sb_tls_cacertdir );
+ if ( !bc->sb_tls_cert )
+ ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CERTFILE,
+ &bc->sb_tls_cert );
+ if ( !bc->sb_tls_key )
+ ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_KEYFILE,
+ &bc->sb_tls_key );
+ if ( !bc->sb_tls_cipher_suite )
+ ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CIPHER_SUITE,
+ &bc->sb_tls_cipher_suite );
+ if ( !bc->sb_tls_reqcert )
+ bc->sb_tls_reqcert = ch_strdup("demand");
+#ifdef HAVE_OPENSSL_CRL
+ if ( !bc->sb_tls_crlcheck )
+ slap_tls_get_config( slap_tls_ld, LDAP_OPT_X_TLS_CRLCHECK,
+ &bc->sb_tls_crlcheck );
+#endif
+ }
+#endif
+}
+
+#ifdef HAVE_TLS
+static struct {
+ const char *key;
+ size_t offset;
+ int opt;
+} bindtlsopts[] = {
+ { "tls_cert", offsetof(slap_bindconf, sb_tls_cert), LDAP_OPT_X_TLS_CERTFILE },
+ { "tls_key", offsetof(slap_bindconf, sb_tls_key), LDAP_OPT_X_TLS_KEYFILE },
+ { "tls_cacert", offsetof(slap_bindconf, sb_tls_cacert), LDAP_OPT_X_TLS_CACERTFILE },
+ { "tls_cacertdir", offsetof(slap_bindconf, sb_tls_cacertdir), LDAP_OPT_X_TLS_CACERTDIR },
+ { "tls_cipher_suite", offsetof(slap_bindconf, sb_tls_cipher_suite), LDAP_OPT_X_TLS_CIPHER_SUITE },
+ {0, 0}
+};
+
+int bindconf_tls_set( slap_bindconf *bc, LDAP *ld )
+{
+ int i, rc, newctx = 0, res = 0;
+ char *ptr = (char *)bc, **word;
+
+ bc->sb_tls_do_init = 0;
+
+ for (i=0; bindtlsopts[i].opt; i++) {
+ word = (char **)(ptr + bindtlsopts[i].offset);
+ if ( *word ) {
+ rc = ldap_set_option( ld, bindtlsopts[i].opt, *word );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bindconf_tls_set: failed to set %s to %s\n",
+ bindtlsopts[i].key, *word, 0 );
+ res = -1;
+ } else
+ newctx = 1;
+ }
+ }
+ if ( bc->sb_tls_reqcert ) {
+ rc = ldap_int_tls_config( ld, LDAP_OPT_X_TLS_REQUIRE_CERT,
+ bc->sb_tls_reqcert );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bindconf_tls_set: failed to set tls_reqcert to %s\n",
+ bc->sb_tls_reqcert, 0, 0 );
+ res = -1;
+ } else
+ newctx = 1;
+ }
+#ifdef HAVE_OPENSSL_CRL
+ if ( bc->sb_tls_crlcheck ) {
+ rc = ldap_int_tls_config( ld, LDAP_OPT_X_TLS_CRLCHECK,
+ bc->sb_tls_crlcheck );
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ "bindconf_tls_set: failed to set tls_crlcheck to %s\n",
+ bc->sb_tls_crlcheck, 0, 0 );
+ res = -1;
+ } else
+ newctx = 1;
+ }
+#endif
+ if ( newctx ) {
+ int opt = 0;
+
+ if ( bc->sb_tls_ctx ) {
+ ldap_pvt_tls_ctx_free( bc->sb_tls_ctx );
+ bc->sb_tls_ctx = NULL;
+ }
+ rc = ldap_set_option( ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
+ if ( rc )
+ res = rc;
+ else
+ ldap_get_option( ld, LDAP_OPT_X_TLS_CTX, &bc->sb_tls_ctx );
+ }
+
+ return res;
+}
+#endif
+
+/*
+ * connect to a client using the bindconf data
+ * note: should move "version" into bindconf...
+ */
+int
+slap_client_connect( LDAP **ldp, slap_bindconf *sb )
+{
+ LDAP *ld = NULL;
+ int rc;
+ struct timeval tv;
+
+ /* Init connection to master */
+ rc = ldap_initialize( &ld, sb->sb_uri.bv_val );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "slap_client_connect: "
+ "ldap_initialize(%s) failed (%d)\n",
+ sb->sb_uri.bv_val, rc, 0 );
+ return rc;
+ }
+
+ if ( sb->sb_version != 0 ) {
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
+ (const void *)&sb->sb_version );
+ }
+
+ if ( sb->sb_timeout_api ) {
+ tv.tv_sec = sb->sb_timeout_api;
+ tv.tv_usec = 0;
+ ldap_set_option( ld, LDAP_OPT_TIMEOUT, &tv );
+ }
+
+ if ( sb->sb_timeout_net ) {
+ tv.tv_sec = sb->sb_timeout_net;
+ tv.tv_usec = 0;
+ ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, &tv );
+ }
+
+#ifdef HAVE_TLS
+ if ( sb->sb_tls_do_init ) {
+ rc = bindconf_tls_set( sb, ld );
+
+ } else if ( sb->sb_tls_ctx ) {
+ rc = ldap_set_option( ld, LDAP_OPT_X_TLS_CTX,
+ sb->sb_tls_ctx );
+ }
+
+ if ( rc ) {
+ Debug( LDAP_DEBUG_ANY,
+ "slap_client_connect: "
+ "URI=%s TLS context initialization failed (%d)\n",
+ sb->sb_uri.bv_val, rc, 0 );
+ return rc;
+ }
+#endif
+
+ /* Bind */
+ if ( sb->sb_tls ) {
+ rc = ldap_start_tls_s( ld, NULL, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "slap_client_connect: URI=%s "
+ "%s, ldap_start_tls failed (%d)\n",
+ sb->sb_uri.bv_val,
+ sb->sb_tls == SB_TLS_CRITICAL ?
+ "Error" : "Warning",
+ rc );
+ if ( sb->sb_tls == SB_TLS_CRITICAL ) {
+ goto done;
+ }
+ }
+ }
+
+ if ( sb->sb_method == LDAP_AUTH_SASL ) {
+#ifdef HAVE_CYRUS_SASL
+ void *defaults;
+
+ if ( sb->sb_secprops != NULL ) {
+ rc = ldap_set_option( ld,
+ LDAP_OPT_X_SASL_SECPROPS, sb->sb_secprops);
+
+ if( rc != LDAP_OPT_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "slap_client_connect: "
+ "error, ldap_set_option "
+ "(%s,SECPROPS,\"%s\") failed!\n",
+ sb->sb_uri.bv_val, sb->sb_secprops, 0 );
+ goto done;
+ }
+ }
+
+ defaults = lutil_sasl_defaults( ld,
+ sb->sb_saslmech.bv_val,
+ sb->sb_realm.bv_val,
+ sb->sb_authcId.bv_val,
+ sb->sb_cred.bv_val,
+ sb->sb_authzId.bv_val );
+ if ( defaults == NULL ) {
+ rc = LDAP_OTHER;
+ goto done;
+ }
+
+ rc = ldap_sasl_interactive_bind_s( ld,
+ sb->sb_binddn.bv_val,
+ sb->sb_saslmech.bv_val,
+ NULL, NULL,
+ LDAP_SASL_QUIET,
+ lutil_sasl_interact,
+ defaults );
+
+ lutil_sasl_freedefs( defaults );
+
+ /* FIXME: different error behaviors according to
+ * 1) return code
+ * 2) on err policy : exit, retry, backoff ...
+ */
+ if ( rc != LDAP_SUCCESS ) {
+ static struct berval bv_GSSAPI = BER_BVC( "GSSAPI" );
+
+ Debug( LDAP_DEBUG_ANY, "slap_client_connect: URI=%s "
+ "ldap_sasl_interactive_bind_s failed (%d)\n",
+ sb->sb_uri.bv_val, rc, 0 );
+
+ /* FIXME (see above comment) */
+ /* if Kerberos credentials cache is not active, retry */
+ if ( ber_bvcmp( &sb->sb_saslmech, &bv_GSSAPI ) == 0 &&
+ rc == LDAP_LOCAL_ERROR )
+ {
+ rc = LDAP_SERVER_DOWN;
+ }
+
+ goto done;
+ }
+#else /* HAVE_CYRUS_SASL */
+ /* Should never get here, we trapped this at config time */
+ assert(0);
+ Debug( LDAP_DEBUG_SYNC, "not compiled with SASL support\n", 0, 0, 0 );
+ rc = LDAP_OTHER;
+ goto done;
+#endif
+
+ } else if ( sb->sb_method == LDAP_AUTH_SIMPLE ) {
+ rc = ldap_sasl_bind_s( ld,
+ sb->sb_binddn.bv_val, LDAP_SASL_SIMPLE,
+ &sb->sb_cred, NULL, NULL, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "slap_client_connect: "
+ "URI=%s DN=\"%s\" "
+ "ldap_sasl_bind_s failed (%d)\n",
+ sb->sb_uri.bv_val, sb->sb_binddn.bv_val, rc );
+ goto done;
+ }
+ }
+
+done:;
+ if ( rc ) {
+ if ( ld ) {
+ ldap_unbind_ext( ld, NULL, NULL );
+ *ldp = NULL;
+ }
+
+ } else {
+ *ldp = ld;
+ }
+
+ return rc;
+}