/* Request a set of auxiliary properties * conn connection context * propnames list of auxiliary property names to request ending with * NULL. * * Subsequent calls will add items to the request list. Call with NULL * to clear the request list. * * errors * SASL_OK -- success * SASL_BADPARAM -- bad count/conn parameter * SASL_NOMEM -- out of memory */ int sasl_auxprop_request(sasl_conn_t *conn, const char **propnames) { int result; sasl_server_conn_t *sconn; if(!conn) return SASL_BADPARAM; if(conn->type != SASL_CONN_SERVER) PARAMERROR(conn); sconn = (sasl_server_conn_t *)conn; if(!propnames) { prop_clear(sconn->sparams->propctx,1); return SASL_OK; } result = prop_request(sconn->sparams->propctx, propnames); RETURN(conn, result); }
/* Convert a SASL authcid or authzid into a DN. Store the DN in an * auxiliary property, so that we can refer to it in sasl_authorize * without interfering with anything else. Also, the SASL username * buffer is constrained to 256 characters, and our DNs could be * much longer (SLAP_LDAPDN_MAXLEN, currently set to 8192) */ 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) { Connection *conn = (Connection *)context; struct propctx *props = sasl_auxprop_getctx( sconn ); struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } }; struct berval dn; int rc, which; const char *names[2]; struct berval bvin; *out_len = 0; Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n", conn ? (long) conn->c_connid : -1L, (flags & SASL_CU_AUTHID) ? "authcid" : "authzid", in ? in : "<empty>"); /* If name is too big, just truncate. We don't care, we're * using DNs, not the usernames. */ if ( inlen > out_max ) inlen = out_max-1; /* This is a Simple Bind using SPASSWD. That means the in-directory * userPassword of the Binding user already points at SASL, so it * cannot be used to actually satisfy a password comparison. Just * ignore it, some other mech will process it. */ if ( !conn->c_sasl_bindop || conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) goto done; /* See if we need to add request, can only do it once */ prop_getnames( props, slap_propnames, auxvals ); if ( !auxvals[0].name ) prop_request( props, slap_propnames ); if ( flags & SASL_CU_AUTHID ) which = SLAP_SASL_PROP_AUTHCLEN; else which = SLAP_SASL_PROP_AUTHZLEN; /* Need to store the Connection for auxprop_lookup */ if ( !auxvals[SLAP_SASL_PROP_CONN].values ) { names[0] = slap_propnames[SLAP_SASL_PROP_CONN]; names[1] = NULL; prop_set( props, names[0], (char *)&conn, sizeof( conn ) ); } /* Already been here? */ if ( auxvals[which].values ) goto done; /* Normally we require an authzID to have a u: or dn: prefix. * However, SASL frequently gives us an authzID that is just * an exact copy of the authcID, without a prefix. We need to * detect and allow this condition. If SASL calls canonicalize * with SASL_CU_AUTHID|SASL_CU_AUTHZID this is a no-brainer. * But if it's broken into two calls, we need to remember the * authcID so that we can compare the authzID later. We store * the authcID temporarily in conn->c_sasl_dn. We necessarily * finish Canonicalizing before Authorizing, so there is no * conflict with slap_sasl_authorize's use of this temp var. * * The SASL EXTERNAL mech is backwards from all the other mechs, * it does authzID before the authcID. If we see that authzID * has already been done, don't do anything special with authcID. */ if ( flags == SASL_CU_AUTHID && !auxvals[SLAP_SASL_PROP_AUTHZ].values ) { conn->c_sasl_dn.bv_val = (char *) in; conn->c_sasl_dn.bv_len = 0; } else if ( flags == SASL_CU_AUTHZID && conn->c_sasl_dn.bv_val ) { rc = strcmp( in, conn->c_sasl_dn.bv_val ); conn->c_sasl_dn.bv_val = NULL; /* They were equal, no work needed */ if ( !rc ) goto done; } bvin.bv_val = (char *)in; bvin.bv_len = inlen; rc = slap_sasl_getdn( conn, NULL, &bvin, (char *)user_realm, &dn, (flags & SASL_CU_AUTHID) ? SLAP_GETDN_AUTHCID : SLAP_GETDN_AUTHZID ); if ( rc != LDAP_SUCCESS ) { sasl_seterror( sconn, 0, ldap_err2string( rc ) ); return SASL_NOAUTHZ; } names[0] = slap_propnames[which]; names[1] = NULL; prop_set( props, names[0], (char *)&dn.bv_len, sizeof( dn.bv_len ) ); which++; names[0] = slap_propnames[which]; prop_set( props, names[0], dn.bv_val, dn.bv_len ); Debug( LDAP_DEBUG_ARGS, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n", conn ? (long) conn->c_connid : -1L, names[0]+1, dn.bv_val ? dn.bv_val : "<EMPTY>" ); /* Not needed any more, SASL has copied it */ if ( conn && conn->c_sasl_bindop ) conn->c_sasl_bindop->o_tmpfree( dn.bv_val, conn->c_sasl_bindop->o_tmpmemctx ); done: AC_MEMCPY( out, in, inlen ); out[inlen] = '\0'; *out_len = inlen; return SASL_OK; }