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; }
int _ldap_bind(LDAP *ld, ldap_conndata_t *info, char ppolicy, LDAPMessage *result, int *msgid) { int rc; LDAPControl **server_ctrls = NULL; LDAPControl *ppolicy_ctrl = NULL; struct berval passwd; DEBUG("_ldap_bind (ld:%p, info:%p, ppolicy:%d, result:%p, msgid:%d)", ld, info, ppolicy, result, *msgid); if (ppolicy == 1) { rc = ldap_create_passwordpolicy_control(ld, &ppolicy_ctrl); if (rc != LDAP_SUCCESS) return rc; server_ctrls = (LDAPControl **)malloc(sizeof(LDAPControl *) * (1 + 1)); if (server_ctrls == NULL) return LDAP_NO_MEMORY; server_ctrls[0] = ppolicy_ctrl; server_ctrls[1] = NULL; } /* Mechanism is set, use SASL interactive bind. */ if (strcmp(info->mech, "SIMPLE") != 0) { if (info->passwd == NULL) info->passwd = ""; rc = ldap_sasl_interactive_bind(ld, info->binddn, info->mech, server_ctrls, NULL, LDAP_SASL_QUIET, sasl_interact, info, result, &(info->rmech), msgid); } else { if (info->passwd == NULL) { passwd.bv_len = 0; } else { passwd.bv_len = strlen(info->passwd); } passwd.bv_val = info->passwd; rc = ldap_sasl_bind(ld, info->binddn, LDAP_SASL_SIMPLE, &passwd, server_ctrls, NULL, msgid); } if (ppolicy_ctrl != NULL) ldap_control_free(ppolicy_ctrl); free(server_ctrls); ldap_msgfree(result); return rc; }
/* * ldap_sasl_interactive_bind_s - interactive SASL authentication * * This routine uses interactive callbacks. * * LDAP_SUCCESS is returned upon success, the ldap error code * otherwise. */ int ldap_sasl_interactive_bind_s( LDAP *ld, LDAP_CONST char *dn, /* usually NULL */ LDAP_CONST char *mechs, LDAPControl **serverControls, LDAPControl **clientControls, unsigned flags, LDAP_SASL_INTERACT_PROC *interact, void *defaults ) { const char *rmech = NULL; LDAPMessage *result = NULL; int rc, msgid; do { rc = ldap_sasl_interactive_bind( ld, dn, mechs, serverControls, clientControls, flags, interact, defaults, result, &rmech, &msgid ); ldap_msgfree( result ); if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) break; #ifdef LDAP_CONNECTIONLESS if (LDAP_IS_UDP(ld)) { break; } #endif if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) { return( ld->ld_errno ); /* ldap_result sets ld_errno */ } } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); return rc; }
/** 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; }