Commit 7c64a459 authored by Quanah Gibson-Mount's avatar Quanah Gibson-Mount
Browse files

ITS#6238

parent 42f8d0e9
......@@ -19,6 +19,7 @@ OpenLDAP 2.4.24 Engineering
Added slapo-sssvlv multiple sorts per connection (ITS#6686)
Added contrib/autogroup LDAP URI with attribute filter (ITS#6536)
Added contrib/dupent module (ITS#6630)
Added contrib/lastbind (ITS#6238)
Added contrib/kinit for kerberos tickets
Added contrib/noopsrch for entry counting (ITS#6598)
Fixed client tools control logging (ITS#6775)
......
......@@ -4,3 +4,4 @@ OLcfgCt{Oc|At}:1 smbk5pwd
OLcfgCt{Oc|At}:2 autogroup
OLcfgCt{Oc|At}:3 nssov
OLcfgCt{Oc|At}:4 cloak
OLcfgCt{Oc|At}:5 lastbind
# $OpenLDAP$
# Copyright 2009 Jonathan Clarke <jonathan@phillipoux.net>.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted only as authorized by the OpenLDAP
# Public License.
#
# A copy of this license is available in the file LICENSE in the
# top-level directory of the distribution or, alternatively, at
# <http://www.OpenLDAP.org/license.html>.
CPPFLAGS+=-I../../../include -I../../../servers/slapd
CPPFLAGS+=-DSLAPD_OVER_LASTBIND=SLAPD_MOD_DYNAMIC
#LIBTOOL=libtool
LIBTOOL=../../../libtool
all: lastbind.la
lastbind.lo: lastbind.c
$(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) -Wall -c $?
lastbind.la: lastbind.lo
$(LIBTOOL) --mode=link $(CC) -version-info 0:0:0 \
-rpath $(PREFIX)/lib -module -o $@ $?
clean:
rm -rf lastbind.lo lastbind.la lastbind.o .libs/
/* lastbind.c - Record timestamp of the last successful bind to entries */
/* $OpenLDAP$ */
/*
* Copyright 2009 Jonathan Clarke <jonathan@phillipoux.net>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work is loosely derived from the ppolicy overlay.
*/
#include "portable.h"
/*
* This file implements an overlay that stores the timestamp of the
* last successful bind operation in a directory entry.
*
* Optimization: to avoid performing a write on each bind,
* a precision for this timestamp may be configured, causing it to
* only be updated if it is older than a given number of seconds.
*/
#ifdef SLAPD_OVER_LASTBIND
#include <ldap.h>
#include "lutil.h"
#include "slap.h"
#include <ac/errno.h>
#include <ac/time.h>
#include <ac/string.h>
#include <ac/ctype.h>
#include "config.h"
/* Per-instance configuration information */
typedef struct lastbind_info {
/* precision to update timestamp in authTimestamp attribute */
int timestamp_precision;
} lastbind_info;
/* Operational attributes */
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;
} lastBind_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 }
};
/* configuration attribute and objectclass */
static ConfigTable lastbindcfg[] = {
{ "lastbind-precision", "seconds", 2, 2, 0,
ARG_INT|ARG_OFFSET,
(void *)offsetof(lastbind_info, timestamp_precision),
"( OLcfgAt:5.1 "
"NAME 'olcLastBindPrecision' "
"DESC 'Precision of authTimestamp attribute' "
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};
static ConfigOCs lastbindocs[] = {
{ "( OLcfgOc:5.1 "
"NAME 'olcLastBindConfig' "
"DESC 'Last Bind configuration' "
"SUP olcOverlayConfig "
"MAY ( olcLastBindPrecision ) )",
Cft_Overlay, lastbindcfg, NULL, NULL },
{ NULL, 0, NULL }
};
static time_t
parse_time( char *atm )
{
struct lutil_tm tm;
struct lutil_timet tt;
time_t ret = (time_t)-1;
if ( lutil_parsetime( atm, &tm ) == 0) {
lutil_tm2time( &tm, &tt );
ret = tt.tt_sec;
}
return ret;
}
static int
lastbind_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;
}
{
lastbind_info *lbi = (lastbind_info *) op->o_callback->sc_private;
time_t now, bindtime = (time_t)-1;
Attribute *a;
Modifications *m;
char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
struct berval timestamp;
/* get the current time */
now = slap_get_time();
/* get authTimestamp attribute, if it exists */
if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL) {
bindtime = parse_time( a->a_nvals[0].bv_val );
if (bindtime != (time_t)-1) {
/* if the recorded bind time is within our precision, we're done
* it doesn't need to be updated (save a write for nothing) */
if ((now - bindtime) < lbi->timestamp_precision) {
goto done;
}
}
}
/* 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_REPLACE;
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;
}
done:
be_entry_release_r( op, e );
/* perform the update, if necessary */
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 );
}
op->o_bd->bd_info = bi;
return SLAP_CB_CONTINUE;
}
static int
lastbind_bind( Operation *op, SlapReply *rs )
{
slap_callback *cb;
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
/* setup a callback to intercept result of this bind operation
* and pass along the lastbind_info struct */
cb = op->o_tmpcalloc( sizeof(slap_callback), 1, op->o_tmpmemctx );
cb->sc_response = lastbind_bind_response;
cb->sc_next = op->o_callback->sc_next;
cb->sc_private = on->on_bi.bi_private;
op->o_callback->sc_next = cb;
return SLAP_CB_CONTINUE;
}
static int
lastbind_db_init(
BackendDB *be,
ConfigReply *cr
)
{
slap_overinst *on = (slap_overinst *) be->bd_info;
/* initialize private structure to store configuration */
on->on_bi.bi_private = ch_calloc( 1, sizeof(lastbind_info) );
return 0;
}
static int
lastbind_db_close(
BackendDB *be,
ConfigReply *cr
)
{
slap_overinst *on = (slap_overinst *) be->bd_info;
lastbind_info *lbi = (lastbind_info *) on->on_bi.bi_private;
/* free private structure to store configuration */
free( lbi );
return 0;
}
static slap_overinst lastbind;
int lastbind_initialize()
{
int i, code;
/* register operational schema for this overlay (authTimestamp attribute) */
for (i=0; lastBind_OpSchema[i].def; i++) {
code = register_at( lastBind_OpSchema[i].def, lastBind_OpSchema[i].ad, 0 );
if ( code ) {
Debug( LDAP_DEBUG_ANY,
"lastbind_initialize: register_at failed\n", 0, 0, 0 );
return code;
}
}
lastbind.on_bi.bi_type = "lastbind";
lastbind.on_bi.bi_db_init = lastbind_db_init;
lastbind.on_bi.bi_db_close = lastbind_db_close;
lastbind.on_bi.bi_op_bind = lastbind_bind;
/* register configuration directives */
lastbind.on_bi.bi_cf_ocs = lastbindocs;
code = config_register_schema( lastbindcfg, lastbindocs );
if ( code ) return code;
return overlay_register( &lastbind );
}
#if SLAPD_OVER_LASTBIND == SLAPD_MOD_DYNAMIC
int init_module(int argc, char *argv[]) {
return lastbind_initialize();
}
#endif
#endif /* defined(SLAPD_OVER_LASTBIND) */
.TH SLAPO-LASTBIND 5 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" Copyright 2009 Jonathan Clarke, All Rights Reserved.
.\" $OpenLDAP$
.SH NAME
slapo-lastbind \- lastbind overlay to slapd
.SH SYNOPSIS
ETCDIR/slapd.conf
.SH DESCRIPTION
The
.B lastbind
overlay to
.BR slapd (8)
allows recording the timestamp of the last successful bind to entries
in the directory, in the
.B authTimestamp
attribute.
The overlay can be configured to update this timestamp only if it is
older than a given value, thus avoiding large numbers of write
operations penalizing performance.
One sample use for this overlay would be to detect unused accounts.
.SH CONFIGURATION
The config directives that are specific to the
.B lastbind
overlay must be prefixed by
.BR lastbind\- ,
to avoid potential conflicts with directives specific to the underlying
database or to other stacked overlays.
.TP
.B overlay lastbind
This directive adds the
.B lastbind
overlay to the current database, see
.BR slapd.conf (5)
for details.
.LP
This
.B slapd.conf
configuration option is defined for the lastbind overlay. It must
appear after the
.B overlay
directive:
.TP
.B lastbind-precision <seconds>
The value
.B <seconds>
is the number of seconds after which to update the
.B authTimestamp
attribute in an entry. If the existing value of
.B authTimestamp
is less than
.B <seconds>
old, it will not be changed.
If this configuration option is omitted, the
.B authTimestamp
attribute is updated on each successful bind operation.
.SH EXAMPLE
This example configures the
.B lastbind
overlay to store
.B authTimestamp
in all entries in a database, with a 1 week precision.
Add the following to
.BR slapd.conf (5):
.LP
.nf
database <database>
# ...
overlay lastbind
lastbind-precision 604800
.fi
.LP
.B slapd
must also load
.B lastbind.la,
if compiled as a run-time module;
.SH FILES
.TP
ETCDIR/slapd.conf
default slapd configuration file
.SH SEE ALSO
.BR slapd.conf (5),
.BR slapd (8).
The
.BR slapo-lastbind (5)
overlay supports dynamic configuration via
.BR back-config.
.SH ACKNOWLEDGEMENTS
.P
This module was written in 2009 by Jonathan Clarke. It is loosely
derived from the password policy overlay.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment