| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- /******************************************************************************
- Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- version 2 as published by the Free Software Foundation.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- Contributors:
- Hewlett-Packard Development Company, L.P.
- ******************************************************************************/
- /* Account Policy plugin */
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <time.h>
- #include "slapi-plugin.h"
- #include "acctpolicy.h"
- /*
- Checks bind entry for last login state and compares current time with last
- login time plus the limit to decide whether to deny the bind.
- */
- static int
- acct_inact_limit( Slapi_PBlock *pb, const char *dn, Slapi_Entry *target_entry, acctPolicy *policy )
- {
- char *lasttimestr = NULL;
- time_t lim_t, last_t, cur_t;
- int rc = 0; /* Optimistic default */
- acctPluginCfg *cfg;
- cfg = get_config();
- if( ( lasttimestr = get_attr_string_val( target_entry,
- cfg->state_attr_name ) ) != NULL ) {
- slapi_log_error( SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME,
- "\"%s\" login timestamp is %s\n", dn, lasttimestr );
- } else if( cfg->alt_state_attr_name && (( lasttimestr = get_attr_string_val( target_entry,
- cfg->alt_state_attr_name ) ) != NULL) ) {
- slapi_log_error( SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME,
- "\"%s\" alternate timestamp is %s\n", dn, lasttimestr );
- } else {
- /* the primary or alternate attribute might not yet exist eg.
- * if only lastlogintime is specified and it id the first login
- */
- slapi_log_error( SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME,
- "\"%s\" has no value for stateattr or altstateattr \n", dn );
- goto done;
- }
- last_t = gentimeToEpochtime( lasttimestr );
- cur_t = time( (time_t*)0 );
- lim_t = policy->inactivitylimit;
- /* Finally do the time comparison */
- if( cur_t > last_t + lim_t ) {
- slapi_log_error( SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME,
- "\"%s\" has exceeded inactivity limit (%ld > (%ld + %ld))\n",
- dn, cur_t, last_t, lim_t );
- rc = 1;
- goto done;
- } else {
- slapi_log_error( SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME,
- "\"%s\" is within inactivity limit (%ld < (%ld + %ld))\n",
- dn, cur_t, last_t, lim_t );
- }
- done:
- /* Deny bind; the account has exceeded the inactivity limit */
- if( rc == 1 ) {
- slapi_send_ldap_result( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
- "Account inactivity limit exceeded."
- " Contact system administrator to reset.", 0, NULL );
- }
- slapi_ch_free_string( &lasttimestr );
- return( rc );
- }
- /*
- This is called after binds, it updates an attribute in the account
- with the current time.
- */
- static int
- acct_record_login( const char *dn )
- {
- int ldrc;
- int rc = 0; /* Optimistic default */
- LDAPMod *mods[2];
- LDAPMod mod;
- struct berval *vals[2];
- struct berval val;
- char *timestr = NULL;
- acctPluginCfg *cfg;
- void *plugin_id;
- Slapi_PBlock *modpb = NULL;
- int skip_mod_attrs = 1; /* value doesn't matter as long as not NULL */
- cfg = get_config();
- /* if we are not allowed to modify the state attr we're done
- * this could be intentional, so just return
- */
- if (! update_is_allowed_attr(cfg->state_attr_name) )
- return rc;
-
- plugin_id = get_identity();
- timestr = epochtimeToGentime( time( (time_t*)0 ) );
- val.bv_val = timestr;
- val.bv_len = strlen( val.bv_val );
- vals [0] = &val;
- vals [1] = NULL;
- mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
- mod.mod_type = cfg->state_attr_name;
- mod.mod_bvalues = vals;
- mods[0] = &mod;
- mods[1] = NULL;
- modpb = slapi_pblock_new();
- slapi_modify_internal_set_pb( modpb, dn, mods, NULL, NULL,
- plugin_id, SLAPI_OP_FLAG_NO_ACCESS_CHECK |
- SLAPI_OP_FLAG_BYPASS_REFERRALS );
- slapi_pblock_set( modpb, SLAPI_SKIP_MODIFIED_ATTRS, &skip_mod_attrs );
- slapi_modify_internal_pb( modpb );
- slapi_pblock_get( modpb, SLAPI_PLUGIN_INTOP_RESULT, &ldrc );
- if (ldrc != LDAP_SUCCESS) {
- slapi_log_error( SLAPI_LOG_FATAL, POST_PLUGIN_NAME,
- "Recording %s=%s failed on \"%s\" err=%d\n", cfg->state_attr_name,
- timestr, dn, ldrc );
- rc = -1;
- goto done;
- } else {
- slapi_log_error( SLAPI_LOG_PLUGIN, POST_PLUGIN_NAME,
- "Recorded %s=%s on \"%s\"\n", cfg->state_attr_name, timestr, dn );
- }
- done:
- slapi_pblock_destroy( modpb );
- slapi_ch_free_string( ×tr );
- return( rc );
- }
- /*
- Handles bind preop callbacks
- */
- int
- acct_bind_preop( Slapi_PBlock *pb )
- {
- const char *dn = NULL;
- Slapi_DN *sdn = NULL;
- Slapi_Entry *target_entry = NULL;
- int rc = 0; /* Optimistic default */
- int ldrc;
- acctPolicy *policy = NULL;
- void *plugin_id;
- slapi_log_error( SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME,
- "=> acct_bind_preop\n" );
- plugin_id = get_identity();
- /* This does not give a copy, so don't free it */
- if( slapi_pblock_get( pb, SLAPI_BIND_TARGET_SDN, &sdn ) != 0 ) {
- slapi_log_error( SLAPI_LOG_FATAL, PRE_PLUGIN_NAME,
- "Error retrieving target DN\n" );
- rc = -1;
- goto done;
- }
- dn = slapi_sdn_get_dn(sdn);
- /* The plugin wouldn't get called for anonymous binds but let's check */
- if ( dn == NULL ) {
- goto done;
- }
- ldrc = slapi_search_internal_get_entry( sdn, NULL, &target_entry,
- plugin_id );
- /* There was a problem retrieving the entry */
- if( ldrc != LDAP_SUCCESS ) {
- if( ldrc != LDAP_NO_SUCH_OBJECT ) {
- /* The problem is not a bad bind or virtual entry; halt bind */
- slapi_log_error( SLAPI_LOG_FATAL, PRE_PLUGIN_NAME,
- "Failed to retrieve entry \"%s\": %d\n", dn, ldrc );
- rc = -1;
- }
- goto done;
- }
- if( get_acctpolicy( pb, target_entry, plugin_id, &policy ) ) {
- slapi_log_error( SLAPI_LOG_FATAL, PRE_PLUGIN_NAME,
- "Account Policy object for \"%s\" is missing\n", dn );
- rc = -1;
- goto done;
- }
- /* Null policy means target isnt's under the influence of a policy */
- if( policy == NULL ) {
- slapi_log_error( SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME,
- "\"%s\" is not governed by an account policy\n", dn);
- goto done;
- }
- /* Check whether the account is in violation of inactivity limit */
- rc = acct_inact_limit( pb, dn, target_entry, policy );
- /* ...Any additional account policy enforcement goes here... */
- done:
- /* Internal error */
- if( rc == -1 ) {
- slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL );
- }
- slapi_entry_free( target_entry );
- free_acctpolicy( &policy );
- slapi_log_error( SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME,
- "<= acct_bind_preop\n" );
- return( rc == 0 ? CALLBACK_OK : CALLBACK_ERR );
- }
- /*
- This is called after binds, it updates an attribute in the entry that the
- bind DN corresponds to with the current time if it has an account policy
- specifier.
- */
- int
- acct_bind_postop( Slapi_PBlock *pb )
- {
- char *dn = NULL;
- int ldrc, tracklogin = 0;
- int rc = 0; /* Optimistic default */
- Slapi_DN *sdn = NULL;
- Slapi_Entry *target_entry = NULL;
- acctPluginCfg *cfg;
- void *plugin_id;
- slapi_log_error( SLAPI_LOG_PLUGIN, POST_PLUGIN_NAME,
- "=> acct_bind_postop\n" );
- plugin_id = get_identity();
- /* Retrieving SLAPI_CONN_DN from the pb gives a copy */
- if( slapi_pblock_get( pb, SLAPI_CONN_DN, &dn ) != 0 ) {
- slapi_log_error( SLAPI_LOG_FATAL, POST_PLUGIN_NAME,
- "Error retrieving bind DN\n" );
- rc = -1;
- goto done;
- }
- /* Client is anonymously bound */
- if( dn == NULL ) {
- goto done;
- }
- cfg = get_config();
- tracklogin = cfg->always_record_login;
- /* We're not always tracking logins, so check whether the entry is
- covered by an account policy to decide whether we should track */
- if( tracklogin == 0 ) {
- sdn = slapi_sdn_new_normdn_byref( dn );
- ldrc = slapi_search_internal_get_entry( sdn, NULL, &target_entry,
- plugin_id );
- if( ldrc != LDAP_SUCCESS ) {
- slapi_log_error( SLAPI_LOG_FATAL, POST_PLUGIN_NAME,
- "Failed to retrieve entry \"%s\": %d\n", dn, ldrc );
- rc = -1;
- goto done;
- } else {
- if( target_entry && has_attr( target_entry,
- cfg->spec_attr_name, NULL ) ) {
- tracklogin = 1;
- }
- }
- }
- if( tracklogin ) {
- rc = acct_record_login( dn );
- }
- /* ...Any additional account policy postops go here... */
- done:
- if( rc == -1 ) {
- slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL );
- }
- slapi_entry_free( target_entry );
- slapi_sdn_free( &sdn );
- slapi_ch_free_string( &dn );
- slapi_log_error( SLAPI_LOG_PLUGIN, POST_PLUGIN_NAME,
- "<= acct_bind_postop\n" );
- return( rc == 0 ? CALLBACK_OK : CALLBACK_ERR );
- }
|