Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
orbea -
OpenLDAP
Commits
419b9ad2
Commit
419b9ad2
authored
Oct 24, 2019
by
Ondřej Kuzník
Browse files
ITS#9156 Implement pwdMaxIdle
parent
8c10b048
Changes
7
Hide whitespace changes
Inline
Side-by-side
doc/man/man5/slapd-config.5
View file @
419b9ad2
...
...
@@ -1429,6 +1429,12 @@ createTimestamp attributes for entries. It also controls
the entryCSN and entryUUID attributes, which are needed
by the syncrepl provider. By default, olcLastMod is TRUE.
.TP
.B olcLastBind: TRUE | FALSE
Controls whether
.B slapd
will automatically maintain the pwdLastSuccess attribute for
entries. By default, olcLastBind is FALSE.
.TP
.B olcLimits: <selector> <limit> [<limit> [...]]
Specify time and size limits based on the operation's initiator or
base DN.
...
...
doc/man/man5/slapd.conf.5
View file @
419b9ad2
...
...
@@ -1364,6 +1364,12 @@ createTimestamp attributes for entries. It also controls
the entryCSN and entryUUID attributes, which are needed
by the syncrepl provider. By default, lastmod is on.
.TP
.B lastbind on | off
Controls whether
.B slapd
will automatically maintain the pwdLastSuccess attribute for
entries. By default, lastbind is off.
.TP
.B limits <selector> <limit> [<limit> [...]]
Specify time and size limits based on the operation's initiator or
base DN.
...
...
servers/slapd/bconfig.c
View file @
419b9ad2
...
...
@@ -178,6 +178,7 @@ enum {
CFG_MODLOAD
,
CFG_MODPATH
,
CFG_LASTMOD
,
CFG_LASTBIND
,
CFG_AZPOLICY
,
CFG_AZREGEXP
,
CFG_AZDUC
,
...
...
@@ -442,6 +443,10 @@ static ConfigTable config_back_cf_table[] = {
&
config_generic
,
"( OLcfgDbAt:0.4 NAME 'olcLastMod' "
"EQUALITY booleanMatch "
"SYNTAX OMsBoolean SINGLE-VALUE )"
,
NULL
,
NULL
},
{
"lastbind"
,
"on|off"
,
2
,
2
,
0
,
ARG_DB
|
ARG_ON_OFF
|
ARG_MAGIC
|
CFG_LASTBIND
,
&
config_generic
,
"( OLcfgDbAt:0.22 NAME 'olcLastBind' "
"EQUALITY booleanMatch "
"SYNTAX OMsBoolean SINGLE-VALUE )"
,
NULL
,
NULL
},
{
"ldapsyntax"
,
"syntax"
,
2
,
0
,
0
,
ARG_PAREN
|
ARG_MAGIC
|
CFG_SYNTAX
,
&
config_generic
,
"( OLcfgGlAt:85 NAME 'olcLdapSyntaxes' "
...
...
@@ -981,7 +986,7 @@ static ConfigOCs cf_ocs[] = {
"SUP olcConfig STRUCTURAL "
"MUST olcDatabase "
"MAY ( olcDisabled $ olcHidden $ olcSuffix $ olcSubordinate $ olcAccess $ "
"olcAddContentAcl $ olcLastMod $ olcLimits $ "
"olcAddContentAcl $ olcLastMod $
olcLastBind $
olcLimits $ "
"olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ "
"olcReplicaArgsFile $ olcReplicaPidFile $ olcReplicationInterval $ "
"olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
...
...
@@ -1321,6 +1326,9 @@ config_generic(ConfigArgs *c) {
case
CFG_LASTMOD
:
c
->
value_int
=
(
SLAP_NOLASTMOD
(
c
->
be
)
==
0
);
break
;
case
CFG_LASTBIND
:
c
->
value_int
=
(
SLAP_NOLASTMOD
(
c
->
be
)
==
0
);
break
;
case
CFG_SYNC_SUBENTRY
:
c
->
value_int
=
(
SLAP_SYNC_SUBENTRY
(
c
->
be
)
!=
0
);
break
;
...
...
@@ -1435,6 +1443,7 @@ config_generic(ConfigArgs *c) {
case
CFG_AZPOLICY
:
case
CFG_DEPTH
:
case
CFG_LASTMOD
:
case
CFG_LASTBIND
:
case
CFG_MONITORING
:
case
CFG_SASLSECP
:
case
CFG_SSTR_IF_MAX
:
...
...
@@ -2276,6 +2285,13 @@ sortval_reject:
SLAP_DBFLAGS
(
c
->
be
)
|=
SLAP_DBFLAG_NOLASTMOD
;
break
;
case
CFG_LASTBIND
:
if
(
c
->
value_int
)
SLAP_DBFLAGS
(
c
->
be
)
|=
SLAP_DBFLAG_LASTBIND
;
else
SLAP_DBFLAGS
(
c
->
be
)
&=
~
SLAP_DBFLAG_LASTBIND
;
break
;
case
CFG_MIRRORMODE
:
if
(
c
->
value_int
&&
!
SLAP_SHADOW
(
c
->
be
))
{
snprintf
(
c
->
cr_msg
,
sizeof
(
c
->
cr_msg
),
"<%s> database is not a shadow"
,
...
...
servers/slapd/bind.c
View file @
419b9ad2
...
...
@@ -31,6 +31,7 @@
#include <ac/string.h>
#include <ac/socket.h>
#include "lutil.h"
#include "slap.h"
int
...
...
@@ -399,6 +400,113 @@ cleanup:;
return
rs
->
sr_err
;
}
int
fe_op_lastbind
(
Operation
*
op
)
{
Operation
op2
=
*
op
;
SlapReply
r2
=
{
REP_RESULT
};
slap_callback
cb
=
{
NULL
,
slap_null_cb
,
NULL
,
NULL
};
LDAPControl
c
,
*
ca
[
2
];
Modifications
*
m
;
Entry
*
e
;
Attribute
*
a
;
char
nowstr
[
LDAP_LUTIL_GENTIME_BUFSIZE
];
struct
berval
timestamp
;
time_t
bindtime
=
(
time_t
)
-
1
;
int
rc
;
rc
=
be_entry_get_rw
(
op
,
&
op
->
o_conn
->
c_ndn
,
NULL
,
NULL
,
0
,
&
e
);
if
(
rc
!=
LDAP_SUCCESS
)
{
return
-
1
;
}
/* get authTimestamp attribute, if it exists */
if
(
(
a
=
attr_find
(
e
->
e_attrs
,
slap_schema
.
si_ad_pwdLastSuccess
))
!=
NULL
)
{
struct
lutil_tm
tm
;
struct
lutil_timet
tt
;
if
(
lutil_parsetime
(
a
->
a_nvals
[
0
].
bv_val
,
&
tm
)
==
0
)
{
lutil_tm2time
(
&
tm
,
&
tt
);
bindtime
=
tt
.
tt_sec
;
}
Debug
(
LDAP_DEBUG_ANY
,
"fe_op_lastbind: "
"old pwdLastSuccess value=%s %lds ago
\n
"
,
a
->
a_nvals
[
0
].
bv_val
,
bindtime
==
(
time_t
)
-
1
?
-
1
:
op
->
o_time
-
bindtime
);
/*
* TODO: If the recorded bind time is within configurable precision,
* it doesn't need to be updated (save a write for nothing)
*/
if
(
bindtime
!=
(
time_t
)
-
1
&&
op
->
o_time
<=
bindtime
)
{
be_entry_release_r
(
op
,
e
);
return
LDAP_SUCCESS
;
}
}
/* update the authTimestamp in the user's entry with the current time */
timestamp
.
bv_val
=
nowstr
;
timestamp
.
bv_len
=
sizeof
(
nowstr
);
slap_timestamp
(
&
op
->
o_time
,
&
timestamp
);
m
=
ch_calloc
(
sizeof
(
Modifications
),
1
);
m
->
sml_op
=
LDAP_MOD_REPLACE
;
m
->
sml_flags
=
0
;
m
->
sml_type
=
slap_schema
.
si_ad_pwdLastSuccess
->
ad_cname
;
m
->
sml_desc
=
slap_schema
.
si_ad_pwdLastSuccess
;
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
);
be_entry_release_r
(
op
,
e
);
op2
.
o_tag
=
LDAP_REQ_MODIFY
;
op2
.
o_req_dn
=
op
->
o_conn
->
c_dn
;
op2
.
o_req_ndn
=
op
->
o_conn
->
c_ndn
;
op2
.
o_callback
=
&
cb
;
op2
.
orm_modlist
=
m
;
op2
.
orm_no_opattrs
=
0
;
op2
.
o_dn
=
op
->
o_bd
->
be_rootdn
;
op2
.
o_ndn
=
op
->
o_bd
->
be_rootndn
;
/*
* TODO: this is core+frontend, not everything works the same way?
*/
/*
* Code for forwarding of updates adapted from ppolicy.c of slapo-ppolicy
*
* If this server is a shadow and forward_updates is true,
* use the frontend to perform this modify. That will trigger
* the update referral, which can then be forwarded by the
* chain overlay. Obviously the updateref and chain overlay
* must be configured appropriately for this to be useful.
*/
if
(
SLAP_SHADOW
(
op
->
o_bd
)
)
{
/* Must use Relax control since these are no-user-mod */
op2
.
o_relax
=
SLAP_CONTROL_CRITICAL
;
op2
.
o_ctrls
=
ca
;
ca
[
0
]
=
&
c
;
ca
[
1
]
=
NULL
;
BER_BVZERO
(
&
c
.
ldctl_value
);
c
.
ldctl_iscritical
=
1
;
c
.
ldctl_oid
=
LDAP_CONTROL_RELAX
;
}
else
{
/* If not forwarding, don't update opattrs and don't replicate */
if
(
SLAP_SINGLE_SHADOW
(
op
->
o_bd
))
{
op2
.
orm_no_opattrs
=
1
;
op2
.
o_dont_replicate
=
1
;
}
}
rc
=
op
->
o_bd
->
be_modify
(
&
op2
,
&
r2
);
slap_mods_free
(
m
,
1
);
done:
return
rc
;
}
int
fe_op_bind_success
(
Operation
*
op
,
SlapReply
*
rs
)
{
...
...
@@ -436,6 +544,10 @@ fe_op_bind_success( Operation *op, SlapReply *rs )
ldap_pvt_thread_mutex_unlock
(
&
op
->
o_conn
->
c_mutex
);
if
(
SLAP_LASTBIND
(
op
->
o_bd
)
)
{
fe_op_lastbind
(
op
);
}
/* send this here to avoid a race condition */
send_ldap_result
(
op
,
rs
);
...
...
servers/slapd/overlays/ppolicy.c
View file @
419b9ad2
...
...
@@ -72,6 +72,8 @@ typedef struct pass_policy {
AttributeDescription
*
ad
;
/* attribute to which the policy applies */
int
pwdMinAge
;
/* minimum time (seconds) until passwd can change */
int
pwdMaxAge
;
/* time in seconds until pwd will expire after change */
int
pwdMaxIdle
;
/* number of seconds since last successful bind before
passwd gets locked out */
int
pwdInHistory
;
/* number of previous passwords kept */
int
pwdCheckQuality
;
/* 0 = don't check quality, 1 = check if possible,
2 = check mandatory; fail if not possible */
...
...
@@ -207,6 +209,7 @@ static struct schema_info {
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )"
,
&
ad_pwdEndTime
},
/* Defined in schema_prep.c now
{ "( 1.3.6.1.4.1.42.2.27.8.1.29 "
"NAME ( 'pwdLastSuccess' ) "
"DESC 'The timestamp of the last successful authentication' "
...
...
@@ -215,6 +218,7 @@ static struct schema_info {
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
&ad_pwdLastSuccess },
*/
{
"( 1.3.6.1.4.1.42.2.27.8.1.33 "
"NAME ( 'pwdAccountTmpLockoutEnd' ) "
"DESC 'Temporary lockout end' "
...
...
@@ -576,6 +580,24 @@ account_locked( Operation *op, Entry *e,
}
}
/* Only check if database maintains lastbind */
if
(
pp
->
pwdMaxIdle
&&
SLAP_LASTBIND
(
op
->
o_bd
)
)
{
time_t
lastbindtime
=
(
time_t
)
-
1
;
la
=
attr_find
(
e
->
e_attrs
,
ad_pwdLastSuccess
);
if
(
la
==
NULL
)
{
la
=
attr_find
(
e
->
e_attrs
,
ad_pwdChangedTime
);
}
if
(
la
!=
NULL
)
{
lastbindtime
=
parse_time
(
la
->
a_nvals
[
0
].
bv_val
);
}
if
(
lastbindtime
!=
(
time_t
)
-
1
&&
op
->
o_time
>
lastbindtime
+
pp
->
pwdMaxIdle
)
{
return
1
;
}
}
if
(
(
la
=
attr_find
(
e
->
e_attrs
,
ad_pwdAccountLockedTime
))
!=
NULL
)
{
BerVarray
vals
=
la
->
a_nvals
;
...
...
@@ -773,6 +795,9 @@ ppolicy_get( Operation *op, Entry *e, PassPolicy *pp )
if
(
(
a
=
attr_find
(
pe
->
e_attrs
,
ad_pwdMaxAge
)
)
&&
lutil_atoi
(
&
pp
->
pwdMaxAge
,
a
->
a_vals
[
0
].
bv_val
)
!=
0
)
goto
defaultpol
;
if
(
(
a
=
attr_find
(
pe
->
e_attrs
,
ad_pwdMaxIdle
)
)
&&
lutil_atoi
(
&
pp
->
pwdMaxIdle
,
a
->
a_vals
[
0
].
bv_val
)
!=
0
)
goto
defaultpol
;
if
(
(
a
=
attr_find
(
pe
->
e_attrs
,
ad_pwdInHistory
)
)
&&
lutil_atoi
(
&
pp
->
pwdInHistory
,
a
->
a_vals
[
0
].
bv_val
)
!=
0
)
goto
defaultpol
;
...
...
@@ -1935,7 +1960,8 @@ ppolicy_modify( Operation *op, SlapReply *rs )
LDAPControl
*
ctrl
=
NULL
;
LDAPControl
**
oldctrls
=
NULL
;
int
is_pwdexop
=
0
;
int
got_del_grace
=
0
,
got_del_lock
=
0
,
got_pw
=
0
,
got_del_fail
=
0
;
int
got_del_grace
=
0
,
got_del_lock
=
0
,
got_pw
=
0
,
got_del_fail
=
0
,
got_del_success
=
0
;
int
got_changed
=
0
,
got_history
=
0
;
op
->
o_bd
->
bd_info
=
(
BackendInfo
*
)
on
->
on_info
;
...
...
@@ -1949,11 +1975,12 @@ ppolicy_modify( Operation *op, SlapReply *rs )
*/
if
(
SLAPD_SYNC_IS_SYNCCONN
(
op
->
o_connid
)
)
{
Modifications
**
prev
;
Attribute
*
a_grace
,
*
a_lock
,
*
a_fail
;
Attribute
*
a_grace
,
*
a_lock
,
*
a_fail
,
*
a_success
;
a_grace
=
attr_find
(
e
->
e_attrs
,
ad_pwdGraceUseTime
);
a_lock
=
attr_find
(
e
->
e_attrs
,
ad_pwdAccountLockedTime
);
a_fail
=
attr_find
(
e
->
e_attrs
,
ad_pwdFailureTime
);
a_success
=
attr_find
(
e
->
e_attrs
,
ad_pwdLastSuccess
);
for
(
prev
=
&
op
->
orm_modlist
,
ml
=
*
prev
;
ml
;
ml
=
*
prev
)
{
...
...
@@ -1988,6 +2015,13 @@ ppolicy_modify( Operation *op, SlapReply *rs )
got_del_fail
=
1
;
}
}
if
(
ml
->
sml_desc
==
ad_pwdLastSuccess
)
{
if
(
!
a_success
||
got_del_success
)
{
drop
=
ml
->
sml_op
==
LDAP_MOD_DELETE
;
}
else
{
got_del_success
=
1
;
}
}
if
(
drop
)
{
*
prev
=
ml
->
sml_next
;
ml
->
sml_next
=
NULL
;
...
...
@@ -1999,7 +2033,7 @@ ppolicy_modify( Operation *op, SlapReply *rs )
}
/* If we're resetting the password, make sure grace, accountlock,
* and failure also get removed.
*
success,
and failure also get removed.
*/
if
(
got_pw
)
{
if
(
a_grace
&&
!
got_del_grace
)
{
...
...
@@ -2039,6 +2073,18 @@ ppolicy_modify( Operation *op, SlapReply *rs )
ml
->
sml_next
=
NULL
;
*
prev
=
ml
;
}
if
(
a_success
&&
!
got_del_success
)
{
ml
=
(
Modifications
*
)
ch_malloc
(
sizeof
(
Modifications
)
);
ml
->
sml_op
=
LDAP_MOD_DELETE
;
ml
->
sml_flags
=
SLAP_MOD_INTERNAL
;
ml
->
sml_type
.
bv_val
=
NULL
;
ml
->
sml_desc
=
ad_pwdLastSuccess
;
ml
->
sml_numvals
=
0
;
ml
->
sml_values
=
NULL
;
ml
->
sml_nvalues
=
NULL
;
ml
->
sml_next
=
NULL
;
*
prev
=
ml
;
}
}
op
->
o_bd
->
bd_info
=
(
BackendInfo
*
)
on
->
on_info
;
be_entry_release_r
(
op
,
e
);
...
...
@@ -2145,6 +2191,8 @@ ppolicy_modify( Operation *op, SlapReply *rs )
got_del_lock
=
1
;
}
else
if
(
ml
->
sml_desc
==
ad_pwdFailureTime
)
{
got_del_fail
=
1
;
}
else
if
(
ml
->
sml_desc
==
ad_pwdLastSuccess
)
{
got_del_success
=
1
;
}
}
if
(
ml
->
sml_desc
==
ad_pwdChangedTime
)
{
...
...
@@ -2463,6 +2511,17 @@ do_modify:
modtail
=
mods
;
}
/* TODO: do we remove pwdLastSuccess or set it to 'now'? */
if
(
!
got_del_success
&&
attr_find
(
e
->
e_attrs
,
ad_pwdLastSuccess
)){
mods
=
(
Modifications
*
)
ch_calloc
(
sizeof
(
Modifications
),
1
);
mods
->
sml_op
=
LDAP_MOD_DELETE
;
mods
->
sml_flags
=
SLAP_MOD_INTERNAL
;
mods
->
sml_desc
=
ad_pwdLastSuccess
;
mods
->
sml_next
=
NULL
;
modtail
->
sml_next
=
mods
;
modtail
=
mods
;
}
/* Delete all pwdInHistory attribute */
if
(
!
got_history
&&
pp
.
pwdInHistory
==
0
&&
attr_find
(
e
->
e_attrs
,
ad_pwdHistory
)){
...
...
@@ -2769,6 +2828,7 @@ int ppolicy_initialize()
SLAP_AT_MANAGEABLE
;
}
}
ad_pwdLastSuccess
=
slap_schema
.
si_ad_pwdLastSuccess
;
{
Syntax
*
syn
;
MatchingRule
*
mr
;
...
...
servers/slapd/schema_prep.c
View file @
419b9ad2
...
...
@@ -1019,6 +1019,19 @@ static struct slap_schema_ad_map {
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
offsetof
(
struct
slap_internal_schema
,
si_ad_pKCS8PrivateKey
)
},
{
"pwdLastSuccess"
,
"( 1.3.6.1.4.1.42.2.27.8.1.29 NAME 'pwdLastSuccess' "
"DESC 'The timestamp of the last successful authentication' "
"EQUALITY generalizedTimeMatch "
"ORDERING generalizedTimeOrderingMatch "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
"SINGLE-VALUE "
"NO-USER-MODIFICATION "
"USAGE directoryOperation )"
,
NULL
,
0
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
offsetof
(
struct
slap_internal_schema
,
si_ad_pwdLastSuccess
)
},
{
NULL
,
NULL
,
NULL
,
0
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
0
}
};
...
...
servers/slapd/slap.h
View file @
419b9ad2
...
...
@@ -987,6 +987,9 @@ struct slap_internal_schema {
/* privateKeys */
AttributeDescription
*
si_ad_pKCS8PrivateKey
;
/* ppolicy lastbind equivalent */
AttributeDescription
*
si_ad_pwdLastSuccess
;
/* Undefined Attribute Type */
AttributeType
*
si_at_undefined
;
...
...
@@ -1867,10 +1870,12 @@ struct BackendDB {
#define SLAP_DBFLAG_SYNC_SUBENTRY 0x40000U
/* use subentry for context */
#define SLAP_DBFLAG_MULTI_SHADOW 0x80000U
/* uses mirrorMode/multi-master */
#define SLAP_DBFLAG_DISABLED 0x100000U
#define SLAP_DBFLAG_LASTBIND 0x200000U
slap_mask_t
be_flags
;
#define SLAP_DBFLAGS(be) ((be)->be_flags)
#define SLAP_NOLASTMOD(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_NOLASTMOD)
#define SLAP_LASTMOD(be) (!SLAP_NOLASTMOD(be))
#define SLAP_LASTBIND(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_LASTBIND)
#define SLAP_DBHIDDEN(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_HIDDEN)
#define SLAP_DBDISABLED(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_DISABLED)
#define SLAP_DB_ONE_SUFFIX(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_ONE_SUFFIX)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment