xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/ppolicy.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: ppolicy.c,v 1.3 2021/08/14 16:14:56 christos Exp $	*/
24e6df137Slukem 
3d11b170bStron /* $OpenLDAP$ */
42de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
52de962bdSlukem  *
6*549b59edSchristos  * Copyright 2004-2021 The OpenLDAP Foundation.
72de962bdSlukem  * Portions Copyright 2004 Hewlett-Packard Company.
82de962bdSlukem  * Portions Copyright 2004 Howard Chu, Symas Corp.
92de962bdSlukem  * All rights reserved.
102de962bdSlukem  *
112de962bdSlukem  * Redistribution and use in source and binary forms, with or without
122de962bdSlukem  * modification, are permitted only as authorized by the OpenLDAP
132de962bdSlukem  * Public License.
142de962bdSlukem  *
152de962bdSlukem  * A copy of this license is available in the file LICENSE in the
162de962bdSlukem  * top-level directory of the distribution or, alternatively, at
172de962bdSlukem  * <http://www.OpenLDAP.org/license.html>.
182de962bdSlukem  */
192de962bdSlukem /* ACKNOWLEDGEMENTS:
202de962bdSlukem  * This work was developed by Howard Chu for inclusion in
212de962bdSlukem  * OpenLDAP Software, based on prior work by Neil Dunbar (HP).
222de962bdSlukem  * This work was sponsored by the Hewlett-Packard Company.
232de962bdSlukem  */
242de962bdSlukem 
25376af7d7Schristos #include <sys/cdefs.h>
26*549b59edSchristos __RCSID("$NetBSD: ppolicy.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
27376af7d7Schristos 
282de962bdSlukem #include "portable.h"
292de962bdSlukem 
302de962bdSlukem #include <stdio.h>
312de962bdSlukem #include <ac/stdlib.h>
322de962bdSlukem #include <ac/string.h>
332de962bdSlukem #include <ac/time.h>
342de962bdSlukem 
352de962bdSlukem #include "ldap-int.h"
362de962bdSlukem 
372de962bdSlukem #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
382de962bdSlukem 
392de962bdSlukem /* IMPLICIT TAGS, all context-specific */
402de962bdSlukem #define PPOLICY_WARNING 0xa0L	/* constructed + 0 */
412de962bdSlukem #define PPOLICY_ERROR 0x81L		/* primitive + 1 */
422de962bdSlukem 
432de962bdSlukem #define PPOLICY_EXPIRE 0x80L	/* primitive + 0 */
442de962bdSlukem #define PPOLICY_GRACE  0x81L	/* primitive + 1 */
452de962bdSlukem 
462de962bdSlukem /*---
472de962bdSlukem    ldap_create_passwordpolicy_control
482de962bdSlukem 
492de962bdSlukem    Create and encode the Password Policy Request
502de962bdSlukem 
512de962bdSlukem    ld        (IN)  An LDAP session handle, as obtained from a call to
522de962bdSlukem 				   ldap_init().
532de962bdSlukem 
542de962bdSlukem    ctrlp     (OUT) A result parameter that will be assigned the address
552de962bdSlukem 				   of an LDAPControl structure that contains the
562de962bdSlukem 				   passwordPolicyRequest control created by this function.
572de962bdSlukem 				   The memory occupied by the LDAPControl structure
582de962bdSlukem 				   SHOULD be freed when it is no longer in use by
592de962bdSlukem 				   calling ldap_control_free().
602de962bdSlukem 
612de962bdSlukem 
622de962bdSlukem    There is no control value for a password policy request
632de962bdSlukem  ---*/
642de962bdSlukem 
652de962bdSlukem int
ldap_create_passwordpolicy_control(LDAP * ld,LDAPControl ** ctrlp)662de962bdSlukem ldap_create_passwordpolicy_control( LDAP *ld,
672de962bdSlukem                                     LDAPControl **ctrlp )
682de962bdSlukem {
692de962bdSlukem 	assert( ld != NULL );
702de962bdSlukem 	assert( LDAP_VALID( ld ) );
712de962bdSlukem 	assert( ctrlp != NULL );
722de962bdSlukem 
732de962bdSlukem 	ld->ld_errno = ldap_control_create( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
742de962bdSlukem 		0, NULL, 0, ctrlp );
752de962bdSlukem 
762de962bdSlukem 	return ld->ld_errno;
772de962bdSlukem }
782de962bdSlukem 
792de962bdSlukem 
802de962bdSlukem /*---
812de962bdSlukem    ldap_parse_passwordpolicy_control
822de962bdSlukem 
832de962bdSlukem    Decode the passwordPolicyResponse control and return information.
842de962bdSlukem 
852de962bdSlukem    ld           (IN)   An LDAP session handle.
862de962bdSlukem 
872de962bdSlukem    ctrl         (IN)   The address of an
882de962bdSlukem 					   LDAPControl structure, either obtained
89*549b59edSchristos 					   by running through the list of response controls or
902de962bdSlukem 					   by a call to ldap_control_find().
912de962bdSlukem 
922de962bdSlukem    exptimep     (OUT)  This result parameter is filled in with the number of seconds before
932de962bdSlukem                                            the password will expire, if expiration is imminent
942de962bdSlukem                                            (imminency defined by the password policy). If expiration
952de962bdSlukem                                            is not imminent, the value is set to -1.
962de962bdSlukem 
972de962bdSlukem    gracep       (OUT)  This result parameter is filled in with the number of grace logins after
982de962bdSlukem                                            the password has expired, before no further login attempts
992de962bdSlukem                                            will be allowed.
1002de962bdSlukem 
1012de962bdSlukem    errorcodep   (OUT)  This result parameter is filled in with the error code of the password operation
1022de962bdSlukem                                            If no error was detected, this error is set to PP_noError.
1032de962bdSlukem 
1042de962bdSlukem    Ber encoding
1052de962bdSlukem 
1062de962bdSlukem    PasswordPolicyResponseValue ::= SEQUENCE {
1072de962bdSlukem        warning [0] CHOICE {
1082de962bdSlukem            timeBeforeExpiration [0] INTEGER (0 .. maxInt),
1092de962bdSlukem            graceLoginsRemaining [1] INTEGER (0 .. maxInt) } OPTIONAL
1102de962bdSlukem        error [1] ENUMERATED {
1112de962bdSlukem            passwordExpired        (0),
1122de962bdSlukem            accountLocked          (1),
1132de962bdSlukem            changeAfterReset       (2),
1142de962bdSlukem            passwordModNotAllowed  (3),
1152de962bdSlukem            mustSupplyOldPassword  (4),
1162de962bdSlukem            invalidPasswordSyntax  (5),
1172de962bdSlukem            passwordTooShort       (6),
1182de962bdSlukem            passwordTooYoung       (7),
1192de962bdSlukem            passwordInHistory      (8) } OPTIONAL }
1202de962bdSlukem 
1212de962bdSlukem ---*/
1222de962bdSlukem 
1232de962bdSlukem int
ldap_parse_passwordpolicy_control(LDAP * ld,LDAPControl * ctrl,ber_int_t * expirep,ber_int_t * gracep,LDAPPasswordPolicyError * errorp)1242de962bdSlukem ldap_parse_passwordpolicy_control(
1252de962bdSlukem 	LDAP           *ld,
1262de962bdSlukem 	LDAPControl    *ctrl,
1272de962bdSlukem 	ber_int_t      *expirep,
1282de962bdSlukem 	ber_int_t      *gracep,
1292de962bdSlukem 	LDAPPasswordPolicyError *errorp )
1302de962bdSlukem {
1312de962bdSlukem 	BerElement  *ber;
1322de962bdSlukem 	int exp = -1, grace = -1;
1332de962bdSlukem 	ber_tag_t tag;
1342de962bdSlukem 	ber_len_t berLen;
1352de962bdSlukem         char *last;
1362de962bdSlukem 	int err = PP_noError;
1372de962bdSlukem 
1382de962bdSlukem 	assert( ld != NULL );
1392de962bdSlukem 	assert( LDAP_VALID( ld ) );
1402de962bdSlukem 	assert( ctrl != NULL );
1412de962bdSlukem 
142d11b170bStron 	if ( !ctrl->ldctl_value.bv_val ) {
143d11b170bStron 		ld->ld_errno = LDAP_DECODING_ERROR;
144d11b170bStron 		return(ld->ld_errno);
145d11b170bStron 	}
146d11b170bStron 
1472de962bdSlukem 	/* Create a BerElement from the berval returned in the control. */
1482de962bdSlukem 	ber = ber_init(&ctrl->ldctl_value);
1492de962bdSlukem 
1502de962bdSlukem 	if (ber == NULL) {
1512de962bdSlukem 		ld->ld_errno = LDAP_NO_MEMORY;
1522de962bdSlukem 		return(ld->ld_errno);
1532de962bdSlukem 	}
1542de962bdSlukem 
1552de962bdSlukem 	tag = ber_peek_tag( ber, &berLen );
1562de962bdSlukem 	if (tag != LBER_SEQUENCE) goto exit;
1572de962bdSlukem 
1582de962bdSlukem 	for( tag = ber_first_element( ber, &berLen, &last );
1592de962bdSlukem 		tag != LBER_DEFAULT;
1602de962bdSlukem 		tag = ber_next_element( ber, &berLen, last ) )
1612de962bdSlukem 	{
1622de962bdSlukem 		switch (tag) {
1632de962bdSlukem 		case PPOLICY_WARNING:
1642de962bdSlukem 			ber_skip_tag(ber, &berLen );
1652de962bdSlukem 			tag = ber_peek_tag( ber, &berLen );
1662de962bdSlukem 			switch( tag ) {
1672de962bdSlukem 			case PPOLICY_EXPIRE:
1682de962bdSlukem 				if (ber_get_int( ber, &exp ) == LBER_DEFAULT) goto exit;
1692de962bdSlukem 				break;
1702de962bdSlukem 			case PPOLICY_GRACE:
1712de962bdSlukem 				if (ber_get_int( ber, &grace ) == LBER_DEFAULT) goto exit;
1722de962bdSlukem 				break;
1732de962bdSlukem 			default:
1742de962bdSlukem 				goto exit;
1752de962bdSlukem 			}
1762de962bdSlukem 			break;
1772de962bdSlukem 		case PPOLICY_ERROR:
1782de962bdSlukem 			if (ber_get_enum( ber, &err ) == LBER_DEFAULT) goto exit;
1792de962bdSlukem 			break;
1802de962bdSlukem 		default:
1812de962bdSlukem 			goto exit;
1822de962bdSlukem 		}
1832de962bdSlukem 	}
1842de962bdSlukem 
1852de962bdSlukem 	ber_free(ber, 1);
1862de962bdSlukem 
1872de962bdSlukem 	/* Return data to the caller for items that were requested. */
1882de962bdSlukem 	if (expirep) *expirep = exp;
1892de962bdSlukem 	if (gracep) *gracep = grace;
1902de962bdSlukem 	if (errorp) *errorp = err;
1912de962bdSlukem 
1922de962bdSlukem 	ld->ld_errno = LDAP_SUCCESS;
1932de962bdSlukem 	return(ld->ld_errno);
1942de962bdSlukem 
1952de962bdSlukem   exit:
1962de962bdSlukem 	ber_free(ber, 1);
1972de962bdSlukem 	ld->ld_errno = LDAP_DECODING_ERROR;
1982de962bdSlukem 	return(ld->ld_errno);
1992de962bdSlukem }
2002de962bdSlukem 
2012de962bdSlukem const char *
ldap_passwordpolicy_err2txt(LDAPPasswordPolicyError err)2022de962bdSlukem ldap_passwordpolicy_err2txt( LDAPPasswordPolicyError err )
2032de962bdSlukem {
2042de962bdSlukem 	switch(err) {
2052de962bdSlukem 	case PP_passwordExpired: return "Password expired";
2062de962bdSlukem 	case PP_accountLocked: return "Account locked";
2072de962bdSlukem 	case PP_changeAfterReset: return "Password must be changed";
2082de962bdSlukem 	case PP_passwordModNotAllowed: return "Policy prevents password modification";
2092de962bdSlukem 	case PP_mustSupplyOldPassword: return "Policy requires old password in order to change password";
2102de962bdSlukem 	case PP_insufficientPasswordQuality: return "Password fails quality checks";
2112de962bdSlukem 	case PP_passwordTooShort: return "Password is too short for policy";
2122de962bdSlukem 	case PP_passwordTooYoung: return "Password has been changed too recently";
2132de962bdSlukem 	case PP_passwordInHistory: return "New password is in list of old passwords";
214*549b59edSchristos 	case PP_passwordTooLong: return "Password is too long for policy";
2152de962bdSlukem 	case PP_noError: return "No error";
2162de962bdSlukem 	default: return "Unknown error code";
2172de962bdSlukem 	}
2182de962bdSlukem }
2192de962bdSlukem 
2202de962bdSlukem #endif /* LDAP_CONTROL_PASSWORDPOLICYREQUEST */
221*549b59edSchristos 
222*549b59edSchristos #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRING
223*549b59edSchristos 
224*549b59edSchristos int
ldap_parse_password_expiring_control(LDAP * ld,LDAPControl * ctrl,long * secondsp)225*549b59edSchristos ldap_parse_password_expiring_control(
226*549b59edSchristos 	LDAP           *ld,
227*549b59edSchristos 	LDAPControl    *ctrl,
228*549b59edSchristos 	long           *secondsp )
229*549b59edSchristos {
230*549b59edSchristos 	long seconds = 0;
231*549b59edSchristos 	char buf[sizeof("-2147483648")];
232*549b59edSchristos 	char *next;
233*549b59edSchristos 
234*549b59edSchristos 	assert( ld != NULL );
235*549b59edSchristos 	assert( LDAP_VALID( ld ) );
236*549b59edSchristos 	assert( ctrl != NULL );
237*549b59edSchristos 
238*549b59edSchristos 	if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ||
239*549b59edSchristos 		ctrl->ldctl_value.bv_len >= sizeof(buf) ) {
240*549b59edSchristos 		ld->ld_errno = LDAP_DECODING_ERROR;
241*549b59edSchristos 		return(ld->ld_errno);
242*549b59edSchristos 	}
243*549b59edSchristos 
244*549b59edSchristos 	memcpy( buf, ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len );
245*549b59edSchristos 	buf[ctrl->ldctl_value.bv_len] = '\0';
246*549b59edSchristos 
247*549b59edSchristos 	seconds = strtol( buf, &next, 10 );
248*549b59edSchristos 	if ( next == buf || next[0] != '\0' ) goto exit;
249*549b59edSchristos 
250*549b59edSchristos 	if ( secondsp != NULL ) {
251*549b59edSchristos 		*secondsp = seconds;
252*549b59edSchristos 	}
253*549b59edSchristos 
254*549b59edSchristos 	ld->ld_errno = LDAP_SUCCESS;
255*549b59edSchristos 	return(ld->ld_errno);
256*549b59edSchristos 
257*549b59edSchristos   exit:
258*549b59edSchristos 	ld->ld_errno = LDAP_DECODING_ERROR;
259*549b59edSchristos 	return(ld->ld_errno);
260*549b59edSchristos }
261*549b59edSchristos 
262*549b59edSchristos #endif /* LDAP_CONTROL_X_PASSWORD_EXPIRING */
263