xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/sasl.c (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1 /*	$NetBSD: sasl.c,v 1.1.1.7 2019/08/08 13:31:37 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2019 The OpenLDAP Foundation.
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 
18 #include <sys/cdefs.h>
19 __RCSID("$NetBSD: sasl.c,v 1.1.1.7 2019/08/08 13:31:37 christos Exp $");
20 
21 #include "portable.h"
22 
23 #include <stdio.h>
24 #ifdef HAVE_LIMITS_H
25 #include <limits.h>
26 #endif
27 
28 #include <ac/stdlib.h>
29 #include <ac/string.h>
30 
31 #include <lber.h>
32 #include <ldap_log.h>
33 
34 #include "slap.h"
35 
36 #ifdef ENABLE_REWRITE
37 #include <rewrite.h>
38 #endif
39 
40 #ifdef HAVE_CYRUS_SASL
41 # ifdef HAVE_SASL_SASL_H
42 #  include <sasl/sasl.h>
43 #  include <sasl/saslplug.h>
44 # else
45 #  include <sasl.h>
46 #  include <saslplug.h>
47 # endif
48 
49 # define	SASL_CONST const
50 
51 #define SASL_VERSION_FULL	((SASL_VERSION_MAJOR << 16) |\
52 	(SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP)
53 
54 #if SASL_VERSION_MINOR >= 0x020119 /* 2.1.25 */
55 typedef sasl_callback_ft slap_sasl_cb_ft;
56 #else
57 typedef int (*slap_sasl_cb_ft)();
58 #endif
59 
60 static sasl_security_properties_t sasl_secprops;
61 #elif defined( SLAP_BUILTIN_SASL )
62 /*
63  * built-in SASL implementation
64  *	only supports EXTERNAL
65  */
66 typedef struct sasl_ctx {
67 	slap_ssf_t sc_external_ssf;
68 	struct berval sc_external_id;
69 } SASL_CTX;
70 
71 #endif
72 
73 #include <lutil.h>
74 
75 static struct berval ext_bv = BER_BVC( "EXTERNAL" );
76 
77 char *slap_sasl_auxprops;
78 
79 #ifdef HAVE_CYRUS_SASL
80 
81 /* Just use our internal auxprop by default */
82 static int
83 slap_sasl_getopt(
84 	void *context,
85 	const char *plugin_name,
86 	const char *option,
87 	const char **result,
88 	unsigned *len)
89 {
90 	if ( strcmp( option, "auxprop_plugin" )) {
91 		return SASL_FAIL;
92 	}
93 	if ( slap_sasl_auxprops )
94 		*result = slap_sasl_auxprops;
95 	else
96 		*result = "slapd";
97 	return SASL_OK;
98 }
99 
100 int
101 slap_sasl_log(
102 	void *context,
103 	int priority,
104 	const char *message)
105 {
106 	Connection *conn = context;
107 	int level;
108 	const char * label;
109 
110 	if ( message == NULL ) {
111 		return SASL_BADPARAM;
112 	}
113 
114 	switch (priority) {
115 	case SASL_LOG_NONE:
116 		level = LDAP_DEBUG_NONE;
117 		label = "None";
118 		break;
119 	case SASL_LOG_ERR:
120 		level = LDAP_DEBUG_ANY;
121 		label = "Error";
122 		break;
123 	case SASL_LOG_FAIL:
124 		level = LDAP_DEBUG_ANY;
125 		label = "Failure";
126 		break;
127 	case SASL_LOG_WARN:
128 		level = LDAP_DEBUG_TRACE;
129 		label = "Warning";
130 		break;
131 	case SASL_LOG_NOTE:
132 		level = LDAP_DEBUG_TRACE;
133 		label = "Notice";
134 		break;
135 	case SASL_LOG_DEBUG:
136 		level = LDAP_DEBUG_TRACE;
137 		label = "Debug";
138 		break;
139 	case SASL_LOG_TRACE:
140 		level = LDAP_DEBUG_TRACE;
141 		label = "Trace";
142 		break;
143 	case SASL_LOG_PASS:
144 		level = LDAP_DEBUG_TRACE;
145 		label = "Password Trace";
146 		break;
147 	default:
148 		return SASL_BADPARAM;
149 	}
150 
151 	Debug( level, "SASL [conn=%ld] %s: %s\n",
152 		conn ? (long) conn->c_connid: -1L,
153 		label, message );
154 
155 
156 	return SASL_OK;
157 }
158 
159 static const char *slap_propnames[] = {
160 	"*slapConn", "*slapAuthcDNlen", "*slapAuthcDN",
161 	"*slapAuthzDNlen", "*slapAuthzDN", NULL };
162 
163 static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL };
164 static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
165 
166 #define	SLAP_SASL_PROP_CONN	0
167 #define	SLAP_SASL_PROP_AUTHCLEN	1
168 #define	SLAP_SASL_PROP_AUTHC	2
169 #define	SLAP_SASL_PROP_AUTHZLEN	3
170 #define	SLAP_SASL_PROP_AUTHZ	4
171 #define	SLAP_SASL_PROP_COUNT	5	/* Number of properties we used */
172 
173 typedef struct lookup_info {
174 	int flags;
175 	const struct propval *list;
176 	sasl_server_params_t *sparams;
177 } lookup_info;
178 
179 static slap_response sasl_ap_lookup;
180 
181 static struct berval sc_cleartext = BER_BVC("{CLEARTEXT}");
182 
183 static int
184 sasl_ap_lookup( Operation *op, SlapReply *rs )
185 {
186 	BerVarray bv;
187 	AttributeDescription *ad;
188 	Attribute *a;
189 	const char *text;
190 	int rc, i;
191 	lookup_info *sl = (lookup_info *)op->o_callback->sc_private;
192 
193 	if (rs->sr_type != REP_SEARCH) return 0;
194 
195 	for( i = 0; sl->list[i].name; i++ ) {
196 		const char *name = sl->list[i].name;
197 
198 		if ( name[0] == '*' ) {
199 			if ( sl->flags & SASL_AUXPROP_AUTHZID ) continue;
200 			/* Skip our private properties */
201 			if ( !strcmp( name, slap_propnames[0] )) {
202 				i += SLAP_SASL_PROP_COUNT - 1;
203 				continue;
204 			}
205 			name++;
206 		} else if ( !(sl->flags & SASL_AUXPROP_AUTHZID ) )
207 			continue;
208 
209 		if ( sl->list[i].values ) {
210 			if ( !(sl->flags & SASL_AUXPROP_OVERRIDE) ) continue;
211 		}
212 		ad = NULL;
213 		rc = slap_str2ad( name, &ad, &text );
214 		if ( rc != LDAP_SUCCESS ) {
215 			Debug( LDAP_DEBUG_TRACE,
216 				"slap_ap_lookup: str2ad(%s): %s\n", name, text, 0 );
217 			continue;
218 		}
219 
220 		/* If it's the rootdn and a rootpw was present, we already set
221 		 * it so don't override it here.
222 		 */
223 		if ( ad == slap_schema.si_ad_userPassword && sl->list[i].values &&
224 			be_isroot_dn( op->o_bd, &op->o_req_ndn ))
225 			continue;
226 
227 		a = attr_find( rs->sr_entry->e_attrs, ad );
228 		if ( !a ) continue;
229 		if ( ! access_allowed( op, rs->sr_entry, ad, NULL, ACL_AUTH, NULL ) ) {
230 			continue;
231 		}
232 		if ( sl->list[i].values && ( sl->flags & SASL_AUXPROP_OVERRIDE ) ) {
233 			sl->sparams->utils->prop_erase( sl->sparams->propctx,
234 			sl->list[i].name );
235 		}
236 		for ( bv = a->a_vals; bv->bv_val; bv++ ) {
237 			/* ITS#3846 don't give hashed passwords to SASL */
238 			if ( ad == slap_schema.si_ad_userPassword &&
239 				bv->bv_val[0] == '{' /*}*/ )
240 			{
241 				if ( lutil_passwd_scheme( bv->bv_val ) ) {
242 					/* If it's not a recognized scheme, just assume it's
243 					 * a cleartext password that happened to include brackets.
244 					 *
245 					 * If it's a recognized scheme, skip this value, unless the
246 					 * scheme is {CLEARTEXT}. In that case, skip over the
247 					 * scheme name and use the remainder. If there is nothing
248 					 * past the scheme name, skip this value.
249 					 */
250 #ifdef SLAPD_CLEARTEXT
251 					if ( !strncasecmp( bv->bv_val, sc_cleartext.bv_val,
252 						sc_cleartext.bv_len )) {
253 						struct berval cbv;
254 						cbv.bv_len = bv->bv_len - sc_cleartext.bv_len;
255 						if ( cbv.bv_len > 0 ) {
256 							cbv.bv_val = bv->bv_val + sc_cleartext.bv_len;
257 							sl->sparams->utils->prop_set( sl->sparams->propctx,
258 								sl->list[i].name, cbv.bv_val, cbv.bv_len );
259 						}
260 					}
261 #endif
262 					continue;
263 				}
264 			}
265 			sl->sparams->utils->prop_set( sl->sparams->propctx,
266 				sl->list[i].name, bv->bv_val, bv->bv_len );
267 		}
268 	}
269 	return LDAP_SUCCESS;
270 }
271 
272 #if SASL_VERSION_FULL >= 0x020118
273 static int
274 #else
275 static void
276 #endif
277 slap_auxprop_lookup(
278 	void *glob_context,
279 	sasl_server_params_t *sparams,
280 	unsigned flags,
281 	const char *user,
282 	unsigned ulen)
283 {
284 	OperationBuffer opbuf = {{ NULL }};
285 	Operation *op = (Operation *)&opbuf;
286 	int i, doit = 0;
287 	Connection *conn = NULL;
288 	lookup_info sl;
289 	int rc = LDAP_SUCCESS;
290 
291 	sl.list = sparams->utils->prop_get( sparams->propctx );
292 	sl.sparams = sparams;
293 	sl.flags = flags;
294 
295 	/* Find our DN and conn first */
296 	for( i = 0; sl.list[i].name; i++ ) {
297 		if ( sl.list[i].name[0] == '*' ) {
298 			if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) {
299 				if ( sl.list[i].values && sl.list[i].values[0] )
300 					AC_MEMCPY( &conn, sl.list[i].values[0], sizeof( conn ) );
301 				continue;
302 			}
303 			if ( flags & SASL_AUXPROP_AUTHZID ) {
304 				if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZLEN] )) {
305 					if ( sl.list[i].values && sl.list[i].values[0] )
306 						AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0],
307 							sizeof( op->o_req_ndn.bv_len ) );
308 				} else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZ] )) {
309 					if ( sl.list[i].values )
310 						op->o_req_ndn.bv_val = (char *)sl.list[i].values[0];
311 					break;
312 				}
313 			}
314 
315 			if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) {
316 				if ( sl.list[i].values && sl.list[i].values[0] )
317 					AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0],
318 						sizeof( op->o_req_ndn.bv_len ) );
319 			} else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) {
320 				if ( sl.list[i].values ) {
321 					op->o_req_ndn.bv_val = (char *)sl.list[i].values[0];
322 					if ( !(flags & SASL_AUXPROP_AUTHZID) )
323 						break;
324 				}
325 			}
326 		}
327 	}
328 
329 	/* we don't know anything about this, ignore it */
330 	if ( !conn ) {
331 		rc = LDAP_SUCCESS;
332 		goto done;
333 	}
334 
335 	/* Now see what else needs to be fetched */
336 	for( i = 0; sl.list[i].name; i++ ) {
337 		const char *name = sl.list[i].name;
338 
339 		if ( name[0] == '*' ) {
340 			if ( flags & SASL_AUXPROP_AUTHZID ) continue;
341 			/* Skip our private properties */
342 			if ( !strcmp( name, slap_propnames[0] )) {
343 				i += SLAP_SASL_PROP_COUNT - 1;
344 				continue;
345 			}
346 			name++;
347 		} else if ( !(flags & SASL_AUXPROP_AUTHZID ) )
348 			continue;
349 
350 		if ( sl.list[i].values ) {
351 			if ( !(flags & SASL_AUXPROP_OVERRIDE) ) continue;
352 		}
353 		doit = 1;
354 		break;
355 	}
356 
357 	if (doit) {
358 		slap_callback cb = { NULL, sasl_ap_lookup, NULL, NULL };
359 
360 		cb.sc_private = &sl;
361 
362 		op->o_bd = select_backend( &op->o_req_ndn, 1 );
363 
364 		if ( op->o_bd ) {
365 			/* For rootdn, see if we can use the rootpw */
366 			if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) &&
367 				!BER_BVISEMPTY( &op->o_bd->be_rootpw )) {
368 				struct berval cbv = BER_BVNULL;
369 
370 				/* If there's a recognized scheme, see if it's CLEARTEXT */
371 				if ( lutil_passwd_scheme( op->o_bd->be_rootpw.bv_val )) {
372 					if ( !strncasecmp( op->o_bd->be_rootpw.bv_val,
373 						sc_cleartext.bv_val, sc_cleartext.bv_len )) {
374 
375 						/* If it's CLEARTEXT, skip past scheme spec */
376 						cbv.bv_len = op->o_bd->be_rootpw.bv_len -
377 							sc_cleartext.bv_len;
378 						if ( cbv.bv_len ) {
379 							cbv.bv_val = op->o_bd->be_rootpw.bv_val +
380 								sc_cleartext.bv_len;
381 						}
382 					}
383 				/* No scheme, use the whole value */
384 				} else {
385 					cbv = op->o_bd->be_rootpw;
386 				}
387 				if ( !BER_BVISEMPTY( &cbv )) {
388 					for( i = 0; sl.list[i].name; i++ ) {
389 						const char *name = sl.list[i].name;
390 
391 						if ( name[0] == '*' ) {
392 							if ( flags & SASL_AUXPROP_AUTHZID ) continue;
393 								name++;
394 						} else if ( !(flags & SASL_AUXPROP_AUTHZID ) )
395 							continue;
396 
397 						if ( !strcasecmp(name,"userPassword") ) {
398 							sl.sparams->utils->prop_set( sl.sparams->propctx,
399 								sl.list[i].name, cbv.bv_val, cbv.bv_len );
400 							break;
401 						}
402 					}
403 				}
404 			}
405 
406 			if ( op->o_bd->be_search ) {
407 				SlapReply rs = {REP_RESULT};
408 				op->o_hdr = conn->c_sasl_bindop->o_hdr;
409 				op->o_controls = opbuf.ob_controls;
410 				op->o_tag = LDAP_REQ_SEARCH;
411 				op->o_dn = conn->c_ndn;
412 				op->o_ndn = conn->c_ndn;
413 				op->o_callback = &cb;
414 				slap_op_time( &op->o_time, &op->o_tincr );
415 				op->o_do_not_cache = 1;
416 				op->o_is_auth_check = 1;
417 				op->o_req_dn = op->o_req_ndn;
418 				op->ors_scope = LDAP_SCOPE_BASE;
419 				op->ors_deref = LDAP_DEREF_NEVER;
420 				op->ors_tlimit = SLAP_NO_LIMIT;
421 				op->ors_slimit = 1;
422 				op->ors_filter = &generic_filter;
423 				op->ors_filterstr = generic_filterstr;
424 				op->o_authz = conn->c_authz;
425 				/* FIXME: we want all attributes, right? */
426 				op->ors_attrs = NULL;
427 
428 				rc = op->o_bd->be_search( op, &rs );
429 			}
430 		}
431 	}
432 done:;
433 #if SASL_VERSION_FULL >= 0x020118
434 	return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK;
435 #endif
436 }
437 
438 #if SASL_VERSION_FULL >= 0x020110
439 static int
440 slap_auxprop_store(
441 	void *glob_context,
442 	sasl_server_params_t *sparams,
443 	struct propctx *prctx,
444 	const char *user,
445 	unsigned ulen)
446 {
447 	Operation op = {0};
448 	Opheader oph;
449 	SlapReply rs = {REP_RESULT};
450 	int rc, i;
451 	unsigned j;
452 	Connection *conn = NULL;
453 	const struct propval *pr;
454 	Modifications *modlist = NULL, **modtail = &modlist, *mod;
455 	slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
456 	char textbuf[SLAP_TEXT_BUFLEN];
457 	const char *text;
458 	size_t textlen = sizeof(textbuf);
459 
460 	/* just checking if we are enabled */
461 	if (!prctx) return SASL_OK;
462 
463 	if (!sparams || !user) return SASL_BADPARAM;
464 
465 	pr = sparams->utils->prop_get( sparams->propctx );
466 
467 	/* Find our DN and conn first */
468 	for( i = 0; pr[i].name; i++ ) {
469 		if ( pr[i].name[0] == '*' ) {
470 			if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) {
471 				if ( pr[i].values && pr[i].values[0] )
472 					AC_MEMCPY( &conn, pr[i].values[0], sizeof( conn ) );
473 				continue;
474 			}
475 			if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) {
476 				if ( pr[i].values && pr[i].values[0] )
477 					AC_MEMCPY( &op.o_req_ndn.bv_len, pr[i].values[0],
478 						sizeof( op.o_req_ndn.bv_len ) );
479 			} else if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) {
480 				if ( pr[i].values )
481 					op.o_req_ndn.bv_val = (char *)pr[i].values[0];
482 			}
483 		}
484 	}
485 	if (!conn || !op.o_req_ndn.bv_val) return SASL_BADPARAM;
486 
487 	op.o_bd = select_backend( &op.o_req_ndn, 1 );
488 
489 	if ( !op.o_bd || !op.o_bd->be_modify ) return SASL_FAIL;
490 
491 	pr = sparams->utils->prop_get( prctx );
492 	if (!pr) return SASL_BADPARAM;
493 
494 	for (i=0; pr[i].name; i++);
495 	if (!i) return SASL_BADPARAM;
496 
497 	for (i=0; pr[i].name; i++) {
498 		mod = (Modifications *)ch_malloc( sizeof(Modifications) );
499 		mod->sml_op = LDAP_MOD_REPLACE;
500 		mod->sml_flags = 0;
501 		ber_str2bv( pr[i].name, 0, 0, &mod->sml_type );
502 		mod->sml_numvals = pr[i].nvalues;
503 		mod->sml_values = (struct berval *)ch_malloc( (pr[i].nvalues + 1) *
504 			sizeof(struct berval));
505 		for (j=0; j<pr[i].nvalues; j++) {
506 			ber_str2bv( pr[i].values[j], 0, 1, &mod->sml_values[j]);
507 		}
508 		BER_BVZERO( &mod->sml_values[j] );
509 		mod->sml_nvalues = NULL;
510 		mod->sml_desc = NULL;
511 		*modtail = mod;
512 		modtail = &mod->sml_next;
513 	}
514 	*modtail = NULL;
515 
516 	rc = slap_mods_check( &op, modlist, &text, textbuf, textlen, NULL );
517 
518 	if ( rc == LDAP_SUCCESS ) {
519 		rc = slap_mods_no_user_mod_check( &op, modlist,
520 			&text, textbuf, textlen );
521 
522 		if ( rc == LDAP_SUCCESS ) {
523 			if ( conn->c_sasl_bindop ) {
524 				op.o_hdr = conn->c_sasl_bindop->o_hdr;
525 			} else {
526 				op.o_hdr = &oph;
527 				memset( &oph, 0, sizeof(oph) );
528 				operation_fake_init( conn, &op, ldap_pvt_thread_pool_context(), 0 );
529 			}
530 			op.o_tag = LDAP_REQ_MODIFY;
531 			op.o_ndn = op.o_req_ndn;
532 			op.o_callback = &cb;
533 			slap_op_time( &op.o_time, &op.o_tincr );
534 			op.o_do_not_cache = 1;
535 			op.o_is_auth_check = 1;
536 			op.o_req_dn = op.o_req_ndn;
537 			op.orm_modlist = modlist;
538 
539 			rc = op.o_bd->be_modify( &op, &rs );
540 		}
541 	}
542 	slap_mods_free( modlist, 1 );
543 	return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK;
544 }
545 #endif /* SASL_VERSION_FULL >= 2.1.16 */
546 
547 static sasl_auxprop_plug_t slap_auxprop_plugin = {
548 	0,	/* Features */
549 	0,	/* spare */
550 	NULL,	/* glob_context */
551 	NULL,	/* auxprop_free */
552 	slap_auxprop_lookup,
553 	"slapd",	/* name */
554 #if SASL_VERSION_FULL >= 0x020110
555 	slap_auxprop_store	/* the declaration of this member changed
556 				 * in cyrus SASL from 2.1.15 to 2.1.16 */
557 #else
558 	NULL
559 #endif
560 };
561 
562 static int
563 slap_auxprop_init(
564 	const sasl_utils_t *utils,
565 	int max_version,
566 	int *out_version,
567 	sasl_auxprop_plug_t **plug,
568 	const char *plugname)
569 {
570 	if ( !out_version || !plug ) return SASL_BADPARAM;
571 
572 	if ( max_version < SASL_AUXPROP_PLUG_VERSION ) return SASL_BADVERS;
573 
574 	*out_version = SASL_AUXPROP_PLUG_VERSION;
575 	*plug = &slap_auxprop_plugin;
576 	return SASL_OK;
577 }
578 
579 /* Convert a SASL authcid or authzid into a DN. Store the DN in an
580  * auxiliary property, so that we can refer to it in sasl_authorize
581  * without interfering with anything else. Also, the SASL username
582  * buffer is constrained to 256 characters, and our DNs could be
583  * much longer (SLAP_LDAPDN_MAXLEN, currently set to 8192)
584  */
585 static int
586 slap_sasl_canonicalize(
587 	sasl_conn_t *sconn,
588 	void *context,
589 	const char *in,
590 	unsigned inlen,
591 	unsigned flags,
592 	const char *user_realm,
593 	char *out,
594 	unsigned out_max,
595 	unsigned *out_len)
596 {
597 	Connection *conn = (Connection *)context;
598 	struct propctx *props = sasl_auxprop_getctx( sconn );
599 	struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } };
600 	struct berval dn;
601 	int rc, which;
602 	const char *names[2];
603 	struct berval	bvin;
604 
605 	*out_len = 0;
606 
607 	Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n",
608 		conn ? (long) conn->c_connid : -1L,
609 		(flags & SASL_CU_AUTHID) ? "authcid" : "authzid",
610 		in ? in : "<empty>");
611 
612 	/* If name is too big, just truncate. We don't care, we're
613 	 * using DNs, not the usernames.
614 	 */
615 	if ( inlen > out_max )
616 		inlen = out_max-1;
617 
618 	/* This is a Simple Bind using SPASSWD. That means the in-directory
619 	 * userPassword of the Binding user already points at SASL, so it
620 	 * cannot be used to actually satisfy a password comparison. Just
621 	 * ignore it, some other mech will process it.
622 	 */
623 	if ( !conn->c_sasl_bindop ||
624 		conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) goto done;
625 
626 	/* See if we need to add request, can only do it once */
627 	prop_getnames( props, slap_propnames, auxvals );
628 	if ( !auxvals[0].name )
629 		prop_request( props, slap_propnames );
630 
631 	if ( flags & SASL_CU_AUTHID )
632 		which = SLAP_SASL_PROP_AUTHCLEN;
633 	else
634 		which = SLAP_SASL_PROP_AUTHZLEN;
635 
636 	/* Need to store the Connection for auxprop_lookup */
637 	if ( !auxvals[SLAP_SASL_PROP_CONN].values ) {
638 		names[0] = slap_propnames[SLAP_SASL_PROP_CONN];
639 		names[1] = NULL;
640 		prop_set( props, names[0], (char *)&conn, sizeof( conn ) );
641 	}
642 
643 	/* Already been here? */
644 	if ( auxvals[which].values )
645 		goto done;
646 
647 	/* Normally we require an authzID to have a u: or dn: prefix.
648 	 * However, SASL frequently gives us an authzID that is just
649 	 * an exact copy of the authcID, without a prefix. We need to
650 	 * detect and allow this condition. If SASL calls canonicalize
651 	 * with SASL_CU_AUTHID|SASL_CU_AUTHZID this is a no-brainer.
652 	 * But if it's broken into two calls, we need to remember the
653 	 * authcID so that we can compare the authzID later. We store
654 	 * the authcID temporarily in conn->c_sasl_dn. We necessarily
655 	 * finish Canonicalizing before Authorizing, so there is no
656 	 * conflict with slap_sasl_authorize's use of this temp var.
657 	 *
658 	 * The SASL EXTERNAL mech is backwards from all the other mechs,
659 	 * it does authzID before the authcID. If we see that authzID
660 	 * has already been done, don't do anything special with authcID.
661 	 */
662 	if ( flags == SASL_CU_AUTHID && !auxvals[SLAP_SASL_PROP_AUTHZ].values ) {
663 		conn->c_sasl_dn.bv_val = (char *) in;
664 		conn->c_sasl_dn.bv_len = 0;
665 	} else if ( flags == SASL_CU_AUTHZID && conn->c_sasl_dn.bv_val ) {
666 		rc = strcmp( in, conn->c_sasl_dn.bv_val );
667 		conn->c_sasl_dn.bv_val = NULL;
668 		/* They were equal, no work needed */
669 		if ( !rc ) goto done;
670 	}
671 
672 	bvin.bv_val = (char *)in;
673 	bvin.bv_len = inlen;
674 	rc = slap_sasl_getdn( conn, NULL, &bvin, (char *)user_realm, &dn,
675 		(flags & SASL_CU_AUTHID) ? SLAP_GETDN_AUTHCID : SLAP_GETDN_AUTHZID );
676 	if ( rc != LDAP_SUCCESS ) {
677 		sasl_seterror( sconn, 0, ldap_err2string( rc ) );
678 		return SASL_NOAUTHZ;
679 	}
680 
681 	names[0] = slap_propnames[which];
682 	names[1] = NULL;
683 	prop_set( props, names[0], (char *)&dn.bv_len, sizeof( dn.bv_len ) );
684 
685 	which++;
686 	names[0] = slap_propnames[which];
687 	prop_set( props, names[0], dn.bv_val, dn.bv_len );
688 
689 	Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n",
690 		conn ? (long) conn->c_connid : -1L, names[0]+1,
691 		dn.bv_val ? dn.bv_val : "<EMPTY>" );
692 
693 	/* Not needed any more, SASL has copied it */
694 	if ( conn && conn->c_sasl_bindop )
695 		conn->c_sasl_bindop->o_tmpfree( dn.bv_val, conn->c_sasl_bindop->o_tmpmemctx );
696 
697 done:
698 	AC_MEMCPY( out, in, inlen );
699 	out[inlen] = '\0';
700 
701 	*out_len = inlen;
702 
703 	return SASL_OK;
704 }
705 
706 static int
707 slap_sasl_authorize(
708 	sasl_conn_t *sconn,
709 	void *context,
710 	char *requested_user,
711 	unsigned rlen,
712 	char *auth_identity,
713 	unsigned alen,
714 	const char *def_realm,
715 	unsigned urlen,
716 	struct propctx *props)
717 {
718 	Connection *conn = (Connection *)context;
719 	/* actually:
720 	 *	(SLAP_SASL_PROP_COUNT - 1)	because we skip "conn",
721 	 *	+ 1				for NULL termination?
722 	 */
723 	struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } };
724 	struct berval authcDN, authzDN = BER_BVNULL;
725 	int rc;
726 
727 	/* Simple Binds don't support proxy authorization, ignore it */
728 	if ( !conn->c_sasl_bindop ||
729 		conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) return SASL_OK;
730 
731 	Debug( LDAP_DEBUG_ARGS, "SASL proxy authorize [conn=%ld]: "
732 		"authcid=\"%s\" authzid=\"%s\"\n",
733 		conn ? (long) conn->c_connid : -1L, auth_identity, requested_user );
734 	if ( conn->c_sasl_dn.bv_val ) {
735 		BER_BVZERO( &conn->c_sasl_dn );
736 	}
737 
738 	/* Skip SLAP_SASL_PROP_CONN */
739 	prop_getnames( props, slap_propnames+1, auxvals );
740 
741 	/* Should not happen */
742 	if ( !auxvals[0].values ) {
743 		sasl_seterror( sconn, 0, "invalid authcid" );
744 		return SASL_NOAUTHZ;
745 	}
746 
747 	AC_MEMCPY( &authcDN.bv_len, auxvals[0].values[0], sizeof(authcDN.bv_len) );
748 	authcDN.bv_val = auxvals[1].values ? (char *)auxvals[1].values[0] : NULL;
749 	conn->c_sasl_dn = authcDN;
750 
751 	/* Nothing to do if no authzID was given */
752 	if ( !auxvals[2].name || !auxvals[2].values ) {
753 		goto ok;
754 	}
755 
756 	AC_MEMCPY( &authzDN.bv_len, auxvals[2].values[0], sizeof(authzDN.bv_len) );
757 	authzDN.bv_val = auxvals[3].values ? (char *)auxvals[3].values[0] : NULL;
758 
759 	rc = slap_sasl_authorized( conn->c_sasl_bindop, &authcDN, &authzDN );
760 	if ( rc != LDAP_SUCCESS ) {
761 		Debug( LDAP_DEBUG_TRACE, "SASL Proxy Authorize [conn=%ld]: "
762 			"proxy authorization disallowed (%d)\n",
763 			conn ? (long) conn->c_connid : -1L, rc, 0 );
764 
765 		sasl_seterror( sconn, 0, "not authorized" );
766 		return SASL_NOAUTHZ;
767 	}
768 
769 	/* FIXME: we need yet another dup because slap_sasl_getdn()
770 	 * is using the bind operation slab */
771 	ber_dupbv( &conn->c_sasl_authz_dn, &authzDN );
772 
773 ok:
774 	if (conn->c_sasl_bindop) {
775 		Statslog( LDAP_DEBUG_STATS,
776 			"%s BIND authcid=\"%s\" authzid=\"%s\"\n",
777 			conn->c_sasl_bindop->o_log_prefix,
778 			auth_identity, requested_user, 0, 0 );
779 	}
780 
781 	Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
782 		" proxy authorization allowed authzDN=\"%s\"\n",
783 		conn ? (long) conn->c_connid : -1L,
784 		authzDN.bv_val ? authzDN.bv_val : "", 0 );
785 	return SASL_OK;
786 }
787 
788 static int
789 slap_sasl_err2ldap( int saslerr )
790 {
791 	int rc;
792 
793 	/* map SASL errors to LDAP resultCode returned by:
794 	 *	sasl_server_new()
795 	 *		SASL_OK, SASL_NOMEM
796 	 *	sasl_server_step()
797 	 *		SASL_OK, SASL_CONTINUE, SASL_TRANS, SASL_BADPARAM, SASL_BADPROT,
798 	 *      ...
799 	 *	sasl_server_start()
800 	 *      + SASL_NOMECH
801 	 *	sasl_setprop()
802 	 *		SASL_OK, SASL_BADPARAM
803 	 */
804 
805 	switch (saslerr) {
806 		case SASL_OK:
807 			rc = LDAP_SUCCESS;
808 			break;
809 		case SASL_CONTINUE:
810 			rc = LDAP_SASL_BIND_IN_PROGRESS;
811 			break;
812 		case SASL_FAIL:
813 		case SASL_NOMEM:
814 			rc = LDAP_OTHER;
815 			break;
816 		case SASL_NOMECH:
817 			rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
818 			break;
819 		case SASL_BADAUTH:
820 		case SASL_NOUSER:
821 		case SASL_TRANS:
822 		case SASL_EXPIRED:
823 			rc = LDAP_INVALID_CREDENTIALS;
824 			break;
825 		case SASL_NOAUTHZ:
826 			rc = LDAP_INSUFFICIENT_ACCESS;
827 			break;
828 		case SASL_TOOWEAK:
829 		case SASL_ENCRYPT:
830 			rc = LDAP_INAPPROPRIATE_AUTH;
831 			break;
832 		case SASL_UNAVAIL:
833 		case SASL_TRYAGAIN:
834 			rc = LDAP_UNAVAILABLE;
835 			break;
836 		case SASL_DISABLED:
837 			rc = LDAP_UNWILLING_TO_PERFORM;
838 			break;
839 		default:
840 			rc = LDAP_OTHER;
841 			break;
842 	}
843 
844 	return rc;
845 }
846 
847 #ifdef SLAPD_SPASSWD
848 
849 static struct berval sasl_pwscheme = BER_BVC("{SASL}");
850 
851 static int chk_sasl(
852 	const struct berval *sc,
853 	const struct berval * passwd,
854 	const struct berval * cred,
855 	const char **text )
856 {
857 	unsigned int i;
858 	int rtn;
859 	void *ctx, *sconn = NULL;
860 
861 	for( i=0; i<cred->bv_len; i++) {
862 		if(cred->bv_val[i] == '\0') {
863 			return LUTIL_PASSWD_ERR;	/* NUL character in password */
864 		}
865 	}
866 
867 	if( cred->bv_val[i] != '\0' ) {
868 		return LUTIL_PASSWD_ERR;	/* cred must behave like a string */
869 	}
870 
871 	for( i=0; i<passwd->bv_len; i++) {
872 		if(passwd->bv_val[i] == '\0') {
873 			return LUTIL_PASSWD_ERR;	/* NUL character in password */
874 		}
875 	}
876 
877 	if( passwd->bv_val[i] != '\0' ) {
878 		return LUTIL_PASSWD_ERR;	/* passwd must behave like a string */
879 	}
880 
881 	rtn = LUTIL_PASSWD_ERR;
882 
883 	ctx = ldap_pvt_thread_pool_context();
884 	ldap_pvt_thread_pool_getkey( ctx, (void *)slap_sasl_bind, &sconn, NULL );
885 
886 	if( sconn != NULL ) {
887 		int sc;
888 		sc = sasl_checkpass( sconn,
889 			passwd->bv_val, passwd->bv_len,
890 			cred->bv_val, cred->bv_len );
891 		rtn = ( sc != SASL_OK ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
892 	}
893 
894 	return rtn;
895 }
896 #endif /* SLAPD_SPASSWD */
897 
898 #endif /* HAVE_CYRUS_SASL */
899 
900 #ifdef ENABLE_REWRITE
901 
902 typedef struct slapd_map_data {
903 	struct berval base;
904 	struct berval filter;
905 	AttributeName attrs[2];
906 	int scope;
907 } slapd_map_data;
908 
909 static void *
910 slapd_rw_config( const char *fname, int lineno, int argc, char **argv )
911 {
912 	slapd_map_data *ret = NULL;
913 	LDAPURLDesc *lud = NULL;
914 	char *uri;
915 	AttributeDescription *ad = NULL;
916 	int rc, flen = 0;
917 	struct berval dn, ndn;
918 
919 	if ( argc != 1 ) {
920 		Debug( LDAP_DEBUG_ANY,
921 			"[%s:%d] slapd map needs URI\n",
922 			fname, lineno, 0 );
923         return NULL;
924 	}
925 
926 	uri = argv[0];
927 	if ( strncasecmp( uri, "uri=", STRLENOF( "uri=" ) ) == 0 ) {
928 		uri += STRLENOF( "uri=" );
929 	}
930 
931 	if ( ldap_url_parse( uri, &lud ) != LDAP_URL_SUCCESS ) {
932 		Debug( LDAP_DEBUG_ANY,
933 			"[%s:%d] illegal URI '%s'\n",
934 			fname, lineno, uri );
935         return NULL;
936 	}
937 
938 	if ( strcasecmp( lud->lud_scheme, "ldap" )) {
939 		Debug( LDAP_DEBUG_ANY,
940 			"[%s:%d] illegal URI scheme '%s'\n",
941 			fname, lineno, lud->lud_scheme );
942 		goto done;
943 	}
944 
945 	if (( lud->lud_host && lud->lud_host[0] ) || lud->lud_exts
946 		|| !lud->lud_dn ) {
947 		Debug( LDAP_DEBUG_ANY,
948 			"[%s:%d] illegal URI '%s'\n",
949 			fname, lineno, uri );
950 		goto done;
951 	}
952 
953 	if ( lud->lud_attrs ) {
954 		if ( lud->lud_attrs[1] ) {
955 			Debug( LDAP_DEBUG_ANY,
956 				"[%s:%d] only one attribute allowed in URI\n",
957 				fname, lineno, 0 );
958 			goto done;
959 		}
960 		if ( strcasecmp( lud->lud_attrs[0], "dn" ) &&
961 			strcasecmp( lud->lud_attrs[0], "entryDN" )) {
962 			const char *text;
963 			rc = slap_str2ad( lud->lud_attrs[0], &ad, &text );
964 			if ( rc )
965 				goto done;
966 		}
967 	}
968 	ber_str2bv( lud->lud_dn, 0, 0, &dn );
969 	if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ))
970 		goto done;
971 
972 	if ( lud->lud_filter ) {
973 		flen = strlen( lud->lud_filter ) + 1;
974 	}
975 	ret = ch_malloc( sizeof( slapd_map_data ) + flen );
976 	ret->base = ndn;
977 	if ( flen ) {
978 		ret->filter.bv_val = (char *)(ret+1);
979 		ret->filter.bv_len = flen - 1;
980 		strcpy( ret->filter.bv_val, lud->lud_filter );
981 	} else {
982 		BER_BVZERO( &ret->filter );
983 	}
984 	ret->scope = lud->lud_scope;
985 	if ( ad ) {
986 		ret->attrs[0].an_name = ad->ad_cname;
987 	} else {
988 		BER_BVZERO( &ret->attrs[0].an_name );
989 	}
990 	ret->attrs[0].an_desc = ad;
991 	BER_BVZERO( &ret->attrs[1].an_name );
992 done:
993 	ldap_free_urldesc( lud );
994 	return ret;
995 }
996 
997 struct slapd_rw_info {
998 	slapd_map_data *si_data;
999 	struct berval si_val;
1000 };
1001 
1002 static int
1003 slapd_rw_cb( Operation *op, SlapReply *rs )
1004 {
1005 	if ( rs->sr_type == REP_SEARCH ) {
1006 		struct slapd_rw_info *si = op->o_callback->sc_private;
1007 
1008 		if ( si->si_data->attrs[0].an_desc ) {
1009 			Attribute *a;
1010 
1011 			a = attr_find( rs->sr_entry->e_attrs,
1012 				si->si_data->attrs[0].an_desc );
1013 			if ( a ) {
1014 				ber_dupbv( &si->si_val, a->a_vals );
1015 			}
1016 		} else {
1017 			ber_dupbv( &si->si_val, &rs->sr_entry->e_name );
1018 		}
1019 	}
1020 	return LDAP_SUCCESS;
1021 }
1022 
1023 static int
1024 slapd_rw_apply( void *private, const char *filter, struct berval *val )
1025 {
1026 	slapd_map_data *sl = private;
1027 	slap_callback cb = { NULL };
1028 	Connection conn = {0};
1029 	OperationBuffer opbuf;
1030 	Operation *op;
1031 	void *thrctx;
1032 	SlapReply rs = {REP_RESULT};
1033 	struct slapd_rw_info si;
1034 	char *ptr;
1035 	int rc;
1036 
1037 	thrctx = ldap_pvt_thread_pool_context();
1038 	connection_fake_init2( &conn, &opbuf, thrctx, 0 );
1039 	op = &opbuf.ob_op;
1040 
1041 	op->o_tag = LDAP_REQ_SEARCH;
1042 	op->o_req_dn = op->o_req_ndn = sl->base;
1043 	op->o_bd = select_backend( &op->o_req_ndn, 1 );
1044 	if ( !op->o_bd ) {
1045 		return REWRITE_ERR;
1046 	}
1047 	si.si_data = sl;
1048 	BER_BVZERO( &si.si_val );
1049 	op->ors_scope = sl->scope;
1050 	op->ors_deref = LDAP_DEREF_NEVER;
1051 	op->ors_slimit = 1;
1052 	op->ors_tlimit = SLAP_NO_LIMIT;
1053 	if ( sl->attrs[0].an_desc ) {
1054 		op->ors_attrs = sl->attrs;
1055 	} else {
1056 		op->ors_attrs = slap_anlist_no_attrs;
1057 	}
1058 	if ( filter ) {
1059 		rc = strlen( filter );
1060 	} else {
1061 		rc = 0;
1062 	}
1063 	rc += sl->filter.bv_len;
1064 	ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( rc + 1, op->o_tmpmemctx );
1065 	if ( sl->filter.bv_len ) {
1066 		ptr = lutil_strcopy( ptr, sl->filter.bv_val );
1067 	} else {
1068 		*ptr = '\0';
1069 	}
1070 	if ( filter ) {
1071 		strcpy( ptr, filter );
1072 	}
1073 	op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1074 	if ( !op->ors_filter ) {
1075 		op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1076 		return REWRITE_ERR;
1077 	}
1078 
1079 	op->ors_attrsonly = 0;
1080 	op->o_dn = op->o_bd->be_rootdn;
1081 	op->o_ndn = op->o_bd->be_rootndn;
1082 	op->o_do_not_cache = 1;
1083 
1084 	cb.sc_response = slapd_rw_cb;
1085 	cb.sc_private = &si;
1086 	op->o_callback = &cb;
1087 
1088 	rc = op->o_bd->be_search( op, &rs );
1089 	if ( rc == LDAP_SUCCESS && !BER_BVISNULL( &si.si_val )) {
1090 		*val = si.si_val;
1091 		rc = REWRITE_SUCCESS;
1092 	} else {
1093 		if ( !BER_BVISNULL( &si.si_val )) {
1094 			ch_free( si.si_val.bv_val );
1095 		}
1096 		rc = REWRITE_ERR;
1097 	}
1098 	filter_free_x( op, op->ors_filter, 1 );
1099 	op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1100 	return rc;
1101 }
1102 
1103 static int
1104 slapd_rw_destroy( void *private )
1105 {
1106 	slapd_map_data *md = private;
1107 
1108 	assert( private != NULL );
1109 
1110 	ch_free( md->base.bv_val );
1111 	ch_free( md );
1112 
1113 	return 0;
1114 }
1115 
1116 static const rewrite_mapper slapd_mapper = {
1117 	"slapd",
1118 	slapd_rw_config,
1119 	slapd_rw_apply,
1120 	slapd_rw_destroy
1121 };
1122 #endif
1123 
1124 int slap_sasl_init( void )
1125 {
1126 #ifdef HAVE_CYRUS_SASL
1127 	int rc;
1128 	static sasl_callback_t server_callbacks[] = {
1129 		{ SASL_CB_LOG, (slap_sasl_cb_ft)&slap_sasl_log, NULL },
1130 		{ SASL_CB_GETOPT, (slap_sasl_cb_ft)&slap_sasl_getopt, NULL },
1131 		{ SASL_CB_LIST_END, NULL, NULL }
1132 	};
1133 #endif
1134 
1135 #ifdef ENABLE_REWRITE
1136 	rewrite_mapper_register( &slapd_mapper );
1137 #endif
1138 
1139 #ifdef HAVE_CYRUS_SASL
1140 #ifdef HAVE_SASL_VERSION
1141 	/* stringify the version number, sasl.h doesn't do it for us */
1142 #define	VSTR0(maj, min, pat)	#maj "." #min "." #pat
1143 #define	VSTR(maj, min, pat)	VSTR0(maj, min, pat)
1144 #define	SASL_VERSION_STRING	VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
1145 				SASL_VERSION_STEP)
1146 
1147 	sasl_version( NULL, &rc );
1148 	if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) ||
1149 		(rc & 0xffff) < SASL_VERSION_STEP)
1150 	{
1151 		char version[sizeof("xxx.xxx.xxxxx")];
1152 		sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff,
1153 			rc & 0xffff );
1154 		Debug( LDAP_DEBUG_ANY, "slap_sasl_init: SASL library version mismatch:"
1155 			" expected %s, got %s\n",
1156 			SASL_VERSION_STRING, version, 0 );
1157 		return -1;
1158 	}
1159 #endif
1160 
1161 	sasl_set_mutex(
1162 		ldap_pvt_sasl_mutex_new,
1163 		ldap_pvt_sasl_mutex_lock,
1164 		ldap_pvt_sasl_mutex_unlock,
1165 		ldap_pvt_sasl_mutex_dispose );
1166 
1167 	generic_filter.f_desc = slap_schema.si_ad_objectClass;
1168 
1169 	rc = sasl_auxprop_add_plugin( "slapd", slap_auxprop_init );
1170 	if( rc != SASL_OK ) {
1171 		Debug( LDAP_DEBUG_ANY, "slap_sasl_init: auxprop add plugin failed\n",
1172 			0, 0, 0 );
1173 		return -1;
1174 	}
1175 
1176 	/* should provide callbacks for logging */
1177 	/* server name should be configurable */
1178 	rc = sasl_server_init( server_callbacks, "slapd" );
1179 
1180 	if( rc != SASL_OK ) {
1181 		Debug( LDAP_DEBUG_ANY, "slap_sasl_init: server init failed\n",
1182 			0, 0, 0 );
1183 
1184 		return -1;
1185 	}
1186 
1187 #ifdef SLAPD_SPASSWD
1188 	lutil_passwd_add( &sasl_pwscheme, chk_sasl, NULL );
1189 #endif
1190 
1191 	Debug( LDAP_DEBUG_TRACE, "slap_sasl_init: initialized!\n",
1192 		0, 0, 0 );
1193 
1194 	/* default security properties */
1195 	memset( &sasl_secprops, '\0', sizeof(sasl_secprops) );
1196 	sasl_secprops.max_ssf = INT_MAX;
1197 	sasl_secprops.maxbufsize = 65536;
1198 	sasl_secprops.security_flags = SASL_SEC_NOPLAINTEXT|SASL_SEC_NOANONYMOUS;
1199 #endif
1200 
1201 	return 0;
1202 }
1203 
1204 int slap_sasl_destroy( void )
1205 {
1206 #ifdef HAVE_CYRUS_SASL
1207 	sasl_done();
1208 #endif
1209 	free( sasl_host );
1210 	sasl_host = NULL;
1211 
1212 	return 0;
1213 }
1214 
1215 static char *
1216 slap_sasl_peer2ipport( struct berval *peer )
1217 {
1218 	int		isv6 = 0;
1219 	char		*ipport, *p,
1220 			*addr = &peer->bv_val[ STRLENOF( "IP=" ) ];
1221 	ber_len_t	plen = peer->bv_len - STRLENOF( "IP=" );
1222 
1223 	/* IPv6? */
1224 	if ( addr[0] == '[' ) {
1225 		isv6 = 1;
1226 		plen--;
1227 	}
1228 	ipport = ch_strdup( &addr[isv6] );
1229 
1230 	/* Convert IPv6/IPv4 addresses to address;port syntax. */
1231 	p = strrchr( ipport, ':' );
1232 	if ( p != NULL ) {
1233 		*p = ';';
1234 		if ( isv6 ) {
1235 			assert( p[-1] == ']' );
1236 			AC_MEMCPY( &p[-1], p, plen - ( p - ipport ) + 1 );
1237 		}
1238 
1239 	} else if ( isv6 ) {
1240 		/* trim ']' */
1241 		plen--;
1242 		assert( addr[plen] == ']' );
1243 		addr[plen] = '\0';
1244 	}
1245 
1246 	return ipport;
1247 }
1248 
1249 int slap_sasl_open( Connection *conn, int reopen )
1250 {
1251 	int sc = LDAP_SUCCESS;
1252 #ifdef HAVE_CYRUS_SASL
1253 	int cb;
1254 
1255 	sasl_conn_t *ctx = NULL;
1256 	sasl_callback_t *session_callbacks;
1257 	char *ipremoteport = NULL, *iplocalport = NULL;
1258 
1259 	assert( conn->c_sasl_authctx == NULL );
1260 
1261 	if ( !reopen ) {
1262 		assert( conn->c_sasl_extra == NULL );
1263 
1264 		session_callbacks =
1265 			SLAP_CALLOC( 5, sizeof(sasl_callback_t));
1266 		if( session_callbacks == NULL ) {
1267 			Debug( LDAP_DEBUG_ANY,
1268 				"slap_sasl_open: SLAP_MALLOC failed", 0, 0, 0 );
1269 			return -1;
1270 		}
1271 		conn->c_sasl_extra = session_callbacks;
1272 
1273 		session_callbacks[cb=0].id = SASL_CB_LOG;
1274 		session_callbacks[cb].proc = (slap_sasl_cb_ft)&slap_sasl_log;
1275 		session_callbacks[cb++].context = conn;
1276 
1277 		session_callbacks[cb].id = SASL_CB_PROXY_POLICY;
1278 		session_callbacks[cb].proc = (slap_sasl_cb_ft)&slap_sasl_authorize;
1279 		session_callbacks[cb++].context = conn;
1280 
1281 		session_callbacks[cb].id = SASL_CB_CANON_USER;
1282 		session_callbacks[cb].proc = (slap_sasl_cb_ft)&slap_sasl_canonicalize;
1283 		session_callbacks[cb++].context = conn;
1284 
1285 		session_callbacks[cb].id = SASL_CB_LIST_END;
1286 		session_callbacks[cb].proc = NULL;
1287 		session_callbacks[cb++].context = NULL;
1288 	} else {
1289 		session_callbacks = conn->c_sasl_extra;
1290 	}
1291 
1292 	conn->c_sasl_layers = 0;
1293 
1294 	/* create new SASL context */
1295 	if ( conn->c_sock_name.bv_len != 0 &&
1296 		strncmp( conn->c_sock_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 )
1297 	{
1298 		iplocalport = slap_sasl_peer2ipport( &conn->c_sock_name );
1299 	}
1300 
1301 	if ( conn->c_peer_name.bv_len != 0 &&
1302 		strncmp( conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 )
1303 	{
1304 		ipremoteport = slap_sasl_peer2ipport( &conn->c_peer_name );
1305 	}
1306 
1307 	sc = sasl_server_new( "ldap", sasl_host, global_realm,
1308 		iplocalport, ipremoteport, session_callbacks, SASL_SUCCESS_DATA, &ctx );
1309 	if ( iplocalport != NULL ) {
1310 		ch_free( iplocalport );
1311 	}
1312 	if ( ipremoteport != NULL ) {
1313 		ch_free( ipremoteport );
1314 	}
1315 
1316 	if( sc != SASL_OK ) {
1317 		Debug( LDAP_DEBUG_ANY, "sasl_server_new failed: %d\n",
1318 			sc, 0, 0 );
1319 
1320 		return -1;
1321 	}
1322 
1323 	conn->c_sasl_authctx = ctx;
1324 
1325 	if( sc == SASL_OK ) {
1326 		sc = sasl_setprop( ctx,
1327 			SASL_SEC_PROPS, &sasl_secprops );
1328 
1329 		if( sc != SASL_OK ) {
1330 			Debug( LDAP_DEBUG_ANY, "sasl_setprop failed: %d\n",
1331 				sc, 0, 0 );
1332 
1333 			slap_sasl_close( conn );
1334 			return -1;
1335 		}
1336 	}
1337 
1338 	sc = slap_sasl_err2ldap( sc );
1339 
1340 #elif defined(SLAP_BUILTIN_SASL)
1341 	/* built-in SASL implementation */
1342 	SASL_CTX *ctx = (SASL_CTX *) SLAP_MALLOC(sizeof(SASL_CTX));
1343 	if( ctx == NULL ) return -1;
1344 
1345 	ctx->sc_external_ssf = 0;
1346 	BER_BVZERO( &ctx->sc_external_id );
1347 
1348 	conn->c_sasl_authctx = ctx;
1349 #endif
1350 
1351 	return sc;
1352 }
1353 
1354 int slap_sasl_external(
1355 	Connection *conn,
1356 	slap_ssf_t ssf,
1357 	struct berval *auth_id )
1358 {
1359 #ifdef HAVE_CYRUS_SASL
1360 	int sc;
1361 	sasl_conn_t *ctx = conn->c_sasl_authctx;
1362 	sasl_ssf_t sasl_ssf = ssf;
1363 
1364 	if ( ctx == NULL ) {
1365 		return LDAP_UNAVAILABLE;
1366 	}
1367 
1368 	sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf );
1369 
1370 	if ( sc != SASL_OK ) {
1371 		return LDAP_OTHER;
1372 	}
1373 
1374 	sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL,
1375 		auth_id ? auth_id->bv_val : NULL );
1376 
1377 	if ( sc != SASL_OK ) {
1378 		return LDAP_OTHER;
1379 	}
1380 #elif defined(SLAP_BUILTIN_SASL)
1381 	/* built-in SASL implementation */
1382 	SASL_CTX *ctx = conn->c_sasl_authctx;
1383 	if ( ctx == NULL ) return LDAP_UNAVAILABLE;
1384 
1385 	ctx->sc_external_ssf = ssf;
1386 	if( auth_id ) {
1387 		ctx->sc_external_id = *auth_id;
1388 		BER_BVZERO( auth_id );
1389 	} else {
1390 		BER_BVZERO( &ctx->sc_external_id );
1391 	}
1392 #endif
1393 
1394 	return LDAP_SUCCESS;
1395 }
1396 
1397 int slap_sasl_reset( Connection *conn )
1398 {
1399 	return LDAP_SUCCESS;
1400 }
1401 
1402 char ** slap_sasl_mechs( Connection *conn )
1403 {
1404 	char **mechs = NULL;
1405 
1406 #ifdef HAVE_CYRUS_SASL
1407 	sasl_conn_t *ctx = conn->c_sasl_authctx;
1408 
1409 	if( ctx == NULL ) ctx = conn->c_sasl_sockctx;
1410 
1411 	if( ctx != NULL ) {
1412 		int sc;
1413 		SASL_CONST char *mechstr;
1414 
1415 		sc = sasl_listmech( ctx,
1416 			NULL, NULL, ",", NULL,
1417 			&mechstr, NULL, NULL );
1418 
1419 		if( sc != SASL_OK ) {
1420 			Debug( LDAP_DEBUG_ANY, "slap_sasl_listmech failed: %d\n",
1421 				sc, 0, 0 );
1422 
1423 			return NULL;
1424 		}
1425 
1426 		mechs = ldap_str2charray( mechstr, "," );
1427 	}
1428 #elif defined(SLAP_BUILTIN_SASL)
1429 	/* builtin SASL implementation */
1430 	SASL_CTX *ctx = conn->c_sasl_authctx;
1431 	if ( ctx != NULL && ctx->sc_external_id.bv_val ) {
1432 		/* should check ssf */
1433 		mechs = ldap_str2charray( "EXTERNAL", "," );
1434 	}
1435 #endif
1436 
1437 	return mechs;
1438 }
1439 
1440 int slap_sasl_close( Connection *conn )
1441 {
1442 #ifdef HAVE_CYRUS_SASL
1443 	sasl_conn_t *ctx = conn->c_sasl_authctx;
1444 
1445 	if( ctx != NULL ) {
1446 		sasl_dispose( &ctx );
1447 	}
1448 	if ( conn->c_sasl_sockctx &&
1449 		conn->c_sasl_authctx != conn->c_sasl_sockctx )
1450 	{
1451 		ctx = conn->c_sasl_sockctx;
1452 		sasl_dispose( &ctx );
1453 	}
1454 
1455 	conn->c_sasl_authctx = NULL;
1456 	conn->c_sasl_sockctx = NULL;
1457 	conn->c_sasl_done = 0;
1458 
1459 	free( conn->c_sasl_extra );
1460 	conn->c_sasl_extra = NULL;
1461 
1462 #elif defined(SLAP_BUILTIN_SASL)
1463 	SASL_CTX *ctx = conn->c_sasl_authctx;
1464 	if( ctx ) {
1465 		if( ctx->sc_external_id.bv_val ) {
1466 			free( ctx->sc_external_id.bv_val );
1467 			BER_BVZERO( &ctx->sc_external_id );
1468 		}
1469 		free( ctx );
1470 		conn->c_sasl_authctx = NULL;
1471 	}
1472 #endif
1473 
1474 	return LDAP_SUCCESS;
1475 }
1476 
1477 int slap_sasl_bind( Operation *op, SlapReply *rs )
1478 {
1479 #ifdef HAVE_CYRUS_SASL
1480 	sasl_conn_t *ctx = op->o_conn->c_sasl_authctx;
1481 	struct berval response;
1482 	unsigned reslen = 0;
1483 	int sc;
1484 
1485 	Debug(LDAP_DEBUG_ARGS,
1486 		"==> sasl_bind: dn=\"%s\" mech=%s datalen=%ld\n",
1487 		op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "",
1488 		op->o_conn->c_sasl_bind_in_progress ? "<continuing>" :
1489 		op->o_conn->c_sasl_bind_mech.bv_val,
1490 		op->orb_cred.bv_len );
1491 
1492 	if( ctx == NULL ) {
1493 		send_ldap_error( op, rs, LDAP_UNAVAILABLE,
1494 			"SASL unavailable on this session" );
1495 		return rs->sr_err;
1496 	}
1497 
1498 #define	START( ctx, mech, cred, clen, resp, rlen, err ) \
1499 	sasl_server_start( ctx, mech, cred, clen, resp, rlen )
1500 #define	STEP( ctx, cred, clen, resp, rlen, err ) \
1501 	sasl_server_step( ctx, cred, clen, resp, rlen )
1502 
1503 	if ( !op->o_conn->c_sasl_bind_in_progress ) {
1504 		/* If we already authenticated once, must use a new context */
1505 		if ( op->o_conn->c_sasl_done ) {
1506 			sasl_ssf_t ssf = 0;
1507 			sasl_ssf_t *ssfp = NULL;
1508 			const char *authid = NULL;
1509 
1510 			sasl_getprop( ctx, SASL_SSF_EXTERNAL, (void *)&ssfp );
1511 			if ( ssfp ) ssf = *ssfp;
1512 
1513 			sasl_getprop( ctx, SASL_AUTH_EXTERNAL, (void *)&authid );
1514 			if ( authid ) authid = ch_strdup( authid );
1515 
1516 			if ( ctx != op->o_conn->c_sasl_sockctx ) {
1517 				sasl_dispose( &ctx );
1518 			}
1519 			op->o_conn->c_sasl_authctx = NULL;
1520 
1521 			slap_sasl_open( op->o_conn, 1 );
1522 			ctx = op->o_conn->c_sasl_authctx;
1523 			sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf );
1524 			if ( authid ) {
1525 				sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid );
1526 				ch_free( (char *)authid );
1527 			}
1528 		}
1529 		sc = START( ctx,
1530 			op->o_conn->c_sasl_bind_mech.bv_val,
1531 			op->orb_cred.bv_val, op->orb_cred.bv_len,
1532 			(SASL_CONST char **)&response.bv_val, &reslen, &rs->sr_text );
1533 
1534 	} else {
1535 		sc = STEP( ctx,
1536 			op->orb_cred.bv_val, op->orb_cred.bv_len,
1537 			(SASL_CONST char **)&response.bv_val, &reslen, &rs->sr_text );
1538 	}
1539 
1540 	response.bv_len = reslen;
1541 
1542 	if ( sc == SASL_OK ) {
1543 		sasl_ssf_t *ssf = NULL;
1544 
1545 		ber_dupbv_x( &op->orb_edn, &op->o_conn->c_sasl_dn, op->o_tmpmemctx );
1546 		BER_BVZERO( &op->o_conn->c_sasl_dn );
1547 		op->o_conn->c_sasl_done = 1;
1548 
1549 		rs->sr_err = LDAP_SUCCESS;
1550 
1551 		(void) sasl_getprop( ctx, SASL_SSF, (void *)&ssf );
1552 		op->orb_ssf = ssf ? *ssf : 0;
1553 
1554 		ctx = NULL;
1555 		if( op->orb_ssf ) {
1556 			ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
1557 			op->o_conn->c_sasl_layers++;
1558 
1559 			/* If there's an old layer, set sockctx to NULL to
1560 			 * tell connection_read() to wait for us to finish.
1561 			 * Otherwise there is a race condition: we have to
1562 			 * send the Bind response using the old security
1563 			 * context and then remove it before reading any
1564 			 * new messages.
1565 			 */
1566 			if ( op->o_conn->c_sasl_sockctx ) {
1567 				ctx = op->o_conn->c_sasl_sockctx;
1568 				op->o_conn->c_sasl_sockctx = NULL;
1569 			} else {
1570 				op->o_conn->c_sasl_sockctx = op->o_conn->c_sasl_authctx;
1571 			}
1572 			ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
1573 		}
1574 
1575 		/* Must send response using old security layer */
1576 		rs->sr_sasldata = (response.bv_len ? &response : NULL);
1577 		send_ldap_sasl( op, rs );
1578 
1579 		/* Now dispose of the old security layer.
1580 		 */
1581 		if ( ctx ) {
1582 			ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
1583 			ldap_pvt_sasl_remove( op->o_conn->c_sb );
1584 			op->o_conn->c_sasl_sockctx = op->o_conn->c_sasl_authctx;
1585 			ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
1586 			sasl_dispose( &ctx );
1587 		}
1588 	} else if ( sc == SASL_CONTINUE ) {
1589 		rs->sr_err = LDAP_SASL_BIND_IN_PROGRESS,
1590 		rs->sr_text = sasl_errdetail( ctx );
1591 		rs->sr_sasldata = &response;
1592 		send_ldap_sasl( op, rs );
1593 
1594 	} else {
1595 		BER_BVZERO( &op->o_conn->c_sasl_dn );
1596 		rs->sr_text = sasl_errdetail( ctx );
1597 		rs->sr_err = slap_sasl_err2ldap( sc ),
1598 		send_ldap_result( op, rs );
1599 	}
1600 
1601 	Debug(LDAP_DEBUG_TRACE, "<== slap_sasl_bind: rc=%d\n", rs->sr_err, 0, 0);
1602 
1603 #elif defined(SLAP_BUILTIN_SASL)
1604 	/* built-in SASL implementation */
1605 	SASL_CTX *ctx = op->o_conn->c_sasl_authctx;
1606 
1607 	if ( ctx == NULL ) {
1608 		send_ldap_error( op, rs, LDAP_OTHER,
1609 			"Internal SASL Error" );
1610 
1611 	} else if ( bvmatch( &ext_bv, &op->o_conn->c_sasl_bind_mech ) ) {
1612 		/* EXTERNAL */
1613 
1614 		if( op->orb_cred.bv_len ) {
1615 			rs->sr_text = "proxy authorization not supported";
1616 			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1617 			send_ldap_result( op, rs );
1618 
1619 		} else {
1620 			op->orb_edn = ctx->sc_external_id;
1621 			rs->sr_err = LDAP_SUCCESS;
1622 			rs->sr_sasldata = NULL;
1623 			send_ldap_sasl( op, rs );
1624 		}
1625 
1626 	} else {
1627 		send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED,
1628 			"requested SASL mechanism not supported" );
1629 	}
1630 #else
1631 	send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED,
1632 		"SASL not supported" );
1633 #endif
1634 
1635 	return rs->sr_err;
1636 }
1637 
1638 char* slap_sasl_secprops( const char *in )
1639 {
1640 #ifdef HAVE_CYRUS_SASL
1641 	int rc = ldap_pvt_sasl_secprops( in, &sasl_secprops );
1642 
1643 	return rc == LDAP_SUCCESS ? NULL : "Invalid security properties";
1644 #else
1645 	return "SASL not supported";
1646 #endif
1647 }
1648 
1649 void slap_sasl_secprops_unparse( struct berval *bv )
1650 {
1651 #ifdef HAVE_CYRUS_SASL
1652 	ldap_pvt_sasl_secprops_unparse( &sasl_secprops, bv );
1653 #endif
1654 }
1655 
1656 #ifdef HAVE_CYRUS_SASL
1657 int
1658 slap_sasl_setpass( Operation *op, SlapReply *rs )
1659 {
1660 	struct berval id = BER_BVNULL;	/* needs to come from connection */
1661 	struct berval new = BER_BVNULL;
1662 	struct berval old = BER_BVNULL;
1663 
1664 	assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 );
1665 
1666 	rs->sr_err = sasl_getprop( op->o_conn->c_sasl_authctx, SASL_USERNAME,
1667 		(SASL_CONST void **)(char *)&id.bv_val );
1668 
1669 	if( rs->sr_err != SASL_OK ) {
1670 		rs->sr_text = "unable to retrieve SASL username";
1671 		rs->sr_err = LDAP_OTHER;
1672 		goto done;
1673 	}
1674 
1675 	Debug( LDAP_DEBUG_ARGS, "==> slap_sasl_setpass: \"%s\"\n",
1676 		id.bv_val ? id.bv_val : "", 0, 0 );
1677 
1678 	rs->sr_err = slap_passwd_parse( op->ore_reqdata,
1679 		NULL, &old, &new, &rs->sr_text );
1680 
1681 	if( rs->sr_err != LDAP_SUCCESS ) {
1682 		goto done;
1683 	}
1684 
1685 	if( new.bv_len == 0 ) {
1686 		slap_passwd_generate(&new);
1687 
1688 		if( new.bv_len == 0 ) {
1689 			rs->sr_text = "password generation failed.";
1690 			rs->sr_err = LDAP_OTHER;
1691 			goto done;
1692 		}
1693 
1694 		rs->sr_rspdata = slap_passwd_return( &new );
1695 	}
1696 
1697 	rs->sr_err = sasl_setpass( op->o_conn->c_sasl_authctx, id.bv_val,
1698 		new.bv_val, new.bv_len, old.bv_val, old.bv_len, 0 );
1699 	if( rs->sr_err != SASL_OK ) {
1700 		rs->sr_text = sasl_errdetail( op->o_conn->c_sasl_authctx );
1701 	}
1702 	switch(rs->sr_err) {
1703 		case SASL_OK:
1704 			rs->sr_err = LDAP_SUCCESS;
1705 			break;
1706 
1707 		case SASL_NOCHANGE:
1708 		case SASL_NOMECH:
1709 		case SASL_DISABLED:
1710 		case SASL_PWLOCK:
1711 		case SASL_FAIL:
1712 		case SASL_BADPARAM:
1713 		default:
1714 			rs->sr_err = LDAP_OTHER;
1715 	}
1716 
1717 done:
1718 	return rs->sr_err;
1719 }
1720 #endif /* HAVE_CYRUS_SASL */
1721 
1722 /* Take any sort of identity string and return a DN with the "dn:" prefix. The
1723  * string returned in *dn is in its own allocated memory, and must be free'd
1724  * by the calling process.  -Mark Adamson, Carnegie Mellon
1725  *
1726  * The "dn:" prefix is no longer used anywhere inside slapd. It is only used
1727  * on strings passed in directly from SASL.  -Howard Chu, Symas Corp.
1728  */
1729 
1730 #define SET_NONE	0
1731 #define	SET_DN		1
1732 #define	SET_U		2
1733 
1734 int slap_sasl_getdn( Connection *conn, Operation *op, struct berval *id,
1735 	char *user_realm, struct berval *dn, int flags )
1736 {
1737 	int rc, is_dn = SET_NONE, do_norm = 1;
1738 	struct berval dn2, *mech;
1739 
1740 	assert( conn != NULL );
1741 	assert( id != NULL );
1742 
1743 	Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: conn %lu id=%s [len=%lu]\n",
1744 		conn->c_connid,
1745 		BER_BVISNULL( id ) ? "NULL" : ( BER_BVISEMPTY( id ) ? "<empty>" : id->bv_val ),
1746 		BER_BVISNULL( id ) ? 0 : ( BER_BVISEMPTY( id ) ? 0 :
1747 		                           (unsigned long) id->bv_len ) );
1748 
1749 	if ( !op ) {
1750 		op = conn->c_sasl_bindop;
1751 	}
1752 	assert( op != NULL );
1753 
1754 	BER_BVZERO( dn );
1755 
1756 	if ( !BER_BVISNULL( id ) ) {
1757 		/* Blatantly anonymous ID */
1758 		static struct berval bv_anonymous = BER_BVC( "anonymous" );
1759 
1760 		if ( ber_bvstrcasecmp( id, &bv_anonymous ) == 0 ) {
1761 			return( LDAP_SUCCESS );
1762 		}
1763 
1764 	} else {
1765 		/* FIXME: if empty, should we stop? */
1766 		BER_BVSTR( id, "" );
1767 	}
1768 
1769 	if ( !BER_BVISEMPTY( &conn->c_sasl_bind_mech ) ) {
1770 		mech = &conn->c_sasl_bind_mech;
1771 	} else {
1772 		mech = &conn->c_authmech;
1773 	}
1774 
1775 	/* An authcID needs to be converted to authzID form. Set the
1776 	 * values directly into *dn; they will be normalized later. (and
1777 	 * normalizing always makes a new copy.) An ID from a TLS certificate
1778 	 * is already normalized, so copy it and skip normalization.
1779 	 */
1780 	if( flags & SLAP_GETDN_AUTHCID ) {
1781 		if( bvmatch( mech, &ext_bv )) {
1782 			/* EXTERNAL DNs are already normalized */
1783 			assert( !BER_BVISNULL( id ) );
1784 
1785 			do_norm = 0;
1786 			is_dn = SET_DN;
1787 			ber_dupbv_x( dn, id, op->o_tmpmemctx );
1788 
1789 		} else {
1790 			/* convert to u:<username> form */
1791 			is_dn = SET_U;
1792 			*dn = *id;
1793 		}
1794 	}
1795 
1796 	if( is_dn == SET_NONE ) {
1797 		if( !strncasecmp( id->bv_val, "u:", STRLENOF( "u:" ) ) ) {
1798 			is_dn = SET_U;
1799 			dn->bv_val = id->bv_val + STRLENOF( "u:" );
1800 			dn->bv_len = id->bv_len - STRLENOF( "u:" );
1801 
1802 		} else if ( !strncasecmp( id->bv_val, "dn:", STRLENOF( "dn:" ) ) ) {
1803 			is_dn = SET_DN;
1804 			dn->bv_val = id->bv_val + STRLENOF( "dn:" );
1805 			dn->bv_len = id->bv_len - STRLENOF( "dn:" );
1806 		}
1807 	}
1808 
1809 	/* No other possibilities from here */
1810 	if( is_dn == SET_NONE ) {
1811 		BER_BVZERO( dn );
1812 		return( LDAP_INAPPROPRIATE_AUTH );
1813 	}
1814 
1815 	/* Username strings */
1816 	if( is_dn == SET_U ) {
1817 		/* ITS#3419: values may need escape */
1818 		LDAPRDN		DN[ 5 ];
1819 		LDAPAVA 	*RDNs[ 4 ][ 2 ];
1820 		LDAPAVA 	AVAs[ 4 ];
1821 		int		irdn;
1822 
1823 		irdn = 0;
1824 		DN[ irdn ] = RDNs[ irdn ];
1825 		RDNs[ irdn ][ 0 ] = &AVAs[ irdn ];
1826 		AVAs[ irdn ].la_attr = slap_schema.si_ad_uid->ad_cname;
1827 		AVAs[ irdn ].la_value = *dn;
1828 		AVAs[ irdn ].la_flags = LDAP_AVA_NULL;
1829 		AVAs[ irdn ].la_private = NULL;
1830 		RDNs[ irdn ][ 1 ] = NULL;
1831 
1832 		if ( user_realm && *user_realm ) {
1833 			irdn++;
1834 			DN[ irdn ] = RDNs[ irdn ];
1835 			RDNs[ irdn ][ 0 ] = &AVAs[ irdn ];
1836 			AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname;
1837 			ber_str2bv( user_realm, 0, 0, &AVAs[ irdn ].la_value );
1838 			AVAs[ irdn ].la_flags = LDAP_AVA_NULL;
1839 			AVAs[ irdn ].la_private = NULL;
1840 			RDNs[ irdn ][ 1 ] = NULL;
1841 		}
1842 
1843 		if ( !BER_BVISNULL( mech ) ) {
1844 			irdn++;
1845 			DN[ irdn ] = RDNs[ irdn ];
1846 			RDNs[ irdn ][ 0 ] = &AVAs[ irdn ];
1847 			AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname;
1848 			AVAs[ irdn ].la_value = *mech;
1849 			AVAs[ irdn ].la_flags = LDAP_AVA_NULL;
1850 			AVAs[ irdn ].la_private = NULL;
1851 			RDNs[ irdn ][ 1 ] = NULL;
1852 		}
1853 
1854 		irdn++;
1855 		DN[ irdn ] = RDNs[ irdn ];
1856 		RDNs[ irdn ][ 0 ] = &AVAs[ irdn ];
1857 		AVAs[ irdn ].la_attr = slap_schema.si_ad_cn->ad_cname;
1858 		BER_BVSTR( &AVAs[ irdn ].la_value, "auth" );
1859 		AVAs[ irdn ].la_flags = LDAP_AVA_NULL;
1860 		AVAs[ irdn ].la_private = NULL;
1861 		RDNs[ irdn ][ 1 ] = NULL;
1862 
1863 		irdn++;
1864 		DN[ irdn ] = NULL;
1865 
1866 		rc = ldap_dn2bv_x( DN, dn, LDAP_DN_FORMAT_LDAPV3,
1867 				op->o_tmpmemctx );
1868 		if ( rc != LDAP_SUCCESS ) {
1869 			BER_BVZERO( dn );
1870 			return rc;
1871 		}
1872 
1873 		Debug( LDAP_DEBUG_TRACE,
1874 			"slap_sasl_getdn: u:id converted to %s\n",
1875 			dn->bv_val, 0, 0 );
1876 
1877 	} else {
1878 
1879 		/* Dup the DN in any case, so we don't risk
1880 		 * leaks or dangling pointers later,
1881 		 * and the DN value is '\0' terminated */
1882 		ber_dupbv_x( &dn2, dn, op->o_tmpmemctx );
1883 		dn->bv_val = dn2.bv_val;
1884 	}
1885 
1886 	/* All strings are in DN form now. Normalize if needed. */
1887 	if ( do_norm ) {
1888 		rc = dnNormalize( 0, NULL, NULL, dn, &dn2, op->o_tmpmemctx );
1889 
1890 		/* User DNs were constructed above and must be freed now */
1891 		slap_sl_free( dn->bv_val, op->o_tmpmemctx );
1892 
1893 		if ( rc != LDAP_SUCCESS ) {
1894 			BER_BVZERO( dn );
1895 			return rc;
1896 		}
1897 		*dn = dn2;
1898 	}
1899 
1900 	/* Run thru regexp */
1901 	slap_sasl2dn( op, dn, &dn2, flags );
1902 	if( !BER_BVISNULL( &dn2 ) ) {
1903 		slap_sl_free( dn->bv_val, op->o_tmpmemctx );
1904 		*dn = dn2;
1905 		Debug( LDAP_DEBUG_TRACE,
1906 			"slap_sasl_getdn: dn:id converted to %s\n",
1907 			dn->bv_val, 0, 0 );
1908 	}
1909 
1910 	return( LDAP_SUCCESS );
1911 }
1912