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