From: Howard Chu Date: Thu, 2 Jul 2015 19:12:51 +0000 (+0100) Subject: Merge authTimestamp from lastbind overlay X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=ea43ac38bf8919b028466e493a69e77fdd91657d;p=openldap Merge authTimestamp from lastbind overlay This code duplicates the basic function of lastbind. The two overlays cannot be used together. The timestamp Mod op is changed to require the old value to still be present at the end of the Bind. This allows us to detect collisions (multiple successful Binds in the same time window) and properly fail the extra Bind attempts. --- diff --git a/contrib/slapd-modules/passwd/totp/README b/contrib/slapd-modules/passwd/totp/README index df84f35ba6..4840c15933 100644 --- a/contrib/slapd-modules/passwd/totp/README +++ b/contrib/slapd-modules/passwd/totp/README @@ -24,8 +24,8 @@ source root. moduleload ...path/to/slapd-sha2.so -5) This module also requires the use of the slapo-lastbind overlay. You -should build that module and also add it to your slapd configuration. +5) This module replaces the function of the slapo-lastbind overlay. You +cannot use that overlay on the same database as this one. 6) Restart slapd. @@ -47,7 +47,6 @@ lastbind overlay and the totp overlay: database mdb ... -overlay lastbind overlay totp diff --git a/contrib/slapd-modules/passwd/totp/slapd-totp.c b/contrib/slapd-modules/passwd/totp/slapd-totp.c index ec8fae61f8..9934fdffcf 100644 --- a/contrib/slapd-modules/passwd/totp/slapd-totp.c +++ b/contrib/slapd-modules/passwd/totp/slapd-totp.c @@ -14,6 +14,9 @@ * top-level directory of the distribution or, alternatively, at * . */ +/* ACKNOWLEDGEMENTS: + * This work includes code from the lastbind overlay. + */ #include @@ -40,6 +43,24 @@ static const struct berval scheme_totp512 = BER_BVC("{TOTP512}"); 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[] = @@ -330,6 +351,7 @@ static void generate( } 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 @@ -370,6 +392,15 @@ static int chk_totp( 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); @@ -509,10 +540,116 @@ static int totp_op_cleanup( /* 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 ) @@ -526,6 +663,7 @@ static int totp_op_bind( 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; @@ -544,9 +682,13 @@ static int totp_db_open( 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;