>From 79f9047955afbcc1c66aea1f538b4359bb834c1b Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce@redhat.com>
Date: Wed, 14 Oct 2009 19:17:57 -0400
Subject: [PATCH] Return the dp error from the providers

---
 server/providers/data_provider_be.c |   60 +++++++++++++++++++++++----
 server/providers/dp_backend.h       |    2 +-
 server/providers/krb5/krb5_auth.c   |   46 +++++++++++++-------
 server/providers/ldap/ldap_auth.c   |   39 +++++++++++------
 server/providers/ldap/ldap_id.c     |   34 ++++++++++-----
 server/providers/proxy.c            |   79 +++++++++++++++++++++-------------
 6 files changed, 179 insertions(+), 81 deletions(-)

diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c
index f6dcf51..7bef6be 100644
--- a/server/providers/data_provider_be.c
+++ b/server/providers/data_provider_be.c
@@ -203,9 +203,40 @@ static int be_check_online(DBusMessage *message, struct sbus_connection *conn)
     return EOK;
 }
 
+static char *dp_err_to_string(TALLOC_CTX *memctx, int dp_err_type, int errnum)
+{
+    switch (dp_err_type) {
+    case DP_ERR_OK:
+        return talloc_strdup(memctx, "Success");
+        break;
+
+    case DP_ERR_OFFLINE:
+        return talloc_asprintf(memctx,
+                               "Provider is Offline (%s)",
+                               strerror(errnum));
+        break;
+
+    case DP_ERR_TIMEOUT:
+        return talloc_asprintf(memctx,
+                               "Request timed out (%s)",
+                               strerror(errnum));
+        break;
+
+    case DP_ERR_FATAL:
+    default:
+        return talloc_asprintf(memctx,
+                               "Internal Error (%s)",
+                               strerror(errnum));
+        break;
+    }
 
+    return NULL;
+}
 
-static void acctinfo_callback(struct be_req *req, int status,
+
+static void acctinfo_callback(struct be_req *req,
+                              int dp_err_type,
+                              int errnum,
                               const char *errstr)
 {
     DBusMessage *reply;
@@ -213,12 +244,18 @@ static void acctinfo_callback(struct be_req *req, int status,
     dbus_bool_t dbret;
     dbus_uint16_t err_maj = 0;
     dbus_uint32_t err_min = 0;
-    const char *err_msg = "Success";
+    const char *err_msg = NULL;
 
-    if (status != EOK) {
-        err_maj = DP_ERR_FATAL;
-        err_min = status;
+    err_maj = dp_err_type;
+    err_min = errnum;
+    if (errstr) {
         err_msg = errstr;
+    } else {
+        err_msg = dp_err_to_string(req, dp_err_type, errnum);
+    }
+    if (!err_msg) {
+        DEBUG(1, ("Failed to set err_msg, Out of memoery?\n"));
+        err_msg = "OOM";
     }
 
     reply = (DBusMessage *)req->pvt;
@@ -385,13 +422,20 @@ done:
     return EOK;
 }
 
-static void be_pam_handler_callback(struct be_req *req, int status,
-                                const char *errstr) {
+static void be_pam_handler_callback(struct be_req *req,
+                                    int dp_err_type,
+                                    int errnum,
+                                    const char *errstr)
+{
     struct pam_data *pd;
     DBusMessage *reply;
     DBusConnection *dbus_conn;
     dbus_bool_t dbret;
 
+    DEBUG(4, ("Backend returned: (%d, %d, %s) [%s]\n",
+              dp_err_type, errnum, errstr?errstr:"<NULL>",
+              dp_err_to_string(req, dp_err_type, 0)));
+
     pd = talloc_get_type(req->req_data, struct pam_data);
 
     DEBUG(4, ("Sending result [%d][%s]\n", pd->pam_status, pd->domain));
@@ -743,7 +787,7 @@ static void be_target_access_permit(struct be_req *be_req)
     DEBUG(9, ("be_target_access_permit called, returning PAM_SUCCESS.\n"));
 
     pd->pam_status = PAM_SUCCESS;
-    be_req->fn(be_req, PAM_SUCCESS, NULL);
+    be_req->fn(be_req, DP_ERR_OK, PAM_SUCCESS, NULL);
 }
 
 static struct bet_ops be_target_access_permit_ops = {
diff --git a/server/providers/dp_backend.h b/server/providers/dp_backend.h
index ae245ef..bee1a85 100644
--- a/server/providers/dp_backend.h
+++ b/server/providers/dp_backend.h
@@ -32,7 +32,7 @@ struct be_req;
 typedef int (*bet_init_fn_t)(TALLOC_CTX *, struct bet_ops **, void **);
 typedef void (*be_shutdown_fn)(void *);
 typedef void (*be_req_fn_t)(struct be_req *);
-typedef void (*be_async_callback_t)(struct be_req *, int, const char *);
+typedef void (*be_async_callback_t)(struct be_req *, int, int, const char *);
 
 enum bet_type {
     BET_NULL = 0,
diff --git a/server/providers/krb5/krb5_auth.c b/server/providers/krb5/krb5_auth.c
index 582d013..91f9196 100644
--- a/server/providers/krb5/krb5_auth.c
+++ b/server/providers/krb5/krb5_auth.c
@@ -177,6 +177,8 @@ static void fd_nonblocking(int fd) {
     return;
 }
 
+static void krb_reply(struct be_req *req, int dp_err, int result);
+
 static void krb5_child_timeout(struct tevent_context *ev,
                                struct tevent_timer *te,
                                struct timeval tv, void *pvt)
@@ -202,7 +204,7 @@ static void krb5_child_timeout(struct tevent_context *ev,
     pd->pam_status = PAM_AUTHINFO_UNAVAIL;
     be_mark_offline(be_req->be_ctx);
 
-    be_req->fn(be_req, pd->pam_status, NULL);
+    krb_reply(be_req, DP_ERR_OFFLINE, pd->pam_status);
 }
 
 static errno_t activate_child_timeout_handler(struct krb5child_req *kr)
@@ -597,22 +599,25 @@ static void krb5_pam_handler_cache_done(struct tevent_req *treq);
 
 static void krb5_pam_handler(struct be_req *be_req)
 {
-    int ret;
     struct pam_data *pd;
-    int pam_status=PAM_SYSTEM_ERR;
     const char **attrs;
+    int pam_status = PAM_SYSTEM_ERR;
+    int dp_err = DP_ERR_FATAL;
+    int ret;
 
     pd = talloc_get_type(be_req->req_data, struct pam_data);
 
     if (be_is_offline(be_req->be_ctx)) {
         DEBUG(4, ("Backend is marked offline, retry later!\n"));
         pam_status = PAM_AUTHINFO_UNAVAIL;
+        dp_err = DP_ERR_OFFLINE;
         goto done;
     }
 
     if (pd->cmd != SSS_PAM_AUTHENTICATE && pd->cmd != SSS_PAM_CHAUTHTOK) {
         DEBUG(4, ("krb5 does not handles pam task %d.\n", pd->cmd));
         pam_status = PAM_SUCCESS;
+        dp_err = DP_ERR_OK;
         goto done;
     }
 
@@ -638,7 +643,7 @@ static void krb5_pam_handler(struct be_req *be_req)
 done:
     pd->pam_status = pam_status;
 
-    be_req->fn(be_req, pam_status, NULL);
+    krb_reply(be_req, dp_err, pd->pam_status);
 }
 
 static void get_user_upn_done(void *pvt, int err, struct ldb_result *res)
@@ -722,8 +727,7 @@ failed:
     talloc_free(kr);
 
     pd->pam_status = pam_status;
-
-    be_req->fn(be_req, pam_status, NULL);
+    krb_reply(be_req, DP_ERR_FATAL, pd->pam_status);
 }
 
 static void krb5_pam_handler_done(struct tevent_req *req)
@@ -744,6 +748,7 @@ static void krb5_pam_handler_done(struct tevent_req *req)
     struct tevent_req *subreq = NULL;
     char *password = NULL;
     char *env = NULL;
+    int dp_err = DP_ERR_FATAL;
 
     pd->pam_status = PAM_SYSTEM_ERR;
     talloc_free(kr);
@@ -778,26 +783,26 @@ static void krb5_pam_handler_done(struct tevent_req *req)
         goto done;
     }
 
-    ret=pam_add_response(pd, *msg_type, *msg_len, &buf[p]);
+    ret = pam_add_response(pd, *msg_type, *msg_len, &buf[p]);
     if (ret != EOK) {
         DEBUG(1, ("pam_add_response failed.\n"));
         goto done;
     }
 
-    pd->pam_status = *msg_status;
-
-    if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) {
+    if (*msg_status == PAM_AUTHINFO_UNAVAIL) {
         be_mark_offline(be_req->be_ctx);
+        pd->pam_status = *msg_status;
+        dp_err = DP_ERR_OFFLINE;
         goto done;
     }
 
-    if (pd->pam_status == PAM_SUCCESS && pd->cmd == SSS_PAM_AUTHENTICATE) {
+    if (*msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_AUTHENTICATE) {
         env = talloc_asprintf(pd, "%s=%s", SSSD_KRB5_REALM, krb5_ctx->realm);
         if (env == NULL) {
             DEBUG(1, ("talloc_asprintf failed.\n"));
             goto done;
         }
-        ret=pam_add_response(pd, PAM_ENV_ITEM, strlen(env)+1, (uint8_t *) env);
+        ret = pam_add_response(pd, PAM_ENV_ITEM, strlen(env)+1, (uint8_t *) env);
         if (ret != EOK) {
             DEBUG(1, ("pam_add_response failed.\n"));
             goto done;
@@ -808,13 +813,16 @@ static void krb5_pam_handler_done(struct tevent_req *req)
             DEBUG(1, ("talloc_asprintf failed.\n"));
             goto done;
         }
-        ret=pam_add_response(pd, PAM_ENV_ITEM, strlen(env)+1, (uint8_t *) env);
+        ret = pam_add_response(pd, PAM_ENV_ITEM, strlen(env)+1, (uint8_t *) env);
         if (ret != EOK) {
             DEBUG(1, ("pam_add_response failed.\n"));
             goto done;
         }
     }
 
+    pd->pam_status = *msg_status;
+    dp_err = DP_ERR_OK;
+
     if (pd->pam_status == PAM_SUCCESS &&
         be_req->be_ctx->domain->cache_credentials == TRUE) {
 
@@ -853,11 +861,11 @@ static void krb5_pam_handler_done(struct tevent_req *req)
             goto done;
         }
         tevent_req_set_callback(subreq, krb5_pam_handler_cache_done, be_req);
-
         return;
     }
+
 done:
-    be_req->fn(be_req, pd->pam_status, NULL);
+    krb_reply(be_req, dp_err, pd->pam_status);
 }
 
 static void krb5_pam_handler_cache_done(struct tevent_req *subreq)
@@ -875,9 +883,15 @@ static void krb5_pam_handler_cache_done(struct tevent_req *subreq)
                   ret, strerror(ret)));
     }
 
-    be_req->fn(be_req, PAM_SUCCESS, NULL);
+    krb_reply(be_req, DP_ERR_OK, PAM_SUCCESS);
 }
 
+static void krb_reply(struct be_req *req, int dp_err, int result)
+{
+    req->fn(req, dp_err, result, NULL);
+}
+
+
 struct bet_ops krb5_auth_ops = {
     .handler = krb5_pam_handler,
     .finalize = NULL,
diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c
index 80726e7..a70817d 100644
--- a/server/providers/ldap/ldap_auth.c
+++ b/server/providers/ldap/ldap_auth.c
@@ -328,7 +328,7 @@ struct sdap_pam_chpass_state {
 
 static void sdap_auth4chpass_done(struct tevent_req *req);
 static void sdap_pam_chpass_done(struct tevent_req *req);
-static void sdap_pam_auth_reply(struct be_req *breq, int result);
+static void sdap_pam_auth_reply(struct be_req *breq, int dp_err, int result);
 
 static void sdap_pam_chpass_send(struct be_req *breq)
 {
@@ -337,6 +337,7 @@ static void sdap_pam_chpass_send(struct be_req *breq)
     struct tevent_req *subreq;
     struct pam_data *pd;
     struct dp_opt_blob authtok;
+    int dp_err = DP_ERR_FATAL;
 
     ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
                           struct sdap_auth_ctx);
@@ -345,6 +346,7 @@ static void sdap_pam_chpass_send(struct be_req *breq)
     if (be_is_offline(ctx->be)) {
         DEBUG(4, ("Backend is marked offline, retry later!\n"));
         pd->pam_status = PAM_AUTHINFO_UNAVAIL;
+        dp_err = DP_ERR_OFFLINE;
         goto done;
     }
 
@@ -383,8 +385,9 @@ static void sdap_pam_chpass_send(struct be_req *breq)
 
     tevent_req_set_callback(subreq, sdap_auth4chpass_done, state);
     return;
+
 done:
-    sdap_pam_auth_reply(breq, pd->pam_status);
+    sdap_pam_auth_reply(breq, dp_err, pd->pam_status);
 }
 
 static void sdap_auth4chpass_done(struct tevent_req *req)
@@ -393,6 +396,7 @@ static void sdap_auth4chpass_done(struct tevent_req *req)
                     tevent_req_callback_data(req, struct sdap_pam_chpass_state);
     struct tevent_req *subreq;
     enum sdap_result result;
+    int dp_err = DP_ERR_FATAL;
     int ret;
 
     ret = auth_recv(req, &result, state, &state->sh, &state->dn);
@@ -421,13 +425,13 @@ static void sdap_auth4chpass_done(struct tevent_req *req)
 
         tevent_req_set_callback(subreq, sdap_pam_chpass_done, state);
         return;
-        break;
+
     default:
         state->pd->pam_status = PAM_SYSTEM_ERR;
     }
 
 done:
-    sdap_pam_auth_reply(state->breq, state->pd->pam_status);
+    sdap_pam_auth_reply(state->breq, dp_err, state->pd->pam_status);
 }
 
 static void sdap_pam_chpass_done(struct tevent_req *req)
@@ -435,6 +439,7 @@ static void sdap_pam_chpass_done(struct tevent_req *req)
     struct sdap_pam_chpass_state *state =
                     tevent_req_callback_data(req, struct sdap_pam_chpass_state);
     enum sdap_result result;
+    int dp_err = DP_ERR_FATAL;
     int ret;
 
     ret = sdap_exop_modify_passwd_recv(req, &result);
@@ -447,13 +452,14 @@ static void sdap_pam_chpass_done(struct tevent_req *req)
     switch (result) {
     case SDAP_SUCCESS:
         state->pd->pam_status = PAM_SUCCESS;
+        dp_err = DP_ERR_OK;
         break;
     default:
         state->pd->pam_status = PAM_SYSTEM_ERR;
     }
 
 done:
-    sdap_pam_auth_reply(state->breq, state->pd->pam_status);
+    sdap_pam_auth_reply(state->breq, dp_err, state->pd->pam_status);
 }
 /* ==Perform-User-Authentication-and-Password-Caching===================== */
 
@@ -466,7 +472,6 @@ struct sdap_pam_auth_state {
 
 static void sdap_pam_auth_done(struct tevent_req *req);
 static void sdap_password_cache_done(struct tevent_req *req);
-static void sdap_pam_auth_reply(struct be_req *breq, int result);
 
 /* FIXME: convert caller to tevent_req too ?*/
 static void sdap_pam_auth_send(struct be_req *breq)
@@ -475,6 +480,7 @@ static void sdap_pam_auth_send(struct be_req *breq)
     struct sdap_auth_ctx *ctx;
     struct tevent_req *subreq;
     struct pam_data *pd;
+    int dp_err = DP_ERR_FATAL;
 
     ctx = talloc_get_type(breq->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
                           struct sdap_auth_ctx);
@@ -483,6 +489,7 @@ static void sdap_pam_auth_send(struct be_req *breq)
     if (be_is_offline(ctx->be)) {
         DEBUG(4, ("Backend is marked offline, retry later!\n"));
         pd->pam_status = PAM_AUTHINFO_UNAVAIL;
+        dp_err = DP_ERR_OFFLINE;
         goto done;
     }
 
@@ -513,10 +520,11 @@ static void sdap_pam_auth_send(struct be_req *breq)
 
     default:
         pd->pam_status = PAM_SUCCESS;
+        dp_err = DP_ERR_OK;
     }
 
 done:
-    sdap_pam_auth_reply(breq, pd->pam_status);
+    sdap_pam_auth_reply(breq, dp_err, pd->pam_status);
 }
 
 static void sdap_pam_auth_done(struct tevent_req *req)
@@ -525,12 +533,14 @@ static void sdap_pam_auth_done(struct tevent_req *req)
                     tevent_req_callback_data(req, struct sdap_pam_auth_state);
     struct tevent_req *subreq;
     enum sdap_result result;
+    int dp_err = DP_ERR_OK;
     int ret;
 
     ret = auth_recv(req, &result, NULL, NULL, NULL);
     talloc_zfree(req);
     if (ret) {
         state->pd->pam_status = PAM_SYSTEM_ERR;
+        dp_err = DP_ERR_FATAL;
         goto done;
     }
 
@@ -549,10 +559,12 @@ static void sdap_pam_auth_done(struct tevent_req *req)
         break;
     default:
         state->pd->pam_status = PAM_SYSTEM_ERR;
+        dp_err = DP_ERR_FATAL;
     }
 
     if (result == SDAP_UNAVAIL) {
         be_mark_offline(state->breq->be_ctx);
+        dp_err = DP_ERR_OFFLINE;
         goto done;
     }
 
@@ -562,6 +574,7 @@ static void sdap_pam_auth_done(struct tevent_req *req)
         char *password = talloc_strndup(state, (char *)
                                         state->password.data,
                                         state->password.length);
+        /* password caching failures are not fatal errors */
         if (!password) {
             DEBUG(2, ("Failed to cache password for %s\n", state->username));
             goto done;
@@ -586,7 +599,7 @@ static void sdap_pam_auth_done(struct tevent_req *req)
     }
 
 done:
-    sdap_pam_auth_reply(state->breq, state->pd->pam_status);
+    sdap_pam_auth_reply(state->breq, dp_err, state->pd->pam_status);
 }
 
 static void sdap_password_cache_done(struct tevent_req *subreq)
@@ -604,14 +617,12 @@ static void sdap_password_cache_done(struct tevent_req *subreq)
         DEBUG(4, ("Password successfully cached for %s\n", state->username));
     }
 
-    sdap_pam_auth_reply(state->breq, state->pd->pam_status);
+    sdap_pam_auth_reply(state->breq, DP_ERR_OK, state->pd->pam_status);
 }
 
-static void sdap_pam_auth_reply(struct be_req *req, int result)
+static void sdap_pam_auth_reply(struct be_req *req, int dp_err, int result)
 {
-    const char *errstr = NULL;
-    if (result) errstr = "Operation failed";
-    req->fn(req, result, errstr);
+    req->fn(req, dp_err, result, NULL);
 }
 
 /* ==Module-Initialization-and-Dispose==================================== */
@@ -619,7 +630,7 @@ static void sdap_pam_auth_reply(struct be_req *req, int result)
 static void sdap_shutdown(struct be_req *req)
 {
     /* TODO: Clean up any internal data */
-    req->fn(req, EOK, NULL);
+    req->fn(req, DP_ERR_OK, EOK, NULL);
 }
 
 struct bet_ops sdap_auth_ops = {
diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index e1a31cf..3663f20 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -47,9 +47,10 @@ struct sdap_id_ctx {
     char *max_group_timestamp;
 };
 
-static void sdap_req_done(struct be_req *req, int ret, const char *err)
+static void sdap_req_done(struct be_req *req, int dp_err,
+                          int error, const char *errstr)
 {
-    return req->fn(req, ret, err);
+    return req->fn(req, dp_err, error, errstr);
 }
 
 static int build_attrs_from_map(TALLOC_CTX *memctx,
@@ -235,6 +236,7 @@ static void users_get_done(struct tevent_req *req)
     struct sdap_id_ctx *ctx;
     enum tevent_req_state tstate;
     uint64_t err;
+    int dp_err = DP_ERR_OK;
     const char *error = NULL;
     int ret = EOK;
 
@@ -244,16 +246,18 @@ static void users_get_done(struct tevent_req *req)
     }
 
     if (ret) {
+        dp_err = DP_ERR_FATAL;
         error = "Enum Users Failed";
 
         if (ret == ETIMEDOUT) {
+            dp_err = DP_ERR_TIMEOUT;
             ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
                                   struct sdap_id_ctx);
             be_mark_offline(ctx->be);
         }
     }
 
-    return sdap_req_done(breq, ret, error);
+    sdap_req_done(breq, dp_err, ret, error);
 }
 
 /* =Groups-Related-Functions-(by-name,by-uid)============================= */
@@ -398,6 +402,7 @@ static void groups_get_done(struct tevent_req *req)
     struct sdap_id_ctx *ctx;
     enum tevent_req_state tstate;
     uint64_t err;
+    int dp_err = DP_ERR_OK;
     const char *error = NULL;
     int ret = EOK;
 
@@ -406,16 +411,18 @@ static void groups_get_done(struct tevent_req *req)
     }
 
     if (ret) {
+        dp_err = DP_ERR_FATAL;
         error = "Enum Groups Failed";
 
         if (ret == ETIMEDOUT) {
+            dp_err = DP_ERR_TIMEOUT;
             ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
                                   struct sdap_id_ctx);
             be_mark_offline(ctx->be);
         }
     }
 
-    return sdap_req_done(breq, ret, error);
+    return sdap_req_done(breq, dp_err, ret, error);
 }
 
 /* =Get-Groups-for-User================================================== */
@@ -535,6 +542,7 @@ static void groups_by_user_done(struct tevent_req *req)
     struct sdap_id_ctx *ctx;
     enum tevent_req_state tstate;
     uint64_t err;
+    int dp_err = DP_ERR_OK;
     const char *error = NULL;
     int ret = EOK;
 
@@ -543,16 +551,18 @@ static void groups_by_user_done(struct tevent_req *req)
     }
 
     if (ret) {
+        dp_err = DP_ERR_FATAL;
         error = "Init Groups Failed";
 
         if (ret == ETIMEDOUT) {
+            dp_err = DP_ERR_TIMEOUT;
             ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
                                   struct sdap_id_ctx);
             be_mark_offline(ctx->be);
         }
     }
 
-    return sdap_req_done(breq, ret, error);
+    return sdap_req_done(breq, dp_err, ret, error);
 }
 
 
@@ -572,7 +582,7 @@ static void sdap_get_account_info(struct be_req *breq)
     ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, struct sdap_id_ctx);
 
     if (be_is_offline(ctx->be)) {
-        return sdap_req_done(breq, EAGAIN, "Offline");
+        return sdap_req_done(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
     }
 
     ar = talloc_get_type(breq->req_data, struct be_acct_req);
@@ -582,7 +592,7 @@ static void sdap_get_account_info(struct be_req *breq)
 
         /* skip enumerations on demand */
         if (strcmp(ar->filter_value, "*") == 0) {
-            return sdap_req_done(breq, EOK, "Success");
+            return sdap_req_done(breq, DP_ERR_OK, EOK, "Success");
         }
 
         req = users_get_send(breq, breq->be_ctx->ev, ctx,
@@ -590,7 +600,7 @@ static void sdap_get_account_info(struct be_req *breq)
                              ar->filter_type,
                              ar->attr_type);
         if (!req) {
-            return sdap_req_done(breq, ENOMEM, "Out of memory");
+            return sdap_req_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory");
         }
 
         tevent_req_set_callback(req, users_get_done, breq);
@@ -600,7 +610,7 @@ static void sdap_get_account_info(struct be_req *breq)
     case BE_REQ_GROUP: /* group */
 
         if (strcmp(ar->filter_value, "*") == 0) {
-            return sdap_req_done(breq, EOK, "Success");
+            return sdap_req_done(breq, DP_ERR_OK, EOK, "Success");
         }
 
         /* skip enumerations on demand */
@@ -609,7 +619,7 @@ static void sdap_get_account_info(struct be_req *breq)
                               ar->filter_type,
                               ar->attr_type);
         if (!req) {
-            return sdap_req_done(breq, ENOMEM, "Out of memory");
+            return sdap_req_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory");
         }
 
         tevent_req_set_callback(req, groups_get_done, breq);
@@ -646,7 +656,7 @@ static void sdap_get_account_info(struct be_req *breq)
         err = "Invalid request type";
     }
 
-    if (ret != EOK) return sdap_req_done(breq, ret, err);
+    if (ret != EOK) return sdap_req_done(breq, DP_ERR_FATAL, ret, err);
 }
 
 
@@ -1148,7 +1158,7 @@ static void enum_groups_op_done(struct tevent_req *subreq)
 static void sdap_shutdown(struct be_req *req)
 {
     /* TODO: Clean up any internal data */
-    sdap_req_done(req, EOK, NULL);
+    sdap_req_done(req, DP_ERR_OK, EOK, NULL);
 }
 
 struct bet_ops sdap_id_ops = {
diff --git a/server/providers/proxy.c b/server/providers/proxy.c
index 54d4487..e3b31c3 100644
--- a/server/providers/proxy.c
+++ b/server/providers/proxy.c
@@ -115,7 +115,7 @@ failed:
 }
 
 static void proxy_pam_handler_cache_done(struct tevent_req *treq);
-static void proxy_reply(struct be_req *req,
+static void proxy_reply(struct be_req *req, int dp_err,
                         int error, const char *errstr);
 
 static void proxy_pam_handler(struct be_req *req) {
@@ -218,7 +218,7 @@ static void proxy_pam_handler(struct be_req *req) {
         password = talloc_size(req, auth_data->authtok_size + 1);
         if (!password) {
             /* password caching failures are not fatal errors */
-            return proxy_reply(req, EOK, NULL);
+            return proxy_reply(req, DP_ERR_OK, EOK, NULL);
         }
         memcpy(password, auth_data->authtok, auth_data->authtok_size);
         password[auth_data->authtok_size] = '\0';
@@ -230,12 +230,12 @@ static void proxy_pam_handler(struct be_req *req) {
                                            pd->user, password);
         if (!subreq) {
             /* password caching failures are not fatal errors */
-            return proxy_reply(req, EOK, NULL);
+            return proxy_reply(req, DP_ERR_OK, EOK, NULL);
         }
         tevent_req_set_callback(subreq, proxy_pam_handler_cache_done, req);
     }
 
-    proxy_reply(req, EOK, NULL);
+    proxy_reply(req, DP_ERR_OK, EOK, NULL);
 }
 
 static void proxy_pam_handler_cache_done(struct tevent_req *subreq)
@@ -253,13 +253,13 @@ static void proxy_pam_handler_cache_done(struct tevent_req *subreq)
                   ret, strerror(ret)));
     }
 
-    return proxy_reply(req, EOK, NULL);
+    return proxy_reply(req, DP_ERR_OK, EOK, NULL);
 }
 
-static void proxy_reply(struct be_req *req, int error, const char *errstr)
+static void proxy_reply(struct be_req *req, int dp_err,
+                        int error, const char *errstr)
 {
-    if (error && !errstr) errstr = "Operation failed";
-    return req->fn(req, error, errstr);
+    return req->fn(req, dp_err, error, errstr);
 }
 
 /* =Common-proxy-tevent_req-utils=========================================*/
@@ -2003,12 +2003,12 @@ static void proxy_get_account_info(struct be_req *breq)
     domain = breq->be_ctx->domain;
 
     if (be_is_offline(breq->be_ctx)) {
-        return proxy_reply(breq, EAGAIN, "Offline");
+        return proxy_reply(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
     }
 
     /* for now we support only core attrs */
     if (ar->attr_type != BE_ATTR_CORE) {
-        return proxy_reply(breq, EINVAL, "Invalid attr type");
+        return proxy_reply(breq, DP_ERR_FATAL, EINVAL, "Invalid attr type");
     }
 
     switch (ar->entry_type) {
@@ -2019,7 +2019,8 @@ static void proxy_get_account_info(struct be_req *breq)
                 subreq = enum_users_send(breq, ev, ctx,
                                          sysdb, domain);
                 if (!subreq) {
-                    return proxy_reply(breq, ENOMEM, "Out of memory");
+                    return proxy_reply(breq, DP_ERR_FATAL,
+                                       ENOMEM, "Out of memory");
                 }
                 tevent_req_set_callback(subreq,
                                proxy_get_account_info_done, breq);
@@ -2029,7 +2030,8 @@ static void proxy_get_account_info(struct be_req *breq)
                                           sysdb, domain,
                                           ar->filter_value);
                 if (!subreq) {
-                    return proxy_reply(breq, ENOMEM, "Out of memory");
+                    return proxy_reply(breq, DP_ERR_FATAL,
+                                       ENOMEM, "Out of memory");
                 }
                 tevent_req_set_callback(subreq,
                                proxy_get_account_info_done, breq);
@@ -2039,18 +2041,21 @@ static void proxy_get_account_info(struct be_req *breq)
 
         case BE_FILTER_IDNUM:
             if (strchr(ar->filter_value, '*')) {
-                return proxy_reply(breq, EINVAL, "Invalid attr type");
+                return proxy_reply(breq, DP_ERR_FATAL,
+                                   EINVAL, "Invalid attr type");
             } else {
                 char *endptr;
                 errno = 0;
                 uid = (uid_t)strtol(ar->filter_value, &endptr, 0);
                 if (errno || *endptr || (ar->filter_value == endptr)) {
-                    return proxy_reply(breq, EINVAL, "Invalid attr type");
+                    return proxy_reply(breq, DP_ERR_FATAL,
+                                       EINVAL, "Invalid attr type");
                 }
                 subreq = get_pw_uid_send(breq, ev, ctx,
                                          sysdb, domain, uid);
                 if (!subreq) {
-                    return proxy_reply(breq, ENOMEM, "Out of memory");
+                    return proxy_reply(breq, DP_ERR_FATAL,
+                                       ENOMEM, "Out of memory");
                 }
                 tevent_req_set_callback(subreq,
                                proxy_get_account_info_done, breq);
@@ -2058,7 +2063,8 @@ static void proxy_get_account_info(struct be_req *breq)
             }
             break;
         default:
-            return proxy_reply(breq, EINVAL, "Invalid filter type");
+            return proxy_reply(breq, DP_ERR_FATAL,
+                               EINVAL, "Invalid filter type");
         }
         break;
 
@@ -2069,7 +2075,8 @@ static void proxy_get_account_info(struct be_req *breq)
                 subreq = enum_groups_send(breq, ev, ctx,
                                           sysdb, domain);
                 if (!subreq) {
-                    return proxy_reply(breq, ENOMEM, "Out of memory");
+                    return proxy_reply(breq, DP_ERR_FATAL,
+                                       ENOMEM, "Out of memory");
                 }
                 tevent_req_set_callback(subreq,
                                proxy_get_account_info_done, breq);
@@ -2079,7 +2086,8 @@ static void proxy_get_account_info(struct be_req *breq)
                                           sysdb, domain,
                                           ar->filter_value);
                 if (!subreq) {
-                    return proxy_reply(breq, ENOMEM, "Out of memory");
+                    return proxy_reply(breq, DP_ERR_FATAL,
+                                       ENOMEM, "Out of memory");
                 }
                 tevent_req_set_callback(subreq,
                                proxy_get_account_info_done, breq);
@@ -2088,18 +2096,21 @@ static void proxy_get_account_info(struct be_req *breq)
             break;
         case BE_FILTER_IDNUM:
             if (strchr(ar->filter_value, '*')) {
-                return proxy_reply(breq, EINVAL, "Invalid attr type");
+                return proxy_reply(breq, DP_ERR_FATAL,
+                                   EINVAL, "Invalid attr type");
             } else {
                 char *endptr;
                 errno = 0;
                 gid = (gid_t)strtol(ar->filter_value, &endptr, 0);
                 if (errno || *endptr || (ar->filter_value == endptr)) {
-                    return proxy_reply(breq, EINVAL, "Invalid attr type");
+                    return proxy_reply(breq, DP_ERR_FATAL,
+                                       EINVAL, "Invalid attr type");
                 }
                 subreq = get_gr_gid_send(breq, ev, ctx,
                                          sysdb, domain, gid);
                 if (!subreq) {
-                    return proxy_reply(breq, ENOMEM, "Out of memory");
+                    return proxy_reply(breq, DP_ERR_FATAL,
+                                       ENOMEM, "Out of memory");
                 }
                 tevent_req_set_callback(subreq,
                                proxy_get_account_info_done, breq);
@@ -2107,24 +2118,29 @@ static void proxy_get_account_info(struct be_req *breq)
             }
             break;
         default:
-            return proxy_reply(breq, EINVAL, "Invalid filter type");
+            return proxy_reply(breq, DP_ERR_FATAL,
+                               EINVAL, "Invalid filter type");
         }
         break;
 
     case BE_REQ_INITGROUPS: /* init groups for user */
         if (ar->filter_type != BE_FILTER_NAME) {
-            return proxy_reply(breq, EINVAL, "Invalid filter type");
+            return proxy_reply(breq, DP_ERR_FATAL,
+                               EINVAL, "Invalid filter type");
         }
         if (strchr(ar->filter_value, '*')) {
-            return proxy_reply(breq, EINVAL, "Invalid filter value");
+            return proxy_reply(breq, DP_ERR_FATAL,
+                               EINVAL, "Invalid filter value");
         }
         if (ctx->ops.initgroups_dyn == NULL) {
-            return proxy_reply(breq, ENODEV, "Initgroups call not supported");
+            return proxy_reply(breq, DP_ERR_FATAL,
+                               ENODEV, "Initgroups call not supported");
         }
         subreq = get_initgr_send(breq, ev, ctx, sysdb,
                                  domain, ar->filter_value);
         if (!subreq) {
-            return proxy_reply(breq, ENOMEM, "Out of memory");
+            return proxy_reply(breq, DP_ERR_FATAL,
+                               ENOMEM, "Out of memory");
         }
         tevent_req_set_callback(subreq,
                        proxy_get_account_info_done, breq);
@@ -2134,7 +2150,8 @@ static void proxy_get_account_info(struct be_req *breq)
         break;
     }
 
-    return proxy_reply(breq, EINVAL, "Invalid request type");
+    return proxy_reply(breq, DP_ERR_FATAL,
+                       EINVAL, "Invalid request type");
 }
 
 static void proxy_get_account_info_done(struct tevent_req *subreq)
@@ -2149,20 +2166,22 @@ static void proxy_get_account_info_done(struct tevent_req *subreq)
             DEBUG(2, ("proxy returned UNAVAIL error, going offline!\n"));
             be_mark_offline(breq->be_ctx);
         }
+        proxy_reply(breq, DP_ERR_FATAL, ret, NULL);
+        return;
     }
-    proxy_reply(breq, ret, NULL);
+    proxy_reply(breq, DP_ERR_OK, EOK, NULL);
 }
 
 static void proxy_shutdown(struct be_req *req)
 {
     /* TODO: Clean up any internal data */
-    req->fn(req, EOK, NULL);
+    req->fn(req, DP_ERR_OK, EOK, NULL);
 }
 
 static void proxy_auth_shutdown(struct be_req *req)
 {
     talloc_free(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data);
-    req->fn(req, EOK, NULL);
+    req->fn(req, DP_ERR_OK, EOK, NULL);
 }
 
 struct bet_ops proxy_id_ops = {
-- 
1.6.2.5

