void pni_process_init(pn_transport_t *transport, const char *mechanism, const pn_bytes_t *recv) { pni_sasl_t *sasl = transport->sasl; int result = pni_wrap_server_start(sasl, mechanism, recv); if (result==SASL_OK) { // We need to filter out a supplied mech in in the inclusion list // as the client could have used a mech that we support, but that // wasn't on the list we sent. if (!pni_included_mech(sasl->included_mechanisms, pn_bytes(strlen(mechanism), mechanism))) { sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context; sasl_seterror(cyrus_conn, 0, "Client mechanism not in mechanism inclusion list."); result = SASL_FAIL; } } pni_process_server_result(transport, 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; }
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) { Connection *conn = (Connection *)context; /* actually: * (SLAP_SASL_PROP_COUNT - 1) because we skip "conn", * + 1 for NULL termination? */ struct propval auxvals[ SLAP_SASL_PROP_COUNT ] = { { 0 } }; struct berval authcDN, authzDN = BER_BVNULL; int rc; /* Simple Binds don't support proxy authorization, ignore it */ if ( !conn->c_sasl_bindop || conn->c_sasl_bindop->orb_method != LDAP_AUTH_SASL ) return SASL_OK; Debug( LDAP_DEBUG_ARGS, "SASL proxy authorize [conn=%ld]: " "authcid=\"%s\" authzid=\"%s\"\n", conn ? (long) conn->c_connid : -1L, auth_identity, requested_user ); if ( conn->c_sasl_dn.bv_val ) { BER_BVZERO( &conn->c_sasl_dn ); } /* Skip SLAP_SASL_PROP_CONN */ prop_getnames( props, slap_propnames+1, auxvals ); /* Should not happen */ if ( !auxvals[0].values ) { sasl_seterror( sconn, 0, "invalid authcid" ); return SASL_NOAUTHZ; } AC_MEMCPY( &authcDN.bv_len, auxvals[0].values[0], sizeof(authcDN.bv_len) ); authcDN.bv_val = auxvals[1].values ? (char *)auxvals[1].values[0] : NULL; conn->c_sasl_dn = authcDN; /* Nothing to do if no authzID was given */ if ( !auxvals[2].name || !auxvals[2].values ) { goto ok; } AC_MEMCPY( &authzDN.bv_len, auxvals[2].values[0], sizeof(authzDN.bv_len) ); authzDN.bv_val = auxvals[3].values ? (char *)auxvals[3].values[0] : NULL; rc = slap_sasl_authorized( conn->c_sasl_bindop, &authcDN, &authzDN ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "SASL Proxy Authorize [conn=%ld]: " "proxy authorization disallowed (%d)\n", conn ? (long) conn->c_connid : -1L, rc, 0 ); sasl_seterror( sconn, 0, "not authorized" ); return SASL_NOAUTHZ; } /* FIXME: we need yet another dup because slap_sasl_getdn() * is using the bind operation slab */ ber_dupbv( &conn->c_sasl_authz_dn, &authzDN ); ok: if (conn->c_sasl_bindop) { Statslog( LDAP_DEBUG_STATS, "%s BIND authcid=\"%s\" authzid=\"%s\"\n", conn->c_sasl_bindop->o_log_prefix, auth_identity, requested_user, 0, 0 ); } Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: " " proxy authorization allowed authzDN=\"%s\"\n", conn ? (long) conn->c_connid : -1L, authzDN.bv_val ? authzDN.bv_val : "", 0 ); return SASL_OK; }
/* Need to make sure that * *) The authnid is permitted to become the given authzid * *) The authnid is included in the given authreg systems DB */ static int _sx_sasl_proxy_policy(sasl_conn_t *conn, void *ctx, const char *requested_user, int rlen, const char *auth_identity, int alen, const char *realm, int urlen, struct propctx *propctx) { _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx; struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; char *buf, *c; size_t len; int ret; sasl_getprop(conn, SASL_MECHNAME, (const void **) &buf); if (strncmp(buf, "ANONYMOUS", 10) == 0) { /* If they're anonymous, their ID comes from us, so it must be OK! */ return SASL_OK; } else { /* This will break with clients that give requested user as a JID, * where requested_user != auth_identity */ if (!requested_user || !auth_identity || rlen == 0 || alen==0) { sasl_seterror(conn, 0, "Bad identities provided"); return SASL_BADAUTH; } /* No guarantee that realm is NULL terminated - so make a terminated * version before we do anything */ /* XXX - Do we also need to check if realm contains NULL values, * and complain if it does? */ buf = malloc(urlen + 1); strncpy(buf, realm?realm:"", urlen); buf[urlen] = '\0'; creds.realm = buf; /* By this point, SASL's default canon_user plugin has appended the * realm to both the auth_identity, and the requested_user. This * isn't what we want. * auth_identity should be a bare username * requested_user should be a JID * * We can't just remove everything after the '@' as some mechanisms * (such as GSSAPI) use the @ to denote users in foreign realms. */ buf = malloc(alen + 1); strncpy(buf, auth_identity, alen); buf[alen] = '\0'; c = strrchr(buf, '@'); if (c && strcmp(c+1, creds.realm) == 0) *c = '\0'; creds.authnid = buf; /* Now, we need to turn requested_user into a JID * (if it isn't already) * * XXX - This will break with s2s SASL, where the authzid is a domain */ len = rlen; if (sd->stream->req_to) len+=strlen(sd->stream->req_to) + 2; buf = malloc(len + 1); strncpy(buf, requested_user, rlen); buf[rlen] = '\0'; c = strrchr(buf, '@'); if (c && strcmp(c + 1, creds.realm) == 0) *c = '\0'; if (sd->stream->req_to && strchr(buf, '@') == 0) { strcat(buf, "@"); strcat(buf, sd->stream->req_to); } creds.authzid = buf; /* If we start being fancy and allow auth_identity to be different from * requested_user, then this will need to be changed to permit it! */ ret = (sd->ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, &creds, NULL, sd->stream, sd->ctx->cbarg); free((void *)creds.authnid); free((void *)creds.authzid); free((void *)creds.realm); if (ret == sx_sasl_ret_OK) { return SASL_OK; } else { sasl_seterror(conn, 0, "Requested identity not permitted for authorization identity"); return SASL_BADAUTH; } } }