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