1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is Sun LDAP C SDK.
15  *
16  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
17  *
18  * Portions created by Sun Microsystems, Inc are Copyright (C) 2005
19  * Sun Microsystems, Inc. All Rights Reserved.
20  *
21  * Contributor(s): abobrov@sun.com
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either the GNU General Public License Version 2 or later (the "GPL"), or
25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the MPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the MPL, the GPL or the LGPL.
34  *
35  * ***** END LICENSE BLOCK ***** */
36 
37 #include "ldap-int.h"
38 
39 /* ldap_create_passwordpolicy_control:
40 
41 Parameters are
42 
43 ld              LDAP pointer to the desired connection
44 
45 ctrlp           the address of a place to put the constructed control
46 */
47 
48 int
49 LDAP_CALL
ldap_create_passwordpolicy_control(LDAP * ld,LDAPControl ** ctrlp)50 ldap_create_passwordpolicy_control (
51 										LDAP *ld,
52 										LDAPControl **ctrlp
53 																	)
54 {
55 	int rc;
56 
57 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
58 		return( LDAP_PARAM_ERROR );
59 	}
60 
61 	if ( ctrlp == NULL ) {
62 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
63 		return ( LDAP_PARAM_ERROR );
64 	}
65 
66 	rc = nsldapi_build_control( LDAP_CONTROL_PASSWD_POLICY,
67 								NULL, 0, 0, ctrlp );
68 
69 	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
70 	return( rc );
71 }
72 
73 /* ldap_create_passwordpolicy_control_ext:
74 
75 Parameters are
76 
77 ld              LDAP pointer to the desired connection
78 
79 ctl_iscritical  Indicates whether the control is critical of not. If
80                 this field is non-zero, the operation will only be car-
81                 ried out if the control is recognized by the server
82                 and/or client
83 
84 ctrlp           the address of a place to put the constructed control
85 */
86 
87 int
88 LDAP_CALL
ldap_create_passwordpolicy_control_ext(LDAP * ld,const char ctl_iscritical,LDAPControl ** ctrlp)89 ldap_create_passwordpolicy_control_ext (
90 											LDAP *ld,
91 											const char ctl_iscritical,
92 											LDAPControl **ctrlp
93 																		)
94 {
95 	int rc;
96 
97 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
98 		return( LDAP_PARAM_ERROR );
99 	}
100 
101 	if ( ctrlp == NULL ) {
102 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
103 		return ( LDAP_PARAM_ERROR );
104 	}
105 
106 	rc = nsldapi_build_control( LDAP_CONTROL_PASSWD_POLICY,
107 								NULL, 0, ctl_iscritical, ctrlp );
108 
109 	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
110 	return( rc );
111 }
112 
113 /* ldap_parse_passwordpolicy_control:
114 
115 Parameters are
116 
117 ld              LDAP pointer to the desired connection
118 
119 ctrlp           pointer to LDAPControl structure, obtained from
120 				calling ldap_find_control() or by other means.
121 
122 exptimep        result parameter is filled in with the number of seconds before
123                 the password will expire.
124 
125 gracep          result parameter is filled in with the number of grace logins
126                 after the password has expired.
127 
128 errorcodep      result parameter is filled in with the error code of the
129                 password operation.
130 */
131 
132 int
133 LDAP_CALL
ldap_parse_passwordpolicy_control(LDAP * ld,LDAPControl * ctrlp,ber_int_t * expirep,ber_int_t * gracep,LDAPPasswordPolicyError * errorp)134 ldap_parse_passwordpolicy_control (
135 									LDAP *ld,
136 									LDAPControl *ctrlp,
137 									ber_int_t *expirep,
138 									ber_int_t *gracep,
139 									LDAPPasswordPolicyError *errorp
140 																	)
141 {
142 	ber_len_t	len;
143 	ber_tag_t	tag;
144 	ber_int_t	pp_exp = -1;
145 	ber_int_t	pp_grace = -1;
146 	ber_int_t	pp_warning = -1;
147 	ber_int_t	pp_err = PP_noError;
148 	BerElement	*ber = NULL;
149 
150 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ) {
151 	    return( LDAP_PARAM_ERROR );
152 	}
153 
154 	if ( ctrlp == NULL ) {
155 		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
156 		return ( LDAP_CONTROL_NOT_FOUND );
157 	}
158 
159 	/*  allocate a Ber element with the contents of the control's struct berval */
160 	if ( ( ber = ber_init( &ctrlp->ldctl_value ) ) == NULL ) {
161 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
162 		return( LDAP_NO_MEMORY );
163 	}
164 
165 	/*
166 	 * The control value should look like this:
167 	 *
168 	 *	PasswordPolicyResponseValue ::= SEQUENCE {
169 	 *		warning [0] CHOICE {
170 	 *			timeBeforeExpiration        [0] INTEGER (0 .. maxInt),
171 	 *			graceLoginsRemaining        [1] INTEGER (0 .. maxInt) } OPTIONAL
172 	 *		error       [1] ENUMERATED {
173 	 *			passwordExpired             (0),
174 	 *			accountLocked               (1),
175 	 *			changeAfterReset            (2),
176 	 *			passwordModNotAllowed       (3),
177 	 *			mustSupplyOldPassword       (4),
178 	 *			insufficientPasswordQuality (5),
179 	 *			passwordTooShort            (6),
180 	 *			passwordTooYoung            (7),
181 	 *			passwordInHistory           (8) } OPTIONAL }
182 	 */
183 
184 	if ( ber_scanf( ber, "{" ) == LBER_ERROR ) {
185         LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
186         ber_free( ber, 1 );
187         return( LDAP_DECODING_ERROR );
188 	}
189 
190 	tag = ber_peek_tag( ber, &len );
191 
192 	while ( (tag != LBER_ERROR) && (tag != LBER_END_OF_SEQORSET) ) {
193 		if ( tag == ( LBER_CONSTRUCTED | LBER_CLASS_CONTEXT ) ) {
194 			ber_skip_tag( ber, &len );
195 			if ( ber_scanf( ber, "ti", &tag, &pp_warning ) == LBER_ERROR ) {
196 				LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
197 				ber_free( ber, 1 );
198 				return( LDAP_DECODING_ERROR );
199 			}
200 			if ( tag == LBER_CLASS_CONTEXT ) {
201 				pp_exp = pp_warning;
202 			} else if ( tag == ( LBER_CLASS_CONTEXT | 0x01 ) ) {
203 				pp_grace = pp_warning;
204 			}
205 		} else if ( tag == ( LBER_CLASS_CONTEXT | 0x01 ) ) {
206 				if ( ber_scanf( ber, "ti", &tag, &pp_err ) == LBER_ERROR ) {
207 					LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
208 					ber_free( ber, 1 );
209 					return( LDAP_DECODING_ERROR );
210 				}
211 		}
212 		if ( tag == LBER_DEFAULT ) {
213 			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
214 			ber_free( ber, 1 );
215 			return( LDAP_DECODING_ERROR );
216 		}
217 		tag = ber_skip_tag( ber, &len );
218 	}
219 
220 	if (expirep) *expirep = pp_exp;
221 	if (gracep) *gracep = pp_grace;
222 	if (errorp) *errorp = pp_err;
223 
224 	/* the ber encoding is no longer needed */
225 	ber_free( ber, 1 );
226 	return( LDAP_SUCCESS );
227 }
228 
229 /* ldap_parse_passwordpolicy_control_ext:
230 
231 Parameters are
232 
233 ld              LDAP pointer to the desired connection
234 
235 ctrlp           An array of controls obtained from calling
236                 ldap_parse_result on the set of results
237                 returned by the server
238 
239 exptimep        result parameter is filled in with the number of seconds before
240                 the password will expire.
241 
242 gracep          result parameter is filled in with the number of grace logins
243                 after the password has expired.
244 
245 errorcodep      result parameter is filled in with the error code of the
246                 password operation.
247 */
248 
249 int
250 LDAP_CALL
ldap_parse_passwordpolicy_control_ext(LDAP * ld,LDAPControl ** ctrlp,ber_int_t * expirep,ber_int_t * gracep,LDAPPasswordPolicyError * errorp)251 ldap_parse_passwordpolicy_control_ext (
252 										LDAP *ld,
253 										LDAPControl **ctrlp,
254 										ber_int_t *expirep,
255 										ber_int_t *gracep,
256 										LDAPPasswordPolicyError *errorp
257 																		)
258 {
259 	int i, foundPPControl;
260 	LDAPControl *PPCtrlp = NULL;
261 
262 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ) {
263 	    return( LDAP_PARAM_ERROR );
264 	}
265 
266 	/* find the control in the list of controls if it exists */
267 	if ( ctrlp == NULL ) {
268 		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
269 		return ( LDAP_CONTROL_NOT_FOUND );
270 	}
271 	foundPPControl = 0;
272 	for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundPPControl )); i++ ) {
273 		foundPPControl = !strcmp( ctrlp[i]->ldctl_oid, LDAP_CONTROL_PASSWD_POLICY );
274 	}
275 	if ( !foundPPControl ) {
276 		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
277 		return ( LDAP_CONTROL_NOT_FOUND );
278 	} else {
279 		/* let local var point to the control */
280 		PPCtrlp = ctrlp[i-1];
281 	}
282 
283 	return (
284 	ldap_parse_passwordpolicy_control( ld, PPCtrlp, expirep, gracep, errorp ));
285 }
286 
287 const char *
288 LDAP_CALL
ldap_passwordpolicy_err2txt(LDAPPasswordPolicyError err)289 ldap_passwordpolicy_err2txt( LDAPPasswordPolicyError err )
290 {
291 	switch(err) {
292 		case PP_passwordExpired:
293 			return "Password expired";
294 		case PP_accountLocked:
295 			return "Account locked";
296 		case PP_changeAfterReset:
297 			return "Password must be changed";
298 		case PP_passwordModNotAllowed:
299 			return "Policy prevents password modification";
300 		case PP_mustSupplyOldPassword:
301 			return "Policy requires old password in order to change password";
302 		case PP_insufficientPasswordQuality:
303 			return "Password fails quality checks";
304 		case PP_passwordTooShort:
305 			return "Password is too short for policy";
306 		case PP_passwordTooYoung:
307 			return "Password has been changed too recently";
308 		case PP_passwordInHistory:
309 			return "New password is in list of old passwords";
310 		case PP_noError:
311 			return "No error";
312 		default:
313 			return "Unknown error code";
314 	}
315 }
316