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