xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/ppolicy.c (revision b5677b36047b601b9addaaa494a58ceae82c2a6c)
1 /* $OpenLDAP: pkg/ldap/libraries/libldap/ppolicy.c,v 1.11.2.4 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2004-2008 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
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
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 	/* Create a BerElement from the berval returned in the control. */
138 	ber = ber_init(&ctrl->ldctl_value);
139 
140 	if (ber == NULL) {
141 		ld->ld_errno = LDAP_NO_MEMORY;
142 		return(ld->ld_errno);
143 	}
144 
145 	tag = ber_peek_tag( ber, &berLen );
146 	if (tag != LBER_SEQUENCE) goto exit;
147 
148 	for( tag = ber_first_element( ber, &berLen, &last );
149 		tag != LBER_DEFAULT;
150 		tag = ber_next_element( ber, &berLen, last ) )
151 	{
152 		switch (tag) {
153 		case PPOLICY_WARNING:
154 			ber_skip_tag(ber, &berLen );
155 			tag = ber_peek_tag( ber, &berLen );
156 			switch( tag ) {
157 			case PPOLICY_EXPIRE:
158 				if (ber_get_int( ber, &exp ) == LBER_DEFAULT) goto exit;
159 				break;
160 			case PPOLICY_GRACE:
161 				if (ber_get_int( ber, &grace ) == LBER_DEFAULT) goto exit;
162 				break;
163 			default:
164 				goto exit;
165 			}
166 			break;
167 		case PPOLICY_ERROR:
168 			if (ber_get_enum( ber, &err ) == LBER_DEFAULT) goto exit;
169 			break;
170 		default:
171 			goto exit;
172 		}
173 	}
174 
175 	ber_free(ber, 1);
176 
177 	/* Return data to the caller for items that were requested. */
178 	if (expirep) *expirep = exp;
179 	if (gracep) *gracep = grace;
180 	if (errorp) *errorp = err;
181 
182 	ld->ld_errno = LDAP_SUCCESS;
183 	return(ld->ld_errno);
184 
185   exit:
186 	ber_free(ber, 1);
187 	ld->ld_errno = LDAP_DECODING_ERROR;
188 	return(ld->ld_errno);
189 }
190 
191 const char *
192 ldap_passwordpolicy_err2txt( LDAPPasswordPolicyError err )
193 {
194 	switch(err) {
195 	case PP_passwordExpired: return "Password expired";
196 	case PP_accountLocked: return "Account locked";
197 	case PP_changeAfterReset: return "Password must be changed";
198 	case PP_passwordModNotAllowed: return "Policy prevents password modification";
199 	case PP_mustSupplyOldPassword: return "Policy requires old password in order to change password";
200 	case PP_insufficientPasswordQuality: return "Password fails quality checks";
201 	case PP_passwordTooShort: return "Password is too short for policy";
202 	case PP_passwordTooYoung: return "Password has been changed too recently";
203 	case PP_passwordInHistory: return "New password is in list of old passwords";
204 	case PP_noError: return "No error";
205 	default: return "Unknown error code";
206 	}
207 }
208 
209 #endif /* LDAP_CONTROL_PASSWORDPOLICYREQUEST */
210