]> git.sur5r.net Git - openldap/commitdiff
Merge authTimestamp from lastbind overlay
authorHoward Chu <hyc@openldap.org>
Thu, 2 Jul 2015 19:12:51 +0000 (20:12 +0100)
committerHoward Chu <hyc@openldap.org>
Thu, 2 Jul 2015 19:12:51 +0000 (20:12 +0100)
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.

contrib/slapd-modules/passwd/totp/README
contrib/slapd-modules/passwd/totp/slapd-totp.c

index df84f35ba600776aaa847c1c4d84c94723311651..4840c15933ccffb60d77a203c5fe5564c7d1b888 100644 (file)
@@ -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
 
 
index ec8fae61f81ed3a40c1d4c760994cc004b55791f..9934fdffcf88afeeafb6addf7000853ac9ac4cda 100644 (file)
@@ -14,6 +14,9 @@
  * 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>
 
@@ -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, &timestamp );
+
+               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], &timestamp );
+               ber_dupbv( &m->sml_nvalues[0], &timestamp );
+               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;