summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/responder/common/responder.h38
-rw-r--r--src/responder/common/responder_common.c8
-rw-r--r--src/responder/common/responder_dp.c801
-rw-r--r--src/responder/nss/nsssrv_cmd.c161
-rw-r--r--src/responder/nss/nsssrv_private.h1
-rw-r--r--src/responder/pam/pamsrv_cmd.c59
6 files changed, 641 insertions, 427 deletions
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 1b39fdd5..3b5ab8a4 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -89,6 +89,8 @@ struct resp_ctx {
struct sss_names_ctx *names;
+ hash_table_t *dp_request_table;
+
void *pvt_ctx;
};
@@ -163,17 +165,41 @@ struct cli_protocol_version *register_cli_protocol_version(void);
typedef void (*sss_dp_callback_t)(uint16_t err_maj, uint32_t err_min,
const char *err_msg, void *ptr);
-void handle_requests_after_reconnect(void);
+struct dp_callback_ctx {
+ sss_dp_callback_t callback;
+ void *ptr;
+
+ void *mem_ctx;
+ struct cli_ctx *cctx;
+};
-int sss_dp_send_acct_req(struct resp_ctx *rctx, TALLOC_CTX *callback_memctx,
- sss_dp_callback_t callback, void *callback_ctx,
- int timeout, const char *domain,
- bool fast_reply, int type,
- const char *opt_name, uint32_t opt_id);
+void handle_requests_after_reconnect(void);
int responder_logrotate(DBusMessage *message,
struct sbus_connection *conn);
+/* Send a request to the data provider
+ * Once this function is called, the communication
+ * with the data provider will always run to
+ * completion. Freeing the returned tevent_req will
+ * cancel the notification of completion, but not
+ * the data provider action.
+ */
+struct tevent_req *
+sss_dp_get_account_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ struct sss_domain_info *dom,
+ bool fast_reply,
+ int type,
+ const char *opt_name,
+ uint32_t opt_id);
+errno_t
+sss_dp_get_account_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ dbus_uint16_t *err_maj,
+ dbus_uint32_t *err_min,
+ char **err_msg);
+
bool sss_utf8_check(const uint8_t *s, size_t n);
#endif /* __SSS_RESPONDER_H__ */
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index f97ec06f..24f9125b 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -592,6 +592,14 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
return ret;
}
+ /* Create DP request table */
+ ret = sss_hash_create(rctx, 30, &rctx->dp_request_table);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ ("Could not create hash table for the request queue\n"));
+ return ret;
+ }
+
DEBUG(1, ("Responder Initialization complete\n"));
*responder_ctx = rctx;
diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c
index 2bf966cd..93c7cae4 100644
--- a/src/responder/common/responder_dp.c
+++ b/src/responder/common/responder_dp.c
@@ -32,14 +32,24 @@ hash_table_t *dp_requests = NULL;
struct sss_dp_req;
+struct dp_get_account_state {
+ struct resp_ctx *rctx;
+ struct sss_domain_info *dom;
+ const char *opt_name;
+ uint32_t opt_id;
+ hash_key_t *key;
+
+ dbus_uint16_t err_maj;
+ dbus_uint32_t err_min;
+ char *err_msg;
+};
+
struct sss_dp_callback {
struct sss_dp_callback *prev;
struct sss_dp_callback *next;
+ struct tevent_req *req;
struct sss_dp_req *sdp_req;
-
- sss_dp_callback_t callback;
- void *callback_ctx;
};
struct sss_dp_req {
@@ -47,7 +57,7 @@ struct sss_dp_req {
struct tevent_context *ev;
DBusPendingCall *pending_reply;
- char *key;
+ hash_key_t *key;
struct tevent_timer *tev;
struct sss_dp_callback *cb_list;
@@ -59,7 +69,8 @@ struct sss_dp_req {
static int sss_dp_callback_destructor(void *ptr)
{
- struct sss_dp_callback *cb = talloc_get_type(ptr, struct sss_dp_callback);
+ struct sss_dp_callback *cb =
+ talloc_get_type(ptr, struct sss_dp_callback);
DLIST_REMOVE(cb->sdp_req->cb_list, cb);
@@ -68,8 +79,9 @@ static int sss_dp_callback_destructor(void *ptr)
static int sss_dp_req_destructor(void *ptr)
{
+ struct sss_dp_callback *cb;
struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req);
- hash_key_t key;
+ struct dp_get_account_state *state;
/* Cancel Dbus pending reply if still pending */
if (sdp_req->pending_reply) {
@@ -77,15 +89,25 @@ static int sss_dp_req_destructor(void *ptr)
sdp_req->pending_reply = NULL;
}
- /* Destroy the hash entry
- * There are some situations when the entry has already
- * been destroyed to avoid race condition, so don't check
- * the result */
- key.type = HASH_KEY_STRING;
- key.str = sdp_req->key;
- int hret = hash_delete(dp_requests, &key);
+ /* If there are callbacks that haven't been invoked, return
+ * an error now.
+ */
+ DLIST_FOR_EACH(cb, sdp_req->cb_list) {
+ state = tevent_req_data(cb->req, struct dp_get_account_state);
+ state->err_maj = DP_ERR_FATAL;
+ state->err_min = EIO;
+ tevent_req_error(cb->req, EIO);
+ }
+
+ /* Destroy the hash entry */
+ int hret = hash_delete(sdp_req->rctx->dp_request_table, sdp_req->key);
if (hret != HASH_SUCCESS) {
- DEBUG(SSSDBG_TRACE_INTERNAL, ("Could not clear entry from request queue\n"));
+ /* This should never happen */
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ ("BUG: Could not clear [%d:%d:%s] from request queue: [%s]\n",
+ sdp_req->key->type, sdp_req->key->ul, sdp_req->key->str,
+ hash_error_string(hret)));
+ return -1;
}
return 0;
@@ -116,180 +138,147 @@ void handle_requests_after_reconnect(void)
talloc_free(sdp_req);
}
}
-
static int sss_dp_get_reply(DBusPendingCall *pending,
dbus_uint16_t *err_maj,
dbus_uint32_t *err_min,
- char **err_msg);
-
-static void sss_dp_invoke_callback(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval t, void *ptr)
+ char **err_msg)
{
- struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req);
- struct sss_dp_callback *cb;
-
- cb = sdp_req->cb_list;
- /* Remove the callback from the list, the caller may free it, within the
- * callback. */
- talloc_set_destructor((TALLOC_CTX *)cb, NULL);
- DLIST_REMOVE(sdp_req->cb_list, cb);
-
- cb->callback(sdp_req->err_maj,
- sdp_req->err_min,
- sdp_req->err_msg,
- cb->callback_ctx);
-
- /* If there are some more callbacks to be invoked,
- * don't destroy the request */
- if (sdp_req->cb_list != NULL) {
- return;
- }
-
- /* steal te on rctx because it will be freed as soon as the handler
- * returns. Causing a double free if we don't, as te is allocated on
- * sdp_req and we are just going to free it */
- talloc_steal(sdp_req->rctx, te);
-
- talloc_zfree(sdp_req);
-}
+ DBusMessage *reply;
+ DBusError dbus_error;
+ dbus_bool_t ret;
+ int type;
+ int err = EOK;
-static void sdp_req_timeout(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval t, void *ptr)
-{
- struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req);
- struct sss_dp_callback *cb, *next;
- struct timeval tv;
- struct tevent_timer *tev;
- hash_key_t key;
+ dbus_error_init(&dbus_error);
- sdp_req->err_maj = DP_ERR_FATAL;
- sdp_req->err_min = ETIMEDOUT;
- sdp_req->err_msg = discard_const_p(char, "Timed out");
+ reply = dbus_pending_call_steal_reply(pending);
+ if (!reply) {
+ /* reply should never be null. This function shouldn't be called
+ * until reply is valid or timeout has occurred. If reply is NULL
+ * here, something is seriously wrong and we should bail out.
+ */
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Severe error. A reply callback was called but no reply "
+ "was received and no timeout occurred\n"));
- /* Destroy the hash entry */
- key.type = HASH_KEY_STRING;
- key.str = sdp_req->key;
- int hret = hash_delete(dp_requests, &key);
- if (hret != HASH_SUCCESS) {
- /* This should never happen */
- DEBUG(0, ("Could not clear entry from request queue\n"));
+ /* FIXME: Destroy this connection ? */
+ err = EIO;
+ goto done;
}
- /* Queue up all callbacks */
- cb = sdp_req->cb_list;
- tv = tevent_timeval_current();
- while (cb) {
- next = cb->next;
- tev = tevent_add_timer(sdp_req->ev, sdp_req, tv,
- sss_dp_invoke_callback, sdp_req);
- if (!tev) {
- return;
+ type = dbus_message_get_type(reply);
+ switch (type) {
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ ret = dbus_message_get_args(reply, &dbus_error,
+ DBUS_TYPE_UINT16, err_maj,
+ DBUS_TYPE_UINT32, err_min,
+ DBUS_TYPE_STRING, err_msg,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("Failed to parse message\n"));
+ /* FIXME: Destroy this connection ? */
+ if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
+ err = EIO;
+ goto done;
}
- cb = next;
- }
-}
-
-static void sss_dp_send_acct_callback(DBusPendingCall *pending, void *ptr)
-{
- int ret;
- struct sss_dp_req *sdp_req;
- struct sss_dp_callback *cb, *next;
- struct timeval tv;
- struct tevent_timer *te;
- hash_key_t key;
-
- sdp_req = talloc_get_type(ptr, struct sss_dp_req);
+ DEBUG(4, ("Got reply (%u, %u, %s) from Data Provider\n",
+ (unsigned int)*err_maj, (unsigned int)*err_min, *err_msg));
- /* prevent trying to cancel a reply that we already received */
- sdp_req->pending_reply = NULL;
+ break;
- ret = sss_dp_get_reply(pending,
- &sdp_req->err_maj,
- &sdp_req->err_min,
- &sdp_req->err_msg);
- if (ret != EOK) {
- if (ret == ETIME) {
- sdp_req->err_maj = DP_ERR_TIMEOUT;
- sdp_req->err_min = ret;
- sdp_req->err_msg = talloc_strdup(sdp_req, "Request timed out");
- }
- else {
- sdp_req->err_maj = DP_ERR_FATAL;
- sdp_req->err_min = ret;
- sdp_req->err_msg =
- talloc_strdup(sdp_req,
- "Failed to get reply from Data Provider");
+ case DBUS_MESSAGE_TYPE_ERROR:
+ if (strcmp(dbus_message_get_error_name(reply),
+ DBUS_ERROR_NO_REPLY) == 0) {
+ err = ETIME;
+ goto done;
}
- }
+ DEBUG(0,("The Data Provider returned an error [%s]\n",
+ dbus_message_get_error_name(reply)));
+ /* Falling through to default intentionally*/
+ default:
+ /*
+ * Timeout or other error occurred or something
+ * unexpected happened.
+ * It doesn't matter which, because either way we
+ * know that this connection isn't trustworthy.
+ * We'll destroy it now.
+ */
- /* Check whether we need to issue any callbacks */
- if (sdp_req->cb_list == NULL) {
- /* No callbacks to invoke. Destroy the hash entry */
- talloc_zfree(sdp_req);
- return;
+ /* FIXME: Destroy this connection ? */
+ err = EIO;
}
- /* Destroy the hash entry */
- key.type = HASH_KEY_STRING;
- key.str = sdp_req->key;
- int hret = hash_delete(dp_requests, &key);
- if (hret != HASH_SUCCESS) {
- /* This should never happen */
- DEBUG(0, ("Could not clear entry from request queue\n"));
- }
+done:
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(reply);
- /* Queue up all callbacks */
- cb = sdp_req->cb_list;
- tv = tevent_timeval_current();
- while (cb) {
- next = cb->next;
- te = tevent_add_timer(sdp_req->ev, sdp_req, tv,
- sss_dp_invoke_callback, sdp_req);
- if (!te) {
- /* Out of memory or other serious error */
- return;
- }
- cb = next;
- }
+ return err;
}
-static int sss_dp_send_acct_req_create(struct resp_ctx *rctx,
- TALLOC_CTX *callback_memctx,
- const char *domain,
- uint32_t be_type,
- char *filter,
- int timeout,
- sss_dp_callback_t callback,
- void *callback_ctx,
- struct sss_dp_req **ndp);
-
-int sss_dp_send_acct_req(struct resp_ctx *rctx, TALLOC_CTX *callback_memctx,
- sss_dp_callback_t callback, void *callback_ctx,
- int timeout, const char *domain,
- bool fast_reply, int type,
- const char *opt_name, uint32_t opt_id)
+static struct tevent_req *
+sss_dp_get_account_int_send(struct resp_ctx *rctx,
+ hash_key_t *key,
+ struct sss_domain_info *dom,
+ uint32_t be_type,
+ const char *filter);
+
+static void
+sss_dp_get_account_done(struct tevent_req *subreq);
+
+static errno_t
+sss_dp_get_account_int_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ dbus_uint16_t *err_maj,
+ dbus_uint32_t *err_min,
+ char **err_msg);
+
+
+/* Send a request to the data provider
+ * Once this function is called, the communication
+ * with the data provider will always run to
+ * completion. Freeing the returned tevent_req will
+ * cancel the notification of completion, but not
+ * the data provider action.
+ */
+struct tevent_req *
+sss_dp_get_account_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ struct sss_domain_info *dom,
+ bool fast_reply,
+ int type,
+ const char *opt_name,
+ uint32_t opt_id)
{
- int ret, hret;
- uint32_t be_type;
+ errno_t ret;
+ int hret;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct dp_get_account_state *state;
+ struct sss_dp_req *sdp_req;
+ struct sss_dp_callback *cb;
char *filter;
- hash_key_t key;
+ uint32_t be_type;
hash_value_t value;
- TALLOC_CTX *tmp_ctx;
- struct timeval tv;
- struct sss_dp_req *sdp_req = NULL;
- struct sss_dp_callback *cb;
+
+ req = tevent_req_create(mem_ctx, &state, struct dp_get_account_state);
+ if (!req) {
+ return NULL;
+ }
/* either, or, not both */
if (opt_name && opt_id) {
- return EINVAL;
+ ret = EINVAL;
+ goto error;
}
- if (!domain) {
- return EINVAL;
+ if (!dom) {
+ ret = EINVAL;
+ goto error;
}
+ state->rctx = rctx;
+ state->dom = dom;
+
switch (type) {
case SSS_DP_USER:
be_type = BE_REQ_USER;
@@ -304,160 +293,233 @@ int sss_dp_send_acct_req(struct resp_ctx *rctx, TALLOC_CTX *callback_memctx,
be_type = BE_REQ_NETGROUP;
break;
default:
- return EINVAL;
+ ret = EINVAL;
+ goto error;
}
if (fast_reply) {
be_type |= BE_REQ_FAST;
}
- if (dp_requests == NULL) {
- /* Create a hash table to handle queued update requests */
- ret = hash_create(10, &dp_requests, NULL, NULL);
- if (ret != HASH_SUCCESS) {
- fprintf(stderr, "cannot create hash table (%s)\n", hash_error_string(ret));
- return EIO;
- }
- }
+ /* Check whether there's already an identical request in progress */
- tmp_ctx = talloc_new(NULL);
- if (!tmp_ctx) {
- return ENOMEM;
+ state->key = talloc(state, hash_key_t);
+ if (!state->key) {
+ ret = ENOMEM;
+ goto error;
}
- key.type = HASH_KEY_STRING;
- key.str = NULL;
+ state->key->type = HASH_KEY_STRING;
if (opt_name) {
- filter = talloc_asprintf(tmp_ctx, "name=%s", opt_name);
- key.str = talloc_asprintf(tmp_ctx, "%d%s@%s", type, opt_name, domain);
+ filter = talloc_asprintf(state, "name=%s", opt_name);
+ state->key->str = talloc_asprintf(state->key, "%d:%s@%s",
+ type, opt_name, dom->name);
} else if (opt_id) {
- filter = talloc_asprintf(tmp_ctx, "idnumber=%u", opt_id);
- key.str = talloc_asprintf(tmp_ctx, "%d%d@%s", type, opt_id, domain);
+ filter = talloc_asprintf(state, "idnumber=%u", opt_id);
+ state->key->str = talloc_asprintf(state->key, "%d:%d@%s",
+ type, opt_id, dom->name);
} else {
- filter = talloc_strdup(tmp_ctx, ENUM_INDICATOR);
- key.str = talloc_asprintf(tmp_ctx, "%d*@%s", type, domain);
+ filter = talloc_strdup(state, ENUM_INDICATOR);
+ state->key->str = talloc_asprintf(state->key, "%d:*@%s",
+ type, dom->name);
}
- if (!filter || !key.str) {
- talloc_zfree(tmp_ctx);
- return ENOMEM;
+ if (!filter || !state->key->str) {
+ ret = ENOMEM;
}
- /* Check whether there's already a request in progress */
- hret = hash_lookup(dp_requests, &key, &value);
+ /* Check the hash for existing references to this request */
+ hret = hash_lookup(rctx->dp_request_table, state->key, &value);
switch (hret) {
case HASH_SUCCESS:
- /* Request already in progress
- * Add an additional callback if needed and return
- */
- DEBUG(2, ("Identical request in progress\n"));
-
- if (callback) {
- /* We have a new request asking for a callback */
- sdp_req = talloc_get_type(value.ptr, struct sss_dp_req);
- if (!sdp_req) {
- DEBUG(0, ("Could not retrieve DP request context\n"));
- ret = EIO;
- goto done;
- }
-
- cb = talloc_zero(callback_memctx, struct sss_dp_callback);
- if (!cb) {
- ret = ENOMEM;
- goto done;
- }
-
- cb->callback = callback;
- cb->callback_ctx = callback_ctx;
- cb->sdp_req = sdp_req;
-
- DLIST_ADD_END(sdp_req->cb_list, cb, struct sss_dp_callback *);
- talloc_set_destructor((TALLOC_CTX *)cb, sss_dp_callback_destructor);
- }
-
- ret = EOK;
+ /* Request already in progress */
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Identical request in progress: [%s]\n", state->key->str));
break;
case HASH_ERROR_KEY_NOT_FOUND:
/* No such request in progress
* Create a new request
*/
- ret = sss_dp_send_acct_req_create(rctx, callback_memctx, domain,
- be_type, filter, timeout,
- callback, callback_ctx,
- &sdp_req);
- if (ret != EOK) {
- goto done;
- }
value.type = HASH_VALUE_PTR;
- value.ptr = sdp_req;
- hret = hash_enter(dp_requests, &key, &value);
- if (hret != HASH_SUCCESS) {
- DEBUG(0, ("Could not store request query (%s)\n",
- hash_error_string(hret)));
- talloc_zfree(sdp_req);
- ret = EIO;
- goto done;
- }
-
- sdp_req->key = talloc_strdup(sdp_req, key.str);
-
- tv = tevent_timeval_current_ofs(timeout, 0);
- sdp_req->tev = tevent_add_timer(sdp_req->ev, sdp_req, tv,
- sdp_req_timeout, sdp_req);
- if (!sdp_req->tev) {
- DEBUG(0, ("Out of Memory!?\n"));
- talloc_zfree(sdp_req);
+ subreq = sss_dp_get_account_int_send(rctx, state->key, dom,
+ be_type, filter);
+ if (!subreq) {
ret = ENOMEM;
- goto done;
+ goto error;
}
+ tevent_req_set_callback(subreq, sss_dp_get_account_done, NULL);
- talloc_set_destructor((TALLOC_CTX *)sdp_req, sss_dp_req_destructor);
+ /* We should now be able to find the sdp_req in the hash table */
+ hret = hash_lookup(rctx->dp_request_table, state->key, &value);
+ if (hret != HASH_SUCCESS) {
+ /* Something must have gone wrong with creating the request */
+ talloc_zfree(subreq);
+ ret = EIO;
+ goto error;
+ }
- ret = EOK;
break;
default:
- DEBUG(0,("Could not query request list (%s)\n",
- hash_error_string(hret)));
- talloc_zfree(sdp_req);
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Could not query request list (%s)\n",
+ hash_error_string(hret)));
ret = EIO;
+ goto error;
}
-done:
- talloc_zfree(tmp_ctx);
- return ret;
+ /* Register this request for results */
+ sdp_req = talloc_get_type(value.ptr, struct sss_dp_req);
+ if (!sdp_req) {
+ DEBUG(0, ("Could not retrieve DP request context\n"));
+ ret = EIO;
+ goto error;
+ }
+
+ cb = talloc_zero(state, struct sss_dp_callback);
+ if (!cb) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ cb->req = req;
+ cb->sdp_req = sdp_req;
+
+ /* Add it to the list of requests to call */
+ DLIST_ADD_END(sdp_req->cb_list, cb,
+ struct sss_dp_callback *);
+ talloc_set_destructor((TALLOC_CTX *)cb,
+ sss_dp_callback_destructor);
+
+ return req;
+
+error:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, rctx->ev);
+ return req;
}
-static int sss_dp_send_acct_req_create(struct resp_ctx *rctx,
- TALLOC_CTX *callback_memctx,
- const char *domain,
- uint32_t be_type,
- char *filter,
- int timeout,
- sss_dp_callback_t callback,
- void *callback_ctx,
- struct sss_dp_req **ndp)
+static void
+sss_dp_get_account_done(struct tevent_req *subreq)
{
- DBusMessage *msg;
+ errno_t ret;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dp_get_account_state *state =
+ tevent_req_data(req, struct dp_get_account_state);
+
+ ret = sss_dp_get_account_int_recv(state, req,
+ &state->err_maj,
+ &state->err_min,
+ &state->err_msg);
+ if (ret != EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+}
+
+errno_t
+sss_dp_get_account_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ dbus_uint16_t *err_maj,
+ dbus_uint32_t *err_min,
+ char **err_msg)
+{
+ struct dp_get_account_state *state =
+ tevent_req_data(req, struct dp_get_account_state);
+
+ enum tevent_req_state TRROEstate;
+ uint64_t TRROEerr;
+
+ *err_maj = state->err_maj;
+ *err_min = state->err_min;
+ *err_msg = talloc_steal(mem_ctx, state->err_msg);
+
+ if (tevent_req_is_error(req, &TRROEstate, &TRROEerr)) {
+ if (TRROEstate == TEVENT_REQ_USER_ERROR) {
+ *err_maj = DP_ERR_FATAL;
+ *err_min = TRROEerr;
+ } else {
+ return EIO;
+ }
+ }
+
+ return EOK;
+}
+
+struct dp_get_account_int_state {
+ struct resp_ctx *rctx;
+ struct sss_domain_info *dom;
+ uint32_t be_type;
+ const char *filter;
+
+ struct sss_dp_req *sdp_req;
DBusPendingCall *pending_reply;
+};
+
+static void sss_dp_get_account_int_done(DBusPendingCall *pending, void *ptr);
+
+static struct tevent_req *
+sss_dp_get_account_int_send(struct resp_ctx *rctx,
+ hash_key_t *key,
+ struct sss_domain_info *dom,
+ uint32_t be_type,
+ const char *filter)
+{
+ errno_t ret;
+ int hret;
+ struct tevent_req *req;
+ struct dp_get_account_int_state *state;
+ struct be_conn *be_conn;
+ DBusMessage *msg;
dbus_bool_t dbret;
- struct sss_dp_callback *cb;
- struct sss_dp_req *sdp_req;
+ bool msg_created = false;
+ hash_value_t value;
uint32_t attrs = BE_ATTR_CORE;
- struct be_conn *be_conn;
- int ret;
+
+ /* Internal requests need to be allocated on the responder context
+ * so that they don't go away if a client disconnects. The worst-
+ * case scenario here is that the cache is updated without any
+ * client expecting a response.
+ */
+ req = tevent_req_create(rctx,
+ &state,
+ struct dp_get_account_int_state);
+ if (!req) return NULL;
+
+ state->rctx = rctx;
+ state->dom = dom;
+ state->be_type = be_type;
+ state->filter = filter;
+
+ state->sdp_req = talloc_zero(state, struct sss_dp_req);
+ if (!state->sdp_req) {
+ ret = ENOMEM;
+ goto error;
+ }
+ state->sdp_req->rctx = rctx;
+ state->sdp_req->ev = rctx->ev;
+
+ /* Copy the key to use when calling the destructor
+ * It needs to be a copy because the original request
+ * might be freed if it no longer cares about the reply.
+ */
+ state->sdp_req->key = talloc_steal(state->sdp_req, key);
/* double check dp_ctx has actually been initialized.
* in some pathological cases it may happen that nss starts up before
* dp connection code is actually able to establish a connection.
*/
- ret = sss_dp_get_domain_conn(rctx, domain, &be_conn);
+ ret = sss_dp_get_domain_conn(rctx, dom->name, &be_conn);
if (ret != EOK) {
- DEBUG(1, ("The Data Provider connection for %s is not available!"
- " This maybe a bug, it shouldn't happen!\n", domain));
- return EIO;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("BUG: The Data Provider connection for %s is not available!",
+ dom->name));
+ ret = EIO;
+ goto error;
}
/* create the message */
@@ -467,11 +529,14 @@ static int sss_dp_send_acct_req_create(struct resp_ctx *rctx,
DP_METHOD_GETACCTINFO);
if (msg == NULL) {
DEBUG(0,("Out of memory?!\n"));
- return ENOMEM;
+ ret = ENOMEM;
+ goto error;
}
+ msg_created = true;
- DEBUG(4, ("Sending request for [%s][%u][%d][%s]\n",
- domain, be_type, attrs, filter));
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Sending request for [%s][%u][%d][%s]\n",
+ dom->name, be_type, attrs, filter));
dbret = dbus_message_append_args(msg,
DBUS_TYPE_UINT32, &be_type,
@@ -480,125 +545,141 @@ static int sss_dp_send_acct_req_create(struct resp_ctx *rctx,
DBUS_TYPE_INVALID);
if (!dbret) {
DEBUG(1,("Failed to build message\n"));
- return EIO;
- }
-
- sdp_req = talloc_zero(rctx, struct sss_dp_req);
- if (!sdp_req) {
- dbus_message_unref(msg);
- return ENOMEM;
+ ret = EIO;
+ goto error;
}
- sdp_req->rctx = rctx;
- ret = sbus_conn_send(be_conn->conn, msg, timeout,
- sss_dp_send_acct_callback,
- sdp_req, &pending_reply);
+ ret = sbus_conn_send(be_conn->conn, msg,
+ SSS_CLI_SOCKET_TIMEOUT / 2,
+ sss_dp_get_account_int_done,
+ req,
+ &state->sdp_req->pending_reply);
dbus_message_unref(msg);
+ msg_created = false;
if (ret != EOK) {
/*
* Critical Failure
* We can't communicate on this connection
- * We'll drop it using the default destructor.
*/
- DEBUG(0, ("D-BUS send failed.\n"));
- return EIO;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("D-BUS send failed.\n"));
+ ret = EIO;
+ goto error;
}
- sdp_req->ev = rctx->ev;
- sdp_req->pending_reply = pending_reply;
+ /* Add this sdp_req to the hash table */
+ value.type = HASH_VALUE_PTR;
+ value.ptr = state->sdp_req;
- if (callback) {
- cb = talloc_zero(callback_memctx, struct sss_dp_callback);
- if (!cb) {
- talloc_zfree(sdp_req);
- return ENOMEM;
- }
- cb->callback = callback;
- cb->callback_ctx = callback_ctx;
- cb->sdp_req = sdp_req;
-
- DLIST_ADD(sdp_req->cb_list, cb);
- talloc_set_destructor((TALLOC_CTX *)cb, sss_dp_callback_destructor);
+ hret = hash_enter(rctx->dp_request_table, key, &value);
+ if (hret != HASH_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Could not store request query (%s)\n",
+ hash_error_string(hret)));
+ ret = EIO;
+ goto error;
}
+ talloc_set_destructor((TALLOC_CTX *)state->sdp_req,
+ sss_dp_req_destructor);
- *ndp = sdp_req;
+ return req;
- return EOK;
+error:
+ if (msg_created) {
+ dbus_message_unref(msg);
+ }
+
+ tevent_req_error(req, ret);
+ tevent_req_post(req, rctx->ev);
+ return req;
}
-static int sss_dp_get_reply(DBusPendingCall *pending,
- dbus_uint16_t *err_maj,
- dbus_uint32_t *err_min,
- char **err_msg)
+static void sss_dp_get_account_int_done(DBusPendingCall *pending, void *ptr)
{
- DBusMessage *reply;
- DBusError dbus_error;
- dbus_bool_t ret;
- int type;
- int err = EOK;
+ int ret;
+ struct tevent_req *req;
+ struct sss_dp_req *sdp_req;
+ struct sss_dp_callback *cb;
+ struct dp_get_account_int_state *state;
+ struct dp_get_account_state *cb_state;
- dbus_error_init(&dbus_error);
+ req = talloc_get_type(ptr, struct tevent_req);
+ state = tevent_req_data(req, struct dp_get_account_int_state);
+ sdp_req = state->sdp_req;
- reply = dbus_pending_call_steal_reply(pending);
- if (!reply) {
- /* reply should never be null. This function shouldn't be called
- * until reply is valid or timeout has occurred. If reply is NULL
- * here, something is seriously wrong and we should bail out.
- */
- DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n"));
+ /* prevent trying to cancel a reply that we already received */
+ sdp_req->pending_reply = NULL;
- /* FIXME: Destroy this connection ? */
- err = EIO;
- goto done;
+ ret = sss_dp_get_reply(pending,
+ &sdp_req->err_maj,
+ &sdp_req->err_min,
+ &sdp_req->err_msg);
+ if (ret != EOK) {
+ if (ret == ETIME) {
+ sdp_req->err_maj = DP_ERR_TIMEOUT;
+ sdp_req->err_min = ret;
+ sdp_req->err_msg = talloc_strdup(sdp_req, "Request timed out");
+ }
+ else {
+ sdp_req->err_maj = DP_ERR_FATAL;
+ sdp_req->err_min = ret;
+ sdp_req->err_msg =
+ talloc_strdup(sdp_req,
+ "Failed to get reply from Data Provider");
+ }
}
- type = dbus_message_get_type(reply);
- switch (type) {
- case DBUS_MESSAGE_TYPE_METHOD_RETURN:
- ret = dbus_message_get_args(reply, &dbus_error,
- DBUS_TYPE_UINT16, err_maj,
- DBUS_TYPE_UINT32, err_min,
- DBUS_TYPE_STRING, err_msg,
- DBUS_TYPE_INVALID);
- if (!ret) {
- DEBUG(1,("Failed to parse message\n"));
- /* FIXME: Destroy this connection ? */
- if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
- err = EIO;
- goto done;
+ /* Check whether we need to issue any callbacks */
+ DLIST_FOR_EACH(cb, sdp_req->cb_list) {
+ cb_state = tevent_req_data(cb->req, struct dp_get_account_state);
+ cb_state->err_maj = sdp_req->err_maj;
+ cb_state->err_min = sdp_req->err_min;
+ cb_state->err_msg = talloc_strdup(cb_state, sdp_req->err_msg);
+ /* Don't bother checking for NULL. If it fails due to ENOMEM,
+ * we can't really handle it annyway.
+ */
+
+ if (ret == EOK) {
+ tevent_req_done(cb->req);
+ } else {
+ tevent_req_error(cb->req, ret);
}
- DEBUG(4, ("Got reply (%u, %u, %s) from Data Provider\n",
- (unsigned int)*err_maj, (unsigned int)*err_min, *err_msg));
+ /* Remove each callback from the list as it's replied to */
+ DLIST_REMOVE(sdp_req->cb_list, cb);
+ }
- break;
+ /* We're done with this request. Free the sdp_req
+ * This will clean up the hash table entry as well
+ */
+ talloc_zfree(sdp_req);
+}
- case DBUS_MESSAGE_TYPE_ERROR:
- if (strcmp(dbus_message_get_error_name(reply),
- DBUS_ERROR_NO_REPLY) == 0) {
- err = ETIME;
- goto done;
- }
- DEBUG(0,("The Data Provider returned an error [%s]\n",
- dbus_message_get_error_name(reply)));
- /* Falling through to default intentionally*/
- default:
- /*
- * Timeout or other error occurred or something
- * unexpected happened.
- * It doesn't matter which, because either way we
- * know that this connection isn't trustworthy.
- * We'll destroy it now.
- */
+static errno_t
+sss_dp_get_account_int_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ dbus_uint16_t *err_maj,
+ dbus_uint32_t *err_min,
+ char **err_msg)
+{
+ struct dp_get_account_int_state *state =
+ tevent_req_data(req, struct dp_get_account_int_state);
- /* FIXME: Destroy this connection ? */
- err = EIO;
- }
+ enum tevent_req_state TRROEstate;
+ uint64_t TRROEerr;
-done:
- dbus_pending_call_unref(pending);
- dbus_message_unref(reply);
+ *err_maj = state->sdp_req->err_maj;
+ *err_min = state->sdp_req->err_min;
+ *err_msg = talloc_steal(mem_ctx, state->sdp_req->err_msg);
- return err;
-}
+ if (tevent_req_is_error(req, &TRROEstate, &TRROEerr)) {
+ if (TRROEstate == TEVENT_REQ_USER_ERROR) {
+ *err_maj = DP_ERR_FATAL;
+ *err_min = TRROEerr;
+ } else {
+ return EIO;
+ }
+ }
+ return EOK;
+}
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index a37bd766..fcfacb73 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -533,6 +533,7 @@ static int nss_cmd_getpw_send_reply(struct nss_dom_ctx *dctx, bool filter)
return EOK;
}
+static void nsssrv_dp_send_acct_req_done(struct tevent_req *req);
/* FIXME: do not check res->count, but get in a msgs and check in parent */
/* FIXME: do not sss_cmd_done, but return error and let parent do it */
@@ -546,7 +547,6 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
void *pvt)
{
errno_t ret;
- int timeout;
time_t now;
uint64_t lastUpdate;
uint64_t cacheExpire = 0;
@@ -554,6 +554,8 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
struct nss_cmd_ctx *cmdctx = dctx->cmdctx;
struct cli_ctx *cctx = cmdctx->cctx;
bool off_band_update = false;
+ struct tevent_req *req = NULL;
+ struct dp_callback_ctx *cb_ctx = NULL;
/* when searching for a user or netgroup, more than one reply is a
* db error
@@ -620,26 +622,27 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
}
if (off_band_update) {
-
- timeout = SSS_CLI_SOCKET_TIMEOUT/2;
-
/* No callback required
* This was an out-of-band update. We'll return EOK
* so the calling function can return the cached entry
* immediately.
*/
- ret = sss_dp_send_acct_req(cctx->rctx, NULL, NULL, NULL,
- timeout, dctx->domain->name,
- true, req_type,
- opt_name, opt_id);
- if (ret != EOK) {
- DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
- ret, strerror(ret)));
+ req = sss_dp_get_account_send(cctx, cctx->rctx, dctx->domain, true,
+ req_type, opt_name, opt_id);
+ if (!req) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Out of memory sending out-of-band data provider "
+ "request\n"));
+ /* This is non-fatal, so we'll continue here */
} else {
-
- DEBUG(3, ("Updating cache out-of-band\n"));
+ DEBUG(SSSDBG_TRACE_FUNC, ("Updating cache out-of-band\n"));
}
+ /* We don't need to listen for a reply, so we will free the
+ * request here.
+ */
+ talloc_zfree(req);
+
} else {
/* This is a cache miss. Or the cache is expired.
* We need to get the updated user information before returning it.
@@ -647,32 +650,66 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
/* dont loop forever :-) */
dctx->check_provider = false;
- timeout = SSS_CLI_SOCKET_TIMEOUT/2;
/* keep around current data in case backend is offline */
if (res->count) {
dctx->res = talloc_steal(dctx, res);
}
- ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
- callback, pvt, timeout,
- dctx->domain->name,
- true, req_type,
- opt_name, opt_id);
- if (ret != EOK) {
- DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
- ret, strerror(ret)));
- ret = nss_cmd_send_error(cmdctx, ret);
- if (ret != EOK) {
- NSS_CMD_FATAL_ERROR_CODE(cctx, EIO);
- }
- sss_cmd_done(cctx, cmdctx);
+ req = sss_dp_get_account_send(dctx, cctx->rctx, dctx->domain, true,
+ req_type, opt_name, opt_id);
+ if (!req) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Out of memory sending data provider request\n"));
+ ret = ENOMEM;
+ goto error;
}
+ cb_ctx = talloc_zero(dctx, struct dp_callback_ctx);
+ if(!cb_ctx) {
+ talloc_zfree(req);
+ ret = ENOMEM;
+ goto error;
+ }
+ cb_ctx->callback = callback;
+ cb_ctx->ptr = dctx;
+ cb_ctx->cctx = dctx->cmdctx->cctx;
+ cb_ctx->mem_ctx = dctx;
+
+ tevent_req_set_callback(req, nsssrv_dp_send_acct_req_done, cb_ctx);
+
return EAGAIN;
}
return EOK;
+
+error:
+ ret = nss_cmd_send_error(cmdctx, ret);
+ if (ret != EOK) {
+ NSS_CMD_FATAL_ERROR_CODE(cctx, ret);
+ }
+ sss_cmd_done(cctx, cmdctx);
+ return EOK;
+}
+
+static void nsssrv_dp_send_acct_req_done(struct tevent_req *req)
+{
+ struct dp_callback_ctx *cb_ctx =
+ tevent_req_callback_data(req, struct dp_callback_ctx);
+
+ errno_t ret;
+ dbus_uint16_t err_maj;
+ dbus_uint32_t err_min;
+ char *err_msg;
+
+ ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
+ &err_maj, &err_min,
+ &err_msg);
+ if (ret != EOK) {
+ NSS_CMD_FATAL_ERROR(cb_ctx->cctx);
+ }
+
+ cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
}
static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min,
@@ -1274,6 +1311,7 @@ struct tevent_req *nss_cmd_setpwent_send(TALLOC_CTX *mem_ctx,
step_ctx->nctx = state->nctx;
step_ctx->getent_ctx = state->getent_ctx;
step_ctx->rctx = client->rctx;
+ step_ctx->cctx = client;
step_ctx->returned_to_mainloop = false;
ret = nss_cmd_setpwent_step(step_ctx);
@@ -1315,7 +1353,8 @@ static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
struct setent_req_list *req;
struct timeval tv;
struct tevent_timer *te;
- int timeout;
+ struct tevent_req *dpreq;
+ struct dp_callback_ctx *cb_ctx;
while (dom) {
while (dom && dom->enumerate == 0) {
@@ -1347,18 +1386,29 @@ static errno_t nss_cmd_setpwent_step(struct setent_step_ctx *step_ctx)
step_ctx->returned_to_mainloop = true;
/* Only do this once per provider */
dctx->check_provider = false;
- timeout = SSS_CLI_SOCKET_TIMEOUT;
- ret = sss_dp_send_acct_req(rctx, step_ctx,
- nss_cmd_setpwent_dp_callback, step_ctx,
- timeout, dom->name, true,
- SSS_DP_USER, NULL, 0);
- if (ret == EOK) {
- return EAGAIN;
+ dpreq = sss_dp_get_account_send(step_ctx, rctx, dctx->domain, true,
+ SSS_DP_USER, NULL, 0);
+ if (!dpreq) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Enum Cache refresh for domain [%s] failed."
+ " Trying to return what we have in cache!\n",
+ dom->name));
} else {
- DEBUG(2, ("Enum Cache refresh for domain [%s] failed."
- " Trying to return what we have in cache!\n",
- dom->name));
+ cb_ctx = talloc_zero(step_ctx, struct dp_callback_ctx);
+ if(!cb_ctx) {
+ talloc_zfree(dpreq);
+ return ENOMEM;
+ }
+
+ cb_ctx->callback = nss_cmd_setpwent_dp_callback;
+ cb_ctx->ptr = step_ctx;
+ cb_ctx->cctx = step_ctx->cctx;
+ cb_ctx->mem_ctx = step_ctx;
+
+ tevent_req_set_callback(dpreq, nsssrv_dp_send_acct_req_done, cb_ctx);
+
+ return EAGAIN;
}
}
@@ -2541,6 +2591,7 @@ struct tevent_req *nss_cmd_setgrent_send(TALLOC_CTX *mem_ctx,
step_ctx->nctx = state->nctx;
step_ctx->getent_ctx = state->getent_ctx;
step_ctx->rctx = client->rctx;
+ step_ctx->cctx = client;
step_ctx->returned_to_mainloop = false;
ret = nss_cmd_setgrent_step(step_ctx);
@@ -2582,7 +2633,8 @@ static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
struct setent_req_list *req;
struct timeval tv;
struct tevent_timer *te;
- int timeout;
+ struct tevent_req *dpreq;
+ struct dp_callback_ctx *cb_ctx;
while (dom) {
while (dom && dom->enumerate == 0) {
@@ -2613,19 +2665,28 @@ static errno_t nss_cmd_setgrent_step(struct setent_step_ctx *step_ctx)
if (dctx->check_provider) {
step_ctx->returned_to_mainloop = true;
/* Only do this once per provider */
- dctx->check_provider = false;
- timeout = SSS_CLI_SOCKET_TIMEOUT;
+ dpreq = sss_dp_get_account_send(step_ctx, rctx, dctx->domain, true,
+ SSS_DP_USER, NULL, 0);
+ if (!dpreq) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Enum Cache refresh for domain [%s] failed."
+ " Trying to return what we have in cache!\n",
+ dom->name));
+ } else {
+ cb_ctx = talloc_zero(step_ctx, struct dp_callback_ctx);
+ if(!cb_ctx) {
+ talloc_zfree(dpreq);
+ return ENOMEM;
+ }
+
+ cb_ctx->callback = nss_cmd_setgrent_dp_callback;
+ cb_ctx->ptr = step_ctx;
+ cb_ctx->cctx = step_ctx->cctx;
+ cb_ctx->mem_ctx = step_ctx;
+
+ tevent_req_set_callback(dpreq, nsssrv_dp_send_acct_req_done, cb_ctx);
- ret = sss_dp_send_acct_req(rctx, step_ctx,
- nss_cmd_setgrent_dp_callback, step_ctx,
- timeout, dom->name, true,
- SSS_DP_GROUP, NULL, 0);
- if (ret == EOK) {
return EAGAIN;
- } else {
- DEBUG(2, ("Enum Cache refresh for domain [%s] failed."
- " Trying to return what we have in cache!\n",
- dom->name));
}
}
diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h
index 27b0e567..2aa322c5 100644
--- a/src/responder/nss/nsssrv_private.h
+++ b/src/responder/nss/nsssrv_private.h
@@ -85,6 +85,7 @@ struct setent_step_ctx {
struct nss_dom_ctx *dctx;
struct getent_ctx *getent_ctx;
struct resp_ctx *rctx;
+ struct cli_ctx *cctx;
bool check_next;
bool returned_to_mainloop;
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index 18ba3fdf..2a000f09 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -807,6 +807,8 @@ done:
return pam_check_user_done(preq, ret);
}
+static void pam_dp_send_acct_req_done(struct tevent_req *req);
+
static int pam_check_user_search(struct pam_auth_req *preq)
{
struct sss_domain_info *dom = preq->domain;
@@ -815,6 +817,8 @@ static int pam_check_user_search(struct pam_auth_req *preq)
struct sysdb_ctx *sysdb;
time_t cacheExpire;
int ret;
+ struct tevent_req *dpreq;
+ struct dp_callback_ctx *cb_ctx;
while (dom) {
/* if it is a domainless search, skip domains that require fully
@@ -904,18 +908,28 @@ static int pam_check_user_search(struct pam_auth_req *preq)
/* dont loop forever :-) */
preq->check_provider = false;
- ret = sss_dp_send_acct_req(preq->cctx->rctx, preq,
- pam_check_user_dp_callback, preq,
- SSS_CLI_SOCKET_TIMEOUT/2,
- dom->name, false,
- SSS_DP_INITGROUPS,
- name, 0);
- if (ret != EOK) {
- DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
- ret, strerror(ret)));
- preq->pd->pam_status = PAM_SYSTEM_ERR;
- return EIO;
+ dpreq = sss_dp_get_account_send(preq, preq->cctx->rctx,
+ dom, false, SSS_DP_INITGROUPS,
+ name, 0);
+ if (!dpreq) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Out of memory sending data provider request\n"));
+ return ENOMEM;
+ }
+
+ cb_ctx = talloc_zero(preq, struct dp_callback_ctx);
+ if(!cb_ctx) {
+ talloc_zfree(dpreq);
+ return ENOMEM;
}
+
+ cb_ctx->callback = pam_check_user_dp_callback;
+ cb_ctx->ptr = preq;
+ cb_ctx->cctx = preq->cctx;
+ cb_ctx->mem_ctx = preq;
+
+ tevent_req_set_callback(dpreq, pam_dp_send_acct_req_done, cb_ctx);
+
/* tell caller we are in an async call */
return EAGAIN;
}
@@ -924,6 +938,29 @@ static int pam_check_user_search(struct pam_auth_req *preq)
return ENOENT;
}
+static void pam_dp_send_acct_req_done(struct tevent_req *req)
+{
+ struct dp_callback_ctx *cb_ctx =
+ tevent_req_callback_data(req, struct dp_callback_ctx);
+
+ errno_t ret;
+ dbus_uint16_t err_maj;
+ dbus_uint32_t err_min;
+ char *err_msg;
+
+ ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
+ &err_maj, &err_min,
+ &err_msg);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Fatal error, killing connection!\n"));
+ talloc_free(cb_ctx->cctx);
+ return;
+ }
+
+ cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
+}
+
static int pam_check_user_done(struct pam_auth_req *preq, int ret)
{
switch (ret) {