* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
+/* ACKNOWLEDGEMENTS:
+ * This work includes code from the lastbind overlay.
+ */
#include <portable.h>
static AttributeDescription *ad_authTimestamp;
+/* This is the definition used by ISODE, as supplied to us in
+ * ITS#6238 Followup #9
+ */
+static struct schema_info {
+ char *def;
+ AttributeDescription **ad;
+} totp_OpSchema[] = {
+ { "( 1.3.6.1.4.1.453.16.2.188 "
+ "NAME 'authTimestamp' "
+ "DESC 'last successful authentication using any method/mech' "
+ "EQUALITY generalizedTimeMatch "
+ "ORDERING generalizedTimeOrderingMatch "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
+ "SINGLE-VALUE NO-USER-MODIFICATION USAGE dsaOperation )",
+ &ad_authTimestamp},
+ { NULL, NULL }
+};
+
/* RFC3548 base32 encoding/decoding */
static const char Base32[] =
}
static int totp_op_cleanup( Operation *op, SlapReply *rs );
+static int totp_bind_response( Operation *op, SlapReply *rs );
#define TIME_STEP 30
#define DIGITS 6
if (told >= t)
rc = LUTIL_PASSWD_ERR;
}
+ if (!rc) { /* seems OK, remember old stamp */
+ slap_callback *sc;
+ for (sc = op->o_callback; sc; sc = sc->sc_next) {
+ if (sc->sc_response == totp_bind_response) {
+ sc->sc_private = ber_dupbv_x(NULL, &a->a_vals[0], op->o_tmpmemctx);
+ break;
+ }
+ }
+ }
} /* else no previous login, 1st use is OK */
be_entry_release_r(op, e);
/* free the callback */
cb = op->o_callback;
op->o_callback = cb->sc_next;
+ if (cb->sc_private)
+ ber_bvfree_x(cb->sc_private, op->o_tmpmemctx);
op->o_tmpfree( cb, op->o_tmpmemctx );
return 0;
}
+static int
+totp_bind_response( Operation *op, SlapReply *rs )
+{
+ Modifications *mod = NULL;
+ BackendInfo *bi = op->o_bd->bd_info;
+ Entry *e;
+ int rc;
+
+ /* we're only interested if the bind was successful */
+ if ( rs->sr_err != LDAP_SUCCESS )
+ return SLAP_CB_CONTINUE;
+
+ rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
+ op->o_bd->bd_info = bi;
+
+ if ( rc != LDAP_SUCCESS ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ {
+ time_t now;
+ Attribute *a;
+ Modifications *m;
+ char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
+ struct berval timestamp;
+
+ /* get the current time */
+ now = op->o_time;
+
+ /* update the authTimestamp in the user's entry with the current time */
+ timestamp.bv_val = nowstr;
+ timestamp.bv_len = sizeof(nowstr);
+ slap_timestamp( &now, ×tamp );
+
+ m = ch_calloc( sizeof(Modifications), 1 );
+ m->sml_op = LDAP_MOD_ADD;
+ m->sml_flags = 0;
+ m->sml_type = ad_authTimestamp->ad_cname;
+ m->sml_desc = ad_authTimestamp;
+ m->sml_numvals = 1;
+ m->sml_values = ch_calloc( sizeof(struct berval), 2 );
+ m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
+
+ ber_dupbv( &m->sml_values[0], ×tamp );
+ ber_dupbv( &m->sml_nvalues[0], ×tamp );
+ m->sml_next = mod;
+ mod = m;
+
+ /* get authTimestamp attribute, if it exists */
+ if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL && op->o_callback->sc_private) {
+ struct berval *bv = op->o_callback->sc_private;
+ m = ch_calloc( sizeof(Modifications), 1 );
+ m->sml_op = LDAP_MOD_DELETE;
+ m->sml_flags = 0;
+ m->sml_type = ad_authTimestamp->ad_cname;
+ m->sml_desc = ad_authTimestamp;
+ m->sml_numvals = 1;
+ m->sml_values = ch_calloc( sizeof(struct berval), 2 );
+ m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
+
+ ber_dupbv( &m->sml_values[0], bv );
+ ber_dupbv( &m->sml_nvalues[0], bv );
+ m->sml_next = mod;
+ mod = m;
+ }
+ }
+
+done:
+ be_entry_release_r( op, e );
+
+ /* perform the update */
+ if ( mod ) {
+ Operation op2 = *op;
+ SlapReply r2 = { REP_RESULT };
+ slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
+
+ /* This is a DSA-specific opattr, it never gets replicated. */
+ op2.o_tag = LDAP_REQ_MODIFY;
+ op2.o_callback = &cb;
+ op2.orm_modlist = mod;
+ op2.o_dn = op->o_bd->be_rootdn;
+ op2.o_ndn = op->o_bd->be_rootndn;
+ op2.o_dont_replicate = 1;
+ rc = op->o_bd->be_modify( &op2, &r2 );
+ slap_mods_free( mod, 1 );
+ if (rc != LDAP_SUCCESS) {
+ /* slapd has logged this as a success already, but we
+ * need to fail it because the authTimestamp changed
+ * out from under us.
+ */
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ connection2anonymous(op->o_conn);
+ op2 = *op;
+ op2.o_callback = NULL;
+ send_ldap_result(&op2, rs);
+ op->o_bd->bd_info = bi;
+ return rs->sr_err;
+ }
+ }
+
+ op->o_bd->bd_info = bi;
+ return SLAP_CB_CONTINUE;
+}
+
static int totp_op_bind(
Operation *op,
SlapReply *rs )
ldap_pvt_thread_pool_setkey( op->o_threadctx,
totp_op_cleanup, op, 0, NULL, NULL );
cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
+ cb->sc_response = totp_bind_response;
cb->sc_cleanup = totp_op_cleanup;
cb->sc_next = op->o_callback;
op->o_callback = cb;
const char *text = NULL;
rc = slap_str2ad("authTimestamp", &ad_authTimestamp, &text);
if (rc) {
- snprintf(cr->msg, sizeof(cr->msg), "unable to find authTimestamp attribute: %s (%d)",
- text, rc);
- Debug(LDAP_DEBUG_ANY, "totp: %s.\n", cr->msg, 0, 0);
+ rc = register_at(totp_OpSchema[0].def, totp_OpSchema[0].ad, 0 );
+ if (rc) {
+ snprintf(cr->msg, sizeof(cr->msg), "unable to find or register authTimestamp attribute: %s (%d)",
+ text, rc);
+ Debug(LDAP_DEBUG_ANY, "totp: %s.\n", cr->msg, 0, 0);
+ }
+ ad_authTimestamp->ad_type->sat_flags |= SLAP_AT_MANAGEABLE;
}
}
return rc;