+static int
+backend_check_controls(
+ Operation *op,
+ SlapReply *rs )
+{
+ LDAPControl **ctrls = op->o_ctrls;
+ rs->sr_err = LDAP_SUCCESS;
+
+ if( ctrls ) {
+ for( ; *ctrls != NULL ; ctrls++ ) {
+ if( (*ctrls)->ldctl_iscritical && !ldap_charray_inlist(
+ op->o_bd->be_controls, (*ctrls)->ldctl_oid ) )
+ {
+ rs->sr_text = "control unavailable in context";
+ rs->sr_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ break;
+ }
+ }
+ }
+
+ return rs->sr_err;
+}
+
+int
+backend_check_restrictions(
+ Operation *op,
+ SlapReply *rs,
+ struct berval *opdata )
+{
+ slap_mask_t restrictops;
+ slap_mask_t requires;
+ slap_mask_t opflag;
+ slap_ssf_set_t *ssf;
+ int updateop = 0;
+ int starttls = 0;
+ int session = 0;
+
+ if( op->o_bd ) {
+ if ( backend_check_controls( op, rs ) != LDAP_SUCCESS ) {
+ return rs->sr_err;
+ }
+
+ restrictops = op->o_bd->be_restrictops;
+ requires = op->o_bd->be_requires;
+ ssf = &op->o_bd->be_ssf_set;
+
+ } else {
+ restrictops = global_restrictops;
+ requires = global_requires;
+ ssf = &global_ssf_set;
+ }
+
+ switch( op->o_tag ) {
+ case LDAP_REQ_ADD:
+ opflag = SLAP_RESTRICT_OP_ADD;
+ updateop++;
+ break;
+ case LDAP_REQ_BIND:
+ opflag = SLAP_RESTRICT_OP_BIND;
+ session++;
+ break;
+ case LDAP_REQ_COMPARE:
+ opflag = SLAP_RESTRICT_OP_COMPARE;
+ break;
+ case LDAP_REQ_DELETE:
+ updateop++;
+ opflag = SLAP_RESTRICT_OP_DELETE;
+ break;
+ case LDAP_REQ_EXTENDED:
+ opflag = SLAP_RESTRICT_OP_EXTENDED;
+
+ if( !opdata ) {
+ /* treat unspecified as a modify */
+ opflag = SLAP_RESTRICT_OP_MODIFY;
+ updateop++;
+ break;
+ }
+
+ {
+ if( bvmatch( opdata, &slap_EXOP_START_TLS ) ) {
+ session++;
+ starttls++;
+ break;
+ }
+ }
+
+ {
+ if( bvmatch( opdata, &slap_EXOP_WHOAMI ) ) {
+ break;
+ }
+ }
+
+#ifdef LDAP_EXOP_X_CANCEL
+ {
+ if ( bvmatch( opdata, &slap_EXOP_CANCEL ) ) {
+ break;
+ }
+ }
+#endif
+
+ /* treat everything else as a modify */
+ opflag = SLAP_RESTRICT_OP_MODIFY;
+ updateop++;
+ break;
+
+ case LDAP_REQ_MODIFY:
+ updateop++;
+ opflag = SLAP_RESTRICT_OP_MODIFY;
+ break;
+ case LDAP_REQ_RENAME:
+ updateop++;
+ opflag = SLAP_RESTRICT_OP_RENAME;
+ break;
+ case LDAP_REQ_SEARCH:
+ opflag = SLAP_RESTRICT_OP_SEARCH;
+ break;
+ case LDAP_REQ_UNBIND:
+ session++;
+ opflag = 0;
+ break;
+ default:
+ rs->sr_text = "restrict operations internal error";
+ rs->sr_err = LDAP_OTHER;
+ return rs->sr_err;
+ }
+
+ if ( !starttls ) {
+ /* these checks don't apply to StartTLS */
+
+ rs->sr_err = LDAP_CONFIDENTIALITY_REQUIRED;
+ if( op->o_transport_ssf < ssf->sss_transport ) {
+ rs->sr_text = "transport confidentiality required";
+ return rs->sr_err;
+ }
+
+ if( op->o_tls_ssf < ssf->sss_tls ) {
+ rs->sr_text = "TLS confidentiality required";
+ return rs->sr_err;
+ }
+
+
+ if( op->o_tag == LDAP_REQ_BIND && opdata == NULL ) {
+ /* simple bind specific check */
+ if( op->o_ssf < ssf->sss_simple_bind ) {
+ rs->sr_text = "confidentiality required";
+ return rs->sr_err;
+ }
+ }
+
+ if( op->o_tag != LDAP_REQ_BIND || opdata == NULL ) {
+ /* these checks don't apply to SASL bind */
+
+ if( op->o_sasl_ssf < ssf->sss_sasl ) {
+ rs->sr_text = "SASL confidentiality required";
+ return rs->sr_err;
+ }
+
+ if( op->o_ssf < ssf->sss_ssf ) {
+ rs->sr_text = "confidentiality required";
+ return rs->sr_err;
+ }
+ }
+
+ if( updateop ) {
+ if( op->o_transport_ssf < ssf->sss_update_transport ) {
+ rs->sr_text = "transport update confidentiality required";
+ return rs->sr_err;
+ }
+
+ if( op->o_tls_ssf < ssf->sss_update_tls ) {
+ rs->sr_text = "TLS update confidentiality required";
+ return rs->sr_err;
+ }
+
+ if( op->o_sasl_ssf < ssf->sss_update_sasl ) {
+ rs->sr_text = "SASL update confidentiality required";
+ return rs->sr_err;
+ }
+
+ if( op->o_ssf < ssf->sss_update_ssf ) {
+ rs->sr_text = "update confidentiality required";
+ return rs->sr_err;
+ }
+
+ if( !( global_allows & SLAP_ALLOW_UPDATE_ANON ) &&
+ op->o_ndn.bv_len == 0 )
+ {
+ rs->sr_text = "modifications require authentication";
+ rs->sr_err = LDAP_STRONG_AUTH_REQUIRED;
+ return rs->sr_err;
+ }
+
+#ifdef SLAP_X_LISTENER_MOD
+ if ( op->o_conn->c_listener && ! ( op->o_conn->c_listener->sl_perms & ( op->o_ndn.bv_len > 0 ? S_IWUSR : S_IWOTH ) ) ) {
+ /* no "w" mode means readonly */
+ rs->sr_text = "modifications not allowed on this listener";
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ return rs->sr_err;
+ }
+#endif /* SLAP_X_LISTENER_MOD */
+ }
+ }
+
+ if ( !session ) {
+ /* these checks don't apply to Bind, StartTLS, or Unbind */
+
+ if( requires & SLAP_REQUIRE_STRONG ) {
+ /* should check mechanism */
+ if( ( op->o_transport_ssf < ssf->sss_transport
+ && op->o_authtype == LDAP_AUTH_SIMPLE ) || op->o_dn.bv_len == 0 )
+ {
+ rs->sr_text = "strong authentication required";
+ rs->sr_err = LDAP_STRONG_AUTH_REQUIRED;
+ return rs->sr_err;
+ }
+ }
+
+ if( requires & SLAP_REQUIRE_SASL ) {
+ if( op->o_authtype != LDAP_AUTH_SASL || op->o_dn.bv_len == 0 ) {
+ rs->sr_text = "SASL authentication required";
+ rs->sr_err = LDAP_STRONG_AUTH_REQUIRED;
+ return rs->sr_err;
+ }
+ }
+
+ if( requires & SLAP_REQUIRE_AUTHC ) {
+ if( op->o_dn.bv_len == 0 ) {
+ rs->sr_text = "authentication required";
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ return rs->sr_err;
+ }
+ }
+
+ if( requires & SLAP_REQUIRE_BIND ) {
+ int version;
+ ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
+ version = op->o_conn->c_protocol;
+ ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
+
+ if( !version ) {
+ /* no bind has occurred */
+ rs->sr_text = "BIND required";
+ rs->sr_err = LDAP_OPERATIONS_ERROR;
+ return rs->sr_err;
+ }
+ }
+
+ if( requires & SLAP_REQUIRE_LDAP_V3 ) {
+ if( op->o_protocol < LDAP_VERSION3 ) {
+ /* no bind has occurred */
+ rs->sr_text = "operation restricted to LDAPv3 clients";
+ rs->sr_err = LDAP_OPERATIONS_ERROR;
+ return rs->sr_err;
+ }
+ }
+
+#ifdef SLAP_X_LISTENER_MOD
+ if ( !starttls && op->o_dn.bv_len == 0 ) {
+ if ( op->o_conn->c_listener && ! ( op->o_conn->c_listener->sl_perms & S_IXOTH ) ) {
+ /* no "x" mode means bind required */
+ rs->sr_text = "bind required on this listener";
+ rs->sr_err = LDAP_STRONG_AUTH_REQUIRED;
+ return rs->sr_err;
+ }
+ }
+
+ if ( !starttls && !updateop ) {
+ if ( op->o_conn->c_listener && ! ( op->o_conn->c_listener->sl_perms & ( op->o_dn.bv_len > 0 ? S_IRUSR : S_IROTH ) ) ) {
+ /* no "r" mode means no read */
+ rs->sr_text = "read not allowed on this listener";
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ return rs->sr_err;
+ }
+ }
+#endif /* SLAP_X_LISTENER_MOD */
+
+ }
+
+ if( restrictops & opflag ) {
+ if( restrictops == SLAP_RESTRICT_OP_READS ) {
+ rs->sr_text = "read operations restricted";
+ } else {
+ rs->sr_text = "operation restricted";
+ }
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ return rs->sr_err;
+ }
+
+ rs->sr_err = LDAP_SUCCESS;
+ return rs->sr_err;
+}
+
+int backend_check_referrals( Operation *op, SlapReply *rs )
+{
+ rs->sr_err = LDAP_SUCCESS;
+
+ if( op->o_bd->be_chk_referrals ) {
+ rs->sr_err = op->o_bd->be_chk_referrals( op, rs );
+
+ if( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_REFERRAL ) {
+ send_ldap_result( op, rs );
+ }
+ }
+
+ return rs->sr_err;
+}
+
+int
+be_entry_get_rw(
+ Operation *op,
+ struct berval *ndn,
+ ObjectClass *oc,
+ AttributeDescription *at,
+ int rw,
+ Entry **e )
+{
+ int rc;
+
+ *e = NULL;
+
+ if (op->o_bd == NULL) {
+ rc = LDAP_NO_SUCH_OBJECT;
+ } else if ( op->o_bd->be_fetch ) {
+ rc = ( op->o_bd->be_fetch )( op, ndn,
+ oc, at, rw, e );
+ } else {
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ }
+ return rc;
+}
+