>From 6199ccd06ce9bfa7416838ff0ad6f302f7032873 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 28 May 2013 18:43:13 +0200 Subject: [PATCH 06/15] LDAP: return sdap search return code to ID By default, the LDAP searches delete the entry from cache if it wasn't found during a search. But if a search wants to try both Global Catalog and LDAP, for example, it might be beneficial to have an option to only delete the entry from cache after the last operation fails to prevent unnecessary memberof operations for example. --- src/providers/ldap/ldap_common.h | 21 +++-- src/providers/ldap/ldap_id.c | 122 ++++++++++++++++++++--------- src/providers/ldap/ldap_id_netgroup.c | 15 +++- src/providers/ldap/ldap_id_services.c | 15 +++- src/providers/ldap/sdap_async_initgroups.c | 4 +- 5 files changed, 126 insertions(+), 51 deletions(-) diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h index 4945853e6cc1e7657d39639e2a39ba2b90646e9e..ee48ed6891c48bc243e22f0bdf42707617ee88ad 100644 --- a/src/providers/ldap/ldap_common.h +++ b/src/providers/ldap/ldap_common.h @@ -104,10 +104,12 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, struct be_acct_req *ar, struct sdap_id_ctx *id_ctx, struct sdap_domain *sdom, - struct sdap_id_conn_ctx *conn); + struct sdap_id_conn_ctx *conn, + bool noexist_delete); errno_t sdap_handle_acct_req_recv(struct tevent_req *req, - int *_dp_error, const char **_err); + int *_dp_error, const char **_err, + int *sdap_ret); /* auth */ void sdap_pam_auth_handler(struct be_req *breq); @@ -181,16 +183,18 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, struct sdap_id_conn_ctx *conn, const char *name, int filter_type, - int attrs_type); -int groups_get_recv(struct tevent_req *req, int *dp_error_out); + int attrs_type, + bool noexist_delete); +int groups_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret); struct tevent_req *ldap_netgroup_get_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_id_ctx *ctx, struct sdap_domain *sdom, struct sdap_id_conn_ctx *conn, - const char *name); -int ldap_netgroup_get_recv(struct tevent_req *req, int *dp_error_out); + const char *name, + bool noexist_delete); +int ldap_netgroup_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret); struct tevent_req * services_get_send(TALLOC_CTX *mem_ctx, @@ -200,10 +204,11 @@ services_get_send(TALLOC_CTX *mem_ctx, struct sdap_id_conn_ctx *conn, const char *name, const char *protocol, - int filter_type); + int filter_type, + bool noexist_delete); errno_t -services_get_recv(struct tevent_req *req, int *dp_error_out); +services_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret); /* setup child logging */ int sdap_setup_child(void); diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c index bfb34cc70b8f098245c2eada505e65b9589cb6a5..b29ab99301bee1f150f1554f0ce659507b627e90 100644 --- a/src/providers/ldap/ldap_id.c +++ b/src/providers/ldap/ldap_id.c @@ -52,6 +52,8 @@ struct users_get_state { const char **attrs; int dp_error; + int sdap_ret; + bool noexist_delete; }; static int users_get_retry(struct tevent_req *req); @@ -65,7 +67,8 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, struct sdap_id_conn_ctx *conn, const char *name, int filter_type, - int attrs_type) + int attrs_type, + bool noexist_delete) { struct tevent_req *req; struct users_get_state *state; @@ -85,6 +88,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, state->sdom = sdom; state->conn = conn; state->dp_error = DP_ERR_FATAL; + state->noexist_delete = noexist_delete; state->op = sdap_id_op_create(state, state->conn->conn_cache); if (!state->op) { @@ -302,6 +306,7 @@ static void users_get_done(struct tevent_req *subreq) } } } + state->sdap_ret = ret; if (ret && ret != ENOENT) { state->dp_error = dp_error; @@ -309,7 +314,7 @@ static void users_get_done(struct tevent_req *subreq) return; } - if (ret == ENOENT) { + if (ret == ENOENT && state->noexist_delete == true) { switch (state->filter_type) { case BE_FILTER_ENUM: tevent_req_error(req, ret); @@ -348,7 +353,7 @@ static void users_get_done(struct tevent_req *subreq) tevent_req_done(req); } -int users_get_recv(struct tevent_req *req, int *dp_error_out) +int users_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret) { struct users_get_state *state = tevent_req_data(req, struct users_get_state); @@ -357,6 +362,10 @@ int users_get_recv(struct tevent_req *req, int *dp_error_out) *dp_error_out = state->dp_error; } + if (sdap_ret) { + *sdap_ret = state->sdap_ret; + } + TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; @@ -380,6 +389,8 @@ struct groups_get_state { const char **attrs; int dp_error; + int sdap_ret; + bool noexist_delete; }; static int groups_get_retry(struct tevent_req *req); @@ -393,7 +404,8 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, struct sdap_id_conn_ctx *conn, const char *name, int filter_type, - int attrs_type) + int attrs_type, + bool noexist_delete) { struct tevent_req *req; struct groups_get_state *state; @@ -415,6 +427,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, state->sdom = sdom; state->conn = conn; state->dp_error = DP_ERR_FATAL; + state->noexist_delete = noexist_delete; state->op = sdap_id_op_create(state, state->conn->conn_cache); if (!state->op) { @@ -617,6 +630,7 @@ static void groups_get_done(struct tevent_req *subreq) return; } + state->sdap_ret = ret; if (ret && ret != ENOENT) { state->dp_error = dp_error; @@ -624,7 +638,7 @@ static void groups_get_done(struct tevent_req *subreq) return; } - if (ret == ENOENT) { + if (ret == ENOENT && state->noexist_delete == true) { switch (state->filter_type) { case BE_FILTER_ENUM: tevent_req_error(req, ret); @@ -663,7 +677,7 @@ static void groups_get_done(struct tevent_req *subreq) tevent_req_done(req); } -int groups_get_recv(struct tevent_req *req, int *dp_error_out) +int groups_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret) { struct groups_get_state *state = tevent_req_data(req, struct groups_get_state); @@ -672,6 +686,10 @@ int groups_get_recv(struct tevent_req *req, int *dp_error_out) *dp_error_out = state->dp_error; } + if (sdap_ret) { + *sdap_ret = state->sdap_ret; + } + TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; @@ -693,6 +711,8 @@ struct groups_by_user_state { const char **attrs; int dp_error; + int sdap_ret; + bool noexist_delete; }; static int groups_by_user_retry(struct tevent_req *req); @@ -704,7 +724,8 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx, struct sdap_domain *sdom, struct sdap_id_conn_ctx *conn, - const char *name) + const char *name, + bool noexist_delete) { struct tevent_req *req; struct groups_by_user_state *state; @@ -718,6 +739,7 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, state->dp_error = DP_ERR_FATAL; state->conn = conn; state->sdom = sdom; + state->noexist_delete = noexist_delete; state->op = sdap_id_op_create(state, state->conn->conn_cache); if (!state->op) { @@ -819,6 +841,7 @@ static void groups_by_user_done(struct tevent_req *subreq) return; } + state->sdap_ret = ret; if (ret && ret != ENOENT) { state->dp_error = dp_error; @@ -826,7 +849,7 @@ static void groups_by_user_done(struct tevent_req *subreq) return; } - if (ret == ENOENT) { + if (ret == ENOENT && state->noexist_delete == true) { ret = sysdb_delete_user(state->ctx->be->domain->sysdb, state->ctx->be->domain, state->name, 0); if (ret != EOK && ret != ENOENT) { @@ -839,7 +862,7 @@ static void groups_by_user_done(struct tevent_req *subreq) tevent_req_done(req); } -int groups_by_user_recv(struct tevent_req *req, int *dp_error_out) +int groups_by_user_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret) { struct groups_by_user_state *state = tevent_req_data(req, struct groups_by_user_state); @@ -848,6 +871,10 @@ int groups_by_user_recv(struct tevent_req *req, int *dp_error_out) *dp_error_out = state->dp_error; } + if (sdap_ret) { + *sdap_ret = state->sdap_ret; + } + TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; @@ -1006,7 +1033,8 @@ static struct tevent_req *get_user_and_group_send(TALLOC_CTX *memctx, struct sdap_id_conn_ctx *conn, const char *name, int filter_type, - int attrs_type); + int attrs_type, + bool noexist_delete); void sdap_account_info_handler(struct be_req *breq) { @@ -1028,6 +1056,7 @@ struct sdap_handle_acct_req_state { struct be_acct_req *ar; const char *err; int dp_error; + int sdap_ret; }; static void sdap_handle_acct_req_done(struct tevent_req *subreq); @@ -1038,7 +1067,8 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, struct be_acct_req *ar, struct sdap_id_ctx *id_ctx, struct sdap_domain *sdom, - struct sdap_id_conn_ctx *conn) + struct sdap_id_conn_ctx *conn, + bool noexist_delete) { struct tevent_req *req; struct tevent_req *subreq; @@ -1078,7 +1108,8 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, sdom, conn, ar->filter_value, ar->filter_type, - ar->attr_type); + ar->attr_type, + noexist_delete); break; case BE_REQ_GROUP: /* group */ @@ -1096,7 +1127,8 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, sdom, conn, ar->filter_value, ar->filter_type, - ar->attr_type); + ar->attr_type, + noexist_delete); break; case BE_REQ_INITGROUPS: /* init groups for user */ @@ -1112,8 +1144,9 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, } subreq = groups_by_user_send(breq, be_ctx->ev, id_ctx, - id_ctx->opts->sdom, sdom, conn, - ar->filter_value); + sdom, conn, + ar->filter_value, + noexist_delete); break; case BE_REQ_NETGROUP: @@ -1124,8 +1157,9 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, } subreq = ldap_netgroup_get_send(breq, be_ctx->ev, id_ctx, - id_ctx->opts->sdom, sdom, conn, - ar->filter_value); + sdom, conn, + ar->filter_value, + noexist_delete); break; case BE_REQ_SERVICES: @@ -1148,7 +1182,8 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, sdom, conn, ar->filter_value, ar->extra_value, - ar->filter_type); + ar->filter_type, + noexist_delete); break; case BE_REQ_BY_SECID: @@ -1162,7 +1197,8 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, sdom, conn, ar->filter_value, ar->filter_type, - ar->attr_type); + ar->attr_type, + noexist_delete); break; case BE_REQ_USER_AND_GROUP: @@ -1177,7 +1213,8 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, sdom, conn, ar->filter_value, ar->filter_type, - ar->attr_type); + ar->attr_type, + noexist_delete); break; default: /*fail*/ @@ -1218,29 +1255,30 @@ sdap_handle_acct_req_done(struct tevent_req *subreq) switch (state->ar->entry_type & BE_REQ_TYPE_MASK) { case BE_REQ_USER: /* user */ err = "User lookup failed"; - ret = users_get_recv(subreq, &state->dp_error); + ret = users_get_recv(subreq, &state->dp_error, &state->sdap_ret); break; case BE_REQ_GROUP: /* group */ err = "Group lookup failed"; - ret = groups_get_recv(subreq, &state->dp_error); + ret = groups_get_recv(subreq, &state->dp_error, &state->sdap_ret); break; case BE_REQ_INITGROUPS: /* init groups for user */ err = "Init group lookup failed"; - ret = groups_by_user_recv(subreq, &state->dp_error); + ret = groups_by_user_recv(subreq, &state->dp_error, &state->sdap_ret); break; case BE_REQ_NETGROUP: err = "Netgroup lookup failed"; - ret = ldap_netgroup_get_recv(subreq, &state->dp_error); + ret = ldap_netgroup_get_recv(subreq, &state->dp_error, &state->sdap_ret); break; case BE_REQ_SERVICES: err = "Service lookup failed"; - ret = services_get_recv(subreq, &state->dp_error); + ret = services_get_recv(subreq, &state->dp_error, &state->sdap_ret); break; case BE_REQ_BY_SECID: /* Fallthrough */ case BE_REQ_USER_AND_GROUP: err = "Lookup by SID failed"; - ret = sdap_get_user_and_group_recv(subreq, &state->dp_error); + ret = sdap_get_user_and_group_recv(subreq, &state->dp_error, + &state->sdap_ret); break; default: /*fail*/ ret = EINVAL; @@ -1260,7 +1298,8 @@ sdap_handle_acct_req_done(struct tevent_req *subreq) errno_t sdap_handle_acct_req_recv(struct tevent_req *req, - int *_dp_error, const char **_err) + int *_dp_error, const char **_err, + int *sdap_ret) { struct sdap_handle_acct_req_state *state; @@ -1274,6 +1313,10 @@ sdap_handle_acct_req_recv(struct tevent_req *req, *_err = state->err; } + if (sdap_ret) { + *sdap_ret = state->sdap_ret; + } + TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; } @@ -1297,7 +1340,7 @@ void sdap_handle_account_info(struct be_req *breq, struct sdap_id_ctx *ctx, } req = sdap_handle_acct_req_send(breq, breq, ar, ctx, - ctx->opts->sdom, conn); + ctx->opts->sdom, conn, NULL); if (req == NULL) { return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory"); } @@ -1311,7 +1354,7 @@ static void sdap_account_info_complete(struct tevent_req *req) struct be_req *breq = tevent_req_callback_data(req, struct be_req); int ret, dp_error; - ret = sdap_handle_acct_req_recv(req, &dp_error, &req_error_text); + ret = sdap_handle_acct_req_recv(req, &dp_error, &req_error_text, NULL); talloc_zfree(req); if (dp_error == DP_ERR_OK) { if (ret == EOK) { @@ -1350,6 +1393,8 @@ struct get_user_and_group_state { const char **attrs; int dp_error; + int sdap_ret; + bool noexist_delete; }; static void get_user_and_group_users_done(struct tevent_req *subreq); @@ -1362,7 +1407,8 @@ static struct tevent_req *get_user_and_group_send(TALLOC_CTX *memctx, struct sdap_id_conn_ctx *conn, const char *filter_val, int filter_type, - int attrs_type) + int attrs_type, + bool noexist_delete) { struct tevent_req *req; struct tevent_req *subreq; @@ -1380,6 +1426,7 @@ static struct tevent_req *get_user_and_group_send(TALLOC_CTX *memctx, state->sdom = sdom; state->conn = conn; state->dp_error = DP_ERR_FATAL; + state->noexist_delete = noexist_delete; state->op = sdap_id_op_create(state, state->conn->conn_cache); if (!state->op) { @@ -1397,7 +1444,7 @@ static struct tevent_req *get_user_and_group_send(TALLOC_CTX *memctx, subreq = users_get_send(req, state->ev, state->id_ctx, state->sdom, state->conn, state->filter_val, state->filter_type, - state->attrs_type); + state->attrs_type, NULL); if (subreq == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("users_get_send failed.\n")); ret = ENOMEM; @@ -1422,7 +1469,7 @@ static void get_user_and_group_users_done(struct tevent_req *subreq) struct get_user_and_group_state); int ret; - ret = users_get_recv(subreq, &state->dp_error); + ret = users_get_recv(subreq, &state->dp_error, NULL); talloc_zfree(subreq); if (ret == EOK) { /* Matching user found */ @@ -1436,7 +1483,7 @@ static void get_user_and_group_users_done(struct tevent_req *subreq) subreq = groups_get_send(req, state->ev, state->id_ctx, state->sdom, state->conn, state->filter_val, state->filter_type, - state->attrs_type); + state->attrs_type, state->noexist_delete); if (subreq == NULL) { DEBUG(SSSDBG_OP_FAILURE, ("groups_get_send failed.\n")); tevent_req_error(req, ENOMEM); @@ -1454,7 +1501,7 @@ static void get_user_and_group_groups_done(struct tevent_req *subreq) struct get_user_and_group_state); int ret; - ret = groups_get_recv(subreq, &state->dp_error); + ret = groups_get_recv(subreq, &state->dp_error, &state->sdap_ret); talloc_zfree(subreq); if (ret == EOK) { /* Matching group found */ @@ -1466,7 +1513,8 @@ static void get_user_and_group_groups_done(struct tevent_req *subreq) return; } -errno_t sdap_get_user_and_group_recv(struct tevent_req *req, int *dp_error_out) +errno_t sdap_get_user_and_group_recv(struct tevent_req *req, + int *dp_error_out, int *sdap_ret) { struct get_user_and_group_state *state = tevent_req_data(req, struct get_user_and_group_state); @@ -1475,6 +1523,10 @@ errno_t sdap_get_user_and_group_recv(struct tevent_req *req, int *dp_error_out) *dp_error_out = state->dp_error; } + if (sdap_ret) { + *sdap_ret = state->sdap_ret; + } + TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; diff --git a/src/providers/ldap/ldap_id_netgroup.c b/src/providers/ldap/ldap_id_netgroup.c index 759a9353bf93ed866d527969fb3006b3bff46216..e48a7da6c81be5a3fecc5f17a4797e0aacc3bacf 100644 --- a/src/providers/ldap/ldap_id_netgroup.c +++ b/src/providers/ldap/ldap_id_netgroup.c @@ -49,6 +49,8 @@ struct ldap_netgroup_get_state { struct sysdb_attrs **netgroups; int dp_error; + int sdap_ret; + bool noexist_delete; }; static int ldap_netgroup_get_retry(struct tevent_req *req); @@ -60,7 +62,8 @@ struct tevent_req *ldap_netgroup_get_send(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx, struct sdap_domain *sdom, struct sdap_id_conn_ctx *conn, - const char *name) + const char *name, + bool noexist_delete) { struct tevent_req *req; struct ldap_netgroup_get_state *state; @@ -75,6 +78,7 @@ struct tevent_req *ldap_netgroup_get_send(TALLOC_CTX *memctx, state->sdom = sdom; state->conn = conn; state->dp_error = DP_ERR_FATAL; + state->noexist_delete = noexist_delete; state->op = sdap_id_op_create(state, state->conn->conn_cache); if (!state->op) { @@ -195,6 +199,7 @@ static void ldap_netgroup_get_done(struct tevent_req *subreq) return; } + state->sdap_ret = ret; if (ret && ret != ENOENT) { state->dp_error = dp_error; @@ -209,7 +214,7 @@ static void ldap_netgroup_get_done(struct tevent_req *subreq) return; } - if (ret == ENOENT) { + if (ret == ENOENT && state->noexist_delete == true) { ret = sysdb_delete_netgroup(state->sysdb, state->domain, state->name); if (ret != EOK && ret != ENOENT) { tevent_req_error(req, ret); @@ -222,7 +227,7 @@ static void ldap_netgroup_get_done(struct tevent_req *subreq) return; } -int ldap_netgroup_get_recv(struct tevent_req *req, int *dp_error_out) +int ldap_netgroup_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret) { struct ldap_netgroup_get_state *state = tevent_req_data(req, struct ldap_netgroup_get_state); @@ -231,6 +236,10 @@ int ldap_netgroup_get_recv(struct tevent_req *req, int *dp_error_out) *dp_error_out = state->dp_error; } + if (sdap_ret) { + *sdap_ret = state->sdap_ret; + } + TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; diff --git a/src/providers/ldap/ldap_id_services.c b/src/providers/ldap/ldap_id_services.c index 8b331cac42756e5a88bbd9222a98baa9ce1014b3..1f3fd8043cb2741a96756909ec88abc659934a22 100644 --- a/src/providers/ldap/ldap_id_services.c +++ b/src/providers/ldap/ldap_id_services.c @@ -48,6 +48,8 @@ struct sdap_services_get_state { int filter_type; int dp_error; + int sdap_ret; + bool noexist_delete; }; static errno_t @@ -65,7 +67,8 @@ services_get_send(TALLOC_CTX *mem_ctx, struct sdap_id_conn_ctx *conn, const char *name, const char *protocol, - int filter_type) + int filter_type, + bool noexist_delete) { errno_t ret; struct tevent_req *req; @@ -87,6 +90,7 @@ services_get_send(TALLOC_CTX *mem_ctx, state->name = name; state->protocol = protocol; state->filter_type = filter_type; + state->noexist_delete = noexist_delete; state->op = sdap_id_op_create(state, state->conn->conn_cache); if (!state->op) { @@ -237,6 +241,7 @@ services_get_done(struct tevent_req *subreq) /* Return to the mainloop to retry */ return; } + state->sdap_ret = ret; /* An error occurred. */ if (ret && ret != ENOENT) { @@ -245,7 +250,7 @@ services_get_done(struct tevent_req *subreq) return; } - if (ret == ENOENT) { + if (ret == ENOENT && state->noexist_delete == true) { /* Ensure that this entry is removed from the sysdb */ switch(state->filter_type) { case BE_FILTER_NAME: @@ -283,7 +288,7 @@ services_get_done(struct tevent_req *subreq) } errno_t -services_get_recv(struct tevent_req *req, int *dp_error_out) +services_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret) { struct sdap_services_get_state *state = tevent_req_data(req, struct sdap_services_get_state); @@ -292,6 +297,10 @@ services_get_recv(struct tevent_req *req, int *dp_error_out) *dp_error_out = state->dp_error; } + if (sdap_ret) { + *sdap_ret = state->sdap_ret; + } + TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c index 68647cfa78e9509867bf4cd78f9eca1a99293b24..7678c7b36d79e40b76305477854ab2d051bbfaa3 100644 --- a/src/providers/ldap/sdap_async_initgroups.c +++ b/src/providers/ldap/sdap_async_initgroups.c @@ -2953,7 +2953,7 @@ static void sdap_get_initgr_done(struct tevent_req *subreq) subreq = groups_get_send(req, state->ev, state->id_ctx, state->id_ctx->opts->sdom, state->conn, - gid, BE_FILTER_IDNUM, BE_ATTR_ALL); + gid, BE_FILTER_IDNUM, BE_ATTR_ALL, NULL); if (!subreq) { ret = ENOMEM; goto fail; @@ -2976,7 +2976,7 @@ static void sdap_get_initgr_pgid(struct tevent_req *subreq) tevent_req_callback_data(subreq, struct tevent_req); errno_t ret; - ret = groups_get_recv(subreq, NULL); + ret = groups_get_recv(subreq, NULL, NULL); talloc_zfree(subreq); if (ret != EOK) { tevent_req_error(req, ret); -- 1.8.2.1