int use_lockout; /* send AccountLocked result? */
int hash_passwords; /* transparently hash cleartext pwds */
int forward_updates; /* use frontend for policy state updates */
+ int send_netscape_controls; /* send netscape password controls */
} pp_info;
/* Our per-connection info - note, it is not per-instance, it is
"( OLcfgOvAt:12.3 NAME 'olcPPolicyUseLockout' "
"DESC 'Warn clients with AccountLocked' "
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+ { "ppolicy_send_netscape_controls", "on|off", 1, 2, 0,
+ ARG_ON_OFF|ARG_OFFSET,
+ (void *)offsetof(pp_info,send_netscape_controls),
+ "( OLcfgOvAt:12.6 NAME 'olcPPolicySendNetscapeControls' "
+ "DESC 'Send Netscape policy controls' "
+ "EQUALITY booleanMatch "
+ "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};
"DESC 'Password Policy configuration' "
"SUP olcOverlayConfig "
"MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ "
- "olcPPolicyUseLockout $ olcPPolicyForwardUpdates ) )",
+ "olcPPolicyUseLockout $ olcPPolicyForwardUpdates $ "
+ "olcPPolicySendNetscapeControls ) )",
Cft_Overlay, ppolicycfg },
{ NULL, 0, NULL }
};
#define PPOLICY_GRACE 0x81L /* primitive + 1 */
static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE;
+static const char ppolicy_pwd_expired_oid[] = LDAP_CONTROL_X_PASSWORD_EXPIRED;
+static const char ppolicy_pwd_expiring_oid[] = LDAP_CONTROL_X_PASSWORD_EXPIRING;
static LDAPControl *
create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyError err )
return cp;
}
+static LDAPControl *
+create_passexpiry( Operation *op, int expired, int warn )
+{
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *) &berbuf;
+ LDAPControl c = { 0 }, *cp;
+ char buf[sizeof("-2147483648")];
+ struct berval bv = { .bv_val = buf, .bv_len = sizeof(buf) };
+ int rc;
+
+ BER_BVZERO( &c.ldctl_value );
+
+ bv.bv_len = snprintf( bv.bv_val, bv.bv_len, "%d", warn );
+
+ ber_init2( ber, NULL, LBER_USE_DER );
+ ber_printf( ber, "O", &bv );
+
+ if (ber_flatten2( ber, &c.ldctl_value, 0 ) == -1) {
+ return NULL;
+ }
+ cp = op->o_tmpalloc( sizeof( LDAPControl ) + c.ldctl_value.bv_len, op->o_tmpmemctx );
+ if ( expired ) {
+ cp->ldctl_oid = (char *)ppolicy_pwd_expired_oid;
+ } else {
+ cp->ldctl_oid = (char *)ppolicy_pwd_expiring_oid;
+ }
+ cp->ldctl_iscritical = 0;
+ cp->ldctl_value.bv_val = (char *)&cp[1];
+ cp->ldctl_value.bv_len = c.ldctl_value.bv_len;
+ AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len );
+fail:
+ (void)ber_free_buf(ber);
+
+ return cp;
+}
+
static LDAPControl **
add_passcontrol( Operation *op, SlapReply *rs, LDAPControl *ctrl )
{
assert( rs->sr_ctrls[0] != NULL );
for ( n = 0; rs->sr_ctrls[n]; n++ ) {
- if ( rs->sr_ctrls[n]->ldctl_oid == ppolicy_ctrl_oid ) {
+ if ( rs->sr_ctrls[n]->ldctl_oid == ppolicy_ctrl_oid ||
+ rs->sr_ctrls[n]->ldctl_oid == ppolicy_pwd_expired_oid ||
+ rs->sr_ctrls[n]->ldctl_oid == ppolicy_pwd_expiring_oid ) {
op->o_tmpfree( rs->sr_ctrls[n], op->o_tmpmemctx );
rs->sr_ctrls[n] = (LDAPControl *)(-1);
break;
{
ppbind *ppb = op->o_callback->sc_private;
slap_overinst *on = ppb->on;
+ pp_info *pi = on->on_bi.bi_private;
Modifications *mod = ppb->mod, *m;
int pwExpired = 0;
int ngut = -1, warn = -1, age, rc;
char nowstr_usec[ LDAP_LUTIL_GENTIME_BUFSIZE+8 ];
struct berval timestamp, timestamp_usec;
BackendInfo *bi = op->o_bd->bd_info;
+ LDAPControl *ctrl = NULL;
Entry *e;
/* If we already know it's locked, just get on with it */
Operation op2 = *op;
SlapReply r2 = { REP_RESULT };
slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
- pp_info *pi = on->on_bi.bi_private;
LDAPControl c, *ca[2];
op2.o_tag = LDAP_REQ_MODIFY;
}
if ( ppb->send_ctrl ) {
- LDAPControl *ctrl = NULL;
- pp_info *pi = on->on_bi.bi_private;
/* Do we really want to tell that the account is locked? */
if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) {
ppb->pErr = PP_noError;
}
ctrl = create_passcontrol( op, warn, ngut, ppb->pErr );
+ } else if ( pi->send_netscape_controls ) {
+ if ( ppb->pErr != PP_noError || ngut > 0 ) {
+ ctrl = create_passexpiry( op, 1, 0 );
+ } else if ( warn > 0 ) {
+ ctrl = create_passexpiry( op, 0, warn );
+ }
+ }
+ if ( ctrl ) {
ppb->oldctrls = add_passcontrol( op, rs, ctrl );
op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup;
}
return code;
}
+ /* We don't expect to receive these controls, only send them */
+ code = register_supported_control( LDAP_CONTROL_X_PASSWORD_EXPIRED,
+ 0, NULL, NULL, NULL );
+ if ( code != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code, 0, 0 );
+ return code;
+ }
+
+ code = register_supported_control( LDAP_CONTROL_X_PASSWORD_EXPIRING,
+ 0, NULL, NULL, NULL );
+ if ( code != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code, 0, 0 );
+ return code;
+ }
+
ldap_pvt_thread_mutex_init( &chk_syntax_mutex );
ppolicy.on_bi.bi_type = "ppolicy";