示例#1
0
/** Parse a bind response from a server
 *
 * @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_read(UNUSED fr_event_list_t *el, UNUSED 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;

	fr_ldap_rcode_t		status;
	struct timeval		tv = { 0, 0 };	/* 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, &tv);
	talloc_free(bind_ctx);			/* Also removes fd events */

	switch (status) {
	case LDAP_PROC_SUCCESS:
		DEBUG("Bind successful");
		fr_ldap_state_next(c);		/* onto the next operation */
		break;

	case LDAP_PROC_NOT_PERMITTED:
		PERROR("Bind as \"%s\" to \"%s\" not permitted",
		       *bind_ctx->bind_dn ? bind_ctx->bind_dn : "(anonymous)", c->config->server);
		fr_ldap_state_error(c);		/* Restart the connection state machine */
		break;

	default:
		PERROR("Bind as \"%s\" to \"%s\" failed",
		       *bind_ctx->bind_dn ? bind_ctx->bind_dn : "(anonymous)", c->config->server);
		fr_ldap_state_error(c);		/* Restart the connection state machine */
		break;
	}
}
示例#2
0
/** Modify something in the LDAP directory
 *
 * Binds as the administrative user and attempts to modify an LDAP object.
 *
 * @param[in] request		Current request.
 * @param[in,out] pconn		to use. May change as this function calls functions which auto re-connect.
 * @param[in] dn		of the object to modify.
 * @param[in] mods		to make, see 'man ldap_modify' for more information.
 * @param[in] serverctrls	Search controls to pass to the server.  May be NULL.
 * @param[in] clientctrls	Search controls for ldap_modify.  May be NULL.
 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
 */
fr_ldap_rcode_t fr_ldap_modify(REQUEST *request, fr_ldap_connection_t **pconn,
			       char const *dn, LDAPMod *mods[],
			       LDAPControl **serverctrls, LDAPControl **clientctrls)
{
	fr_ldap_rcode_t	status = LDAP_PROC_ERROR;

	int		msgid;		// Message id returned by ldap_search_ext.

	LDAPControl	*our_serverctrls[LDAP_MAX_CONTROLS];
	LDAPControl	*our_clientctrls[LDAP_MAX_CONTROLS];

	fr_ldap_control_merge(our_serverctrls, our_clientctrls,
			      sizeof(our_serverctrls) / sizeof(*our_serverctrls),
			      sizeof(our_clientctrls) / sizeof(*our_clientctrls),
			      *pconn, serverctrls, clientctrls);

	rad_assert(*pconn && (*pconn)->handle);

	if (RDEBUG_ENABLED4) fr_ldap_timeout_debug(request, *pconn, NULL, __FUNCTION__);

	/*
	 *	Perform all modifications as the admin user.
	 */
	if ((*pconn)->rebound) {
		status = fr_ldap_bind(request, pconn,
				      (*pconn)->config->admin_identity, (*pconn)->config->admin_password,
				      &(*pconn)->config->admin_sasl,
				      NULL, NULL, NULL);
		if (status != LDAP_PROC_SUCCESS) {
			return LDAP_PROC_ERROR;
		}

		rad_assert(*pconn);

		(*pconn)->rebound = false;
	}

	RDEBUG2("Modifying object with DN \"%s\"", dn);
	(void) ldap_modify_ext((*pconn)->handle, dn, mods, our_serverctrls, our_clientctrls, &msgid);

	RDEBUG2("Waiting for modify result...");
	status = fr_ldap_result(NULL, NULL, *pconn, msgid, 0, dn, NULL);
	switch (status) {
	case LDAP_PROC_SUCCESS:
		break;

	case LDAP_PROC_BAD_CONN:
		break;

		/* FALL-THROUGH */
	default:
		ROPTIONAL(RPEDEBUG, RPERROR, "Failed modifying object");

		goto finish;
	}

finish:
	return status;
}
示例#3
0
/** Search for something in the LDAP directory
 *
 * Binds as the administrative user and performs a search, dealing with any errors.
 *
 * @param[out] result		Where to store the result. Must be freed with ldap_msgfree
 *				if LDAP_PROC_SUCCESS is returned.
 *				May be NULL in which case result will be automatically freed after use.
 * @param[in] request		Current request.
 * @param[in,out] pconn		to use. May change as this function calls functions which auto re-connect.
 * @param[in] dn		to use as base for the search.
 * @param[in] scope		to use (LDAP_SCOPE_BASE, LDAP_SCOPE_ONE, LDAP_SCOPE_SUB).
 * @param[in] filter		to use, should be pre-escaped.
 * @param[in] attrs		to retrieve.
 * @param[in] serverctrls	Search controls to pass to the server.  May be NULL.
 * @param[in] clientctrls	Search controls for ldap_search.  May be NULL.
 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
 */
fr_ldap_rcode_t fr_ldap_search(LDAPMessage **result, REQUEST *request,
			       fr_ldap_connection_t **pconn,
			       char const *dn, int scope, char const *filter, char const * const *attrs,
			       LDAPControl **serverctrls, LDAPControl **clientctrls)
{
	fr_ldap_rcode_t			status = LDAP_PROC_ERROR;
	LDAPMessage			*our_result = NULL;

	fr_ldap_config_t const	*handle_config = (*pconn)->config;

	int				msgid;		// Message id returned by
							// ldap_search_ext.

	int				count = 0;	// Number of results we got.

	struct timeval			tv;		// Holds timeout values.

	LDAPControl			*our_serverctrls[LDAP_MAX_CONTROLS];
	LDAPControl			*our_clientctrls[LDAP_MAX_CONTROLS];

	fr_ldap_control_merge(our_serverctrls, our_clientctrls,
			      sizeof(our_serverctrls) / sizeof(*our_serverctrls),
			      sizeof(our_clientctrls) / sizeof(*our_clientctrls),
			      *pconn, serverctrls, clientctrls);

	rad_assert(*pconn && (*pconn)->handle);

	if (DEBUG_ENABLED4 || (request && RDEBUG_ENABLED4)) {
		fr_ldap_timeout_debug(request, *pconn, NULL, __FUNCTION__);
	}

	/*
	 *	OpenLDAP library doesn't declare attrs array as const, but
	 *	it really should be *sigh*.
	 */
	char **search_attrs;
	memcpy(&search_attrs, &attrs, sizeof(attrs));

	/*
	 *	Do all searches as the admin user.
	 */
	if ((*pconn)->rebound) {
		status = fr_ldap_bind(request, pconn,
				      (*pconn)->config->admin_identity, (*pconn)->config->admin_password,
				      &(*pconn)->config->admin_sasl, NULL,
				      NULL, NULL);
		if (status != LDAP_PROC_SUCCESS) return LDAP_PROC_ERROR;

		rad_assert(*pconn);

		(*pconn)->rebound = false;
	}

	if (filter) {
		ROPTIONAL(RDEBUG2, DEBUG2, "Performing search in \"%s\" with filter \"%s\", scope \"%s\"", dn, filter,
			  fr_int2str(fr_ldap_scope, scope, "<INVALID>"));
	} else {
		ROPTIONAL(RDEBUG2, DEBUG2, "Performing unfiltered search in \"%s\", scope \"%s\"", dn,
			  fr_int2str(fr_ldap_scope, scope, "<INVALID>"));
	}
	/*
	 *	If LDAP search produced an error it should also be logged
	 *	to the ld. result should pick it up without us
	 *	having to pass it explicitly.
	 */
	memset(&tv, 0, sizeof(tv));

	(void) ldap_search_ext((*pconn)->handle, dn, scope, filter, search_attrs,
			       0, our_serverctrls, our_clientctrls, NULL, 0, &msgid);

	ROPTIONAL(RDEBUG2, DEBUG2, "Waiting for search result...");
	status = fr_ldap_result(&our_result, NULL, *pconn, msgid, 1, dn, NULL);
	switch (status) {
	case LDAP_PROC_SUCCESS:
		break;

	default:
		ROPTIONAL(RPEDEBUG, PERROR, "Failed performing search");

		goto finish;
	}

	count = ldap_count_entries((*pconn)->handle, our_result);
	if (count < 0) {
		ROPTIONAL(REDEBUG, ERROR, "Error counting results: %s", fr_ldap_error_str(*pconn));
		status = LDAP_PROC_ERROR;

		ldap_msgfree(our_result);
		our_result = NULL;
	} else if (count == 0) {
		ROPTIONAL(RDEBUG2, DEBUG2, "Search returned no results");
		status = LDAP_PROC_NO_RESULT;

		ldap_msgfree(our_result);
		our_result = NULL;
	}

finish:

	/*
	 *	We always need to get the result to count entries, but the caller
	 *	may not of requested one. If that's the case, free it, else write
	 *	it to where our caller said.
	 */
	if (!result) {
		if (our_result) ldap_msgfree(our_result);
	} else {
		*result = our_result;
	}

	return status;
}
示例#4
0
/** Bind to the LDAP directory as a user
 *
 * Performs a simple bind to the LDAP directory, and handles any errors that occur.
 *
 * @param[in] request		Current request, this may be NULL, in which case all
 *				debug logging is done with log.
 * @param[in,out] pconn		to use. May change as this function calls functions
 *				which auto re-connect.
 * @param[in] dn		of the user, may be NULL to bind anonymously.
 * @param[in] password		of the user, may be NULL if no password is specified.
 * @param[in] sasl		mechanism to use for bind, and additional parameters.
 * @param[in] timeout		Maximum time bind is allowed to take.
 * @param[in] serverctrls	Only used for SASL binds.  May be NULL.
 * @param[in] clientctrls	Search controls for sasl_bind.
 *				Only used for SASL binds. May be NULL.
 * @return One of the LDAP_PROC_* (#fr_ldap_rcode_t) values.
 */
fr_ldap_rcode_t fr_ldap_bind(REQUEST *request,
			     fr_ldap_connection_t **pconn,
			     char const *dn, char const *password,
#ifdef WITH_SASL
			     fr_ldap_sasl_t const *sasl,
#else
			     NDEBUG_UNUSED fr_ldap_sasl_t const *sasl,
#endif
			     struct timeval const *timeout,
			     LDAPControl **serverctrls, LDAPControl **clientctrls)
{
	fr_ldap_rcode_t			status = LDAP_PROC_ERROR;
	fr_ldap_config_t const	*handle_config = (*pconn)->config;

	int				msgid = -1;

	rad_assert(*pconn && (*pconn)->handle);

#ifndef WITH_SASL
	rad_assert(!sasl || !sasl->mech);
#endif

	if (DEBUG_ENABLED4 || (request && RDEBUG_ENABLED4)) {
		fr_ldap_timeout_debug(request, *pconn, timeout, __FUNCTION__);
	}

	/*
	 *	Bind as anonymous user
	 */
	if (!dn) dn = "";

#ifdef WITH_SASL
	if (sasl && sasl->mech) {
		status =  fr_ldap_sasl_interactive(request, *pconn, dn, password, sasl,
						   serverctrls, clientctrls, timeout);
	} else
#endif
	{
		int ret;
		struct berval cred;

		if (password) {
			memcpy(&cred.bv_val, &password, sizeof(cred.bv_val));
			cred.bv_len = talloc_array_length(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((*pconn)->handle, dn, LDAP_SASL_SIMPLE, &cred,
				     serverctrls, clientctrls, &msgid);

		/* We got a valid message ID */
		if ((ret == 0) && (msgid >= 0)) ROPTIONAL(RDEBUG2, DEBUG2, "Waiting for bind result...");

		status = fr_ldap_result(NULL, NULL, *pconn, msgid, 0, dn, NULL);
	}

	switch (status) {
	case LDAP_PROC_SUCCESS:
		ROPTIONAL(RDEBUG2, DEBUG2, "Bind successful");
		break;

	case LDAP_PROC_NOT_PERMITTED:
		ROPTIONAL(RPEDEBUG, PERROR, "Bind as \"%s\" to \"%s\" not permitted",
			  *dn ? dn : "(anonymous)", handle_config->server);
		break;

	default:
		ROPTIONAL(RPEDEBUG, PERROR, "Bind as \"%s\" to \"%s\" failed",
			  *dn ? dn : "(anonymous)", handle_config->server);
		break;
	}

	return status; /* caller closes the connection */
}