Back to index

openldap  2.4.31
lastbind.c
Go to the documentation of this file.
00001 /* lastbind.c - Record timestamp of the last successful bind to entries */
00002 /* $OpenLDAP$ */
00003 /*
00004  * Copyright 2009 Jonathan Clarke <jonathan@phillipoux.net>.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* ACKNOWLEDGEMENTS:
00016  * This work is loosely derived from the ppolicy overlay.
00017  */
00018 
00019 #include "portable.h"
00020 
00021 /*
00022  * This file implements an overlay that stores the timestamp of the
00023  * last successful bind operation in a directory entry.
00024  *
00025  * Optimization: to avoid performing a write on each bind,
00026  * a precision for this timestamp may be configured, causing it to
00027  * only be updated if it is older than a given number of seconds.
00028  */
00029 
00030 #ifdef SLAPD_OVER_LASTBIND
00031 
00032 #include <ldap.h>
00033 #include "lutil.h"
00034 #include "slap.h"
00035 #include <ac/errno.h>
00036 #include <ac/time.h>
00037 #include <ac/string.h>
00038 #include <ac/ctype.h>
00039 #include "config.h"
00040 
00041 /* Per-instance configuration information */
00042 typedef struct lastbind_info {
00043        /* precision to update timestamp in authTimestamp attribute */
00044        int timestamp_precision;
00045 } lastbind_info;
00046 
00047 /* Operational attributes */
00048 static AttributeDescription *ad_authTimestamp;
00049 
00050 /* This is the definition used by ISODE, as supplied to us in
00051  * ITS#6238 Followup #9
00052  */
00053 static struct schema_info {
00054        char *def;
00055        AttributeDescription **ad;
00056 } lastBind_OpSchema[] = {
00057        {      "( 1.3.6.1.4.1.453.16.2.188 "
00058               "NAME 'authTimestamp' "
00059               "DESC 'last successful authentication using any method/mech' "
00060               "EQUALITY generalizedTimeMatch "
00061               "ORDERING generalizedTimeOrderingMatch "
00062               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
00063               "SINGLE-VALUE NO-USER-MODIFICATION USAGE dsaOperation )",
00064               &ad_authTimestamp},
00065        { NULL, NULL }
00066 };
00067 
00068 /* configuration attribute and objectclass */
00069 static ConfigTable lastbindcfg[] = {
00070        { "lastbind-precision", "seconds", 2, 2, 0,
00071          ARG_INT|ARG_OFFSET,
00072          (void *)offsetof(lastbind_info, timestamp_precision),
00073          "( OLcfgAt:5.1 "
00074          "NAME 'olcLastBindPrecision' "
00075          "DESC 'Precision of authTimestamp attribute' "
00076          "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00077        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
00078 };
00079 
00080 static ConfigOCs lastbindocs[] = {
00081        { "( OLcfgOc:5.1 "
00082          "NAME 'olcLastBindConfig' "
00083          "DESC 'Last Bind configuration' "
00084          "SUP olcOverlayConfig "
00085          "MAY ( olcLastBindPrecision ) )",
00086          Cft_Overlay, lastbindcfg, NULL, NULL },
00087        { NULL, 0, NULL }
00088 };
00089 
00090 static time_t
00091 parse_time( char *atm )
00092 {
00093        struct lutil_tm tm;
00094        struct lutil_timet tt;
00095        time_t ret = (time_t)-1;
00096 
00097        if ( lutil_parsetime( atm, &tm ) == 0) {
00098               lutil_tm2time( &tm, &tt );
00099               ret = tt.tt_sec;
00100        }
00101        return ret;
00102 }
00103 
00104 static int
00105 lastbind_bind_response( Operation *op, SlapReply *rs )
00106 {
00107        Modifications *mod = NULL;
00108        BackendInfo *bi = op->o_bd->bd_info;
00109        Entry *e;
00110        int rc;
00111 
00112        /* we're only interested if the bind was successful */
00113        if ( rs->sr_err != LDAP_SUCCESS )
00114               return SLAP_CB_CONTINUE;
00115 
00116        rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
00117        op->o_bd->bd_info = bi;
00118 
00119        if ( rc != LDAP_SUCCESS ) {
00120               return SLAP_CB_CONTINUE;
00121        }
00122 
00123        {
00124               lastbind_info *lbi = (lastbind_info *) op->o_callback->sc_private;
00125 
00126               time_t now, bindtime = (time_t)-1;
00127               Attribute *a;
00128               Modifications *m;
00129               char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
00130               struct berval timestamp;
00131 
00132               /* get the current time */
00133               now = slap_get_time();
00134 
00135               /* get authTimestamp attribute, if it exists */
00136               if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL) {
00137                      bindtime = parse_time( a->a_nvals[0].bv_val );
00138 
00139                      if (bindtime != (time_t)-1) {
00140                             /* if the recorded bind time is within our precision, we're done
00141                              * it doesn't need to be updated (save a write for nothing) */
00142                             if ((now - bindtime) < lbi->timestamp_precision) {
00143                                    goto done;
00144                             }
00145                      }
00146               }
00147 
00148               /* update the authTimestamp in the user's entry with the current time */
00149               timestamp.bv_val = nowstr;
00150               timestamp.bv_len = sizeof(nowstr);
00151               slap_timestamp( &now, &timestamp );
00152 
00153               m = ch_calloc( sizeof(Modifications), 1 );
00154               m->sml_op = LDAP_MOD_REPLACE;
00155               m->sml_flags = 0;
00156               m->sml_type = ad_authTimestamp->ad_cname;
00157               m->sml_desc = ad_authTimestamp;
00158               m->sml_numvals = 1;
00159               m->sml_values = ch_calloc( sizeof(struct berval), 2 );
00160               m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
00161 
00162               ber_dupbv( &m->sml_values[0], &timestamp );
00163               ber_dupbv( &m->sml_nvalues[0], &timestamp );
00164               m->sml_next = mod;
00165               mod = m;
00166        }
00167 
00168 done:
00169        be_entry_release_r( op, e );
00170 
00171        /* perform the update, if necessary */
00172        if ( mod ) {
00173               Operation op2 = *op;
00174               SlapReply r2 = { REP_RESULT };
00175               slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
00176 
00177               /* This is a DSA-specific opattr, it never gets replicated. */
00178               op2.o_tag = LDAP_REQ_MODIFY;
00179               op2.o_callback = &cb;
00180               op2.orm_modlist = mod;
00181               op2.o_dn = op->o_bd->be_rootdn;
00182               op2.o_ndn = op->o_bd->be_rootndn;
00183               op2.o_dont_replicate = 1;
00184               rc = op->o_bd->be_modify( &op2, &r2 );
00185               slap_mods_free( mod, 1 );
00186        }
00187 
00188        op->o_bd->bd_info = bi;
00189        return SLAP_CB_CONTINUE;
00190 }
00191 
00192 static int
00193 lastbind_bind( Operation *op, SlapReply *rs )
00194 {
00195        slap_callback *cb;
00196        slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
00197 
00198        /* setup a callback to intercept result of this bind operation
00199         * and pass along the lastbind_info struct */
00200        cb = op->o_tmpcalloc( sizeof(slap_callback), 1, op->o_tmpmemctx );
00201        cb->sc_response = lastbind_bind_response;
00202        cb->sc_next = op->o_callback->sc_next;
00203        cb->sc_private = on->on_bi.bi_private;
00204        op->o_callback->sc_next = cb;
00205 
00206        return SLAP_CB_CONTINUE;
00207 }
00208 
00209 static int
00210 lastbind_db_init(
00211        BackendDB *be,
00212        ConfigReply *cr
00213 )
00214 {
00215        slap_overinst *on = (slap_overinst *) be->bd_info;
00216 
00217        /* initialize private structure to store configuration */
00218        on->on_bi.bi_private = ch_calloc( 1, sizeof(lastbind_info) );
00219 
00220        return 0;
00221 }
00222 
00223 static int
00224 lastbind_db_close(
00225        BackendDB *be,
00226        ConfigReply *cr
00227 )
00228 {
00229        slap_overinst *on = (slap_overinst *) be->bd_info;
00230        lastbind_info *lbi = (lastbind_info *) on->on_bi.bi_private;
00231 
00232        /* free private structure to store configuration */
00233        free( lbi );
00234 
00235        return 0;
00236 }
00237 
00238 static slap_overinst lastbind;
00239 
00240 int lastbind_initialize()
00241 {
00242        int i, code;
00243 
00244        /* register operational schema for this overlay (authTimestamp attribute) */
00245        for (i=0; lastBind_OpSchema[i].def; i++) {
00246               code = register_at( lastBind_OpSchema[i].def, lastBind_OpSchema[i].ad, 0 );
00247               if ( code ) {
00248                      Debug( LDAP_DEBUG_ANY,
00249                             "lastbind_initialize: register_at failed\n", 0, 0, 0 );
00250                      return code;
00251               }
00252        }
00253 
00254        ad_authTimestamp->ad_type->sat_flags |= SLAP_AT_MANAGEABLE;
00255 
00256        lastbind.on_bi.bi_type = "lastbind";
00257        lastbind.on_bi.bi_db_init = lastbind_db_init;
00258        lastbind.on_bi.bi_db_close = lastbind_db_close;
00259        lastbind.on_bi.bi_op_bind = lastbind_bind;
00260 
00261        /* register configuration directives */
00262        lastbind.on_bi.bi_cf_ocs = lastbindocs;
00263        code = config_register_schema( lastbindcfg, lastbindocs );
00264        if ( code ) return code;
00265 
00266        return overlay_register( &lastbind );
00267 }
00268 
00269 #if SLAPD_OVER_LASTBIND == SLAPD_MOD_DYNAMIC
00270 int init_module(int argc, char *argv[]) {
00271        return lastbind_initialize();
00272 }
00273 #endif
00274 
00275 #endif /* defined(SLAPD_OVER_LASTBIND) */