static int slap_auxprop_store( void *glob_context, sasl_server_params_t *sparams, struct propctx *prctx, const char *user, unsigned ulen) { Operation op = {0}; Opheader oph; SlapReply rs = {REP_RESULT}; int rc, i; unsigned j; Connection *conn = NULL; const struct propval *pr; Modifications *modlist = NULL, **modtail = &modlist, *mod; slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; char textbuf[SLAP_TEXT_BUFLEN]; const char *text; size_t textlen = sizeof(textbuf); /* just checking if we are enabled */ if (!prctx) return SASL_OK; if (!sparams || !user) return SASL_BADPARAM; pr = sparams->utils->prop_get( sparams->propctx ); /* Find our DN and conn first */ for( i = 0; pr[i].name; i++ ) { if ( pr[i].name[0] == '*' ) { if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_CONN] ) ) { if ( pr[i].values && pr[i].values[0] ) AC_MEMCPY( &conn, pr[i].values[0], sizeof( conn ) ); continue; } if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) { if ( pr[i].values && pr[i].values[0] ) AC_MEMCPY( &op.o_req_ndn.bv_len, pr[i].values[0], sizeof( op.o_req_ndn.bv_len ) ); } else if ( !strcmp( pr[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) { if ( pr[i].values ) op.o_req_ndn.bv_val = (char *)pr[i].values[0]; } } } if (!conn || !op.o_req_ndn.bv_val) return SASL_BADPARAM; op.o_bd = select_backend( &op.o_req_ndn, 1 ); if ( !op.o_bd || !op.o_bd->bd_info->bi_op_modify ) return SASL_FAIL; pr = sparams->utils->prop_get( prctx ); if (!pr) return SASL_BADPARAM; for (i=0; pr[i].name; i++); if (!i) return SASL_BADPARAM; for (i=0; pr[i].name; i++) { mod = (Modifications *)ch_malloc( sizeof(Modifications) ); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_flags = 0; ber_str2bv( pr[i].name, 0, 0, &mod->sml_type ); mod->sml_numvals = pr[i].nvalues; mod->sml_values = (struct berval *)ch_malloc( (pr[i].nvalues + 1) * sizeof(struct berval)); for (j=0; j<pr[i].nvalues; j++) { ber_str2bv( pr[i].values[j], 0, 1, &mod->sml_values[j]); } BER_BVZERO( &mod->sml_values[j] ); mod->sml_nvalues = NULL; mod->sml_desc = NULL; *modtail = mod; modtail = &mod->sml_next; } *modtail = NULL; rc = slap_mods_check( &op, modlist, &text, textbuf, textlen, NULL ); if ( rc == LDAP_SUCCESS ) { rc = slap_mods_no_user_mod_check( &op, modlist, &text, textbuf, textlen ); if ( rc == LDAP_SUCCESS ) { if ( conn->c_sasl_bindop ) { op.o_hdr = conn->c_sasl_bindop->o_hdr; } else { op.o_hdr = &oph; memset( &oph, 0, sizeof(oph) ); operation_fake_init( conn, &op, ldap_pvt_thread_pool_context(), 0 ); } op.o_tag = LDAP_REQ_MODIFY; op.o_ndn = op.o_req_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.orm_modlist = modlist; rc = slap_biglock_call_be( op_modify, &op, &rs ); } } slap_mods_free( modlist, 1 ); return rc != LDAP_SUCCESS ? SASL_FAIL : SASL_OK; }
int fe_op_modify( Operation *op, SlapReply *rs ) { BackendDB *op_be, *bd = op->o_bd; char textbuf[ SLAP_TEXT_BUFLEN ]; size_t textlen = sizeof( textbuf ); if ( BER_BVISEMPTY( &op->o_req_ndn ) ) { Debug( LDAP_DEBUG_ANY, "%s do_modify: root dse!\n", op->o_log_prefix ); send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "modify upon the root DSE not supported" ); goto cleanup; } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { Debug( LDAP_DEBUG_ANY, "%s do_modify: subschema subentry!\n", op->o_log_prefix ); send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "modification of subschema subentry not supported" ); goto cleanup; } /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd == NULL ) { op->o_bd = bd; rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); if ( !rs->sr_ref ) { rs->sr_ref = default_referral; } if ( rs->sr_ref != NULL ) { rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if ( rs->sr_ref != default_referral ) { ber_bvarray_free( rs->sr_ref ); } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "no global superior knowledge" ); } goto cleanup; } /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { op->o_bd = select_backend( &op->o_req_ndn, 0 ); } /* check restrictions */ if ( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } /* check for referrals */ if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { goto cleanup; } rs->sr_err = slap_mods_obsolete_check( op, op->orm_modlist, &rs->sr_text, textbuf, textlen ); if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } /* check for modify/increment support */ if ( op->orm_increment && !SLAP_INCREMENT( op->o_bd ) ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "modify/increment not supported in context" ); goto cleanup; } /* * do the modify if 1 && (2 || 3) * 1) there is a modify function implemented in this backend; * 2) this backend is master for what it holds; * 3) it's a replica and the dn supplied is the update_ndn. */ if ( op->o_bd->bd_info->bi_op_modify ) { /* do the update here */ int repl_user = be_isupdate( op ); /* * Multimaster slapd does not have to check for replicator dn * because it accepts each modify request */ if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn ); op->o_bd = op_be; if ( !update ) { rs->sr_err = slap_mods_no_user_mod_check( op, op->orm_modlist, &rs->sr_text, textbuf, textlen ); if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } } slap_biglock_call_be( op_modify, op, rs ); } else { /* send a referral */ BerVarray defref = op->o_bd->be_update_refs ? op->o_bd->be_update_refs : default_referral; if ( defref != NULL ) { rs->sr_ref = referral_rewrite( defref, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); if ( rs->sr_ref == NULL ) { /* FIXME: must duplicate, because * overlays may muck with it */ rs->sr_ref = defref; } rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if ( rs->sr_ref != defref ) { ber_bvarray_free( rs->sr_ref ); } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "shadow context; no update referral" ); } } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "operation not supported within namingContext" ); } cleanup:; op->o_bd = bd; return rs->sr_err; }
int do_modify( Operation *op, SlapReply *rs ) { struct berval dn = BER_BVNULL; char textbuf[ SLAP_TEXT_BUFLEN ]; size_t textlen = sizeof( textbuf ); #ifdef LDAP_DEBUG Modifications *tmp; #endif Debug( LDAP_DEBUG_TRACE, "%s do_modify\n", op->o_log_prefix ); /* * Parse the modify request. It looks like this: * * ModifyRequest := [APPLICATION 6] SEQUENCE { * name DistinguishedName, * mods SEQUENCE OF SEQUENCE { * operation ENUMERATED { * add (0), * delete (1), * replace (2) * }, * modification SEQUENCE { * type AttributeType, * values SET OF AttributeValue * } * } * } */ if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) { Debug( LDAP_DEBUG_ANY, "%s do_modify: ber_scanf failed\n", op->o_log_prefix ); send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); return SLAPD_DISCONNECT; } Debug( LDAP_DEBUG_ARGS, "%s do_modify: dn (%s)\n", op->o_log_prefix, dn.bv_val ); rs->sr_err = slap_parse_modlist( op, rs, op->o_ber, &op->oq_modify ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_modify: slap_parse_modlist failed err=%d msg=%s\n", op->o_log_prefix, rs->sr_err, rs->sr_text ); send_ldap_result( op, rs ); goto cleanup; } if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_modify: get_ctrls failed\n", op->o_log_prefix ); /* get_ctrls has sent results. Now clean up. */ goto cleanup; } rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); if( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s do_modify: invalid dn (%s)\n", op->o_log_prefix, dn.bv_val ); send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); goto cleanup; } op->orm_no_opattrs = 0; #ifdef LDAP_DEBUG Debug( LDAP_DEBUG_ARGS, "%s modifications:\n", op->o_log_prefix ); for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) { Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n", tmp->sml_op == LDAP_MOD_ADD ? "add" : (tmp->sml_op == LDAP_MOD_INCREMENT ? "increment" : (tmp->sml_op == LDAP_MOD_DELETE ? "delete" : "replace")), tmp->sml_type.bv_val ); if ( tmp->sml_values == NULL ) { Debug( LDAP_DEBUG_ARGS, "%s\n", "\t\tno values" ); } else if ( BER_BVISNULL( &tmp->sml_values[ 0 ] ) ) { Debug( LDAP_DEBUG_ARGS, "%s\n", "\t\tzero values" ); } else if ( BER_BVISNULL( &tmp->sml_values[ 1 ] ) ) { Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n", "\t\tone value", (long) tmp->sml_values[0].bv_len ); } else { Debug( LDAP_DEBUG_ARGS, "%s\n", "\t\tmultiple values" ); } } if ( StatslogTest( LDAP_DEBUG_STATS ) ) { char abuf[BUFSIZ/2], *ptr = abuf; int len = 0; Statslog( LDAP_DEBUG_STATS, "%s MOD dn=\"%s\"\n", op->o_log_prefix, op->o_req_dn.bv_val ); for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) { if (len + 1 + tmp->sml_type.bv_len > sizeof(abuf)) { Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n", op->o_log_prefix, abuf ); len = 0; ptr = abuf; if( 1 + tmp->sml_type.bv_len > sizeof(abuf)) { Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n", op->o_log_prefix, tmp->sml_type.bv_val ); continue; } } if (len) { *ptr++ = ' '; len++; } ptr = lutil_strcopy(ptr, tmp->sml_type.bv_val); len += tmp->sml_type.bv_len; } if (len) { Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n", op->o_log_prefix, abuf ); } } #endif /* LDAP_DEBUG */ rs->sr_err = slap_mods_check( op, op->orm_modlist, &rs->sr_text, textbuf, textlen, NULL ); if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } op->o_bd = frontendDB; rs->sr_err = slap_biglock_call_be( op_modify, op, rs ); #ifdef LDAP_X_TXN if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) { /* skip cleanup */ return rs->sr_err; } #endif cleanup: op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); if ( op->orm_modlist != NULL ) slap_mods_free( op->orm_modlist, 1 ); return rs->sr_err; }
static int dds_op_extended( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; dds_info_t *di = on->on_bi.bi_private; if ( DDS_OFF( di ) ) { return SLAP_CB_CONTINUE; } if ( bvmatch( &op->ore_reqoid, &slap_EXOP_REFRESH ) ) { Entry *e = NULL; time_t ttl; BackendDB db = *op->o_bd; SlapReply rs2 = { REP_RESULT }; Operation op2 = *op; slap_callback sc = { 0 }; Modifications ttlmod = { { 0 } }; struct berval ttlvalues[ 2 ]; char ttlbuf[STRLENOF("31557600") + 1]; rs->sr_err = slap_parse_refresh( op->ore_reqdata, NULL, &ttl, &rs->sr_text, NULL ); assert( rs->sr_err == LDAP_SUCCESS ); if ( ttl <= 0 || ttl > DDS_RF2589_MAX_TTL ) { rs->sr_err = LDAP_PROTOCOL_ERROR; rs->sr_text = "invalid time-to-live for dynamicObject"; return rs->sr_err; } if ( ttl > di->di_max_ttl ) { /* FIXME: I don't understand if this has to be an error, * or an indication that the requested Ttl has been * shortened to di->di_max_ttl >= 1 day */ rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; rs->sr_text = "time-to-live for dynamicObject exceeds limit"; return rs->sr_err; } if ( di->di_min_ttl && ttl < di->di_min_ttl ) { ttl = di->di_min_ttl; } /* This does not apply to multi-master case */ if ( !( !SLAP_SINGLE_SHADOW( op->o_bd ) || be_isupdate( op ) ) ) { /* we SHOULD return a referral in this case */ BerVarray defref = op->o_bd->be_update_refs ? op->o_bd->be_update_refs : default_referral; if ( defref != NULL ) { rs->sr_ref = referral_rewrite( op->o_bd->be_update_refs, NULL, NULL, LDAP_SCOPE_DEFAULT ); if ( rs->sr_ref ) { rs->sr_flags |= REP_REF_MUSTBEFREED; } else { rs->sr_ref = defref; } rs->sr_err = LDAP_REFERRAL; } else { rs->sr_text = "shadow context; no update referral"; rs->sr_err = LDAP_UNWILLING_TO_PERFORM; } return rs->sr_err; } assert( !BER_BVISNULL( &op->o_req_ndn ) ); /* check if exists but not dynamicObject */ op->o_bd->bd_info = (BackendInfo *)on->on_info; rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn, slap_schema.si_oc_dynamicObject, NULL, 0, &e ); if ( rs->sr_err != LDAP_SUCCESS ) { rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) { /* return referral only if "disclose" * is granted on the object */ if ( ! access_allowed( op, e, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } else { rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "refresh operation only applies to dynamic objects"; } be_entry_release_r( op, e ); } else { rs->sr_err = LDAP_NO_SUCH_OBJECT; } return rs->sr_err; } else if ( e != NULL ) { be_entry_release_r( op, e ); } /* we require manage privileges on the entryTtl, * and fake a Relax control */ op2.o_tag = LDAP_REQ_MODIFY; op2.o_bd = &db; db.bd_info = (BackendInfo *)on->on_info; op2.o_callback = ≻ sc.sc_response = slap_null_cb; op2.o_relax = SLAP_CONTROL_CRITICAL; op2.orm_modlist = &ttlmod; ttlmod.sml_op = LDAP_MOD_REPLACE; ttlmod.sml_flags = SLAP_MOD_MANAGING; ttlmod.sml_desc = slap_schema.si_ad_entryTtl; ttlmod.sml_values = ttlvalues; ttlmod.sml_numvals = 1; ttlvalues[ 0 ].bv_val = ttlbuf; ttlvalues[ 0 ].bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl ); BER_BVZERO( &ttlvalues[ 1 ] ); /* the entryExpireTimestamp is added by modify */ rs->sr_err = slap_biglock_call_be( op_modify, &op2, &rs2 ); if ( ttlmod.sml_next != NULL ) { slap_mods_free( ttlmod.sml_next, 1 ); } if ( rs->sr_err == LDAP_SUCCESS ) { int rc; BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_init_w_nullc( ber, LBER_USE_DER ); rc = ber_printf( ber, "{tiN}", LDAP_TAG_EXOP_REFRESH_RES_TTL, (int)ttl ); if ( rc < 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; } else { (void)ber_flatten( ber, &rs->sr_rspdata ); rs->sr_rspoid = ch_strdup( slap_EXOP_REFRESH.bv_val ); Log3( LDAP_DEBUG_TRACE, LDAP_LEVEL_INFO, "%s REFRESH dn=\"%s\" TTL=%ld\n", op->o_log_prefix, op->o_req_ndn.bv_val, ttl ); } ber_free_buf( ber ); } return rs->sr_err; } return SLAP_CB_CONTINUE; }