📄 bind.c
字号:
*binddn = slap_empty_bv; *bindcred = slap_empty_bv; if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) { ndn = op->o_conn->c_ndn; } else { ndn = op->o_ndn; } switch ( li->li_idassert_mode ) { case LDAP_BACK_IDASSERT_LEGACY: if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) { if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) ) { *binddn = li->li_idassert_authcDN; *bindcred = li->li_idassert_passwd; dobind = 1; } } break; default: /* NOTE: rootdn can always idassert */ if ( BER_BVISNULL( &ndn ) && li->li_idassert_authz == NULL && !( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) { if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { rs->sr_err = LDAP_INAPPROPRIATE_AUTH; if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); dobind = -1; } } else { rs->sr_err = LDAP_SUCCESS; *binddn = slap_empty_bv; *bindcred = slap_empty_bv; break; } goto done; } else if ( li->li_idassert_authz && !be_isroot( op ) ) { struct berval authcDN; if ( BER_BVISNULL( &ndn ) ) { authcDN = slap_empty_bv; } else { authcDN = ndn; } rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz, &authcDN, &authcDN ); if ( rs->sr_err != LDAP_SUCCESS ) { if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); dobind = -1; } } else { rs->sr_err = LDAP_SUCCESS; *binddn = slap_empty_bv; *bindcred = slap_empty_bv; break; } goto done; } } *binddn = li->li_idassert_authcDN; *bindcred = li->li_idassert_passwd; dobind = 1; break; }done:; return dobind;}static intldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred ){ ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; struct berval ndn; int msgid; int rc; if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) { ndn = op->o_conn->c_ndn; } else { ndn = op->o_ndn; } if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {#ifdef HAVE_CYRUS_SASL void *defaults = NULL; struct berval authzID = BER_BVNULL; int freeauthz = 0; /* if SASL supports native authz, prepare for it */ if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) && ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) ) { switch ( li->li_idassert_mode ) { case LDAP_BACK_IDASSERT_OTHERID: case LDAP_BACK_IDASSERT_OTHERDN: authzID = li->li_idassert_authzID; break; case LDAP_BACK_IDASSERT_ANONYMOUS: BER_BVSTR( &authzID, "dn:" ); break; case LDAP_BACK_IDASSERT_SELF: if ( BER_BVISNULL( &ndn ) ) { /* connection is not authc'd, so don't idassert */ BER_BVSTR( &authzID, "dn:" ); break; } authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len; authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx ); AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ); AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ), ndn.bv_val, ndn.bv_len + 1 ); freeauthz = 1; break; default: break; } } if ( li->li_idassert_secprops != NULL ) { rs->sr_err = ldap_set_option( lc->lc_ld, LDAP_OPT_X_SASL_SECPROPS, (void *)li->li_idassert_secprops ); if ( rs->sr_err != LDAP_OPT_SUCCESS ) { rs->sr_err = LDAP_OTHER; if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); goto done; } } defaults = lutil_sasl_defaults( lc->lc_ld, li->li_idassert_sasl_mech.bv_val, li->li_idassert_sasl_realm.bv_val, li->li_idassert_authcID.bv_val, li->li_idassert_passwd.bv_val, authzID.bv_val ); rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn->bv_val, li->li_idassert_sasl_mech.bv_val, NULL, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults ); rs->sr_err = slap_map_api2result( rs ); if ( rs->sr_err != LDAP_SUCCESS ) { LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } } else { LDAP_BACK_CONN_ISBOUND_SET( lc ); } lutil_sasl_freedefs( defaults ); if ( freeauthz ) { slap_sl_free( authzID.bv_val, op->o_tmpmemctx ); } goto done;#endif /* HAVE_CYRUS_SASL */ } switch ( li->li_idassert_authmethod ) { case LDAP_AUTH_NONE: /* FIXME: do we really need this? */ BER_BVSTR( binddn, "" ); BER_BVSTR( bindcred, "" ); /* fallthru */ case LDAP_AUTH_SIMPLE: rs->sr_err = ldap_sasl_bind( lc->lc_ld, binddn->bv_val, LDAP_SASL_SIMPLE, bindcred, NULL, NULL, &msgid ); rc = ldap_back_op_result( lc, op, rs, msgid, -1, ( sendok | LDAP_BACK_BINDING ) ); break; default: /* unsupported! */ LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED; if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); } goto done; } if ( rc == LDAP_SUCCESS ) { /* set rebind stuff in case of successful proxyAuthz bind, * so that referral chasing is attempted using the right * identity */ LDAP_BACK_CONN_ISBOUND_SET( lc ); ber_bvreplace( &lc->lc_bound_ndn, binddn ); if ( !BER_BVISNULL( &lc->lc_cred ) ) { memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len ); } if ( LDAP_BACK_SAVECRED( li ) ) { ber_bvreplace( &lc->lc_cred, bindcred ); ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); } else { lc->lc_cred.bv_len = 0; } }done:; return LDAP_BACK_CONN_ISBOUND( lc );}/* * ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control * to existing server-side controls if required; if not, * the existing server-side controls are placed in *pctrls. * The caller, after using the controls in client API * operations, if ( *pctrls != op->o_ctrls ), should * free( (*pctrls)[ 0 ] ) and free( *pctrls ). * The function returns success if the control could * be added if required, or if it did nothing; in the future, * it might return some error if it failed. * * if no bind took place yet, but the connection is bound * and the "proxyauthzdn" is set, then bind as "proxyauthzdn" * and explicitly add proxyAuthz the control to every operation * with the dn bound to the connection as control value. * * If no server-side controls are defined for the operation, * simply add the proxyAuthz control; otherwise, if the * proxyAuthz control is not already set, add it as * the first one * * FIXME: is controls order significant for security? * ANSWER: controls ordering and interoperability * must be indicated by the specs of each control; if none * is specified, the order is irrelevant. */intldap_back_proxy_authz_ctrl( struct berval *bound_ndn, int version, slap_idassert_t *si, Operation *op, SlapReply *rs, LDAPControl ***pctrls ){ LDAPControl **ctrls = NULL; int i = 0; slap_idassert_mode_t mode; struct berval assertedID, ndn; int isroot = 0; *pctrls = NULL; rs->sr_err = LDAP_SUCCESS; /* don't proxyAuthz if protocol is not LDAPv3 */ switch ( version ) { case LDAP_VERSION3: break; case 0: if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { break; } /* fall thru */ default: goto done; } /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID, * but if it is not set this test fails. We need a different * means to detect if idassert is enabled */ if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) ) && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) ) ) { goto done; } if ( !op->o_conn || op->o_do_not_cache || ( isroot = be_isroot( op ) ) ) { goto done; } if ( op->o_tag == LDAP_REQ_BIND ) { ndn = op->o_req_ndn; } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) { ndn = op->o_conn->c_ndn; } else { ndn = op->o_ndn; } if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) { if ( op->o_proxy_authz ) { /* * FIXME: we do not want to perform proxyAuthz * on behalf of the client, because this would * be performed with "proxyauthzdn" privileges. * * This might actually be too strict, since * the "proxyauthzdn" authzTo, and each entry's * authzFrom attributes may be crafted * to avoid unwanted proxyAuthz to take place. */#if 0 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "proxyAuthz not allowed within namingContext";#endif goto done; } if ( !BER_BVISNULL( bound_ndn ) ) { goto done; } if ( BER_BVISNULL( &ndn ) ) { goto done; } if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) { goto done; } } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) { if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) ) { /* already asserted in SASL via native authz */ goto done; } } else if ( si->si_authz && !isroot ) { int rc; struct berval authcDN; if ( BER_BVISNULL( &ndn ) ) { authcDN = slap_empty_bv; } else { authcDN = ndn; } rc = slap_sasl_matches( op, si->si_authz, &authcDN, & authcDN ); if ( rc != LDAP_SUCCESS ) { if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { /* ndn is not authorized * to use idassert */ rs->sr_err = rc; } goto done; } } if ( op->o_proxy_authz ) { /* * FIXME: we can: * 1) ignore the already set proxyAuthz control * 2) leave it in place, and don't set ours * 3) add both * 4) reject the operation * * option (4) is very drastic * option (3) will make the remote server reject * the operation, thus being equivalent to (4) * option (2) will likely break the idassert * assumptions, so we cannot accept it; * option (1) means that we are contradicting * the client's reques. * * I think (4) is the only correct choice. */ rs->sr_err = LDAP_UNWILLING_TO_PERFORM; rs->sr_text = "proxyAuthz not allowed within namingContext"; } if ( op->o_is_auth_check ) { mode = LDAP_BACK_IDASSERT_NOASSERT; } else { mode = si->si_mode; } switch ( mode ) { case LDAP_BACK_IDASSERT_LEGACY: /* original behavior: * assert the client's identity */ case LDAP_BACK_IDASSERT_SELF: assertedID = ndn; break; case LDAP_BACK_IDASSERT_ANONYMOUS: /* assert "anonymous" */ assertedID = slap_empty_bv; break; case LDAP_BACK_IDASSERT_NOASSERT: /* don't assert; bind as proxyauthzdn */ goto done; case LDAP_BACK_IDASSERT_OTHERID: case LDAP_BACK_IDASSERT_OTHERDN: /* assert idassert DN */ assertedID = si->si_bc.sb_authzId; break; default: assert( 0 ); } /* if we got here, "" is allowed to proxyAuthz */ if ( BER_BVISNULL( &assertedID ) ) { assertedID = slap_empty_bv; } /* don't idassert the bound DN (ITS#4497) */ if ( dn_match( &assertedID, bound_ndn ) ) { goto done; } if ( op->o_ctrls ) { for ( i = 0; op->o_ctrls[ i ]; i++ ) /* just count ctrls */ ; } ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + 2) + sizeof( LDAPControl ), op->o_tmpmemctx ); ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + 2 ]; ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; ctrls[ 0 ]->ldctl_iscritical = 1; switch ( si->si_mode ) { /* already in u:ID or dn:DN form */ case LDAP_BACK_IDASSERT_OTHERID: case LDAP_BACK_IDASSERT_OTHERDN: ber_dupbv_x( &ctrls[ 0 ]->ldctl_value, &assertedID, op->o_tmpmemctx ); break; /* needs the dn: prefix */ default: ctrls[ 0 ]->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" ); ctrls[ 0 ]->ldctl_value.bv_val = op->o_tmpalloc( ctrls[ 0 ]->ldctl_value.bv_len + 1, op->o_tmpmemctx ); AC_MEMCPY( ctrls[ 0 ]->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) ); AC_MEMCPY( &ctrls[ 0 ]->ldctl_value.bv_val[ STRLENOF( "dn:" ) ], assertedID.bv_val, assertedID.bv_len + 1 ); break; } /* Older versions of <draft-weltman-ldapv3-proxy> required * to encode the value of the authzID (and called it proxyDN); * this hack provides compatibility with those DSAs that * implement it this way */ if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) { struct berval authzID = ctrls[ 0 ]->ldctl_value; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_tag_t tag; ber_init2( ber, 0, LBER_USE_DER ); ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); tag = ber_printf( ber, "O", &authzID ); if ( tag == LBER_ERROR ) { rs->sr_err = LDAP_OTHER; goto free_ber; } if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) { rs->sr_err = LDAP_OTHER; goto free_ber; }free_ber:; op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx ); ber_free_buf( ber ); if ( rs->sr_err != LDAP_SUCCESS ) { op->o_tmpfree( ctrls, op->o_tmpmemctx ); ctrls = NULL; goto done; } } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) { struct berval authzID = ctrls[ 0 ]->ldctl_value, tmp; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_tag_t tag; if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) { op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx ); op->o_tmpfree( ctrls, op->o_tmpmemctx ); ctrls = NULL; rs->sr_err = LDAP_PROTOCOL_ERROR; goto done; } tmp = authzID; tmp.bv_val += STRLENOF( "dn:" ); tmp.bv_len -= STRLENOF( "dn:" ); ber_init2( ber, 0, LBER_USE_DER ); ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); /* apparently, Mozilla API encodes this * as "SEQUENCE { LDAPDN }" */ tag = ber_printf( ber, "{O}", &tmp ); if ( tag == LBER_ERROR ) { rs->sr_err = LDAP_OTHER; goto free_ber2; } if ( ber_flatten2( ber, &ctrls[ 0 ]->ldctl_value, 1 ) == -1 ) { rs->sr_err = LDAP_OTHER; goto free_ber2; }free_ber2:; op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx ); ber_free_buf( ber ); if ( rs->sr_err != LDAP_SUCCESS ) { op->o_tmpfree( ctrls, op->o_tmpmemctx ); ctrls = NULL; goto done; } ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ; } if ( op->o_ctrls ) { for ( i = 0; op->o_ctrls[ i ]; i++ ) { ctrls[ i + 1 ] = op->o_ctrls[ i ]; } } ctrls[ i + 1 ] = NULL;done:; if ( ctrls == NULL ) { ctrls = op->o_ctrls; } *pctrls = ctrls; return rs->sr_err;}intldap_back_proxy_authz_ctrl_free( Operation *op, LDAPControl ***pctrls ){ LDAPControl **ctrls = *pctrls; /* we assume that the first control is the proxyAuthz * added by back-ldap, so it's the only one we explicitly * free */ if ( ctrls && ctrls != op->o_ctrls ) { assert( ctrls[ 0 ] != NULL ); if ( !BER_BVISNULL( &ctrls[ 0 ]->ldctl_value ) ) { op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx ); } op->o_tmpfree( ctrls, op->o_tmpmemctx ); } *pctrls = NULL; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -