static int #else static void #endif slap_auxprop_lookup( void *glob_context, sasl_server_params_t *sparams, unsigned flags, const char *user, unsigned ulen) { OperationBuffer opbuf = {{ NULL }}; Operation *op = (Operation *)&opbuf; int i, doit = 0; Connection *conn = NULL; lookup_info sl; int rc = LDAP_SUCCESS; #ifdef SLAP_AUXPROP_DONTUSECOPY int dontUseCopy = 0; BackendDB *dontUseCopy_bd = NULL; #endif /* SLAP_AUXPROP_DONTUSECOPY */ sl.list = sparams->utils->prop_get( sparams->propctx ); sl.sparams = sparams; sl.flags = flags; /* Find our DN and conn first */ for( i = 0; sl.list[i].name; i++ ) { if ( sl.list[i].name[0] == '*' ) { if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) { if ( sl.list[i].values && sl.list[i].values[0] ) AC_MEMCPY( &conn, sl.list[i].values[0], sizeof( conn ) ); continue; } if ( flags & SASL_AUXPROP_AUTHZID ) { if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZLEN] )) { if ( sl.list[i].values && sl.list[i].values[0] ) AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0], sizeof( op->o_req_ndn.bv_len ) ); } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZ] )) { if ( sl.list[i].values ) op->o_req_ndn.bv_val = (char *)sl.list[i].values[0]; break; } } if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) { if ( sl.list[i].values && sl.list[i].values[0] ) AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0], sizeof( op->o_req_ndn.bv_len ) ); } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) { if ( sl.list[i].values ) { op->o_req_ndn.bv_val = (char *)sl.list[i].values[0]; if ( !(flags & SASL_AUXPROP_AUTHZID) ) break; } } #ifdef SLAP_AUXPROP_DONTUSECOPY if ( slap_dontUseCopy_propnames != NULL ) { int j; struct berval bv; ber_str2bv( &sl.list[i].name[1], 0, 1, &bv ); for ( j = 0; !BER_BVISNULL( &slap_dontUseCopy_propnames[ j ]); j++ ) { if ( bvmatch( &bv, &slap_dontUseCopy_propnames[ j ] ) ) { dontUseCopy = 1; break; } } } #endif /* SLAP_AUXPROP_DONTUSECOPY */ } } /* Now see what else needs to be fetched */ for( i = 0; sl.list[i].name; i++ ) { const char *name = sl.list[i].name; if ( name[0] == '*' ) { if ( flags & SASL_AUXPROP_AUTHZID ) continue; /* Skip our private properties */ if ( !strcmp( name, slap_propnames[0] )) { i += SLAP_SASL_PROP_COUNT - 1; continue; } name++; } else if ( !(flags & SASL_AUXPROP_AUTHZID ) ) continue; if ( sl.list[i].values ) { if ( !(flags & SASL_AUXPROP_OVERRIDE) ) continue; } doit = 1; break; } if (doit) { slap_callback cb = { NULL, sasl_ap_lookup, NULL, NULL }; cb.sc_private = &sl; op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd ) { /* For rootdn, see if we can use the rootpw */ if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) && !BER_BVISEMPTY( &op->o_bd->be_rootpw )) { struct berval cbv = BER_BVNULL; /* If there's a recognized scheme, see if it's CLEARTEXT */ if ( lutil_passwd_scheme( op->o_bd->be_rootpw.bv_val )) { if ( !strncasecmp( op->o_bd->be_rootpw.bv_val, sc_cleartext.bv_val, sc_cleartext.bv_len )) { /* If it's CLEARTEXT, skip past scheme spec */ cbv.bv_len = op->o_bd->be_rootpw.bv_len - sc_cleartext.bv_len; if ( cbv.bv_len ) { cbv.bv_val = op->o_bd->be_rootpw.bv_val + sc_cleartext.bv_len; } } /* No scheme, use the whole value */ } else { cbv = op->o_bd->be_rootpw; } if ( !BER_BVISEMPTY( &cbv )) { for( i = 0; sl.list[i].name; i++ ) { const char *name = sl.list[i].name; if ( name[0] == '*' ) { if ( flags & SASL_AUXPROP_AUTHZID ) continue; name++; } else if ( !(flags & SASL_AUXPROP_AUTHZID ) ) continue; if ( !strcasecmp(name,"userPassword") ) { sl.sparams->utils->prop_set( sl.sparams->propctx, sl.list[i].name, cbv.bv_val, cbv.bv_len ); break; } } } } #ifdef SLAP_AUXPROP_DONTUSECOPY if ( SLAP_SHADOW( op->o_bd ) && dontUseCopy ) { dontUseCopy_bd = op->o_bd; op->o_bd = frontendDB; } retry_dontUseCopy:; #endif /* SLAP_AUXPROP_DONTUSECOPY */ if ( op->o_bd->be_search ) { SlapReply rs = {REP_RESULT}; #ifdef SLAP_AUXPROP_DONTUSECOPY LDAPControl **save_ctrls = NULL, c; int save_dontUseCopy; #endif /* SLAP_AUXPROP_DONTUSECOPY */ op->o_hdr = conn->c_sasl_bindop->o_hdr; op->o_controls = opbuf.ob_controls; op->o_tag = LDAP_REQ_SEARCH; op->o_dn = conn->c_ndn; op->o_ndn = conn->c_ndn; op->o_callback = &cb; slap_op_time( &op->o_time, &op->o_tincr ); op->o_do_not_cache = 1; op->o_is_auth_check = 1; op->o_req_dn = op->o_req_ndn; op->ors_scope = LDAP_SCOPE_BASE; op->ors_deref = LDAP_DEREF_NEVER; op->ors_tlimit = SLAP_NO_LIMIT; op->ors_slimit = 1; op->ors_filter = &generic_filter; op->ors_filterstr = generic_filterstr; op->o_authz = conn->c_authz; /* FIXME: we want all attributes, right? */ op->ors_attrs = NULL; #ifdef SLAP_AUXPROP_DONTUSECOPY if ( dontUseCopy ) { save_dontUseCopy = op->o_dontUseCopy; if ( !op->o_dontUseCopy ) { int cnt = 0; save_ctrls = op->o_ctrls; if ( op->o_ctrls ) { for ( ; op->o_ctrls[ cnt ]; cnt++ ) ; } op->o_ctrls = op->o_tmpcalloc( sizeof(LDAPControl *), cnt + 2, op->o_tmpmemctx ); if ( cnt ) { for ( cnt = 0; save_ctrls[ cnt ]; cnt++ ) { op->o_ctrls[ cnt ] = save_ctrls[ cnt ]; } } c.ldctl_oid = LDAP_CONTROL_DONTUSECOPY; c.ldctl_iscritical = 1; BER_BVZERO( &c.ldctl_value ); op->o_ctrls[ cnt ] = &c; } op->o_dontUseCopy = SLAP_CONTROL_CRITICAL; } #endif /* SLAP_AUXPROP_DONTUSECOPY */ rc = op->o_bd->be_search( op, &rs ); #ifdef SLAP_AUXPROP_DONTUSECOPY if ( dontUseCopy ) { if ( save_ctrls != op->o_ctrls ) { op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx ); op->o_ctrls = save_ctrls; op->o_dontUseCopy = save_dontUseCopy; } if ( rs.sr_err == LDAP_UNAVAILABLE && slap_dontUseCopy_ignore ) { op->o_bd = dontUseCopy_bd; dontUseCopy = 0; goto retry_dontUseCopy; } } #endif /* SLAP_AUXPROP_DONTUSECOPY */ } } } #if SASL_VERSION_FULL >= 0x020118 return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK; #endif }
static int #else static void #endif slap_auxprop_lookup( void *glob_context, sasl_server_params_t *sparams, unsigned flags, const char *user, unsigned ulen) { OperationBuffer opbuf = {{ NULL }}; Operation *op = (Operation *)&opbuf; int i, doit = 0; Connection *conn = NULL; lookup_info sl; int rc = LDAP_SUCCESS; sl.list = sparams->utils->prop_get( sparams->propctx ); sl.sparams = sparams; sl.flags = flags; /* Find our DN and conn first */ for( i = 0; sl.list[i].name; i++ ) { if ( sl.list[i].name[0] == '*' ) { if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) { if ( sl.list[i].values && sl.list[i].values[0] ) AC_MEMCPY( &conn, sl.list[i].values[0], sizeof( conn ) ); continue; } if ( flags & SASL_AUXPROP_AUTHZID ) { if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZLEN] )) { if ( sl.list[i].values && sl.list[i].values[0] ) AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0], sizeof( op->o_req_ndn.bv_len ) ); } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZ] )) { if ( sl.list[i].values ) op->o_req_ndn.bv_val = (char *)sl.list[i].values[0]; break; } } if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) { if ( sl.list[i].values && sl.list[i].values[0] ) AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0], sizeof( op->o_req_ndn.bv_len ) ); } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) { if ( sl.list[i].values ) { op->o_req_ndn.bv_val = (char *)sl.list[i].values[0]; if ( !(flags & SASL_AUXPROP_AUTHZID) ) break; } } } } /* we don't know anything about this, ignore it */ if ( !conn ) { rc = LDAP_SUCCESS; goto done; } /* Now see what else needs to be fetched */ for( i = 0; sl.list[i].name; i++ ) { const char *name = sl.list[i].name; if ( name[0] == '*' ) { if ( flags & SASL_AUXPROP_AUTHZID ) continue; /* Skip our private properties */ if ( !strcmp( name, slap_propnames[0] )) { i += SLAP_SASL_PROP_COUNT - 1; continue; } name++; } else if ( !(flags & SASL_AUXPROP_AUTHZID ) ) continue; if ( sl.list[i].values ) { if ( !(flags & SASL_AUXPROP_OVERRIDE) ) continue; } doit = 1; break; } if (doit) { slap_callback cb = { NULL, sasl_ap_lookup, NULL, NULL }; cb.sc_private = &sl; op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd ) { /* For rootdn, see if we can use the rootpw */ if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) && !BER_BVISEMPTY( &op->o_bd->be_rootpw )) { struct berval cbv = BER_BVNULL; /* If there's a recognized scheme, see if it's CLEARTEXT */ if ( lutil_passwd_scheme( op->o_bd->be_rootpw.bv_val )) { if ( !strncasecmp( op->o_bd->be_rootpw.bv_val, sc_cleartext.bv_val, sc_cleartext.bv_len )) { /* If it's CLEARTEXT, skip past scheme spec */ cbv.bv_len = op->o_bd->be_rootpw.bv_len - sc_cleartext.bv_len; if ( cbv.bv_len ) { cbv.bv_val = op->o_bd->be_rootpw.bv_val + sc_cleartext.bv_len; } } /* No scheme, use the whole value */ } else { cbv = op->o_bd->be_rootpw; } if ( !BER_BVISEMPTY( &cbv )) { for( i = 0; sl.list[i].name; i++ ) { const char *name = sl.list[i].name; if ( name[0] == '*' ) { if ( flags & SASL_AUXPROP_AUTHZID ) continue; name++; } else if ( !(flags & SASL_AUXPROP_AUTHZID ) ) continue; if ( !strcasecmp(name,"userPassword") ) { sl.sparams->utils->prop_set( sl.sparams->propctx, sl.list[i].name, cbv.bv_val, cbv.bv_len ); break; } } } } if ( op->o_bd->be_search ) { SlapReply rs = {REP_RESULT}; op->o_hdr = conn->c_sasl_bindop->o_hdr; op->o_controls = opbuf.ob_controls; op->o_tag = LDAP_REQ_SEARCH; op->o_dn = conn->c_ndn; op->o_ndn = conn->c_ndn; op->o_callback = &cb; slap_op_time( &op->o_time, &op->o_tincr ); op->o_do_not_cache = 1; op->o_is_auth_check = 1; op->o_req_dn = op->o_req_ndn; op->ors_scope = LDAP_SCOPE_BASE; op->ors_deref = LDAP_DEREF_NEVER; op->ors_tlimit = SLAP_NO_LIMIT; op->ors_slimit = 1; op->ors_filter = &generic_filter; op->ors_filterstr = generic_filterstr; op->o_authz = conn->c_authz; /* FIXME: we want all attributes, right? */ op->ors_attrs = NULL; rc = op->o_bd->be_search( op, &rs ); } } } done:; #if SASL_VERSION_FULL >= 0x020118 return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK; #endif }
static int sasl_ap_lookup( Operation *op, SlapReply *rs ) { BerVarray bv; AttributeDescription *ad; Attribute *a; const char *text; int rc, i; lookup_info *sl = (lookup_info *)op->o_callback->sc_private; /* return the actual error code, * to allow caller to handle specific errors */ if (rs->sr_type != REP_SEARCH) return rs->sr_err; for( i = 0; sl->list[i].name; i++ ) { const char *name = sl->list[i].name; if ( name[0] == '*' ) { if ( sl->flags & SASL_AUXPROP_AUTHZID ) continue; /* Skip our private properties */ if ( !strcmp( name, slap_propnames[0] )) { i += SLAP_SASL_PROP_COUNT - 1; continue; } name++; } else if ( !(sl->flags & SASL_AUXPROP_AUTHZID ) ) continue; if ( sl->list[i].values ) { if ( !(sl->flags & SASL_AUXPROP_OVERRIDE) ) continue; } ad = NULL; rc = slap_str2ad( name, &ad, &text ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "slap_ap_lookup: str2ad(%s): %s\n", name, text, 0 ); continue; } /* If it's the rootdn and a rootpw was present, we already set * it so don't override it here. */ if ( ad == slap_schema.si_ad_userPassword && sl->list[i].values && be_isroot_dn( op->o_bd, &op->o_req_ndn )) continue; a = attr_find( rs->sr_entry->e_attrs, ad ); if ( !a ) continue; if ( ! access_allowed( op, rs->sr_entry, ad, NULL, ACL_AUTH, NULL ) ) { continue; } if ( sl->list[i].values && ( sl->flags & SASL_AUXPROP_OVERRIDE ) ) { sl->sparams->utils->prop_erase( sl->sparams->propctx, sl->list[i].name ); } for ( bv = a->a_vals; bv->bv_val; bv++ ) { /* ITS#3846 don't give hashed passwords to SASL */ if ( ad == slap_schema.si_ad_userPassword && bv->bv_val[0] == '{' /*}*/ ) { if ( lutil_passwd_scheme( bv->bv_val ) ) { /* If it's not a recognized scheme, just assume it's * a cleartext password that happened to include brackets. * * If it's a recognized scheme, skip this value, unless the * scheme is {CLEARTEXT}. In that case, skip over the * scheme name and use the remainder. If there is nothing * past the scheme name, skip this value. */ #ifdef SLAPD_CLEARTEXT if ( !strncasecmp( bv->bv_val, sc_cleartext.bv_val, sc_cleartext.bv_len )) { struct berval cbv; cbv.bv_len = bv->bv_len - sc_cleartext.bv_len; if ( cbv.bv_len > 0 ) { cbv.bv_val = bv->bv_val + sc_cleartext.bv_len; sl->sparams->utils->prop_set( sl->sparams->propctx, sl->list[i].name, cbv.bv_val, cbv.bv_len ); } } #endif continue; } } sl->sparams->utils->prop_set( sl->sparams->propctx, sl->list[i].name, bv->bv_val, bv->bv_len ); } } return LDAP_SUCCESS; }
static int dds_op_add( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; dds_info_t *di = on->on_bi.bi_private; int is_dynamicObject; if ( DDS_OFF( di ) ) { return SLAP_CB_CONTINUE; } is_dynamicObject = is_entry_dynamicObject( op->ora_e ); /* FIXME: do not allow this right now, pending clarification */ if ( is_dynamicObject ) { rs->sr_err = LDAP_SUCCESS; if ( is_entry_referral( op->ora_e ) ) { rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "a referral cannot be a dynamicObject"; } else if ( is_entry_alias( op->ora_e ) ) { rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "an alias cannot be a dynamicObject"; } if ( rs->sr_err != LDAP_SUCCESS ) { op->o_bd->bd_info = (BackendInfo *)on->on_info; send_ldap_result( op, rs ); return rs->sr_err; } } /* we don't allow dynamicObjects to have static subordinates */ if ( !dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) { struct berval p_ndn; Entry *e = NULL; int rc; BackendInfo *bi = op->o_bd->bd_info; dnParent( &op->o_req_ndn, &p_ndn ); op->o_bd->bd_info = (BackendInfo *)on->on_info; rc = be_entry_get_rw( op, &p_ndn, slap_schema.si_oc_dynamicObject, NULL, 0, &e ); if ( rc == LDAP_SUCCESS && e != NULL ) { if ( !is_dynamicObject ) { /* return referral only if "disclose" * is granted on the object */ if ( ! access_allowed( op, e, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { rc = rs->sr_err = LDAP_NO_SUCH_OBJECT; send_ldap_result( op, rs ); } else { rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION; send_ldap_error( op, rs, rc, "no static subordinate entries allowed for dynamicObject" ); } } be_entry_release_r( op, e ); if ( rc != LDAP_SUCCESS ) { return rc; } } op->o_bd->bd_info = bi; } /* handle dynamic object operational attr(s) */ if ( is_dynamicObject ) { time_t ttl, expire; char ttlbuf[STRLENOF("31557600") + 1]; char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; struct berval bv; if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { ldap_pvt_thread_mutex_lock( &di->di_mutex ); rs->sr_err = ( di->di_max_dynamicObjects && di->di_num_dynamicObjects >= di->di_max_dynamicObjects ); ldap_pvt_thread_mutex_unlock( &di->di_mutex ); if ( rs->sr_err ) { op->o_bd->bd_info = (BackendInfo *)on->on_info; send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "too many dynamicObjects in context" ); return rs->sr_err; } } ttl = DDS_DEFAULT_TTL( di ); /* assert because should be checked at configure */ assert( ttl <= DDS_RF2589_MAX_TTL ); bv.bv_val = ttlbuf; bv.bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl ); assert( bv.bv_len < sizeof( ttlbuf ) ); /* FIXME: apparently, values in op->ora_e are malloc'ed * on the thread's slab; works fine by chance, * only because the attribute doesn't exist yet. */ assert( attr_find( op->ora_e->e_attrs, slap_schema.si_ad_entryTtl ) == NULL ); attr_merge_one( op->ora_e, slap_schema.si_ad_entryTtl, &bv, &bv ); expire = slap_get_time() + ttl; bv.bv_val = tsbuf; bv.bv_len = sizeof( tsbuf ); slap_timestamp( &expire, &bv ); assert( attr_find( op->ora_e->e_attrs, ad_entryExpireTimestamp ) == NULL ); attr_merge_one( op->ora_e, ad_entryExpireTimestamp, &bv, &bv ); /* if required, install counter callback */ if ( di->di_max_dynamicObjects > 0) { slap_callback *sc; sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx ); sc->sc_cleanup = dds_freeit_cb; sc->sc_response = dds_counter_cb; sc->sc_private = di; sc->sc_next = op->o_callback; op->o_callback = sc; } } return SLAP_CB_CONTINUE; }