/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Setup: * - Set environment variables as below for each URL being * tested, along with dns and credentials. * - Copy the server certificates to the data/ directory. * All DER type certificates must have the .der extention. * All BASE64 or PEM certificates must have the .b64 * extension. All certificate files copied to the /data * directory will be added to the ldap certificate store. */ /* This test covers the following three types of connections: * * - Unsecure ldap:// * - Secure ldaps:// * - Secure ldap://+Start_TLS * - Unix ldapi:// * * Environment variables: * * One or more of the following, based on what you have available. * * - TESTLDAP=ldap://localhost:389 * - TESTLDAP_TLS=ldap://starttls.server:389 * - TESTLDAPS=ldaps://ssl.server:636 * - TESTLDAPI=/tmp/slapd-server.socket * * Simple bind: * * - TESTLDAP_DN=cn=Directory Manager * - TESTLDAP_PASS=opensesame * * SASL PLAIN bind: * * - TESTLDAP_USER=sasluser * - TESTLDAP_AUTHNAME=sasluser * - TESTLDAP_PASS=opensesame * * SASL EXTERNAL bind is attempted where supported. */ /* * For a working example of an asynchronous LDAP conversation involving a bind, * followed by a search, followed by a compare, start at test_ldap_connection() * below. */ #include "testutil.h" #include "apr.h" #include "apr_general.h" #include "apr_ldap.h" #include "apr_escape.h" #include "apr_file_io.h" #include "apr_file_info.h" #include "apr_poll.h" #include "apr_strings.h" #if APR_HAVE_STDLIB_H #include #endif #define APR_WANT_STDIO #define APR_WANT_STRFUNC #include "apr_want.h" #define DIRNAME "data" #define FILENAME DIRNAME "/host.data" #define CERTFILEDER DIRNAME "/*.der" #define CERTFILEB64 DIRNAME "/*.b64" #if APR_HAS_LDAP static int add_ldap_certs(abts_case *tc) { apr_status_t status; apr_dir_t *thedir; apr_finfo_t dirent; apu_err_t err; if ((status = apr_dir_open(&thedir, DIRNAME, p)) == APR_SUCCESS) { apr_ldap_opt_tls_cert_t *cert = (apr_ldap_opt_tls_cert_t *)apr_pcalloc(p, sizeof(apr_ldap_opt_tls_cert_t)); do { status = apr_dir_read(&dirent, APR_FINFO_MIN | APR_FINFO_NAME, thedir); if (APR_STATUS_IS_INCOMPLETE(status)) { continue; /* ignore un-stat()able files */ } else if (status != APR_SUCCESS) { break; } if (strstr(dirent.name, ".der")) { cert->type = APR_LDAP_CA_TYPE_DER; cert->path = apr_pstrcat (p, DIRNAME, "/", dirent.name, NULL); apr_ldap_option_set(p, NULL, APR_LDAP_OPT_TLS_CERT, (void *)cert, &err); ABTS_TRUE(tc, err.rc == APR_SUCCESS); } if (strstr(dirent.name, ".b64")) { cert->type = APR_LDAP_CA_TYPE_BASE64; cert->path = apr_pstrcat (p, DIRNAME, "/", dirent.name, NULL); apr_ldap_option_set(p, NULL, APR_LDAP_OPT_TLS_CERT, (void *)cert, &err); ABTS_TRUE(tc, err.rc == APR_SUCCESS); } } while (1); apr_dir_close(thedir); } return 0; } static apr_status_t bind_interact_simple(apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx) { switch (interact->id) { case APR_LDAP_INTERACT_DN: { char *dn = getenv("TESTLDAP_DN"); apr_buffer_str_set(&interact->result, dn ? dn : "", APR_BUFFER_STRING); break; } case APR_LDAP_INTERACT_PASS: { char *pass = getenv("TESTLDAP_PASS"); apr_buffer_str_set(&interact->result, pass ? pass : "opensesame", APR_BUFFER_STRING); break; } default: break; } return APR_SUCCESS; } static apr_status_t bind_interact_external(apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx) { return APR_SUCCESS; } static apr_status_t bind_interact_plain(apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx) { switch (interact->id) { case APR_LDAP_INTERACT_USER: { char *user = getenv("TESTLDAP_USER"); apr_buffer_str_set(&interact->result, user ? user : "", APR_BUFFER_STRING); break; } case APR_LDAP_INTERACT_AUTHNAME: { char *authname = getenv("TESTLDAP_AUTHNAME"); apr_buffer_str_set(&interact->result, authname ? authname : "", APR_BUFFER_STRING); break; } case APR_LDAP_INTERACT_PASS: { char *pass = getenv("TESTLDAP_PASS"); apr_buffer_str_set(&interact->result, pass ? pass : "opensesame", APR_BUFFER_STRING); break; } default: break; } return APR_SUCCESS; } static apr_status_t bind_interact_abandon(apr_ldap_t *ld, unsigned int flags, apr_ldap_bind_interact_t *interact, void *ctx) { switch (interact->id) { case APR_LDAP_INTERACT_USER: { apr_buffer_str_set(&interact->result, "cn=notexist", APR_BUFFER_STRING); break; } case APR_LDAP_INTERACT_AUTHNAME: { apr_buffer_str_set(&interact->result, "cn=notexist", APR_BUFFER_STRING); break; } case APR_LDAP_INTERACT_PASS: { apr_buffer_str_set(&interact->result, "wrongpassword", APR_BUFFER_STRING); break; } default: break; } return APR_SUCCESS; } typedef struct test_ldap_connection_t { abts_case *tc; apr_pool_t *pool; apr_ldap_t *ldap; apr_pool_t *bind_pool; const char *mech; apr_ldap_bind_interact_cb *interact; apr_pollcb_t *poll; apr_pollfd_t socket_read; apr_pollfd_t socket_write; apu_err_t err; int must_bind; } test_ldap_connection_t; static apr_status_t test_ldap_compare_cb(apr_ldap_t *ldap, apr_status_t status, const char *matcheddn, apr_ldap_control_t **serverctrls, void *ctx, apu_err_t *err) { test_ldap_connection_t *test = (test_ldap_connection_t *)ctx; /* * Step 13: compare result callback triggered, result is complete. */ abts_log_message("comparison matcheddn: \n", matcheddn); ABTS_INT_EQUAL(test->tc, APR_COMPARE_TRUE, status); return APR_SUCCESS; } static apr_status_t test_ldap_search_entry_cb(apr_ldap_t *ldap, const char *dn, int eidx, int nattrs, int aidx, const char *attr, int nvals, int vidx, apr_buffer_t *val, int binary, void *ctx, apu_err_t *err) { test_ldap_connection_t *test = (test_ldap_connection_t *)ctx; /* * Step 8: search entry callback triggered, start processing results. */ if (!nattrs && !vidx && attr) { /* first attribute and first value and attr present? output dn */ abts_log_message("dn: %s", dn); } if (val) { abts_log_message("%s: %s", attr, apr_buffer_pstrdup(test->pool, val)); } return APR_SUCCESS; } static apr_status_t test_ldap_search_result_cb(apr_ldap_t *ldap, apr_status_t status, apr_size_t nentries, const char *matcheddn, apr_ldap_control_t **serverctrls, void *ctx, apu_err_t *err) { char errbuf[128]; test_ldap_connection_t *test = (test_ldap_connection_t *)ctx; /* * Step 9: search result callback triggered, finish up. */ abts_log_message("\n"); ABTS_INT_EQUAL(test->tc, APR_SUCCESS, status); if (APR_SUCCESS == status) { /* * Step 10: search successful, it is time to trigger the compare. */ apr_buffer_t val; apr_buffer_str_set(&val, "top", APR_BUFFER_STRING); /* * Step 11: we're writable, trigger a compare, then wait for readable. */ status = apr_ldap_compare(test->pool, test->ldap, "" /* root dn */, "objectclass" /* attribute */, &val /* value */, NULL /* serverctls */, NULL /* clientctls */, apr_time_from_sec(5) /* timeout */, test_ldap_compare_cb, test, &test->err); ABTS_INT_EQUAL(test->tc, APR_WANT_READ, status); switch (status) { case APR_SUCCESS: case APR_WANT_READ: case APR_WANT_WRITE: break; default: abts_log_message("apr_ldap_result: %s [%s]\n", test->err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); } } else { abts_log_message("apr_ldap_search() failed: %s\n", apr_strerror(status, errbuf, sizeof(errbuf))); } return status; } static apr_status_t test_ldap_bind_cb(apr_ldap_t *ldap, apr_status_t status, const char *matcheddn, apr_ldap_control_t **serverctrls, void *ctx, apu_err_t *err) { char errbuf[128]; test_ldap_connection_t *test = (test_ldap_connection_t *)ctx; if (APR_SUCCESS == status) { /* * Step 5: bind successful, it is time to trigger the search. */ const char *attrs[2]; attrs[0] = "+"; attrs[1] = NULL; /* * Step 6: we're writable, trigger a search, then wait for readable. */ status = apr_ldap_search(test->pool, test->ldap, "" /* root dn */, APR_LDAP_SCOPE_BASE, "(objectclass=*)" /* filter */, attrs /* attrs */, APR_LDAP_OPT_OFF /* attrsonly */, NULL /* serverctls */, NULL /* clientctls */, apr_time_from_sec(5) /* timelimit */, 0 /* sizelimit */, test_ldap_search_result_cb, test_ldap_search_entry_cb, test, &test->err); ABTS_INT_EQUAL(test->tc, APR_WANT_READ, status); switch (status) { case APR_SUCCESS: case APR_WANT_READ: case APR_WANT_WRITE: break; default: abts_log_message("apr_ldap_result: %s [%s]\n", test->err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); } } else { abts_log_message("apr_ldap_bind() failed: %s\n", apr_strerror(status, errbuf, sizeof(errbuf))); } return status; } static apr_status_t test_ldap_initialise_cb(apr_ldap_t *ldap, apr_status_t status, void *ctx, apu_err_t *err) { char errbuf[128]; test_ldap_connection_t *test = (test_ldap_connection_t *)ctx; if (APR_SUCCESS == status) { /* * Step 2: we're writable, trigger the initial bind, then wait for readable. */ status = apr_ldap_bind(test->pool, test->ldap, test->mech, test->interact, NULL, apr_time_from_sec(0), test_ldap_bind_cb, test, &test->err); ABTS_INT_EQUAL(test->tc, APR_WANT_READ, status); switch (status) { case APR_SUCCESS: case APR_WANT_READ: case APR_WANT_WRITE: return status; default: abts_log_message("apr_ldap_result: %s [%s]\n", test->err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); return status; } } else { abts_log_message("initialise failed: %s\n", apr_strerror(status, errbuf, sizeof(errbuf))); } return status; } static apr_status_t test_ldap_connection_cb(void *baton, apr_pollfd_t *descriptor) { char errbuf[128]; test_ldap_connection_t *test = (test_ldap_connection_t *) baton; apr_status_t status = APR_SUCCESS; /* remove our event */ apr_pollcb_remove(test->poll, descriptor); /* are we ready to write? */ if (descriptor->rtnevents & APR_POLLOUT) { /* * Step 4: bind callback triggered, continue the bind processing. */ /* handle oustanding tasks */ status = apr_ldap_process(test->pool, test->ldap, apr_time_from_sec(0), &test->err); switch (status) { case APR_SUCCESS: case APR_WANT_READ: case APR_WANT_WRITE: break; default: abts_log_message("apr_ldap_result: %s [%s]\n", test->err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); } } /* are we ready to read? */ else if (descriptor->rtnevents & APR_POLLIN) { /* * Step 3: we're readable, fetch the bind result, then request a write to be scheduled. */ /* * Step 7: we're readable, fetch the search result, then trigger search callback. */ /* * Step 12: we're readable, fetch the compare result, then trigger compare callback. */ status = apr_ldap_result(test->pool, test->ldap, -1, &test->err); switch (status) { case APR_SUCCESS: case APR_WANT_READ: case APR_WANT_WRITE: break; default: abts_log_message("apr_ldap_result: %s [%s]\n", test->err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); } } return status; } /* * Asynchronous test of an LDAP connection. * * Like all async code, we jump around a lot. In this example we make * an attempt to bind, and that that was successful, we make an * attempt to search for the root DSE, then if that was successful, * we attempt a compare. * * Start at "Step 1" and follow each step through the callbacks. */ static void test_ldap_connection(abts_case *tc, apr_pool_t *pool, apr_ldap_t *ldap, const char *mech, apr_ldap_bind_interact_cb *interact) { char errbuf[128]; apu_err_t err; test_ldap_connection_t test; apr_ldap_opt_t opt; apr_status_t status; memset(&test, 0, sizeof(test_ldap_connection_t)); test.tc = tc; test.pool = pool; test.ldap = ldap; test.mech = mech; test.interact = interact; /* always default to LDAP V3 */ opt.pv = APR_LDAP_VERSION3; apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_PROTOCOL_VERSION, &opt, &err); /* * Step 1: call us back when we're writable. */ /* set the initialise callback */ apr_ldap_prepare(pool, ldap, test_ldap_initialise_cb, &test); apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_HANDLE, &opt, &err); ABTS_TRUE(tc, opt.handle != NULL); status = apr_ldap_connect(pool, ldap, apr_time_from_sec(5), &err); if (APR_SUCCESS != status) { abts_log_message("%s - %s (%d)\n", err.reason, err.msg, err.rc); return; } status = apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_DESC, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); ABTS_ASSERT(tc, "failed to get descriptor", opt.socket != NULL); status = apr_pollcb_create(&test.poll, 1, pool, APR_POLLSET_DEFAULT); if (APR_ENOTIMPL == status) { abts_log_message("apr_pollcb_create() not implemented on this platform, skipping test\n"); return; } ABTS_TRUE(tc, status == APR_SUCCESS); if (APR_SUCCESS != status) { return; } /* set up read descriptor */ test.socket_read.desc_type = APR_POLL_SOCKET; test.socket_read.reqevents = APR_POLLIN; test.socket_read.desc.s = opt.socket; test.socket_read.client_data = opt.socket; /* set up write descriptor */ test.socket_write.desc_type = APR_POLL_SOCKET; test.socket_write.reqevents = APR_POLLOUT; test.socket_write.desc.s = opt.socket; test.socket_write.client_data = opt.socket; status = APR_WANT_WRITE; do { if (APR_SUCCESS == status) { abts_log_message("apr_pollcb_poll() complete\n"); break; } else if (APR_WANT_READ == status) { /* wait for socket to be readable, then process another result */ status = apr_pollcb_add(test.poll, &test.socket_read); ABTS_INT_EQUAL(tc, APR_SUCCESS, status); if (APR_SUCCESS != status) { break; } } else if (APR_WANT_WRITE == status) { /* wait for socket to be writeable, then process result */ status = apr_pollcb_add(test.poll, &test.socket_write); ABTS_INT_EQUAL(tc, APR_SUCCESS, status); if (APR_SUCCESS != status) { break; } } else { abts_log_message("apr_ldap_process/apr_ldap_result: %s [%s]\n", test.err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); break; } status = apr_pollcb_poll(test.poll, -1, test_ldap_connection_cb, &test); } while (1); /* * Step 14: bind, search, compare, result is complete, event loop unwound. */ return; } /* * Synchronous test of an LDAP connection. * * The code below is identical to the above code, but uses the event loop inside * apr_ldap_poll(). * * The initial callback test_ldap_initialise_cb is set, all queries are bootstrapped * from this callback. */ #if 0 static void test_ldap_connection(abts_case *tc, apr_pool_t *pool, apr_ldap_t *ldap, const char *mech, apr_ldap_bind_interact_cb *interact) { char errbuf[128]; apu_err_t err; test_ldap_connection_t test; apr_ldap_opt_t opt; apr_status_t status; memset(&test, 0, sizeof(test_ldap_connection_t)); test.tc = tc; test.pool = pool; test.ldap = ldap; test.mech = mech; test.interact = interact; /* always default to LDAP V3 */ opt.pv = APR_LDAP_VERSION3; apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_PROTOCOL_VERSION, &opt, &err); /* set the initialise callback */ apr_ldap_prepare(pool, ldap, test_ldap_initialise_cb, &test); /* initial connect */ status = apr_ldap_connect(pool, ldap, apr_time_from_sec(5), &err); if (APR_SUCCESS != status) { abts_log_message("%s - %s (%d)\n", err.reason, err.msg, err.rc); return; } /* run the callbacks */ status = apr_ldap_poll(pool, ldap, apr_time_from_sec(5), &err); if (APR_SUCCESS == status) { abts_log_message("apr_pollcb_poll() complete\n"); } else { abts_log_message("apr_ldap_process/apr_ldap_result: %s [%s]\n", test.err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); } return; } #endif static apr_status_t test_ldap_abandon_cb(void *baton, apr_pollfd_t *descriptor) { char errbuf[128]; test_ldap_connection_t *test = (test_ldap_connection_t *) baton; apr_status_t status = APR_SUCCESS; /* remove our event */ apr_pollcb_remove(test->poll, descriptor); /* are we ready to write? */ if (descriptor->rtnevents & APR_POLLOUT) { if (test->must_bind) { /* * Step B: we're writable, trigger the initial bind from the bind_pool, then wait for readable. */ status = apr_ldap_bind(test->bind_pool, test->ldap, test->mech, test->interact, NULL, apr_time_from_sec(0), test_ldap_bind_cb, test, &test->err); test->must_bind = 0; ABTS_INT_EQUAL(test->tc, APR_WANT_READ, status); if (APR_SUCCESS == status) { /* should not have happened */ return status; } else if (APR_WANT_READ == status) { /* * Step C: spanner in the works - lets abandon the bind. */ apr_pool_destroy(test->bind_pool); test->bind_pool = NULL; abts_log_message("bind abandon triggered\n"); /* and then continue as if nothing had happened */ return status; } else { return status; } } /* * Step E: write callback triggered, send the abandon. */ /* handle oustanding tasks */ status = apr_ldap_process(test->pool, test->ldap, apr_time_from_sec(0), &test->err); ABTS_INT_EQUAL(test->tc, APR_SUCCESS, status); switch (status) { case APR_SUCCESS: case APR_WANT_READ: case APR_WANT_WRITE: return status; default: abts_log_message("apr_ldap_result: %s [%s]\n", test->err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); return status; } } /* are we ready to read? */ if (descriptor->rtnevents & APR_POLLIN) { /* * Step D: we're readable, but our bind has been abandoned. */ status = apr_ldap_result(test->pool, test->ldap, -1, &test->err); ABTS_INT_EQUAL(test->tc, APR_WANT_WRITE, status); switch (status) { case APR_SUCCESS: case APR_WANT_READ: case APR_WANT_WRITE: return status; default: abts_log_message("apr_ldap_result: %s [%s]\n", test->err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); return status; } } return status; } static void test_ldap_abandon(abts_case *tc, apr_pool_t *pool, apr_ldap_t *ldap) { char errbuf[128]; apu_err_t err; test_ldap_connection_t test; apr_ldap_opt_t opt; apr_status_t status; memset(&test, 0, sizeof(test_ldap_connection_t)); test.tc = tc; test.pool = pool; test.ldap = ldap; test.mech = "PLAIN"; test.interact = bind_interact_abandon; test.must_bind = 1; apr_pool_create(&test.bind_pool, test.pool); /* always default to LDAP V3 */ opt.pv = APR_LDAP_VERSION3; apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_PROTOCOL_VERSION, &opt, &err); apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_HANDLE, &opt, &err); ABTS_TRUE(tc, opt.handle != NULL); status = apr_ldap_connect(pool, ldap, apr_time_from_sec(5), &err); if (APR_SUCCESS != status) { abts_log_message("%s - %s (%d)\n", err.reason, err.msg, err.rc); return; } status = apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_DESC, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); ABTS_ASSERT(tc, "failed to get descriptor", opt.socket != NULL); status = apr_pollcb_create(&test.poll, 1, pool, APR_POLLSET_DEFAULT); if (APR_ENOTIMPL == status) { abts_log_message("apr_pollcb_create() not implemented on this platform, skipping test\n"); return; } ABTS_TRUE(tc, status == APR_SUCCESS); if (APR_SUCCESS != status) { return; } /* set up read descriptor */ test.socket_read.desc_type = APR_POLL_SOCKET; test.socket_read.reqevents = APR_POLLIN; test.socket_read.desc.s = opt.socket; test.socket_read.client_data = opt.socket; /* set up write descriptor */ test.socket_write.desc_type = APR_POLL_SOCKET; test.socket_write.reqevents = APR_POLLOUT; test.socket_write.desc.s = opt.socket; test.socket_write.client_data = opt.socket; /* * Step A: call us back when we're writable. */ status = APR_WANT_WRITE; do { if (APR_SUCCESS == status) { abts_log_message("apr_pollcb_poll() complete\n"); break; } else if (APR_WANT_READ == status) { /* wait for socket to be readable, then process another result */ status = apr_pollcb_add(test.poll, &test.socket_read); ABTS_INT_EQUAL(tc, APR_SUCCESS, status); if (APR_SUCCESS != status) { break; } } else if (APR_WANT_WRITE == status) { /* wait for socket to be writeable, then process result */ status = apr_pollcb_add(test.poll, &test.socket_write); ABTS_INT_EQUAL(tc, APR_SUCCESS, status); if (APR_SUCCESS != status) { break; } } else { abts_log_message("apr_ldap_result: %s [%s]\n", test.err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); break; } status = apr_pollcb_poll(test.poll, -1, test_ldap_abandon_cb, &test); } while (1); /* * Step F: bind, result, abandon is complete, event loop unwound. */ return; } static void test_ldap_global_opts(abts_case *tc, void *data) { apr_pool_t *pool; apu_err_t err; apr_ldap_opt_t opt; apr_status_t status; char errbuf[128]; apr_pool_create(&pool, p); status = apr_ldap_option_get(pool, NULL, APR_LDAP_OPT_API_INFO, &opt, &err); if (status != APR_SUCCESS) { abts_log_message("apr_ldap_option_get: %s [%s]\n", err.reason, apr_strerror(status, errbuf, sizeof(errbuf))); } ABTS_TRUE(tc, status == APR_SUCCESS); ABTS_TRUE(tc, err.rc == 0); ABTS_TRUE(tc, opt.info.vendor_name != NULL); opt.ldfi.name = "THREAD_SAFE"; status = apr_ldap_option_get(pool, NULL, APR_LDAP_OPT_API_FEATURE_INFO, &opt, &err); /* feature may exist, or may not */ ABTS_TRUE(tc, status == APR_SUCCESS || status == APR_EINVAL); status = apr_ldap_option_get(pool, NULL, APR_LDAP_OPT_DEBUG_LEVEL, &opt, &err); if (APR_ENOTIMPL == status) { abts_log_message("apr_ldap_option_get(APR_LDAP_OPT_DEBUG_LEVEL) not implemented on this platform, skipping test\n"); return; } else { ABTS_TRUE(tc, status == APR_SUCCESS); } apr_pool_destroy(pool); } static void test_ldap_opts(abts_case *tc, void *data) { apr_pool_t *pool; apr_ldap_t *ldap = NULL; apu_err_t err; const char *url; apr_pool_create(&pool, p); url = apr_psprintf(pool, "ldap://%s:%d", "localhost", APR_LDAP_PORT); apr_ldap_initialise(pool, &ldap, &(err)); ABTS_TRUE(tc, ldap != NULL); if (ldap) { apr_status_t status; apr_ldap_opt_t opt; opt.uri = url; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_URI, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); status = apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_URI, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); ABTS_ASSERT(tc, "failed to set uri", !strcmp(opt.uri, url)); opt.pv = APR_LDAP_VERSION3; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_PROTOCOL_VERSION, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); status = apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_PROTOCOL_VERSION, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); ABTS_ASSERT(tc, "failed to set protocol version", opt.pv == APR_LDAP_VERSION3); opt.deref = APR_LDAP_DEREF_ALWAYS; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_DEREF, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); status = apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_DEREF, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); ABTS_ASSERT(tc, "failed to set deref", opt.deref == APR_LDAP_DEREF_ALWAYS); opt.refs = APR_LDAP_OPT_ON; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_REFERRALS, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); status = apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_REFERRALS, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); ABTS_ASSERT(tc, "failed to set referrals", opt.refs == APR_LDAP_OPT_ON); #if 0 opt.refhoplimit = 5; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_REFHOPLIMIT, &opt, &err); if (APR_ENOTIMPL != status) { ABTS_TRUE(tc, status == APR_SUCCESS); status = apr_ldap_option_get(pool, ldap, APR_LDAP_OPT_REFHOPLIMIT, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); ABTS_ASSERT(tc, "failed to set refhoplimit", opt.refhoplimit == 5); } #endif } apr_pool_destroy(pool); } static void test_ldap(abts_case *tc, void *data) { apr_pool_t *pool; apr_ldap_t *ldap; apu_err_t err; const char *url; apr_ldap_opt_t opt; apr_status_t status; const char *testldap = getenv("TESTLDAP"); if (!testldap) { ABTS_NOT_IMPL(tc, "Environment TESTLDAP unset - skipping"); return; } apr_pool_create(&pool, p); url = apr_psprintf(pool, "ldap://%s:%d", testldap, APR_LDAP_PORT); apr_ldap_initialise(pool, &ldap, &(err)); ABTS_TRUE(tc, ldap != NULL); opt.uri = url; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_URI, &opt, &err); if (status == APR_SUCCESS) { test_ldap_connection(tc, pool, ldap, NULL, bind_interact_simple); } apr_pool_destroy(pool); } static void test_ldaps(abts_case *tc, void *data) { apr_pool_t *pool; apr_ldap_t *ldap; apu_err_t err; const char *url; apr_ldap_opt_t opt; apr_status_t status; const char *testldaps = getenv("TESTLDAPS"); if (!testldaps) { ABTS_NOT_IMPL(tc, "Environment TESTLDAPS unset - skipping"); return; } apr_pool_create(&pool, p); url = apr_psprintf(pool, "ldaps://%s:%d", testldaps, APR_LDAPS_PORT); apr_ldap_initialise(pool, &ldap, &(err)); ABTS_TRUE(tc, ldap != NULL); opt.uri = url; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_URI, &opt, &err); if (status == APR_SUCCESS) { add_ldap_certs(tc); test_ldap_connection(tc, pool, ldap, "EXTERNAL", bind_interact_external); test_ldap_connection(tc, pool, ldap, "PLAIN", bind_interact_plain); test_ldap_connection(tc, pool, ldap, NULL, bind_interact_simple); } apr_pool_destroy(pool); } static void test_ldap_tls(abts_case *tc, void *data) { apr_pool_t *pool; apr_ldap_t *ldap; apu_err_t err; const char *url; apr_ldap_opt_t opt; apr_status_t status; const char *testldap_tls = getenv("TESTLDAP_TLS"); if (!testldap_tls) { ABTS_NOT_IMPL(tc, "Environment TESTLDAP_TLS unset - skipping"); return; } apr_pool_create(&pool, p); opt.tls = APR_LDAP_TLS_STARTTLS; url = apr_psprintf(pool, "ldap://%s:%d", testldap_tls, APR_LDAP_PORT); apr_ldap_initialise(pool, &ldap, &(err)); if (err.rc == APR_SUCCESS) { apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_TLS, &opt, &(err)); } ABTS_TRUE(tc, ldap != NULL); opt.uri = url; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_URI, &opt, &err); if (status == APR_SUCCESS) { add_ldap_certs(tc); test_ldap_connection(tc, pool, ldap, "EXTERNAL", bind_interact_external); test_ldap_connection(tc, pool, ldap, "PLAIN", bind_interact_plain); test_ldap_connection(tc, pool, ldap, NULL, bind_interact_simple); } apr_pool_destroy(pool); } static void test_ldapi(abts_case *tc, void *data) { apr_pool_t *pool; apr_ldap_t *ldap; apu_err_t err; const char *url; apr_ldap_opt_t opt; apr_status_t status; const char *testldapi = getenv("TESTLDAPI"); if (!testldapi) { ABTS_NOT_IMPL(tc, "Environment TESTLDAPI unset - skipping"); return; } apr_pool_create(&pool, p); opt.tls = APR_LDAP_TLS_STARTTLS; url = apr_psprintf(pool, "ldapi://%s", apr_pescape_urlencoded(pool, testldapi)); apr_ldap_initialise(pool, &ldap, &(err)); ABTS_TRUE(tc, ldap != NULL); opt.uri = url; status = apr_ldap_option_set(pool, ldap, APR_LDAP_OPT_URI, &opt, &err); ABTS_TRUE(tc, status == APR_SUCCESS); abts_log_message("Initialiased LDAP url [%s]: %s - %s (%d)\n", url, err.reason, err.msg, err.rc); if (status == APR_SUCCESS) { test_ldap_connection(tc, pool, ldap, "EXTERNAL", bind_interact_external); test_ldap_connection(tc, pool, ldap, "PLAIN", bind_interact_plain); test_ldap_connection(tc, pool, ldap, NULL, bind_interact_simple); test_ldap_abandon(tc, pool, ldap); } status = apr_ldap_unbind(ldap, NULL, NULL, &err); ABTS_TRUE(tc, status == APR_SUCCESS); apr_pool_destroy(pool); } #endif /* APR_HAS_LDAP */ abts_suite *testldap(abts_suite *suite) { #if APR_HAS_LDAP suite = ADD_SUITE(suite); abts_run_test(suite, test_ldap_global_opts, NULL); abts_run_test(suite, test_ldap_opts, NULL); abts_run_test(suite, test_ldap, NULL); abts_run_test(suite, test_ldaps, NULL); abts_run_test(suite, test_ldap_tls, NULL); abts_run_test(suite, test_ldapi, NULL); #endif /* APR_HAS_LDAP */ return suite; }