I realize that development discussion is supposed to go to openldap-devel, but despite having subscribed to that a month ago, none of my postings have gone through. I hear they are having some technical difficulties with that list, so for the sake of this submission not being indefinitely delayed, here it is.
Attached is a proposed patch to fix ITS #7161. It uses the same method as the accesslog module to generate a subsecond generalized time, appending the o_tincr value from the operation structure as fractional seconds. The only other code that looks at the value of that attribute calls parse_time to pull seconds out of it (ignoring the fractional second part), so other than modifying the format the attribute is stored in I don't believe there are any other changes required with this.
>From 800de5001a42fb421d814b04b09154f1ecccdc0b Mon Sep 17 00:00:00 2001 From: "Paul B. Henson" <[email protected]> Date: Fri, 23 May 2014 14:10:54 -0700 Subject: [PATCH] ITS#7161 ppolicy pwdFailureTime resolution should be better than 1 second --- servers/slapd/overlays/ppolicy.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index 83aa099..822d9fd 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -910,9 +910,10 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) int pwExpired = 0; int ngut = -1, warn = -1, age, rc; Attribute *a; - time_t now, pwtime = (time_t)-1; - char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ]; - struct berval timestamp; + time_t pwtime = (time_t)-1; + char timestr[ LDAP_LUTIL_GENTIME_BUFSIZE ]; + char failtimestr[ LDAP_LUTIL_GENTIME_BUFSIZE+8 ]; + struct berval timestamp, failtimestamp; BackendInfo *bi = op->o_bd->bd_info; Entry *e; @@ -929,10 +930,16 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) return SLAP_CB_CONTINUE; } - now = slap_get_time(); /* stored for later consideration */ - timestamp.bv_val = nowstr; - timestamp.bv_len = sizeof(nowstr); - slap_timestamp( &now, ×tamp ); + timestamp.bv_val = timestr; + timestamp.bv_len = sizeof(timestr); + slap_timestamp( &op->o_time, ×tamp ); + + /* Separate timestamp for pwdFailureTime with subsecond granularity */ + failtimestamp.bv_val = failtimestr; + failtimestamp.bv_len = sizeof(failtimestr); + slap_timestamp( &op->o_time, &failtimestamp ); + snprintf( failtimestamp.bv_val + failtimestamp.bv_len-1, sizeof(".123456Z"), ".%06dZ", op->o_tincr ); + failtimestamp.bv_len += STRLENOF(".123456"); if ( rs->sr_err == LDAP_INVALID_CREDENTIALS ) { int i = 0, fc = 0; @@ -946,8 +953,8 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) m->sml_values = ch_calloc( sizeof(struct berval), 2 ); m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); - ber_dupbv( &m->sml_values[0], ×tamp ); - ber_dupbv( &m->sml_nvalues[0], ×tamp ); + ber_dupbv( &m->sml_values[0], &failtimestamp ); + ber_dupbv( &m->sml_nvalues[0], &failtimestamp ); m->sml_next = mod; mod = m; @@ -966,7 +973,7 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) */ if (ppb->pp.pwdFailureCountInterval == 0) { fc++; - } else if (now <= + } else if (op->o_time <= parse_time(a->a_nvals[i].bv_val) + ppb->pp.pwdFailureCountInterval) { @@ -1052,7 +1059,7 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) * the password older than the maximum age * allowed. (Ignore case 2 from I-D, it's just silly.) */ - if (now - pwtime > ppb->pp.pwdMaxAge ) pwExpired = 1; + if (op->o_time - pwtime > ppb->pp.pwdMaxAge ) pwExpired = 1; } } @@ -1108,7 +1115,7 @@ check_expiring_password: if ((ppb->pp.pwdMaxAge < 1) || (pwExpired) || (ppb->pp.pwdExpireWarning < 1)) goto done; - age = (int)(now - pwtime); + age = (int)(op->o_time - pwtime); /* * We know that there is a password Change Time attribute - if -- 1.8.3.2
