2004-03-13 17:13:11 +08:00
|
|
|
/* $OpenLDAP$ */
|
|
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
|
|
*
|
2021-01-12 03:25:53 +08:00
|
|
|
* Copyright 2004-2021 The OpenLDAP Foundation.
|
2004-04-08 11:05:16 +08:00
|
|
|
* Portions Copyright 2004 Hewlett-Packard Company.
|
|
|
|
* Portions Copyright 2004 Howard Chu, Symas Corp.
|
2004-03-13 17:13:11 +08:00
|
|
|
* 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.
|
2004-03-13 05:22:32 +08:00
|
|
|
*
|
2004-03-13 17:13:11 +08:00
|
|
|
* 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>.
|
2004-03-13 05:22:32 +08:00
|
|
|
*/
|
2004-04-08 11:05:16 +08:00
|
|
|
/* ACKNOWLEDGEMENTS:
|
|
|
|
* This work was developed by Howard Chu for inclusion in
|
|
|
|
* OpenLDAP Software, based on prior work by Neil Dunbar (HP).
|
|
|
|
* This work was sponsored by the Hewlett-Packard Company.
|
|
|
|
*/
|
2004-03-13 05:22:32 +08:00
|
|
|
|
|
|
|
#include "portable.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ac/stdlib.h>
|
|
|
|
#include <ac/string.h>
|
|
|
|
#include <ac/time.h>
|
|
|
|
|
|
|
|
#include "ldap-int.h"
|
|
|
|
|
2004-03-16 09:48:21 +08:00
|
|
|
#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
|
|
|
|
|
2006-04-22 07:47:53 +08:00
|
|
|
/* IMPLICIT TAGS, all context-specific */
|
|
|
|
#define PPOLICY_WARNING 0xa0L /* constructed + 0 */
|
2006-04-22 08:23:44 +08:00
|
|
|
#define PPOLICY_ERROR 0x81L /* primitive + 1 */
|
2004-03-13 05:22:32 +08:00
|
|
|
|
2006-04-22 07:47:53 +08:00
|
|
|
#define PPOLICY_EXPIRE 0x80L /* primitive + 0 */
|
|
|
|
#define PPOLICY_GRACE 0x81L /* primitive + 1 */
|
2004-03-13 05:22:32 +08:00
|
|
|
|
|
|
|
/*---
|
|
|
|
ldap_create_passwordpolicy_control
|
|
|
|
|
|
|
|
Create and encode the Password Policy Request
|
|
|
|
|
|
|
|
ld (IN) An LDAP session handle, as obtained from a call to
|
|
|
|
ldap_init().
|
|
|
|
|
|
|
|
ctrlp (OUT) A result parameter that will be assigned the address
|
|
|
|
of an LDAPControl structure that contains the
|
|
|
|
passwordPolicyRequest control created by this function.
|
|
|
|
The memory occupied by the LDAPControl structure
|
|
|
|
SHOULD be freed when it is no longer in use by
|
|
|
|
calling ldap_control_free().
|
|
|
|
|
|
|
|
|
|
|
|
There is no control value for a password policy request
|
|
|
|
---*/
|
|
|
|
|
|
|
|
int
|
|
|
|
ldap_create_passwordpolicy_control( LDAP *ld,
|
|
|
|
LDAPControl **ctrlp )
|
|
|
|
{
|
|
|
|
assert( ld != NULL );
|
|
|
|
assert( LDAP_VALID( ld ) );
|
|
|
|
assert( ctrlp != NULL );
|
|
|
|
|
2007-08-23 06:35:14 +08:00
|
|
|
ld->ld_errno = ldap_control_create( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
|
|
|
|
0, NULL, 0, ctrlp );
|
2004-03-13 05:22:32 +08:00
|
|
|
|
2007-08-23 06:35:14 +08:00
|
|
|
return ld->ld_errno;
|
2004-03-13 05:22:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*---
|
|
|
|
ldap_parse_passwordpolicy_control
|
|
|
|
|
|
|
|
Decode the passwordPolicyResponse control and return information.
|
|
|
|
|
|
|
|
ld (IN) An LDAP session handle.
|
|
|
|
|
2006-01-09 03:11:57 +08:00
|
|
|
ctrl (IN) The address of an
|
2007-08-23 06:35:14 +08:00
|
|
|
LDAPControl structure, either obtained
|
2017-02-26 15:49:31 +08:00
|
|
|
by running through the list of response controls or
|
2007-08-23 06:35:14 +08:00
|
|
|
by a call to ldap_control_find().
|
2004-03-13 05:22:32 +08:00
|
|
|
|
|
|
|
exptimep (OUT) This result parameter is filled in with the number of seconds before
|
|
|
|
the password will expire, if expiration is imminent
|
|
|
|
(imminency defined by the password policy). If expiration
|
|
|
|
is not imminent, the value is set to -1.
|
|
|
|
|
|
|
|
gracep (OUT) This result parameter is filled in with the number of grace logins after
|
|
|
|
the password has expired, before no further login attempts
|
|
|
|
will be allowed.
|
|
|
|
|
|
|
|
errorcodep (OUT) This result parameter is filled in with the error code of the password operation
|
|
|
|
If no error was detected, this error is set to PP_noError.
|
|
|
|
|
|
|
|
Ber encoding
|
|
|
|
|
|
|
|
PasswordPolicyResponseValue ::= SEQUENCE {
|
|
|
|
warning [0] CHOICE {
|
|
|
|
timeBeforeExpiration [0] INTEGER (0 .. maxInt),
|
|
|
|
graceLoginsRemaining [1] INTEGER (0 .. maxInt) } OPTIONAL
|
|
|
|
error [1] ENUMERATED {
|
|
|
|
passwordExpired (0),
|
|
|
|
accountLocked (1),
|
|
|
|
changeAfterReset (2),
|
|
|
|
passwordModNotAllowed (3),
|
|
|
|
mustSupplyOldPassword (4),
|
|
|
|
invalidPasswordSyntax (5),
|
|
|
|
passwordTooShort (6),
|
|
|
|
passwordTooYoung (7),
|
|
|
|
passwordInHistory (8) } OPTIONAL }
|
|
|
|
|
|
|
|
---*/
|
|
|
|
|
|
|
|
int
|
|
|
|
ldap_parse_passwordpolicy_control(
|
|
|
|
LDAP *ld,
|
2004-03-16 07:53:37 +08:00
|
|
|
LDAPControl *ctrl,
|
2006-01-09 13:22:46 +08:00
|
|
|
ber_int_t *expirep,
|
|
|
|
ber_int_t *gracep,
|
2006-01-09 01:11:15 +08:00
|
|
|
LDAPPasswordPolicyError *errorp )
|
2004-03-13 05:22:32 +08:00
|
|
|
{
|
|
|
|
BerElement *ber;
|
2005-07-11 18:39:32 +08:00
|
|
|
int exp = -1, grace = -1;
|
2004-03-13 05:22:32 +08:00
|
|
|
ber_tag_t tag;
|
|
|
|
ber_len_t berLen;
|
|
|
|
char *last;
|
2005-07-10 17:40:34 +08:00
|
|
|
int err = PP_noError;
|
2004-03-13 05:22:32 +08:00
|
|
|
|
|
|
|
assert( ld != NULL );
|
|
|
|
assert( LDAP_VALID( ld ) );
|
2005-07-18 14:22:33 +08:00
|
|
|
assert( ctrl != NULL );
|
2004-03-13 05:22:32 +08:00
|
|
|
|
2013-12-08 00:36:14 +08:00
|
|
|
if ( !ctrl->ldctl_value.bv_val ) {
|
|
|
|
ld->ld_errno = LDAP_DECODING_ERROR;
|
|
|
|
return(ld->ld_errno);
|
|
|
|
}
|
|
|
|
|
2004-03-13 05:22:32 +08:00
|
|
|
/* Create a BerElement from the berval returned in the control. */
|
2004-03-16 07:53:37 +08:00
|
|
|
ber = ber_init(&ctrl->ldctl_value);
|
2004-03-13 05:22:32 +08:00
|
|
|
|
|
|
|
if (ber == NULL) {
|
|
|
|
ld->ld_errno = LDAP_NO_MEMORY;
|
|
|
|
return(ld->ld_errno);
|
|
|
|
}
|
|
|
|
|
2006-01-09 01:11:15 +08:00
|
|
|
tag = ber_peek_tag( ber, &berLen );
|
|
|
|
if (tag != LBER_SEQUENCE) goto exit;
|
|
|
|
|
|
|
|
for( tag = ber_first_element( ber, &berLen, &last );
|
|
|
|
tag != LBER_DEFAULT;
|
|
|
|
tag = ber_next_element( ber, &berLen, last ) )
|
|
|
|
{
|
|
|
|
switch (tag) {
|
|
|
|
case PPOLICY_WARNING:
|
|
|
|
ber_skip_tag(ber, &berLen );
|
|
|
|
tag = ber_peek_tag( ber, &berLen );
|
|
|
|
switch( tag ) {
|
|
|
|
case PPOLICY_EXPIRE:
|
|
|
|
if (ber_get_int( ber, &exp ) == LBER_DEFAULT) goto exit;
|
|
|
|
break;
|
|
|
|
case PPOLICY_GRACE:
|
|
|
|
if (ber_get_int( ber, &grace ) == LBER_DEFAULT) goto exit;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PPOLICY_ERROR:
|
|
|
|
if (ber_get_enum( ber, &err ) == LBER_DEFAULT) goto exit;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-13 05:22:32 +08:00
|
|
|
ber_free(ber, 1);
|
|
|
|
|
|
|
|
/* Return data to the caller for items that were requested. */
|
2006-01-09 01:11:15 +08:00
|
|
|
if (expirep) *expirep = exp;
|
|
|
|
if (gracep) *gracep = grace;
|
|
|
|
if (errorp) *errorp = err;
|
2004-03-13 05:22:32 +08:00
|
|
|
|
|
|
|
ld->ld_errno = LDAP_SUCCESS;
|
|
|
|
return(ld->ld_errno);
|
|
|
|
|
|
|
|
exit:
|
2006-01-09 01:11:15 +08:00
|
|
|
ber_free(ber, 1);
|
|
|
|
ld->ld_errno = LDAP_DECODING_ERROR;
|
|
|
|
return(ld->ld_errno);
|
2004-03-13 05:22:32 +08:00
|
|
|
}
|
2004-03-16 07:53:37 +08:00
|
|
|
|
|
|
|
const char *
|
|
|
|
ldap_passwordpolicy_err2txt( LDAPPasswordPolicyError err )
|
|
|
|
{
|
|
|
|
switch(err) {
|
2006-01-09 01:11:15 +08:00
|
|
|
case PP_passwordExpired: return "Password expired";
|
|
|
|
case PP_accountLocked: return "Account locked";
|
|
|
|
case PP_changeAfterReset: return "Password must be changed";
|
|
|
|
case PP_passwordModNotAllowed: return "Policy prevents password modification";
|
|
|
|
case PP_mustSupplyOldPassword: return "Policy requires old password in order to change password";
|
|
|
|
case PP_insufficientPasswordQuality: return "Password fails quality checks";
|
|
|
|
case PP_passwordTooShort: return "Password is too short for policy";
|
|
|
|
case PP_passwordTooYoung: return "Password has been changed too recently";
|
|
|
|
case PP_passwordInHistory: return "New password is in list of old passwords";
|
2019-10-24 20:54:36 +08:00
|
|
|
case PP_passwordTooLong: return "Password is too long for policy";
|
2006-01-09 01:11:15 +08:00
|
|
|
case PP_noError: return "No error";
|
|
|
|
default: return "Unknown error code";
|
2004-03-16 07:53:37 +08:00
|
|
|
}
|
|
|
|
}
|
2004-03-16 09:48:21 +08:00
|
|
|
|
|
|
|
#endif /* LDAP_CONTROL_PASSWORDPOLICYREQUEST */
|
2020-06-23 18:49:00 +08:00
|
|
|
|
|
|
|
#ifdef LDAP_CONTROL_X_PASSWORD_EXPIRING
|
|
|
|
|
|
|
|
int
|
|
|
|
ldap_parse_password_expiring_control(
|
|
|
|
LDAP *ld,
|
|
|
|
LDAPControl *ctrl,
|
|
|
|
long *secondsp )
|
|
|
|
{
|
|
|
|
long seconds = 0;
|
2020-07-27 19:53:00 +08:00
|
|
|
char buf[sizeof("-2147483648")];
|
2020-06-23 18:49:00 +08:00
|
|
|
char *next;
|
|
|
|
|
|
|
|
assert( ld != NULL );
|
|
|
|
assert( LDAP_VALID( ld ) );
|
|
|
|
assert( ctrl != NULL );
|
|
|
|
|
2020-07-27 19:53:00 +08:00
|
|
|
if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ||
|
|
|
|
ctrl->ldctl_value.bv_len >= sizeof(buf) ) {
|
2020-06-23 18:49:00 +08:00
|
|
|
ld->ld_errno = LDAP_DECODING_ERROR;
|
|
|
|
return(ld->ld_errno);
|
|
|
|
}
|
|
|
|
|
2020-07-27 19:53:00 +08:00
|
|
|
memcpy( buf, ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len );
|
|
|
|
buf[ctrl->ldctl_value.bv_len] = '\0';
|
2020-06-23 18:49:00 +08:00
|
|
|
|
2020-07-27 19:53:00 +08:00
|
|
|
seconds = strtol( buf, &next, 10 );
|
|
|
|
if ( next == buf || next[0] != '\0' ) goto exit;
|
2020-06-23 18:49:00 +08:00
|
|
|
|
|
|
|
if ( secondsp != NULL ) {
|
|
|
|
*secondsp = seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
ld->ld_errno = LDAP_SUCCESS;
|
|
|
|
return(ld->ld_errno);
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ld->ld_errno = LDAP_DECODING_ERROR;
|
|
|
|
return(ld->ld_errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* LDAP_CONTROL_X_PASSWORD_EXPIRING */
|