process_read_entry_controls(Slapi_PBlock *pb, char *oid)
{
    struct berval *req_value = NULL;
    struct berval *res_value = NULL;
    LDAPControl **req_ctls = NULL;
    Slapi_Entry *e = NULL;
    char **attrs = NULL;
    int attr_count = 0;
    int iscritical = 0;
    int all_attrs = 0;
    int no_attrs = 0;
    int rc = 0;

    slapi_pblock_get(pb, SLAPI_REQCONTROLS, &req_ctls);

    /*
     * Check for the PRE Read Entry Control, and return the pre-modified entry
     */
    if (slapi_control_present(req_ctls, oid, &req_value, &iscritical)) {
        BerElement *req_ber = NULL;
        Operation *op = NULL;
        slapi_pblock_get(pb, SLAPI_OPERATION, &op);
        if (op == NULL) {
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "op is NULL\n");
            rc = -1;
            goto done;
        }

        if (strcmp(oid, LDAP_CONTROL_PRE_READ_ENTRY) == 0) {
            /* first verify this is the correct operation for a pre-read entry control */
            if (op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_DELETE ||
                op->o_tag == LDAP_REQ_MODDN) {
                slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
            } else {
                /* Ok, read control not used for this type of operation */
                slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Read Entry Controls "
                                                                            "can not be used for a %s operation.\n",
                              op_to_string(op->o_tag));
                rc = -1;
                goto done;
            }
        } else {
            /* first verify this is the correct operation for a post-read entry control */
            if (op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_ADD ||
                op->o_tag == LDAP_REQ_MODDN) {
                slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
            } else {
                /* Ok, read control not used for this type of operation */
                slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Read Entry Controls "
                                                                            "can not be used for a %s operation.\n",
                              op_to_string(op->o_tag));
                rc = -1;
                goto done;
            }
        }
        if (e == NULL) {
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Unable to retrieve entry\n");
            rc = -1;
            goto done;
        }

#if !defined(DISABLE_ACL_CHECK)
        /* even though we can modify the entry, that doesn't mean we can read it */
        if (plugin_call_acl_plugin(pb, e, attrs, NULL, SLAPI_ACL_READ,
                                   ACLPLUGIN_ACCESS_READ_ON_ENTRY, NULL) != LDAP_SUCCESS) {
            slapi_log_err(SLAPI_LOG_ACL, "process_read_entry_controls", "Access to entry not allowed (%s)\n",
                          slapi_entry_get_dn_const(e));
            rc = -1;
            goto done;
        }
#endif
        /*
         *  Check the ctl_value for any requested attributes
         */
        if (req_value && req_value->bv_len != 0 && req_value->bv_val) {
            if ((req_ber = ber_init(req_value)) == NULL) {
                rc = -1;
                goto free;
            }
            if (ber_scanf(req_ber, "{") == LBER_ERROR) {
                rc = -1;
                goto free;
            }
            /* process the attributes */
            while (1) {
                char *payload = NULL;

                if (ber_get_stringa(req_ber, &payload) != LBER_ERROR) {
                    if (strcmp(payload, LDAP_ALL_USER_ATTRS) == 0) {
                        all_attrs = 1;
                        slapi_ch_free_string(&payload);
                    } else if (strcmp(payload, LDAP_NO_ATTRS) == 0) {
                        no_attrs = 1;
                        slapi_ch_free_string(&payload);
                    } else {
                        charray_add(&attrs, payload);
                        attr_count++;
                    }
                } else {
                    /* we're done */
                    break;
                }
            }
            if (no_attrs && (all_attrs || attr_count)) {
                /* Can't have both no attrs and some attributes */
                slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Both no attributes \"1.1\" and "
                                                                            "specific attributes were requested.\n");
                rc = -1;
                goto free;
            }

            if (ber_scanf(req_ber, "}") == LBER_ERROR) {
                rc = -1;
                goto free;
            }
        } else {
            /* this is a problem, malformed request control value */
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Invalid control value.\n");
            rc = -1;
            goto free;
        }

        /*
         * Get the ber encoded string, and add it to the response control
         */
        res_value = encode_read_entry(pb, e, attrs, all_attrs, attr_count);
        if (res_value && res_value->bv_len > 0) {
            LDAPControl new_ctrl = {0};

            new_ctrl.ldctl_oid = oid;
            new_ctrl.ldctl_value = *res_value;
            new_ctrl.ldctl_iscritical = iscritical;
            slapi_pblock_set(pb, SLAPI_ADD_RESCONTROL, &new_ctrl);
            ber_bvfree(res_value);
        } else {
            /* failed to encode the result entry */
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Failed to process READ ENTRY"
                                                                        " Control (%s), error encoding result entry\n",
                          oid);
            rc = -1;
        }

    free:
        if (NULL != req_ber) {
            ber_free(req_ber, 1);
        }
        if (rc != 0) {
            /* log an error */
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Failed to process READ ENTRY "
                                                                        "Control (%s) ber decoding error\n",
                          oid);
        }
    }
done:
    if (iscritical) {
        return rc;
    } else {
        return 0;
    }
}
process_read_entry_controls(Slapi_PBlock *pb, char *oid)
{
    struct berval *req_value = NULL;
    struct berval *res_value = NULL;
    LDAPControl **req_ctls = NULL;
    Slapi_Entry *e = NULL;
    char **attrs = NULL;
    int attr_count = 0;
    int iscritical = 0;
    int all_attrs = 0;
    int no_attrs = 0;
    int rc = 0;

    slapi_pblock_get(pb, SLAPI_REQCONTROLS, &req_ctls);

     
    if (slapi_control_present(req_ctls, oid, &req_value, &iscritical)) {
        BerElement *req_ber = NULL;
        Operation *op = NULL;
        slapi_pblock_get(pb, SLAPI_OPERATION, &op);
        if (op == NULL) {
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "op is NULL\n");
            rc = -1;
            goto done;
        }

        if (strcmp(oid, LDAP_CONTROL_PRE_READ_ENTRY) == 0) {
             
            if (op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_DELETE ||
                op->o_tag == LDAP_REQ_MODDN) {
                slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
            } else {
                 
                slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Read Entry Controls "
                                                                            "can not be used for a %s operation.\n",
                              op_to_string(op->o_tag));
                rc = -1;
                goto done;
            }
        } else {
             
            if (op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_ADD ||
                op->o_tag == LDAP_REQ_MODDN) {
                slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
            } else {
                 
                slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Read Entry Controls "
                                                                            "can not be used for a %s operation.\n",
                              op_to_string(op->o_tag));
                rc = -1;
                goto done;
            }
        }
        if (e == NULL) {
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Unable to retrieve entry\n");
            rc = -1;
            goto done;
        }

#if !defined(DISABLE_ACL_CHECK)
         
        if (plugin_call_acl_plugin(pb, e, attrs, NULL, SLAPI_ACL_READ,
                                   ACLPLUGIN_ACCESS_READ_ON_ENTRY, NULL) != LDAP_SUCCESS) {
            slapi_log_err(SLAPI_LOG_ACL, "process_read_entry_controls", "Access to entry not allowed (%s)\n",
                          slapi_entry_get_dn_const(e));
            rc = -1;
            goto done;
        }
#endif
         
        if (req_value && req_value->bv_len != 0 && req_value->bv_val) {
            if ((req_ber = ber_init(req_value)) == NULL) {
                rc = -1;
                goto free;
            }
            if (ber_scanf(req_ber, "{") == LBER_ERROR) {
                rc = -1;
                goto free;
            }
             
            while (1) {
                char *payload = NULL;

                if (ber_get_stringa(req_ber, &payload) != LBER_ERROR) {
                    if (strcmp(payload, LDAP_ALL_USER_ATTRS) == 0) {
                        all_attrs = 1;
                        slapi_ch_free_string(&payload);
                    } else if (strcmp(payload, LDAP_NO_ATTRS) == 0) {
                        no_attrs = 1;
                        slapi_ch_free_string(&payload);
                    } else {
                        charray_add(&attrs, payload);
                        attr_count++;
                    }
                } else {
                     
                    break;
                }
            }
            if (no_attrs && (all_attrs || attr_count)) {
                 
                slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Both no attributes \"1.1\" and "
                                                                            "specific attributes were requested.\n");
                rc = -1;
                goto free;
            }

            if (ber_scanf(req_ber, "}") == LBER_ERROR) {
                rc = -1;
                goto free;
            }
        } else {
             
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Invalid control value.\n");
            rc = -1;
            goto free;
        }

         
        res_value = encode_read_entry(pb, e, attrs, all_attrs, attr_count);
        if (res_value && res_value->bv_len > 0) {
            LDAPControl new_ctrl = {0};

            new_ctrl.ldctl_oid = oid;
            new_ctrl.ldctl_value = *res_value;
            new_ctrl.ldctl_iscritical = iscritical;
            slapi_pblock_set(pb, SLAPI_ADD_RESCONTROL, &new_ctrl);
            ber_bvfree(res_value);
        } else {
             
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Failed to process READ ENTRY"
                                                                        " Control (%s), error encoding result entry\n",
                          oid);
            rc = -1;
        }

    free:
        if (NULL != req_ber) {
            ber_free(req_ber, 1);
        }
        if (rc != 0) {
             
            slapi_log_err(SLAPI_LOG_ERR, "process_read_entry_controls", "Failed to process READ ENTRY "
                                                                        "Control (%s) ber decoding error\n",
                          oid);
        }
    }
done:
    if (iscritical) {
        return rc;
    } else {
        return 0;
    }
}