fr_ldap_state_t state; //!< LDAP connection state machine.
+ int fd; //!< File descriptor for this connection.
+
void *uctx; //!< User data associated with the handle.
} fr_ldap_connection_t;
fr_ldap_connection_t *fr_ldap_connection_alloc(TALLOC_CTX *ctx);
fr_connection_t *fr_ldap_connection_state_alloc(TALLOC_CTX *ctx, fr_event_list_t *el,
- fr_ldap_config_t const *config, char *log_prefix);
+ fr_ldap_config_t const *config, char const *log_prefix);
int fr_ldap_connection_configure(fr_ldap_connection_t *c, fr_ldap_config_t const *config);
/*
* We're I/O driven, if there's no data someone lied to us
*/
- status = fr_ldap_result(NULL, NULL, c, bind_ctx->msgid, LDAP_MSG_ALL,
- bind_ctx->bind_dn, fr_time_delta_wrap(0));
- talloc_free(bind_ctx); /* Also removes fd events */
-
+ status = fr_ldap_result(NULL, NULL, c, bind_ctx->msgid, LDAP_MSG_ALL, bind_ctx->bind_dn, fr_time_delta_wrap(0));
switch (status) {
case LDAP_PROC_SUCCESS:
- DEBUG("Bind successful");
+ DEBUG("Bind as \"%s\" to \"%s\" successful",
+ *bind_ctx->bind_dn? bind_ctx->bind_dn : "(anonymous)", c->config->server);
fr_ldap_state_next(c); /* onto the next operation */
break;
fr_ldap_state_error(c); /* Restart the connection state machine */
break;
}
+ talloc_free(bind_ctx); /* Also removes fd events */
}
-/** Send a bind request to a aserver
+/** Send a bind request to a server
*
* @param[in] el the event occurred in.
* @param[in] fd the event occurred on.
NUM_ELEMENTS(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, &fr_time_delta_to_timeval(fr_time_delta_wrap(0)));
-
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;
break;
case LDAP_SUCCESS:
+ if (fd < 0 ) {
+ ret = ldap_get_option(c->handle, LDAP_OPT_DESC, &fd);
+ if ((ret != LDAP_OPT_SUCCESS) || (fd < 0)) goto error;
+ }
+ c->fd = fd;
ret = fr_event_fd_insert(bind_ctx, el, fd,
_ldap_bind_io_read,
NULL,
el = c->conn->el;
- if (ldap_get_option(c->handle, LDAP_OPT_DESC, &fd) == LDAP_SUCCESS) {
+ /*
+ * ldap_get_option can return a LDAP_SUCCESS even if the fd is not yet available
+ * - hence the test for fd >= 0
+ */
+ if ((ldap_get_option(c->handle, LDAP_OPT_DESC, &fd) == LDAP_SUCCESS) && (fd >= 0)) {
int ret;
ret = fr_event_fd_insert(bind_ctx, el, fd,
return -1;
}
} else {
+ /*
+ * Connections initialised with ldap_init() do not have a fd until
+ * the first request (usually bind) occurs - so this code path
+ * starts the bind process to open the connection.
+ */
_ldap_bind_io_write(el, -1, 0, bind_ctx);
}
fr_ldap_state_t state;
c = fr_ldap_connection_alloc(conn);
+ c->conn = conn;
/*
* Configure/allocate the libldap handle
* @param[in] log_prefix to prepend to connection state messages.
*/
fr_connection_t *fr_ldap_connection_state_alloc(TALLOC_CTX *ctx, fr_event_list_t *el,
- fr_ldap_config_t const *config, char *log_prefix)
+ fr_ldap_config_t const *config, char const *log_prefix)
{
fr_connection_t *conn;
.reconnection_delay = config->reconnection_delay
},
log_prefix, config);
- if (!conn) return NULL;
+ if (!conn) {
+ PERROR("Failed allocating state handler for new LDAP connection");
+ return NULL;
+ }
return conn;
}
{ FR_CONF_OFFSET("sasl_secprops", FR_TYPE_STRING, rlm_ldap_t, handle_config.sasl_secprops) },
#ifdef LDAP_OPT_NETWORK_TIMEOUT
- /* timeout on network activity */
- { FR_CONF_DEPRECATED("net_timeout", FR_TYPE_TIME_DELTA, rlm_ldap_t, handle_config.net_timeout), .dflt = "10" },
+ /*
+ * We use this config option to populate libldap's LDAP_OPT_NETWORK_TIMEOUT -
+ * timeout on network activity - specifically libldap's initial call to "connect"
+ * Must be non-zero for async connections to start correctly.
+ */
+ { FR_CONF_OFFSET("net_timeout", FR_TYPE_TIME_DELTA, rlm_ldap_t, handle_config.net_timeout), .dflt = "10" },
#endif
#ifdef LDAP_OPT_X_KEEPALIVE_IDLE