+ char *c1;
+ int rc, is_dn = 0, do_norm = 1;
+ sasl_conn_t *ctx;
+ struct berval dn2;
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_getdn: conn %d id=%s\n",
+ conn ? conn->c_connid : -1,
+ id ? (*id ? id : "<empty>") : "NULL" ));
+#else
+ Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: id=%s\n",
+ id?(*id?id:"<empty>"):"NULL",0,0 );
+#endif
+
+ dn->bv_val = NULL;
+ dn->bv_len = 0;
+
+ if ( id ) {
+ if ( len == 0 ) len = strlen( id );
+
+ /* Blatantly anonymous ID */
+ if ( len == sizeof("anonymous") - 1 &&
+ !strcasecmp( id, "anonymous" ) ) {
+ return( LDAP_SUCCESS );
+ }
+ } else {
+ len = 0;
+ }
+
+ ctx = conn->c_sasl_context;
+
+ /* An authcID needs to be converted to authzID form. Set the
+ * values directly into *dn; they will be normalized later. (and
+ * normalizing always makes a new copy.) An ID from a TLS certificate
+ * is already normalized, so copy it and skip normalization.
+ */
+ if( flags & FLAG_GETDN_AUTHCID ) {
+#ifdef HAVE_TLS
+ if( conn->c_is_tls && conn->c_sasl_bind_mech.bv_len == ext_bv.bv_len
+ && ( strcasecmp( ext_bv.bv_val, conn->c_sasl_bind_mech.bv_val ) == 0 ) ) {
+ /* X.509 DN is already normalized */
+ do_norm = 0;
+ is_dn = SET_DN;
+ ber_str2bv( id, len, 1, dn );
+
+ } else
+#endif
+ {
+ /* convert to u:<username> form */
+ is_dn = SET_U;
+ dn->bv_val = id;
+ dn->bv_len = len;
+ }
+ }
+ if( !is_dn ) {
+ if( !strncasecmp( id, "u:", sizeof("u:")-1 )) {
+ is_dn = SET_U;
+ dn->bv_val = id+2;
+ dn->bv_len = len-2;
+ } else if ( !strncasecmp( id, "dn:", sizeof("dn:")-1) ) {
+ is_dn = SET_DN;
+ dn->bv_val = id+3;
+ dn->bv_len = len-3;
+ }
+ }
+
+ /* No other possibilities from here */
+ if( !is_dn ) {
+ dn->bv_val = NULL;
+ dn->bv_len = 0;
+ return( LDAP_INAPPROPRIATE_AUTH );
+ }
+
+ /* Username strings */
+ if( is_dn == SET_U ) {
+ char *p, *realm;
+ len = dn->bv_len + sizeof("uid=")-1 + sizeof(",cn=auth")-1;
+
+ /* username may have embedded realm name */
+ if( realm = strchr( dn->bv_val, '@') ) {
+ *realm++ = '\0';
+ len += sizeof(",cn=")-2;
+ } else if( user_realm && *user_realm ) {
+ len += strlen( user_realm ) + sizeof(",cn=")-1;
+ }
+
+ if( conn->c_sasl_bind_mech.bv_len ) {
+ len += conn->c_sasl_bind_mech.bv_len + sizeof(",cn=")-1;
+ }
+
+ /* Build the new dn */
+ c1 = dn->bv_val;
+ dn->bv_val = ch_malloc( len+1 );
+ p = slap_strcopy( dn->bv_val, "uid=" );
+ p = slap_strncopy( p, c1, dn->bv_len );
+
+ if( realm ) {
+ int rlen = dn->bv_len - ( realm - c1 );
+ p = slap_strcopy( p, ",cn=" );
+ p = slap_strncopy( p, realm, rlen );
+ realm[-1] = '@';
+ } else if( user_realm && *user_realm ) {
+ p = slap_strcopy( p, ",cn=" );
+ p = slap_strcopy( p, user_realm );
+ }
+
+ if( conn->c_sasl_bind_mech.bv_len ) {
+ p = slap_strcopy( p, ",cn=" );
+ p = slap_strcopy( p, conn->c_sasl_bind_mech.bv_val );
+ }
+ p = slap_strcopy( p, ",cn=auth" );
+ dn->bv_len = p - dn->bv_val;
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_getdn: u:id converted to %s.\n", dn->bv_val ));
+#else
+ Debug( LDAP_DEBUG_TRACE, "getdn: u:id converted to %s\n", dn->bv_val,0,0 );
+#endif
+ }
+
+ /* All strings are in DN form now. Normalize if needed. */
+ if ( do_norm ) {
+ rc = dnNormalize2( NULL, dn, &dn2 );
+
+ /* User DNs were constructed above and must be freed now */
+ if ( is_dn == SET_U )
+ ch_free( dn->bv_val );
+
+ if ( rc != LDAP_SUCCESS ) {
+ dn->bv_val = NULL;
+ dn->bv_len = 0;
+ return rc;
+ }
+ *dn = dn2;
+ }
+
+ /* Run thru regexp */
+ slap_sasl2dn( conn, dn, &dn2 );
+ if( dn2.bv_val ) {
+ ch_free( dn->bv_val );
+ *dn = dn2;
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+ "slap_sasl_getdn: dn:id converted to %s.\n", dn->bv_val ));
+#else
+ Debug( LDAP_DEBUG_TRACE, "getdn: dn:id converted to %s\n",
+ dn->bv_val, 0, 0 );
+#endif
+ }
+
+ return( LDAP_SUCCESS );