/** Create and return a new connection * * Create a new ldap connection and allocate memory for a new rlm_handle_t */ void *mod_conn_create(TALLOC_CTX *ctx, void *instance, struct timeval const *timeout) { fr_ldap_rcode_t status; fr_ldap_connection_t *conn; fr_ldap_config_t const *handle_config = instance; /* Not talloced */ conn = fr_ldap_connection_alloc(ctx); if (!conn) return NULL; if (fr_ldap_connection_configure(conn, handle_config) < 0) { talloc_free(conn); return NULL; } fr_ldap_connection_timeout_set(conn, timeout); if (handle_config->start_tls) { if (ldap_start_tls_s(conn->handle, NULL, NULL) != LDAP_SUCCESS) { int ldap_errno; ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); ERROR("Could not start TLS: %s", ldap_err2string(ldap_errno)); error: talloc_free(conn); return NULL; } } status = fr_ldap_bind(NULL, &conn, conn->config->admin_identity, conn->config->admin_password, &(conn->config->admin_sasl), timeout, NULL, NULL); if (status != LDAP_PROC_SUCCESS) goto error; fr_ldap_connection_timeout_reset(conn); /* * Only error out on memory allocation errors */ if (fr_ldap_directory_alloc(conn, &conn->directory, &conn) < 0) goto error; return conn; }
/** Send a bind request to a aserver * * @param[in] el the event occurred in. * @param[in] fd the event occurred on. * @param[in] flags from kevent. * @param[in] uctx bind_ctx containing credentials, and connection config/handle. */ static void _ldap_bind_io_write(fr_event_list_t *el, int fd, UNUSED int flags, void *uctx) { fr_ldap_bind_ctx_t *bind_ctx = talloc_get_type_abort(uctx, fr_ldap_bind_ctx_t); fr_ldap_connection_t *c = bind_ctx->c; LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS]; LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS]; struct timeval tv = { 0, 0 }; int ret; struct berval cred; fr_ldap_control_merge(our_serverctrls, our_clientctrls, sizeof(our_serverctrls) / sizeof(*our_serverctrls), sizeof(our_clientctrls) / sizeof(*our_clientctrls), c, bind_ctx->serverctrls, bind_ctx->clientctrls); /* * Set timeout to be 0.0, which is the magic * non-blocking value. */ (void) ldap_set_option(c->handle, LDAP_OPT_NETWORK_TIMEOUT, &tv); if (bind_ctx->password) { memcpy(&cred.bv_val, &bind_ctx->password, sizeof(cred.bv_val)); cred.bv_len = talloc_array_length(bind_ctx->password) - 1; } else { cred.bv_val = NULL; cred.bv_len = 0; } /* * Yes, confusingly named. This is the simple version * of the SASL bind function that should always be * available. */ ret = ldap_sasl_bind(c->handle, bind_ctx->bind_dn, LDAP_SASL_SIMPLE, &cred, our_serverctrls, our_clientctrls, &bind_ctx->msgid); switch (ret) { /* * If the handle was not connected, this operation * can return either LDAP_X_CONNECTING or LDAP_SUCCESS * depending on how fast the connection came up * and whether it was connectionless. */ case LDAP_X_CONNECTING: /* Connection in progress - retry later */ ret = ldap_get_option(c->handle, LDAP_OPT_DESC, &fd); if (!fr_cond_assert(ret == LDAP_OPT_SUCCESS)) { error: talloc_free(bind_ctx); fr_ldap_connection_timeout_reset(c); fr_ldap_state_error(c); /* Restart the connection state machine */ return; } ret = fr_event_fd_insert(bind_ctx, el, fd, NULL, _ldap_bind_io_write, /* We'll be called again when the conn is open */ _ldap_bind_io_error, bind_ctx); if (!fr_cond_assert(ret == 0)) goto error; break; case LDAP_SUCCESS: ret = fr_event_fd_insert(bind_ctx, el, fd, _ldap_bind_io_read, NULL, _ldap_bind_io_error, bind_ctx); if (!fr_cond_assert(ret == 0)) goto error; break; default: ERROR("Bind failed: %s", ldap_err2string(ret)); goto error; } fr_ldap_connection_timeout_reset(c); }