xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/ppolicy.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: ppolicy.c,v 1.3 2021/08/14 16:14:56 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2004-2021 The OpenLDAP Foundation.
7  * Portions Copyright 2004 Hewlett-Packard Company.
8  * Portions Copyright 2004 Howard Chu, Symas Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was developed by Howard Chu for inclusion in
21  * OpenLDAP Software, based on prior work by Neil Dunbar (HP).
22  * This work was sponsored by the Hewlett-Packard Company.
23  */
24 
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: ppolicy.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
27 
28 #include "portable.h"
29 
30 #include <stdio.h>
31 #include <ac/stdlib.h>
32 #include <ac/string.h>
33 #include <ac/time.h>
34 
35 #include "ldap-int.h"
36 
37 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
38 
39 /* IMPLICIT TAGS, all context-specific */
40 #define PPOLICY_WARNING 0xa0L	/* constructed + 0 */
41 #define PPOLICY_ERROR 0x81L		/* primitive + 1 */
42 
43 #define PPOLICY_EXPIRE 0x80L	/* primitive + 0 */
44 #define PPOLICY_GRACE  0x81L	/* primitive + 1 */
45 
46 /*---
47    ldap_create_passwordpolicy_control
48 
49    Create and encode the Password Policy Request
50 
51    ld        (IN)  An LDAP session handle, as obtained from a call to
52 				   ldap_init().
53 
54    ctrlp     (OUT) A result parameter that will be assigned the address
55 				   of an LDAPControl structure that contains the
56 				   passwordPolicyRequest control created by this function.
57 				   The memory occupied by the LDAPControl structure
58 				   SHOULD be freed when it is no longer in use by
59 				   calling ldap_control_free().
60 
61 
62    There is no control value for a password policy request
63  ---*/
64 
65 int
ldap_create_passwordpolicy_control(LDAP * ld,LDAPControl ** ctrlp)66 ldap_create_passwordpolicy_control( LDAP *ld,
67                                     LDAPControl **ctrlp )
68 {
69 	assert( ld != NULL );
70 	assert( LDAP_VALID( ld ) );
71 	assert( ctrlp != NULL );
72 
73 	ld->ld_errno = ldap_control_create( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
74 		0, NULL, 0, ctrlp );
75 
76 	return ld->ld_errno;
77 }
78 
79 
80 /*---
81    ldap_parse_passwordpolicy_control
82 
83    Decode the passwordPolicyResponse control and return information.
84 
85    ld           (IN)   An LDAP session handle.
86 
87    ctrl         (IN)   The address of an
88 					   LDAPControl structure, either obtained
89 					   by running through the list of response controls or
90 					   by a call to ldap_control_find().
91 
92    exptimep     (OUT)  This result parameter is filled in with the number of seconds before
93                                            the password will expire, if expiration is imminent
94                                            (imminency defined by the password policy). If expiration
95                                            is not imminent, the value is set to -1.
96 
97    gracep       (OUT)  This result parameter is filled in with the number of grace logins after
98                                            the password has expired, before no further login attempts
99                                            will be allowed.
100 
101    errorcodep   (OUT)  This result parameter is filled in with the error code of the password operation
102                                            If no error was detected, this error is set to PP_noError.
103 
104    Ber encoding
105 
106    PasswordPolicyResponseValue ::= SEQUENCE {
107        warning [0] CHOICE {
108            timeBeforeExpiration [0] INTEGER (0 .. maxInt),
109            graceLoginsRemaining [1] INTEGER (0 .. maxInt) } OPTIONAL
110        error [1] ENUMERATED {
111            passwordExpired        (0),
112            accountLocked          (1),
113            changeAfterReset       (2),
114            passwordModNotAllowed  (3),
115            mustSupplyOldPassword  (4),
116            invalidPasswordSyntax  (5),
117            passwordTooShort       (6),
118            passwordTooYoung       (7),
119            passwordInHistory      (8) } OPTIONAL }
120 
121 ---*/
122 
123 int
ldap_parse_passwordpolicy_control(LDAP * ld,LDAPControl * ctrl,ber_int_t * expirep,ber_int_t * gracep,LDAPPasswordPolicyError * errorp)124 ldap_parse_passwordpolicy_control(
125 	LDAP           *ld,
126 	LDAPControl    *ctrl,
127 	ber_int_t      *expirep,
128 	ber_int_t      *gracep,
129 	LDAPPasswordPolicyError *errorp )
130 {
131 	BerElement  *ber;
132 	int exp = -1, grace = -1;
133 	ber_tag_t tag;
134 	ber_len_t berLen;
135         char *last;
136 	int err = PP_noError;
137 
138 	assert( ld != NULL );
139 	assert( LDAP_VALID( ld ) );
140 	assert( ctrl != NULL );
141 
142 	if ( !ctrl->ldctl_value.bv_val ) {
143 		ld->ld_errno = LDAP_DECODING_ERROR;
144 		return(ld->ld_errno);
145 	}
146 
147 	/* Create a BerElement from the berval returned in the control. */
148 	ber = ber_init(&ctrl->ldctl_value);
149 
150 	if (ber == NULL) {
151 		ld->ld_errno = LDAP_NO_MEMORY;
152 		return(ld->ld_errno);
153 	}
154 
155 	tag = ber_peek_tag( ber, &berLen );
156 	if (tag != LBER_SEQUENCE) goto exit;
157 
158 	for( tag = ber_first_element( ber, &berLen, &last );
159 		tag != LBER_DEFAULT;
160 		tag = ber_next_element( ber, &berLen, last ) )
161 	{
162 		switch (tag) {
163 		case PPOLICY_WARNING:
164 			ber_skip_tag(ber, &berLen );
165 			tag = ber_peek_tag( ber, &berLen );
166 			switch( tag ) {
167 			case PPOLICY_EXPIRE:
168 				if (ber_get_int( ber, &exp ) == LBER_DEFAULT) goto exit;
169 				break;
170 			case PPOLICY_GRACE:
171 				if (ber_get_int( ber, &grace ) == LBER_DEFAULT) goto exit;
172 				break;
173 			default:
174 				goto exit;
175 			}
176 			break;
177 		case PPOLICY_ERROR:
178 			if (ber_get_enum( ber, &err ) == LBER_DEFAULT) goto exit;
179 			break;
180 		default:
181 			goto exit;
182 		}
183 	}
184 
185 	ber_free(ber, 1);
186 
187 	/* Return data to the caller for items that were requested. */
188 	if (expirep) *expirep = exp;
189 	if (gracep) *gracep = grace;
190 	if (errorp) *errorp = err;
191 
192 	ld->ld_errno = LDAP_SUCCESS;
193 	return(ld->ld_errno);
194 
195   exit:
196 	ber_free(ber, 1);
197 	ld->ld_errno = LDAP_DECODING_ERROR;
198 	return(ld->ld_errno);
199 }
200 
201 const char *
ldap_passwordpolicy_err2txt(LDAPPasswordPolicyError err)202 ldap_passwordpolicy_err2txt( LDAPPasswordPolicyError err )
203 {
204 	switch(err) {
205 	case PP_passwordExpired: return "Password expired";
206 	case PP_accountLocked: return "Account locked";
207 	case PP_changeAfterReset: return "Password must be changed";
208 	case PP_passwordModNotAllowed: return "Policy prevents password modification";
209 	case PP_mustSupplyOldPassword: return "Policy requires old password in order to change password";
210 	case PP_insufficientPasswordQuality: return "Password fails quality checks";
211 	case PP_passwordTooShort: return "Password is too short for policy";
212 	case PP_passwordTooYoung: return "Password has been changed too recently";
213 	case PP_passwordInHistory: return "New password is in list of old passwords";
214 	case PP_passwordTooLong: return "Password is too long for policy";
215 	case PP_noError: return "No error";
216 	default: return "Unknown error code";
217 	}
218 }
219 
220 #endif /* LDAP_CONTROL_PASSWORDPOLICYREQUEST */
221 
222 #ifdef LDAP_CONTROL_X_PASSWORD_EXPIRING
223 
224 int
ldap_parse_password_expiring_control(LDAP * ld,LDAPControl * ctrl,long * secondsp)225 ldap_parse_password_expiring_control(
226 	LDAP           *ld,
227 	LDAPControl    *ctrl,
228 	long           *secondsp )
229 {
230 	long seconds = 0;
231 	char buf[sizeof("-2147483648")];
232 	char *next;
233 
234 	assert( ld != NULL );
235 	assert( LDAP_VALID( ld ) );
236 	assert( ctrl != NULL );
237 
238 	if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ||
239 		ctrl->ldctl_value.bv_len >= sizeof(buf) ) {
240 		ld->ld_errno = LDAP_DECODING_ERROR;
241 		return(ld->ld_errno);
242 	}
243 
244 	memcpy( buf, ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len );
245 	buf[ctrl->ldctl_value.bv_len] = '\0';
246 
247 	seconds = strtol( buf, &next, 10 );
248 	if ( next == buf || next[0] != '\0' ) goto exit;
249 
250 	if ( secondsp != NULL ) {
251 		*secondsp = seconds;
252 	}
253 
254 	ld->ld_errno = LDAP_SUCCESS;
255 	return(ld->ld_errno);
256 
257   exit:
258 	ld->ld_errno = LDAP_DECODING_ERROR;
259 	return(ld->ld_errno);
260 }
261 
262 #endif /* LDAP_CONTROL_X_PASSWORD_EXPIRING */
263