+
+/*
+ * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
+ * return the LDAP DN to which it matches. The SASL regexp rules in the config
+ * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
+ * search with scope=base), just return the URI (or its searchbase). Otherwise
+ * an internal search must be done, and if that search returns exactly one
+ * entry, return the DN of that one entry.
+ */
+void slap_sasl2dn( Operation *opx,
+ struct berval *saslname, struct berval *sasldn, int flags )
+{
+ int rc;
+ slap_callback cb = { NULL, sasl_sc_sasl2dn, NULL, NULL };
+ Operation op = {0};
+ SlapReply rs = {REP_RESULT};
+ struct berval regout = BER_BVNULL;
+
+ Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
+ "converting SASL name %s to a DN\n",
+ saslname->bv_val, 0,0 );
+
+ sasldn->bv_val = NULL;
+ sasldn->bv_len = 0;
+ cb.sc_private = sasldn;
+
+ /* Convert the SASL name into a minimal URI */
+ if( !slap_authz_regexp( saslname, ®out, flags, opx->o_tmpmemctx ) ) {
+ goto FINISHED;
+ }
+
+ rc = slap_parseURI( opx, ®out, &op.o_req_dn,
+ &op.o_req_ndn, &op.ors_scope, &op.ors_filter,
+ &op.ors_filterstr );
+ if ( !BER_BVISNULL( ®out ) ) slap_sl_free( regout.bv_val, opx->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ goto FINISHED;
+ }
+
+ /* Must do an internal search */
+ op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
+
+ switch ( op.ors_scope ) {
+ case LDAP_X_SCOPE_EXACT:
+ *sasldn = op.o_req_ndn;
+ BER_BVZERO( &op.o_req_ndn );
+ /* intentionally continue to next case */
+
+ case LDAP_X_SCOPE_REGEX:
+ case LDAP_X_SCOPE_SUBTREE:
+ case LDAP_X_SCOPE_CHILDREN:
+ case LDAP_X_SCOPE_ONELEVEL:
+ case LDAP_X_SCOPE_GROUP:
+ case LDAP_X_SCOPE_USERS:
+ /* correctly parsed, but illegal */
+ goto FINISHED;
+
+ case LDAP_SCOPE_BASE:
+ case LDAP_SCOPE_ONELEVEL:
+ case LDAP_SCOPE_SUBTREE:
+#ifdef LDAP_SCOPE_SUBORDINATE
+ case LDAP_SCOPE_SUBORDINATE:
+#endif
+ /* do a search */
+ break;
+
+ default:
+ /* catch unhandled cases (there shouldn't be) */
+ assert( 0 );
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
+ op.o_req_ndn.bv_val, op.ors_scope, 0 );
+
+ if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
+ goto FINISHED;
+ }
+
+ op.o_conn = opx->o_conn;
+ op.o_connid = opx->o_connid;
+ op.o_tag = LDAP_REQ_SEARCH;
+ op.o_protocol = LDAP_VERSION3;
+ op.o_ndn = opx->o_conn->c_ndn;
+ op.o_callback = &cb;
+ op.o_time = slap_get_time();
+ op.o_do_not_cache = 1;
+ op.o_is_auth_check = 1;
+ op.o_threadctx = opx->o_threadctx;
+ op.o_tmpmemctx = opx->o_tmpmemctx;
+ op.o_tmpmfuncs = opx->o_tmpmfuncs;
+#ifdef LDAP_SLAPI
+ op.o_pb = opx->o_pb;
+#endif
+ op.ors_deref = LDAP_DEREF_NEVER;
+ op.ors_slimit = 1;
+ op.ors_tlimit = SLAP_NO_LIMIT;
+ op.ors_attrs = slap_anlist_no_attrs;
+ op.ors_attrsonly = 1;
+ op.o_sync_slog_size = -1;
+ /* use req_ndn as req_dn instead of non-pretty base of uri */
+ if( !BER_BVISNULL( &op.o_req_dn ) ) ch_free( op.o_req_dn.bv_val );
+ ber_dupbv_x( &op.o_req_dn, &op.o_req_ndn, op.o_tmpmemctx );
+
+ op.o_bd->be_search( &op, &rs );
+
+FINISHED:
+ if( !BER_BVISEMPTY( sasldn ) ) {
+ opx->o_conn->c_authz_backend = op.o_bd;
+ }
+ if( !BER_BVISNULL( &op.o_req_dn ) ) {
+ slap_sl_free( op.o_req_dn.bv_val, opx->o_tmpmemctx );
+ }
+ if( !BER_BVISNULL( &op.o_req_ndn ) ) {
+ slap_sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
+ }
+ if( op.ors_filter ) {
+ filter_free_x( opx, op.ors_filter );
+ }
+ if( !BER_BVISNULL( &op.ors_filterstr ) ) {
+ ch_free( op.ors_filterstr.bv_val );
+ }
+
+ Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
+ !BER_BVISEMPTY( sasldn ) ? sasldn->bv_val : "<nothing>", 0, 0 );
+
+ return;
+}