]> git.sur5r.net Git - openldap/blob - servers/slapd/passwd.c
2f50c2a94899fccb121015f83097357a7880f782
[openldap] / servers / slapd / passwd.c
1 /* passwd.c - password extended operation routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2003 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20
21 #include <ac/krb.h>
22 #include <ac/socket.h>
23 #include <ac/string.h>
24 #include <ac/unistd.h>
25
26 #include "slap.h"
27
28 #include <lber_pvt.h>
29 #include <lutil.h>
30
31 int passwd_extop(
32         Operation *op,
33         SlapReply *rs )
34 {
35         struct berval tmpbv, id, old, new;
36         
37         assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 );
38
39         if( op->o_dn.bv_len == 0 ) {
40                 rs->sr_text = "only authenticated users may change passwords";
41                 return LDAP_STRONG_AUTH_REQUIRED;
42         }
43
44         /* FIXME: need to parse the reqdata to determine the backend
45          * of the DN the passwd_extop () will apply to; this, on turn,
46          * requires to duplicate the reqdata because slap_passwd_parse()
47          * apparently alters it!
48          *
49          * Maybe we can make a lightweight version of slap_passwd_parse()
50          * that extracts the DN with no impact on the reqdata value?
51          */
52         ber_dupbv_x( &tmpbv, op->oq_extended.rs_reqdata, op->o_tmpmemctx );
53         rs->sr_err = slap_passwd_parse( &tmpbv, &id, &old, &new, &rs->sr_text );
54         if (rs->sr_err != LDAP_SUCCESS) {
55                 ber_memfree_x( tmpbv.bv_val, op->o_tmpmemctx );
56                 return rs->sr_err;
57         }
58         
59         ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
60         /* FIXME: we select the appropriate backend based on the DN
61          * in the reqdata
62          */
63         if ( id.bv_len ) {
64                 op->o_bd = select_backend( &id, 0, 0 );
65                 
66         } else {
67                 op->o_bd = op->o_conn->c_authz_backend;
68         }
69         ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
70         ber_memfree_x( tmpbv.bv_val, op->o_tmpmemctx );
71
72         if( op->o_bd && !op->o_bd->be_extended ) {
73                 rs->sr_text = "operation not supported for current user";
74                 return LDAP_UNWILLING_TO_PERFORM;
75         }
76
77         if (backend_check_restrictions( op, rs,
78                         (struct berval *)&slap_EXOP_MODIFY_PASSWD ) != LDAP_SUCCESS) {
79                 return rs->sr_err;
80         }
81
82         if( op->o_bd == NULL ) {
83 #ifdef HAVE_CYRUS_SASL
84                 rs->sr_err = slap_sasl_setpass( op, rs );
85 #else
86                 rs->sr_text = "no authz backend";
87                 rs->sr_err = LDAP_OTHER;
88 #endif
89
90 #ifndef SLAPD_MULTIMASTER
91         /* This does not apply to multi-master case */
92         } else if( op->o_bd->be_update_ndn.bv_len ) {
93                 /* we SHOULD return a referral in this case */
94                 BerVarray defref = NULL;
95                 if ( !LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
96                         syncinfo_t *si;
97                         LDAP_STAILQ_FOREACH( si, &op->o_bd->be_syncinfo, si_next ) {
98                                 struct berval tmpbv;
99                                 ber_dupbv( &tmpbv, &si->si_provideruri_bv[0] );
100                                 ber_bvarray_add( &defref, &tmpbv );
101                         }
102                 } else {
103                         defref = referral_rewrite( op->o_bd->be_update_refs,
104                                 NULL, NULL, LDAP_SCOPE_DEFAULT );
105                 }
106                 rs->sr_ref = defref;
107                 rs->sr_err = LDAP_REFERRAL;
108 #endif /* !SLAPD_MULTIMASTER */
109
110         } else {
111                 rs->sr_err = op->o_bd->be_extended( op, rs );
112         }
113
114         return rs->sr_err;
115 }
116
117 int slap_passwd_parse( struct berval *reqdata,
118         struct berval *id,
119         struct berval *oldpass,
120         struct berval *newpass,
121         const char **text )
122 {
123         int rc = LDAP_SUCCESS;
124         ber_tag_t tag;
125         ber_len_t len;
126         BerElementBuffer berbuf;
127         BerElement *ber = (BerElement *)&berbuf;
128
129         if( reqdata == NULL ) {
130                 return LDAP_SUCCESS;
131         }
132
133         if( reqdata->bv_len == 0 ) {
134                 *text = "empty request data field";
135                 return LDAP_PROTOCOL_ERROR;
136         }
137
138         /* ber_init2 uses reqdata directly, doesn't allocate new buffers */
139         ber_init2( ber, reqdata, 0 );
140
141         tag = ber_scanf( ber, "{" /*}*/ );
142
143         if( tag != LBER_ERROR ) {
144                 tag = ber_peek_tag( ber, &len );
145         }
146
147         if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_ID ) {
148                 if( id == NULL ) {
149 #ifdef NEW_LOGGING
150                         LDAP_LOG( OPERATION, ERR,
151                            "slap_passwd_parse: ID not allowed.\n", 0, 0, 0 );
152 #else
153                         Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID not allowed.\n",
154                                 0, 0, 0 );
155 #endif
156
157                         *text = "user must change own password";
158                         rc = LDAP_UNWILLING_TO_PERFORM;
159                         goto done;
160                 }
161
162                 tag = ber_scanf( ber, "m", id );
163
164                 if( tag == LBER_ERROR ) {
165 #ifdef NEW_LOGGING
166                         LDAP_LOG( OPERATION, ERR,
167                            "slap_passwd_parse:  ID parse failed.\n", 0, 0, 0 );
168 #else
169                         Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID parse failed.\n",
170                                 0, 0, 0 );
171 #endif
172
173                         goto decoding_error;
174                 }
175
176                 tag = ber_peek_tag( ber, &len);
177         }
178
179         if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_OLD ) {
180                 if( oldpass == NULL ) {
181 #ifdef NEW_LOGGING
182                         LDAP_LOG( OPERATION, ERR,
183                            "slap_passwd_parse: OLD not allowed.\n" , 0, 0, 0 );
184 #else
185                         Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD not allowed.\n",
186                                 0, 0, 0 );
187 #endif
188
189                         *text = "use bind to verify old password";
190                         rc = LDAP_UNWILLING_TO_PERFORM;
191                         goto done;
192                 }
193
194                 tag = ber_scanf( ber, "m", oldpass );
195
196                 if( tag == LBER_ERROR ) {
197 #ifdef NEW_LOGGING
198                         LDAP_LOG( OPERATION, ERR,
199                            "slap_passwd_parse:  ID parse failed.\n" , 0, 0, 0 );
200 #else
201                         Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID parse failed.\n",
202                                 0, 0, 0 );
203 #endif
204
205                         goto decoding_error;
206                 }
207
208                 tag = ber_peek_tag( ber, &len );
209         }
210
211         if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ) {
212                 if( newpass == NULL ) {
213 #ifdef NEW_LOGGING
214                         LDAP_LOG( OPERATION, ERR,
215                            "slap_passwd_parse:  NEW not allowed.\n", 0, 0, 0 );
216 #else
217                         Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: NEW not allowed.\n",
218                                 0, 0, 0 );
219 #endif
220
221                         *text = "user specified passwords disallowed";
222                         rc = LDAP_UNWILLING_TO_PERFORM;
223                         goto done;
224                 }
225
226                 tag = ber_scanf( ber, "m", newpass );
227
228                 if( tag == LBER_ERROR ) {
229 #ifdef NEW_LOGGING
230                         LDAP_LOG( OPERATION, ERR,
231                            "slap_passwd_parse:  OLD parse failed.\n", 0, 0, 0 );
232 #else
233                         Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD parse failed.\n",
234                                 0, 0, 0 );
235 #endif
236
237                         goto decoding_error;
238                 }
239
240                 tag = ber_peek_tag( ber, &len );
241         }
242
243         if( len != 0 ) {
244 decoding_error:
245 #ifdef NEW_LOGGING
246                 LDAP_LOG( OPERATION, ERR, 
247                         "slap_passwd_parse: decoding error, len=%ld\n", (long)len, 0, 0 );
248 #else
249                 Debug( LDAP_DEBUG_TRACE,
250                         "slap_passwd_parse: decoding error, len=%ld\n",
251                         (long) len, 0, 0 );
252 #endif
253
254                 *text = "data decoding error";
255                 rc = LDAP_PROTOCOL_ERROR;
256         }
257
258 done:
259         return rc;
260 }
261
262 struct berval * slap_passwd_return(
263         struct berval           *cred )
264 {
265         int rc;
266         struct berval *bv = NULL;
267         BerElementBuffer berbuf;
268         /* opaque structure, size unknown but smaller than berbuf */
269         BerElement *ber = (BerElement *)&berbuf;
270
271         assert( cred != NULL );
272
273 #ifdef NEW_LOGGING
274         LDAP_LOG( OPERATION, ENTRY, 
275                 "slap_passwd_return: %ld\n",(long)cred->bv_len, 0, 0 );
276 #else
277         Debug( LDAP_DEBUG_TRACE, "slap_passwd_return: %ld\n",
278                 (long) cred->bv_len, 0, 0 );
279 #endif
280         
281         ber_init_w_nullc( ber, LBER_USE_DER );
282
283         rc = ber_printf( ber, "{tON}",
284                 LDAP_TAG_EXOP_MODIFY_PASSWD_GEN, cred );
285
286         if( rc >= 0 ) {
287                 (void) ber_flatten( ber, &bv );
288         }
289
290         ber_free_buf( ber );
291
292         return bv;
293 }
294
295 int
296 slap_passwd_check(
297         Connection *conn,
298         Attribute *a,
299         struct berval *cred,
300         const char **text )
301 {
302         int result = 1;
303         struct berval *bv;
304
305 #if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD )
306         ldap_pvt_thread_mutex_lock( &passwd_mutex );
307 #ifdef SLAPD_SPASSWD
308         lutil_passwd_sasl_conn = conn->c_sasl_authctx;
309 #endif
310 #endif
311
312         for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
313                 if( !lutil_passwd( bv, cred, NULL, text ) ) {
314                         result = 0;
315                         break;
316                 }
317         }
318
319 #if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD )
320 #ifdef SLAPD_SPASSWD
321         lutil_passwd_sasl_conn = NULL;
322 #endif
323         ldap_pvt_thread_mutex_unlock( &passwd_mutex );
324 #endif
325
326         return result;
327 }
328
329 void
330 slap_passwd_generate( struct berval *pass )
331 {
332         struct berval *tmp;
333 #ifdef NEW_LOGGING
334         LDAP_LOG( OPERATION, ENTRY, "slap_passwd_generate: begin\n", 0, 0, 0 );
335 #else
336         Debug( LDAP_DEBUG_TRACE, "slap_passwd_generate\n", 0, 0, 0 );
337 #endif
338         /*
339          * generate passwords of only 8 characters as some getpass(3)
340          * implementations truncate at 8 characters.
341          */
342         tmp = lutil_passwd_generate( 8 );
343         if (tmp) {
344                 *pass = *tmp;
345                 free(tmp);
346         } else {
347                 pass->bv_val = NULL;
348                 pass->bv_len = 0;
349         }
350 }
351
352 void
353 slap_passwd_hash(
354         struct berval * cred,
355         struct berval * new,
356         const char **text )
357 {
358         struct berval *tmp;
359 #ifdef LUTIL_SHA1_BYTES
360         char* hash = default_passwd_hash ?  default_passwd_hash : "{SSHA}";
361 #else
362         char* hash = default_passwd_hash ?  default_passwd_hash : "{SMD5}";
363 #endif
364         
365
366 #if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD )
367         ldap_pvt_thread_mutex_lock( &passwd_mutex );
368 #endif
369
370         tmp = lutil_passwd_hash( cred , hash, text );
371         
372 #if defined( SLAPD_CRYPT ) || defined( SLAPD_SPASSWD )
373         ldap_pvt_thread_mutex_unlock( &passwd_mutex );
374 #endif
375
376         if( tmp == NULL ) {
377                 new->bv_len = 0;
378                 new->bv_val = NULL;
379         }
380
381         *new = *tmp;
382         free( tmp );
383         return;
384 }