ldap_rcode_t rlm_ldap_sasl_interactive(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t *conn, char const *identity, char const *password, ldap_sasl *sasl, char const **error, char **extra) { ldap_rcode_t status; int ret = 0; int msgid; char const *mech; LDAPMessage *result = NULL; rlm_ldap_sasl_ctx_t sasl_ctx; /* SASL defaults */ memset(&sasl_ctx, 0, sizeof(sasl_ctx)); sasl_ctx.inst = inst; sasl_ctx.request = request; sasl_ctx.identity = identity; sasl_ctx.password = password; ROPTIONAL(RDEBUG2, DEBUG2, "Starting SASL mech(s): %s", sasl->mech); do { ret = ldap_sasl_interactive_bind(conn->handle, NULL, sasl->mech, NULL, NULL, LDAP_SASL_AUTOMATIC, _sasl_interact, &sasl_ctx, result, &mech, &msgid); ldap_msgfree(result); /* We always need to free the old message */ if (ret >= 0) ROPTIONAL(RDEBUG3, DEBUG3, "Continuing SASL mech %s...", mech); status = rlm_ldap_result(inst, conn, msgid, identity, &result, error, extra); /* * Write the servers response to the debug log */ if (((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) && result) { struct berval *srv_cred; if (ldap_parse_sasl_bind_result(conn->handle, result, &srv_cred, 0) == 0) { char *escaped; escaped = fr_aprints(request, srv_cred->bv_val, srv_cred->bv_len, '\0'); ROPTIONAL(RDEBUG3, DEBUG3, "SASL response : %s", escaped); talloc_free(escaped); ldap_memfree(srv_cred); } } } while (status == LDAP_PROC_CONTINUE); ldap_msgfree(result); return status; }
/** Initiate an LDAP interactive bind * * @param[in] inst rlm_ldap configuration. * @param[in] request Current request, this may be NULL, in which case all debug logging is done with radlog. * @param[in] conn to use. May change as this function calls functions which auto re-connect. * @param[in] identity of the user. * @param[in] password of the user. * @param[in] sasl mechanism to use for bind, and additional parameters. * @param[in] serverctrls Search controls to pass to the server. May be NULL. * @param[in] clientctrls Search controls for ldap_sasl_interactive. May be NULL. * @param[out] error message resulting from bind. * @param[out] extra information about the error. * @return One of the LDAP_PROC_* (#ldap_rcode_t) values. */ ldap_rcode_t rlm_ldap_sasl_interactive(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t *conn, char const *identity, char const *password, ldap_sasl *sasl, LDAPControl **serverctrls, LDAPControl **clientctrls, char const **error, char **extra) { ldap_rcode_t status; int ret = 0; int msgid; char const *mech; LDAPMessage *result = NULL; rlm_ldap_sasl_ctx_t sasl_ctx; /* SASL defaults */ LDAPControl *our_serverctrls[LDAP_MAX_CONTROLS]; LDAPControl *our_clientctrls[LDAP_MAX_CONTROLS]; rlm_ldap_control_merge(our_serverctrls, our_clientctrls, sizeof(our_serverctrls) / sizeof(*our_serverctrls), sizeof(our_clientctrls) / sizeof(*our_clientctrls), conn, serverctrls, clientctrls); /* rlm_ldap_result may not be called */ if (error) *error = NULL; if (extra) *extra = NULL; sasl_ctx.inst = inst; sasl_ctx.request = request; sasl_ctx.identity = identity; sasl_ctx.password = password; sasl_ctx.extra = sasl; MOD_ROPTIONAL(RDEBUG2, DEBUG2, "Starting SASL mech(s): %s", sasl->mech); for (;;) { ret = ldap_sasl_interactive_bind(conn->handle, NULL, sasl->mech, our_serverctrls, our_clientctrls, LDAP_SASL_AUTOMATIC, _sasl_interact, &sasl_ctx, result, &mech, &msgid); /* * If ldap_sasl_interactive_bind indicates it didn't want * to continue, then we're done. * * Calling ldap_result here, results in a timeout in some * cases, so we need to figure out whether the bind was * successful without the help of ldap_result. */ if (ret != LDAP_SASL_BIND_IN_PROGRESS) { status = rlm_ldap_result(inst, conn, -1, identity, NULL, error, extra); break; /* Old result gets freed on after exit */ } ldap_msgfree(result); /* We always need to free the old message */ /* * If LDAP parse result indicates there was an error * then we're done. */ status = rlm_ldap_result(inst, conn, msgid, identity, &result, error, extra); switch (status) { case LDAP_PROC_SUCCESS: /* ldap_sasl_interactive_bind should have indicated success */ case LDAP_PROC_CONTINUE: break; default: goto done; } /* * ...otherwise, the bind is still in progress. */ MOD_ROPTIONAL(RDEBUG3, DEBUG3, "Continuing SASL mech %s...", mech); /* * Write the servers response to the debug log */ if (((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) && result) { struct berval *srv_cred; if (ldap_parse_sasl_bind_result(conn->handle, result, &srv_cred, 0) == 0) { char *escaped; escaped = fr_asprint(request, srv_cred->bv_val, srv_cred->bv_len, '\0'); MOD_ROPTIONAL(RDEBUG3, DEBUG3, "SASL response : %s", escaped); talloc_free(escaped); ldap_memfree(srv_cred); } } } done: ldap_msgfree(result); return status; }