From 5affbfa428c62582f1a0192a033bba304ec90d91 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sun, 10 Apr 2005 23:44:06 +0000 Subject: [PATCH] add SASL bind for acl-authc; use slap_bindconf --- servers/slapd/back-ldap/back-ldap.h | 73 ++++---- servers/slapd/back-ldap/bind.c | 58 ++++++- servers/slapd/back-ldap/chain.c | 2 +- servers/slapd/back-ldap/config.c | 253 +++++++++++++++++++++++----- servers/slapd/back-ldap/init.c | 23 ++- 5 files changed, 319 insertions(+), 90 deletions(-) diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index 48b2e949ad..0c0e826bdd 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -37,56 +37,53 @@ struct ldapconn { struct berval lc_bound_ndn; struct berval lc_local_ndn; int lc_bound; + int lc_ispriv; ldap_pvt_thread_mutex_t lc_mutex; }; -struct ldapauth { - struct berval la_authcID; - struct berval la_authcDN; - struct berval la_passwd; - - struct berval la_authzID; - - int la_authmethod; - int la_sasl_flags; - struct berval la_sasl_mech; - struct berval la_sasl_realm; - -#define LDAP_BACK_AUTH_NONE 0x00U -#define LDAP_BACK_AUTH_NATIVE_AUTHZ 0x01U -#define LDAP_BACK_AUTH_OVERRIDE 0x02U - unsigned la_flags; +/* + * identity assertion modes + */ +enum { + LDAP_BACK_IDASSERT_LEGACY, + LDAP_BACK_IDASSERT_NOASSERT, + LDAP_BACK_IDASSERT_ANONYMOUS, + LDAP_BACK_IDASSERT_SELF, + LDAP_BACK_IDASSERT_OTHERDN, + LDAP_BACK_IDASSERT_OTHERID }; struct ldapinfo { char *url; LDAPURLDesc *lud; - struct ldapauth acl_la; -#define acl_authcDN acl_la.la_authcDN -#define acl_passwd acl_la.la_passwd + + slap_bindconf acl_la; +#define acl_authcID acl_la.sb_authcId +#define acl_authcDN acl_la.sb_binddn +#define acl_passwd acl_la.sb_cred +#define acl_authzID acl_la.sb_authzId +#define acl_authmethod acl_la.sb_method +#define acl_sasl_mech acl_la.sb_saslmech +#define acl_sasl_realm acl_la.sb_realm /* ID assert stuff */ int idassert_mode; -#define LDAP_BACK_IDASSERT_LEGACY 0 -#define LDAP_BACK_IDASSERT_NOASSERT 1 -#define LDAP_BACK_IDASSERT_ANONYMOUS 2 -#define LDAP_BACK_IDASSERT_SELF 3 -#define LDAP_BACK_IDASSERT_OTHERDN 4 -#define LDAP_BACK_IDASSERT_OTHERID 5 - - struct ldapauth idassert_la; -#define idassert_authcID idassert_la.la_authcID -#define idassert_authcDN idassert_la.la_authcDN -#define idassert_passwd idassert_la.la_passwd -#define idassert_authzID idassert_la.la_authzID -#define idassert_authmethod idassert_la.la_authmethod -#define idassert_sasl_flags idassert_la.la_sasl_flags -#define idassert_sasl_mech idassert_la.la_sasl_mech -#define idassert_sasl_realm idassert_la.la_sasl_realm -#define idassert_flags idassert_la.la_flags + + slap_bindconf idassert_la; +#define idassert_authcID idassert_la.sb_authcId +#define idassert_authcDN idassert_la.sb_binddn +#define idassert_passwd idassert_la.sb_cred +#define idassert_authzID idassert_la.sb_authzId +#define idassert_authmethod idassert_la.sb_method +#define idassert_sasl_mech idassert_la.sb_saslmech +#define idassert_sasl_realm idassert_la.sb_realm + + unsigned idassert_flags; +#define LDAP_BACK_AUTH_NONE 0x00U +#define LDAP_BACK_AUTH_NATIVE_AUTHZ 0x01U +#define LDAP_BACK_AUTH_OVERRIDE 0x02U + BerVarray idassert_authz; - - int idassert_ppolicy; /* end of ID assert stuff */ ldap_pvt_thread_mutex_t conn_mutex; diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 446ce1c458..1371f865e7 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -360,8 +360,7 @@ struct ldapconn * ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok ) { struct ldapinfo *li = (struct ldapinfo *)op->o_bd->be_private; - struct ldapconn *lc, lc_curr; - int is_priv = 0; + struct ldapconn *lc, lc_curr = { 0 }; /* Searches for a ldapconn in the avl tree */ @@ -381,7 +380,7 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok ) if ( op->o_do_not_cache || be_isroot( op ) ) { lc_curr.lc_local_ndn = op->o_bd->be_rootndn; lc_curr.lc_conn = NULL; - is_priv = 1; + lc_curr.lc_ispriv = 1; } else { lc_curr.lc_local_ndn = op->o_ndn; @@ -404,9 +403,10 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok ) ldap_pvt_thread_mutex_init( &lc->lc_mutex ); - if ( is_priv ) { + if ( lc_curr.lc_ispriv ) { ber_dupbv( &lc->lc_cred, &li->acl_passwd ); ber_dupbv( &lc->lc_bound_ndn, &li->acl_authcDN ); + lc->lc_ispriv = lc_curr.lc_ispriv; } else { BER_BVZERO( &lc->lc_cred ); @@ -498,6 +498,8 @@ ldap_back_dobind_int( * It allows to use SASL bind and yet proxyAuthz users */ if ( op->o_conn != NULL && + !op->o_do_not_cache && + !be_isroot( op ) && ( BER_BVISNULL( &lc->lc_bound_ndn ) || ( li->idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) { @@ -505,6 +507,50 @@ ldap_back_dobind_int( goto done; } +#ifdef HAVE_CYRUS_SASL + if ( lc->lc_ispriv && li->acl_authmethod == LDAP_AUTH_SASL ) { + void *defaults = NULL; + +#if 0 /* will deal with this later... */ + if ( sasl_secprops != NULL ) { + rs->sr_err = ldap_set_option( lc->lc_ld, LDAP_OPT_X_SASL_SECPROPS, + (void *) sasl_secprops ); + + if ( rs->sr_err != LDAP_OPT_SUCCESS ) { + send_ldap_result( op, rs ); + lc->lc_bound = 0; + goto done; + } + } +#endif + + defaults = lutil_sasl_defaults( lc->lc_ld, + li->acl_sasl_mech.bv_val, + li->acl_sasl_realm.bv_val, + li->acl_authcID.bv_val, + li->acl_passwd.bv_val, + NULL ); + + rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, + li->acl_authcDN.bv_val, + li->acl_sasl_mech.bv_val, NULL, NULL, + LDAP_SASL_QUIET, lutil_sasl_interact, + defaults ); + + lutil_sasl_freedefs( defaults ); + + rs->sr_err = slap_map_api2result( rs ); + if ( rs->sr_err != LDAP_SUCCESS ) { + lc->lc_bound = 0; + send_ldap_result( op, rs ); + + } else { + lc->lc_bound = 1; + } + goto done; + } +#endif /* HAVE_CYRUS_SASL */ + retry:; rs->sr_err = ldap_sasl_bind( lc->lc_ld, lc->lc_bound_ndn.bv_val, @@ -803,7 +849,7 @@ ldap_back_proxy_authz_bind( struct ldapconn *lc, Operation *op, SlapReply *rs ) rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn.bv_val, li->idassert_sasl_mech.bv_val, NULL, NULL, - li->idassert_sasl_flags, lutil_sasl_interact, + LDAP_SASL_QUIET, lutil_sasl_interact, defaults ); lutil_sasl_freedefs( defaults ); @@ -898,7 +944,7 @@ ldap_back_proxy_authz_ctrl( goto done; } - if ( !op->o_conn ) { + if ( !op->o_conn || op->o_do_not_cache || be_isroot( op ) ) { goto done; } diff --git a/servers/slapd/back-ldap/chain.c b/servers/slapd/back-ldap/chain.c index 543960f228..573ab84ebe 100644 --- a/servers/slapd/back-ldap/chain.c +++ b/servers/slapd/back-ldap/chain.c @@ -350,7 +350,7 @@ done:; static int ldap_chain_response( Operation *op, SlapReply *rs ) { - slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; void *private = op->o_bd->be_private; slap_callback *sc = op->o_callback, sc2 = { 0 }; diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 436c713c57..6cd07ba40a 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -41,6 +41,10 @@ static int parse_idassert( BackendDB *be, const char *fname, int lineno, int argc, char **argv ); +static int +parse_acl_auth( BackendDB *be, const char *fname, int lineno, + int argc, char **argv ); + int ldap_back_db_config( BackendDB *be, @@ -258,47 +262,14 @@ ldap_back_db_config( li->flags |= LDAP_BACK_F_PROPAGATE_TLS; } - /* name to use for ldap_back_group */ - } else if ( strcasecmp( argv[0], "acl-authcdn" ) == 0 - || strcasecmp( argv[0], "binddn" ) == 0 ) - { - if ( argc != 2 ) { - fprintf( stderr, - "%s: line %d: missing name in \"%s \" line\n", - fname, lineno, argv[0] ); - return( 1 ); - } - - if ( strcasecmp( argv[0], "binddn" ) == 0 ) { - fprintf( stderr, "%s: line %d: " - "\"binddn\" statement is deprecated; " - "use \"acl-authcDN\" instead\n", - fname, lineno ); - /* FIXME: some day we'll need to throw an error */ - } - - ber_str2bv( argv[1], 0, 1, &li->acl_authcDN ); - - /* password to use for ldap_back_group */ - } else if ( strcasecmp( argv[0], "acl-passwd" ) == 0 - || strcasecmp( argv[0], "bindpw" ) == 0 ) + /* remote ACL stuff... */ + } else if ( strncasecmp( argv[0], "acl-", STRLENOF( "acl-" ) ) == 0 + || strncasecmp( argv[0], "bind", STRLENOF( "bind" ) ) == 0 ) { - if ( argc != 2 ) { - fprintf( stderr, - "%s: line %d: missing password in \"%s \" line\n", - fname, lineno, argv[0] ); - return( 1 ); - } - - if ( strcasecmp( argv[0], "bindpw" ) == 0 ) { - fprintf( stderr, "%s: line %d: " - "\"bindpw\" statement is deprecated; " - "use \"acl-passwd\" instead\n", - fname, lineno ); - /* FIXME: some day we'll need to throw an error */ - } - - ber_str2bv( argv[1], 0, 1, &li->acl_passwd ); + /* NOTE: "bind{DN,pw}" was initially used; it's now + * deprected and undocumented, it can be dropped at some + * point, since nobody should be really using it */ + return parse_acl_auth( be, fname, lineno, argc, argv ); /* identity assertion stuff... */ } else if ( strncasecmp( argv[0], "idassert-", STRLENOF( "idassert-" ) ) == 0 @@ -783,3 +754,205 @@ parse_idassert( return 0; } + +static int +parse_acl_auth( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv +) +{ + struct ldapinfo *li = (struct ldapinfo *) be->be_private; + + /* name to use for remote ACL access */ + if ( strcasecmp( argv[0], "acl-authcdn" ) == 0 + || strcasecmp( argv[0], "binddn" ) == 0 ) + { + struct berval dn; + int rc; + + /* FIXME: "binddn" is no longer documented, and + * temporarily supported for backwards compatibility */ + + if ( argc != 2 ) { + fprintf( stderr, + "%s: line %d: missing name in \"%s \" line\n", + fname, lineno, argv[0] ); + return( 1 ); + } + + if ( !BER_BVISNULL( &li->acl_authcDN ) ) { + fprintf( stderr, "%s: line %d: " + "authcDN already defined; replacing...\n", + fname, lineno ); + ch_free( li->acl_authcDN.bv_val ); + } + + ber_str2bv( argv[1], 0, 0, &dn ); + rc = dnNormalize( 0, NULL, NULL, &dn, &li->acl_authcDN, NULL ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: acl ID \"%s\" is not a valid DN\n", + fname, lineno, argv[1] ); + return 1; + } + + /* password to use for remote ACL access */ + } else if ( strcasecmp( argv[0], "acl-passwd" ) == 0 + || strcasecmp( argv[0], "bindpw" ) == 0 ) + { + /* FIXME: "bindpw" is no longer documented, and + * temporarily supported for backwards compatibility */ + + if ( argc != 2 ) { + fprintf( stderr, + "%s: line %d: missing password in \"%s \" line\n", + fname, lineno, argv[0] ); + return( 1 ); + } + + if ( !BER_BVISNULL( &li->acl_passwd ) ) { + fprintf( stderr, "%s: line %d: " + "passwd already defined; replacing...\n", + fname, lineno ); + ch_free( li->acl_passwd.bv_val ); + } + + ber_str2bv( argv[1], 0, 1, &li->acl_passwd ); + + } else if ( strcasecmp( argv[0], "acl-method" ) == 0 ) { + if ( argc < 2 ) { + fprintf( stderr, + "%s: line %d: missing method in \"%s \" line\n", + fname, lineno, argv[0] ); + return( 1 ); + } + + if ( strcasecmp( argv[1], "none" ) == 0 ) { + /* FIXME: is this at all useful? */ + li->acl_authmethod = LDAP_AUTH_NONE; + + if ( argc != 2 ) { + fprintf( stderr, + "%s: line %d: trailing args in \"%s %s ...\" line ignored\"\n", + fname, lineno, argv[0], argv[1] ); + } + + } else if ( strcasecmp( argv[1], "simple" ) == 0 ) { + li->acl_authmethod = LDAP_AUTH_SIMPLE; + + if ( argc != 2 ) { + fprintf( stderr, + "%s: line %d: trailing args in \"%s %s ...\" line ignored\"\n", + fname, lineno, argv[0], argv[1] ); + } + + } else if ( strcasecmp( argv[1], "sasl" ) == 0 ) { +#ifdef HAVE_CYRUS_SASL + int arg; + + for ( arg = 2; arg < argc; arg++ ) { + if ( strncasecmp( argv[arg], "mech=", STRLENOF( "mech=" ) ) == 0 ) { + char *val = argv[arg] + STRLENOF( "mech=" ); + + if ( !BER_BVISNULL( &li->acl_sasl_mech ) ) { + fprintf( stderr, "%s: line %d: " + "SASL mech already defined; replacing...\n", + fname, lineno ); + ch_free( li->acl_sasl_mech.bv_val ); + } + ber_str2bv( val, 0, 1, &li->acl_sasl_mech ); + + } else if ( strncasecmp( argv[arg], "realm=", STRLENOF( "realm=" ) ) == 0 ) { + char *val = argv[arg] + STRLENOF( "realm=" ); + + if ( !BER_BVISNULL( &li->acl_sasl_realm ) ) { + fprintf( stderr, "%s: line %d: " + "SASL realm already defined; replacing...\n", + fname, lineno ); + ch_free( li->acl_sasl_realm.bv_val ); + } + ber_str2bv( val, 0, 1, &li->acl_sasl_realm ); + + } else if ( strncasecmp( argv[arg], "authcdn=", STRLENOF( "authcdn=" ) ) == 0 ) { + char *val = argv[arg] + STRLENOF( "authcdn=" ); + struct berval dn; + int rc; + + if ( !BER_BVISNULL( &li->acl_authcDN ) ) { + fprintf( stderr, "%s: line %d: " + "SASL authcDN already defined; replacing...\n", + fname, lineno ); + ch_free( li->acl_authcDN.bv_val ); + } + if ( strncasecmp( argv[arg], "dn:", STRLENOF( "dn:" ) ) == 0 ) { + val += STRLENOF( "dn:" ); + } + + ber_str2bv( val, 0, 0, &dn ); + rc = dnNormalize( 0, NULL, NULL, &dn, &li->acl_authcDN, NULL ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: SASL authcdn \"%s\" is not a valid DN\n", + fname, lineno, val ); + return 1; + } + + } else if ( strncasecmp( argv[arg], "authcid=", STRLENOF( "authcid=" ) ) == 0 ) { + char *val = argv[arg] + STRLENOF( "authcid=" ); + + if ( !BER_BVISNULL( &li->acl_authcID ) ) { + fprintf( stderr, "%s: line %d: " + "SASL authcID already defined; replacing...\n", + fname, lineno ); + ch_free( li->acl_authcID.bv_val ); + } + if ( strncasecmp( argv[arg], "u:", STRLENOF( "u:" ) ) == 0 ) { + val += STRLENOF( "u:" ); + } + ber_str2bv( val, 0, 1, &li->acl_authcID ); + + } else if ( strncasecmp( argv[arg], "cred=", STRLENOF( "cred=" ) ) == 0 ) { + char *val = argv[arg] + STRLENOF( "cred=" ); + + if ( !BER_BVISNULL( &li->acl_passwd ) ) { + fprintf( stderr, "%s: line %d: " + "SASL cred already defined; replacing...\n", + fname, lineno ); + ch_free( li->acl_passwd.bv_val ); + } + ber_str2bv( val, 0, 1, &li->acl_passwd ); + + } else { + fprintf( stderr, "%s: line %d: " + "unknown SASL parameter %s\n", + fname, lineno, argv[arg] ); + return 1; + } + } + + li->acl_authmethod = LDAP_AUTH_SASL; + +#else /* !HAVE_CYRUS_SASL */ + fprintf( stderr, "%s: line %d: " + "compile --with-cyrus-sasl to enable SASL auth\n", + fname, lineno ); + return 1; +#endif /* !HAVE_CYRUS_SASL */ + + } else { + fprintf( stderr, "%s: line %d: " + "unhandled acl-method method %s\n", + fname, lineno, argv[1] ); + return 1; + } + + } else { + return SLAP_CONF_UNKNOWN; + } + + return 0; +} + diff --git a/servers/slapd/back-ldap/init.c b/servers/slapd/back-ldap/init.c index 08767a4811..328e3ceaa8 100644 --- a/servers/slapd/back-ldap/init.c +++ b/servers/slapd/back-ldap/init.c @@ -87,9 +87,13 @@ ldap_back_db_init( Backend *be ) return -1; } + BER_BVZERO( &li->acl_authcID ); BER_BVZERO( &li->acl_authcDN ); BER_BVZERO( &li->acl_passwd ); + li->acl_authmethod = LDAP_AUTH_SIMPLE; + BER_BVZERO( &li->acl_sasl_mech ); + li->idassert_mode = LDAP_BACK_IDASSERT_LEGACY; BER_BVZERO( &li->idassert_authcID ); @@ -97,18 +101,15 @@ ldap_back_db_init( Backend *be ) BER_BVZERO( &li->idassert_passwd ); BER_BVZERO( &li->idassert_authzID ); - li->idassert_authz = NULL; li->idassert_authmethod = LDAP_AUTH_SIMPLE; - li->idassert_sasl_flags = LDAP_SASL_QUIET; BER_BVZERO( &li->idassert_sasl_mech ); - BER_BVZERO( &li->idassert_sasl_realm ); - - li->idassert_ppolicy = 0; /* by default, use proxyAuthz control on each operation */ li->idassert_flags = LDAP_BACK_AUTH_NONE; + li->idassert_authz = NULL; + /* initialize flags */ li->flags = LDAP_BACK_F_CHASE_REFERRALS; @@ -217,6 +218,10 @@ ldap_back_db_destroy( ldap_free_urldesc( li->lud ); li->lud = NULL; } + if ( !BER_BVISNULL( &li->acl_authcID ) ) { + ch_free( li->acl_authcID.bv_val ); + BER_BVZERO( &li->acl_authcID ); + } if ( !BER_BVISNULL( &li->acl_authcDN ) ) { ch_free( li->acl_authcDN.bv_val ); BER_BVZERO( &li->acl_authcDN ); @@ -225,6 +230,14 @@ ldap_back_db_destroy( ch_free( li->acl_passwd.bv_val ); BER_BVZERO( &li->acl_passwd ); } + if ( !BER_BVISNULL( &li->acl_sasl_mech ) ) { + ch_free( li->acl_sasl_mech.bv_val ); + BER_BVZERO( &li->acl_sasl_mech ); + } + if ( !BER_BVISNULL( &li->acl_sasl_realm ) ) { + ch_free( li->acl_sasl_realm.bv_val ); + BER_BVZERO( &li->acl_sasl_realm ); + } if ( !BER_BVISNULL( &li->idassert_authcID ) ) { ch_free( li->idassert_authcID.bv_val ); BER_BVZERO( &li->idassert_authcID ); -- 2.39.5