xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/passwd.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: passwd.c,v 1.1.1.4 2014/05/28 09:58:47 tron Exp $	*/
2 
3 /* passwd.c - password extended operation routines */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2014 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 
19 #include "portable.h"
20 
21 #include <stdio.h>
22 
23 #include <ac/socket.h>
24 #include <ac/string.h>
25 #include <ac/unistd.h>
26 
27 #ifdef SLAPD_CRYPT
28 #include <ac/crypt.h>
29 #endif
30 
31 #include "slap.h"
32 
33 #include <lber_pvt.h>
34 #include <lutil.h>
35 #include <lutil_sha1.h>
36 
37 const struct berval slap_EXOP_MODIFY_PASSWD = BER_BVC(LDAP_EXOP_MODIFY_PASSWD);
38 
39 static const char *defhash[] = {
40 #ifdef LUTIL_SHA1_BYTES
41 	"{SSHA}",
42 #else
43 	"{SMD5}",
44 #endif
45 	NULL
46 };
47 
48 int passwd_extop(
49 	Operation *op,
50 	SlapReply *rs )
51 {
52 	struct berval id = {0, NULL}, hash, *rsp = NULL;
53 	req_pwdexop_s *qpw = &op->oq_pwdexop;
54 	req_extended_s qext = op->oq_extended;
55 	Modifications *ml;
56 	slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
57 	int i, nhash;
58 	char **hashes, idNul;
59 	int rc;
60 	BackendDB *op_be;
61 	int freenewpw = 0;
62 	struct berval dn = BER_BVNULL, ndn = BER_BVNULL;
63 
64 	assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 );
65 
66 	if( op->o_dn.bv_len == 0 ) {
67 		Statslog( LDAP_DEBUG_STATS, "%s PASSMOD\n",
68 			op->o_log_prefix, 0, 0, 0, 0 );
69 		rs->sr_text = "only authenticated users may change passwords";
70 		return LDAP_STRONG_AUTH_REQUIRED;
71 	}
72 
73 	qpw->rs_old.bv_len = 0;
74 	qpw->rs_old.bv_val = NULL;
75 	qpw->rs_new.bv_len = 0;
76 	qpw->rs_new.bv_val = NULL;
77 	qpw->rs_mods = NULL;
78 	qpw->rs_modtail = NULL;
79 
80 	rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
81 		&qpw->rs_old, &qpw->rs_new, &rs->sr_text );
82 
83 	if ( !BER_BVISNULL( &id )) {
84 		idNul = id.bv_val[id.bv_len];
85 		id.bv_val[id.bv_len] = '\0';
86 	}
87 	if ( rs->sr_err == LDAP_SUCCESS && !BER_BVISEMPTY( &id ) ) {
88 		Statslog( LDAP_DEBUG_STATS, "%s PASSMOD id=\"%s\"%s%s\n",
89 			op->o_log_prefix, id.bv_val,
90 			qpw->rs_old.bv_val ? " old" : "",
91 			qpw->rs_new.bv_val ? " new" : "", 0 );
92 	} else {
93 		Statslog( LDAP_DEBUG_STATS, "%s PASSMOD%s%s\n",
94 			op->o_log_prefix,
95 			qpw->rs_old.bv_val ? " old" : "",
96 			qpw->rs_new.bv_val ? " new" : "", 0, 0 );
97 	}
98 
99 	if ( rs->sr_err != LDAP_SUCCESS ) {
100 		if ( !BER_BVISNULL( &id ))
101 			id.bv_val[id.bv_len] = idNul;
102 		return rs->sr_err;
103 	}
104 
105 	if ( !BER_BVISEMPTY( &id ) ) {
106 		rs->sr_err = dnPrettyNormal( NULL, &id, &dn, &ndn, op->o_tmpmemctx );
107 		id.bv_val[id.bv_len] = idNul;
108 		if ( rs->sr_err != LDAP_SUCCESS ) {
109 			rs->sr_text = "Invalid DN";
110 			rc = rs->sr_err;
111 			goto error_return;
112 		}
113 		op->o_req_dn = dn;
114 		op->o_req_ndn = ndn;
115 		op->o_bd = select_backend( &op->o_req_ndn, 1 );
116 
117 	} else {
118 		ber_dupbv_x( &dn, &op->o_dn, op->o_tmpmemctx );
119 		ber_dupbv_x( &ndn, &op->o_ndn, op->o_tmpmemctx );
120 		op->o_req_dn = dn;
121 		op->o_req_ndn = ndn;
122 		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
123 		op->o_bd = op->o_conn->c_authz_backend;
124 		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
125 	}
126 
127 	if( op->o_bd == NULL ) {
128 		if ( qpw->rs_old.bv_val != NULL ) {
129 			rs->sr_text = "unwilling to verify old password";
130 			rc = LDAP_UNWILLING_TO_PERFORM;
131 			goto error_return;
132 		}
133 
134 #ifdef HAVE_CYRUS_SASL
135 		rc = slap_sasl_setpass( op, rs );
136 #else
137 		rs->sr_text = "no authz backend";
138 		rc = LDAP_OTHER;
139 #endif
140 		goto error_return;
141 	}
142 
143 	if ( op->o_req_ndn.bv_len == 0 ) {
144 		rs->sr_text = "no password is associated with the Root DSE";
145 		rc = LDAP_UNWILLING_TO_PERFORM;
146 		goto error_return;
147 	}
148 
149 	/* If we've got a glued backend, check the real backend */
150 	op_be = op->o_bd;
151 	if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
152 		op->o_bd = select_backend( &op->o_req_ndn, 0 );
153 	}
154 
155 	if (backend_check_restrictions( op, rs,
156 			(struct berval *)&slap_EXOP_MODIFY_PASSWD ) != LDAP_SUCCESS) {
157 		rc = rs->sr_err;
158 		goto error_return;
159 	}
160 
161 	/* check for referrals */
162 	if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
163 		rc = rs->sr_err;
164 		goto error_return;
165 	}
166 
167 	/* This does not apply to multi-master case */
168 	if(!( !SLAP_SINGLE_SHADOW( op->o_bd ) || be_isupdate( op ))) {
169 		/* we SHOULD return a referral in this case */
170 		BerVarray defref = op->o_bd->be_update_refs
171 			? op->o_bd->be_update_refs : default_referral;
172 
173 		if( defref != NULL ) {
174 			rs->sr_ref = referral_rewrite( op->o_bd->be_update_refs,
175 				NULL, NULL, LDAP_SCOPE_DEFAULT );
176 			if(rs->sr_ref) {
177 				rs->sr_flags |= REP_REF_MUSTBEFREED;
178 			} else {
179 				rs->sr_ref = defref;
180 			}
181 			rc = LDAP_REFERRAL;
182 			goto error_return;
183 
184 		}
185 
186 		rs->sr_text = "shadow context; no update referral";
187 		rc = LDAP_UNWILLING_TO_PERFORM;
188 		goto error_return;
189 	}
190 
191 	/* generate a new password if none was provided */
192 	if ( qpw->rs_new.bv_len == 0 ) {
193 		slap_passwd_generate( &qpw->rs_new );
194 		if ( qpw->rs_new.bv_len ) {
195 			rsp = slap_passwd_return( &qpw->rs_new );
196 			freenewpw = 1;
197 		}
198 	}
199 	if ( qpw->rs_new.bv_len == 0 ) {
200 		rs->sr_text = "password generation failed";
201 		rc = LDAP_OTHER;
202 		goto error_return;
203 	}
204 
205 	op->o_bd = op_be;
206 
207 	/* Give the backend a chance to handle this itself */
208 	if ( op->o_bd->be_extended ) {
209 		rs->sr_err = op->o_bd->be_extended( op, rs );
210 		if ( rs->sr_err != LDAP_UNWILLING_TO_PERFORM &&
211 			rs->sr_err != SLAP_CB_CONTINUE )
212 		{
213 			rc = rs->sr_err;
214 			if ( rsp ) {
215 				rs->sr_rspdata = rsp;
216 				rsp = NULL;
217 			}
218 			goto error_return;
219 		}
220 	}
221 
222 	/* The backend didn't handle it, so try it here */
223 	if( op->o_bd && !op->o_bd->be_modify ) {
224 		rs->sr_text = "operation not supported for current user";
225 		rc = LDAP_UNWILLING_TO_PERFORM;
226 		goto error_return;
227 	}
228 
229 	if ( qpw->rs_old.bv_val != NULL ) {
230 		Entry *e = NULL;
231 
232 		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL,
233 			slap_schema.si_ad_userPassword, 0, &e );
234 		if ( rc == LDAP_SUCCESS && e ) {
235 			Attribute *a = attr_find( e->e_attrs,
236 				slap_schema.si_ad_userPassword );
237 			if ( a )
238 				rc = slap_passwd_check( op, e, a, &qpw->rs_old, &rs->sr_text );
239 			else
240 				rc = 1;
241 			be_entry_release_r( op, e );
242 			if ( rc == LDAP_SUCCESS )
243 				goto old_good;
244 		}
245 		rs->sr_text = "unwilling to verify old password";
246 		rc = LDAP_UNWILLING_TO_PERFORM;
247 		goto error_return;
248 	}
249 
250 old_good:
251 	ml = ch_malloc( sizeof(Modifications) );
252 	if ( !qpw->rs_modtail ) qpw->rs_modtail = &ml->sml_next;
253 
254 	if ( default_passwd_hash ) {
255 		for ( nhash = 0; default_passwd_hash[nhash]; nhash++ );
256 		hashes = default_passwd_hash;
257 	} else {
258 		nhash = 1;
259 		hashes = (char **)defhash;
260 	}
261 	ml->sml_numvals = nhash;
262 	ml->sml_values = ch_malloc( (nhash+1)*sizeof(struct berval) );
263 	for ( i=0; hashes[i]; i++ ) {
264 		slap_passwd_hash_type( &qpw->rs_new, &hash, hashes[i], &rs->sr_text );
265 		if ( hash.bv_len == 0 ) {
266 			if ( !rs->sr_text ) {
267 				rs->sr_text = "password hash failed";
268 			}
269 			break;
270 		}
271 		ml->sml_values[i] = hash;
272 	}
273 	ml->sml_values[i].bv_val = NULL;
274 	ml->sml_nvalues = NULL;
275 	ml->sml_desc = slap_schema.si_ad_userPassword;
276 	ml->sml_type = ml->sml_desc->ad_cname;
277 	ml->sml_op = LDAP_MOD_REPLACE;
278 	ml->sml_flags = 0;
279 	ml->sml_next = qpw->rs_mods;
280 	qpw->rs_mods = ml;
281 
282 	if ( hashes[i] ) {
283 		rs->sr_err = LDAP_OTHER;
284 
285 	} else {
286 		slap_callback *sc = op->o_callback;
287 
288 		op->o_tag = LDAP_REQ_MODIFY;
289 		op->o_callback = &cb;
290 		op->orm_modlist = qpw->rs_mods;
291 		op->orm_no_opattrs = 0;
292 
293 		cb.sc_private = qpw;	/* let Modify know this was pwdMod,
294 					 * if it cares... */
295 
296 		rs->sr_err = op->o_bd->be_modify( op, rs );
297 
298 		/* be_modify() might have shuffled modifications */
299 		qpw->rs_mods = op->orm_modlist;
300 
301 		if ( rs->sr_err == LDAP_SUCCESS ) {
302 			rs->sr_rspdata = rsp;
303 
304 		} else if ( rsp ) {
305 			ber_bvfree( rsp );
306 			rsp = NULL;
307 		}
308 		op->o_tag = LDAP_REQ_EXTENDED;
309 		op->o_callback = sc;
310 	}
311 
312 	rc = rs->sr_err;
313 	op->oq_extended = qext;
314 
315 error_return:;
316 	if ( qpw->rs_mods ) {
317 		slap_mods_free( qpw->rs_mods, 1 );
318 	}
319 	if ( freenewpw ) {
320 		free( qpw->rs_new.bv_val );
321 	}
322 	if ( !BER_BVISNULL( &dn ) ) {
323 		op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
324 		BER_BVZERO( &op->o_req_dn );
325 	}
326 	if ( !BER_BVISNULL( &ndn ) ) {
327 		op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
328 		BER_BVZERO( &op->o_req_ndn );
329 	}
330 
331 	return rc;
332 }
333 
334 /* NOTE: The DN in *id is NOT NUL-terminated here. dnNormalize will
335  * reject it in this condition, the caller must NUL-terminate it.
336  * FIXME: should dnNormalize still be complaining about that?
337  */
338 int slap_passwd_parse( struct berval *reqdata,
339 	struct berval *id,
340 	struct berval *oldpass,
341 	struct berval *newpass,
342 	const char **text )
343 {
344 	int rc = LDAP_SUCCESS;
345 	ber_tag_t tag;
346 	ber_len_t len = -1;
347 	BerElementBuffer berbuf;
348 	BerElement *ber = (BerElement *)&berbuf;
349 
350 	if( reqdata == NULL ) {
351 		return LDAP_SUCCESS;
352 	}
353 
354 	if( reqdata->bv_len == 0 ) {
355 		*text = "empty request data field";
356 		return LDAP_PROTOCOL_ERROR;
357 	}
358 
359 	/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
360 	ber_init2( ber, reqdata, 0 );
361 
362 	tag = ber_skip_tag( ber, &len );
363 
364 	if( tag != LBER_SEQUENCE ) {
365 		Debug( LDAP_DEBUG_TRACE,
366 			"slap_passwd_parse: decoding error\n", 0, 0, 0 );
367 		rc = LDAP_PROTOCOL_ERROR;
368 		goto done;
369 	}
370 
371 	tag = ber_peek_tag( ber, &len );
372 	if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_ID ) {
373 		if( id == NULL ) {
374 			Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID not allowed.\n",
375 				0, 0, 0 );
376 
377 			*text = "user must change own password";
378 			rc = LDAP_UNWILLING_TO_PERFORM;
379 			goto done;
380 		}
381 
382 		tag = ber_get_stringbv( ber, id, LBER_BV_NOTERM );
383 
384 		if( tag == LBER_ERROR ) {
385 			Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: ID parse failed.\n",
386 				0, 0, 0 );
387 
388 			goto decoding_error;
389 		}
390 
391 		tag = ber_peek_tag( ber, &len );
392 	}
393 
394 	if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_OLD ) {
395 		if( oldpass == NULL ) {
396 			Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD not allowed.\n",
397 				0, 0, 0 );
398 
399 			*text = "use bind to verify old password";
400 			rc = LDAP_UNWILLING_TO_PERFORM;
401 			goto done;
402 		}
403 
404 		tag = ber_get_stringbv( ber, oldpass, LBER_BV_NOTERM );
405 
406 		if( tag == LBER_ERROR ) {
407 			Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD parse failed.\n",
408 				0, 0, 0 );
409 
410 			goto decoding_error;
411 		}
412 
413 		if( oldpass->bv_len == 0 ) {
414 			Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: OLD empty.\n",
415 				0, 0, 0 );
416 
417 			*text = "old password value is empty";
418 			rc = LDAP_UNWILLING_TO_PERFORM;
419 			goto done;
420 		}
421 
422 		tag = ber_peek_tag( ber, &len );
423 	}
424 
425 	if( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ) {
426 		if( newpass == NULL ) {
427 			Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: NEW not allowed.\n",
428 				0, 0, 0 );
429 
430 			*text = "user specified passwords disallowed";
431 			rc = LDAP_UNWILLING_TO_PERFORM;
432 			goto done;
433 		}
434 
435 		tag = ber_get_stringbv( ber, newpass, LBER_BV_NOTERM );
436 
437 		if( tag == LBER_ERROR ) {
438 			Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: NEW parse failed.\n",
439 				0, 0, 0 );
440 
441 			goto decoding_error;
442 		}
443 
444 		if( newpass->bv_len == 0 ) {
445 			Debug( LDAP_DEBUG_TRACE, "slap_passwd_parse: NEW empty.\n",
446 				0, 0, 0 );
447 
448 			*text = "new password value is empty";
449 			rc = LDAP_UNWILLING_TO_PERFORM;
450 			goto done;
451 		}
452 
453 		tag = ber_peek_tag( ber, &len );
454 	}
455 
456 	if( len != 0 ) {
457 decoding_error:
458 		Debug( LDAP_DEBUG_TRACE,
459 			"slap_passwd_parse: decoding error, len=%ld\n",
460 			(long) len, 0, 0 );
461 
462 		*text = "data decoding error";
463 		rc = LDAP_PROTOCOL_ERROR;
464 	}
465 
466 done:
467 	return rc;
468 }
469 
470 struct berval * slap_passwd_return(
471 	struct berval		*cred )
472 {
473 	int rc;
474 	struct berval *bv = NULL;
475 	BerElementBuffer berbuf;
476 	/* opaque structure, size unknown but smaller than berbuf */
477 	BerElement *ber = (BerElement *)&berbuf;
478 
479 	assert( cred != NULL );
480 
481 	Debug( LDAP_DEBUG_TRACE, "slap_passwd_return: %ld\n",
482 		(long) cred->bv_len, 0, 0 );
483 
484 	ber_init_w_nullc( ber, LBER_USE_DER );
485 
486 	rc = ber_printf( ber, "{tON}",
487 		LDAP_TAG_EXOP_MODIFY_PASSWD_GEN, cred );
488 
489 	if( rc >= 0 ) {
490 		(void) ber_flatten( ber, &bv );
491 	}
492 
493 	ber_free_buf( ber );
494 
495 	return bv;
496 }
497 
498 /*
499  * if "e" is provided, access to each value of the password is checked first
500  */
501 int
502 slap_passwd_check(
503 	Operation	*op,
504 	Entry		*e,
505 	Attribute	*a,
506 	struct berval	*cred,
507 	const char	**text )
508 {
509 	int			result = 1;
510 	struct berval		*bv;
511 	AccessControlState	acl_state = ACL_STATE_INIT;
512 	char		credNul = cred->bv_val[cred->bv_len];
513 
514 #ifdef SLAPD_SPASSWD
515 	void		*old_authctx = NULL;
516 
517 	ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)slap_sasl_bind,
518 		op->o_conn->c_sasl_authctx, 0, &old_authctx, NULL );
519 #endif
520 
521 	if ( credNul ) cred->bv_val[cred->bv_len] = 0;
522 
523 	for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
524 		/* if e is provided, check access */
525 		if ( e && access_allowed( op, e, a->a_desc, bv,
526 					ACL_AUTH, &acl_state ) == 0 )
527 		{
528 			continue;
529 		}
530 
531 		if ( !lutil_passwd( bv, cred, NULL, text ) ) {
532 			result = 0;
533 			break;
534 		}
535 	}
536 
537 	if ( credNul ) cred->bv_val[cred->bv_len] = credNul;
538 
539 #ifdef SLAPD_SPASSWD
540 	ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)slap_sasl_bind,
541 		old_authctx, 0, NULL, NULL );
542 #endif
543 
544 	return result;
545 }
546 
547 void
548 slap_passwd_generate( struct berval *pass )
549 {
550 	Debug( LDAP_DEBUG_TRACE, "slap_passwd_generate\n", 0, 0, 0 );
551 	BER_BVZERO( pass );
552 
553 	/*
554 	 * generate passwords of only 8 characters as some getpass(3)
555 	 * implementations truncate at 8 characters.
556 	 */
557 	lutil_passwd_generate( pass, 8 );
558 }
559 
560 void
561 slap_passwd_hash_type(
562 	struct berval * cred,
563 	struct berval * new,
564 	char *hash,
565 	const char **text )
566 {
567 	new->bv_len = 0;
568 	new->bv_val = NULL;
569 
570 	assert( hash != NULL );
571 
572 	lutil_passwd_hash( cred , hash, new, text );
573 }
574 void
575 slap_passwd_hash(
576 	struct berval * cred,
577 	struct berval * new,
578 	const char **text )
579 {
580 	char *hash = NULL;
581 	if ( default_passwd_hash ) {
582 		hash = default_passwd_hash[0];
583 	}
584 	if ( !hash ) {
585 		hash = (char *)defhash[0];
586 	}
587 
588 	slap_passwd_hash_type( cred, new, hash, text );
589 }
590 
591 #ifdef SLAPD_CRYPT
592 static ldap_pvt_thread_mutex_t passwd_mutex;
593 static lutil_cryptfunc slapd_crypt;
594 
595 static int slapd_crypt( const char *key, const char *salt, char **hash )
596 {
597 	char *cr;
598 	int rc;
599 
600 	ldap_pvt_thread_mutex_lock( &passwd_mutex );
601 
602 	cr = crypt( key, salt );
603 	if ( cr == NULL || cr[0] == '\0' ) {
604 		/* salt must have been invalid */
605 		rc = LUTIL_PASSWD_ERR;
606 	} else {
607 		if ( hash ) {
608 			*hash = ber_strdup( cr );
609 			rc = LUTIL_PASSWD_OK;
610 
611 		} else {
612 			rc = strcmp( salt, cr ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
613 		}
614 	}
615 
616 	ldap_pvt_thread_mutex_unlock( &passwd_mutex );
617 	return rc;
618 }
619 #endif /* SLAPD_CRYPT */
620 
621 void slap_passwd_init()
622 {
623 #ifdef SLAPD_CRYPT
624 	ldap_pvt_thread_mutex_init( &passwd_mutex );
625 	lutil_cryptptr = slapd_crypt;
626 #endif
627 }
628 
629