summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/providers/ipa/ipa_s2n_exop.c889
1 files changed, 802 insertions, 87 deletions
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index ccf4c2317..76494a031 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -36,18 +36,22 @@ enum input_types {
enum request_types {
REQ_SIMPLE = 1,
- REQ_FULL
+ REQ_FULL,
+ REQ_FULL_WITH_MEMBERS
};
enum response_types {
RESP_SID = 1,
RESP_NAME,
RESP_USER,
- RESP_GROUP
+ RESP_GROUP,
+ RESP_USER_GROUPLIST,
+ RESP_GROUP_MEMBERS
};
/* ==Sid2Name Extended Operation============================================= */
#define EXOP_SID2NAME_OID "2.16.840.1.113730.3.8.10.4"
+#define EXOP_SID2NAME_V1_OID "2.16.840.1.113730.3.8.10.4.1"
struct ipa_s2n_exop_state {
struct sdap_handle *sh;
@@ -65,6 +69,8 @@ static void ipa_s2n_exop_done(struct sdap_op *op,
static struct tevent_req *ipa_s2n_exop_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sdap_handle *sh,
+ bool is_v1,
+ int timeout,
struct berval *bv)
{
struct tevent_req *req = NULL;
@@ -81,18 +87,19 @@ static struct tevent_req *ipa_s2n_exop_send(TALLOC_CTX *mem_ctx,
DEBUG(SSSDBG_TRACE_FUNC, "Executing extended operation\n");
- ret = ldap_extended_operation(state->sh->ldap, EXOP_SID2NAME_OID,
- bv, NULL, NULL, &msgid);
+ ret = ldap_extended_operation(state->sh->ldap,
+ is_v1 ? EXOP_SID2NAME_V1_OID : EXOP_SID2NAME_OID,
+ bv, NULL, NULL, &msgid);
if (ret == -1 || msgid == -1) {
DEBUG(SSSDBG_CRIT_FAILURE, "ldap_extended_operation failed\n");
ret = ERR_NETWORK_IO;
goto fail;
}
- DEBUG(SSSDBG_TRACE_INTERNAL, "ldap_extended_operation sent, msgid = %d\n", msgid);
+ DEBUG(SSSDBG_TRACE_INTERNAL, "ldap_extended_operation sent, msgid = %d\n",
+ msgid);
- /* FIXME: get timeouts from configuration, for now 10 secs. */
- ret = sdap_op_add(state, ev, state->sh, msgid, ipa_s2n_exop_done, req, 10,
- &state->op);
+ ret = sdap_op_add(state, ev, state->sh, msgid, ipa_s2n_exop_done, req,
+ timeout, &state->op);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
ret = ERR_INTERNAL;
@@ -129,7 +136,8 @@ static void ipa_s2n_exop_done(struct sdap_op *op,
&result, &errmsg, NULL, NULL,
NULL, 0);
if (ret != LDAP_SUCCESS) {
- DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_result failed (%d)\n", state->op->msgid);
+ DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_result failed (%d)\n",
+ state->op->msgid);
ret = ERR_NETWORK_IO;
goto done;
}
@@ -145,7 +153,8 @@ static void ipa_s2n_exop_done(struct sdap_op *op,
ret = ldap_parse_extended_result(state->sh->ldap, reply->msg,
&retoid, &retdata, 0);
if (ret != LDAP_SUCCESS) {
- DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_extendend_result failed (%d)\n", ret);
+ DEBUG(SSSDBG_OP_FAILURE, "ldap_parse_extendend_result failed (%d)\n",
+ ret);
ret = ERR_NETWORK_IO;
goto done;
}
@@ -250,6 +259,7 @@ done:
* requestType ENUMERATED {
* simple (1),
* full (2)
+ * full_with_members (3)
* },
* data InputData
* }
@@ -370,7 +380,9 @@ done:
* sid (1),
* name (2),
* posix_user (3),
- * posix_group (4)
+ * posix_group (4),
+ * posix_user_grouplist (5),
+ * posix_group_members (6)
* },
* data OutputData
* }
@@ -379,7 +391,10 @@ done:
* sid OCTET STRING,
* name NameDomainData,
* user PosixUser,
- * group PosixGroup
+ * group PosixGroup,
+ * usergrouplist PosixUserGrouplist,
+ * groupmembers PosixGroupMembers
+ *
* }
*
* NameDomainData ::= SEQUENCE {
@@ -400,6 +415,27 @@ done:
* gid INTEGER
* }
*
+ * PosixUserGrouplist ::= SEQUENCE {
+ * domain_name OCTET STRING,
+ * user_name OCTET STRING,
+ * uid INTEGER,
+ * gid INTEGER,
+ * gecos OCTET STRING,
+ * home_directory OCTET STRING,
+ * shell OCTET STRING,
+ * grouplist GroupNameList
+ * }
+ *
+ * GroupNameList ::= SEQUENCE OF OCTET STRING
+ *
+ * PosixGroupMembers ::= SEQUENCE {
+ * domain_name OCTET STRING,
+ * group_name OCTET STRING,
+ * gid INTEGER,
+ * members GroupMemberList
+ * }
+ *
+ * GroupMemberList ::= SEQUENCE OF OCTET STRING
*/
struct resp_attrs {
@@ -411,8 +447,227 @@ struct resp_attrs {
char *sid_str;
char *name;
} a;
+ size_t ngroups;
+ char **groups;
+ struct sysdb_attrs *sysdb_attrs;
};
+static errno_t get_extra_attrs(BerElement *ber, struct resp_attrs *resp_attrs)
+{
+ ber_tag_t tag;
+ ber_len_t ber_len;
+ char *ber_cookie;
+ char *name;
+ struct berval **values;
+ struct ldb_val v;
+ int ret;
+ size_t c;
+
+ if (resp_attrs->sysdb_attrs == NULL) {
+ resp_attrs->sysdb_attrs = sysdb_new_attrs(resp_attrs);
+ if (resp_attrs->sysdb_attrs == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+ return ENOMEM;
+ }
+ }
+
+ DEBUG(SSSDBG_TRACE_ALL, "Found new sequence.\n");
+ for (tag = ber_first_element(ber, &ber_len, &ber_cookie);
+ tag != LBER_DEFAULT;
+ tag = ber_next_element(ber, &ber_len, ber_cookie)) {
+
+ tag = ber_scanf(ber, "{a{V}}", &name, &values);
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ return EINVAL;
+ }
+ DEBUG(SSSDBG_TRACE_ALL, "Extra attribute [%s].\n", name);
+
+ for (c = 0; values[c] != NULL; c++) {
+
+ v.data = (uint8_t *) values[c]->bv_val;
+ v.length = values[c]->bv_len;
+
+ ret = sysdb_attrs_add_val(resp_attrs->sysdb_attrs, name, &v);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
+ ldap_memfree(name);
+ ber_bvecfree(values);
+ return ret;
+ }
+ }
+
+ ldap_memfree(name);
+ ber_bvecfree(values);
+ }
+
+ return EOK;
+}
+
+static errno_t add_v1_user_data(BerElement *ber, struct resp_attrs *attrs)
+{
+ ber_tag_t tag;
+ ber_len_t ber_len;
+ int ret;
+ char *gecos = NULL;
+ char *homedir = NULL;
+ char *shell = NULL;
+ char **list = NULL;
+ size_t c;
+
+ tag = ber_scanf(ber, "aaa", &gecos, &homedir, &shell);
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (gecos == NULL || *gecos == '\0') {
+ attrs->a.user.pw_gecos = NULL;
+ } else {
+ attrs->a.user.pw_gecos = talloc_strdup(attrs, gecos);
+ if (attrs->a.user.pw_gecos == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ if (homedir == NULL || *homedir == '\0') {
+ attrs->a.user.pw_dir = NULL;
+ } else {
+ attrs->a.user.pw_dir = talloc_strdup(attrs, homedir);
+ if (attrs->a.user.pw_dir == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ if (shell == NULL || *shell == '\0') {
+ attrs->a.user.pw_shell = NULL;
+ } else {
+ attrs->a.user.pw_shell = talloc_strdup(attrs, shell);
+ if (attrs->a.user.pw_shell == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ tag = ber_scanf(ber, "{v}", &list);
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ for (attrs->ngroups = 0; list[attrs->ngroups] != NULL;
+ attrs->ngroups++);
+
+ if (attrs->ngroups > 0) {
+ attrs->groups = talloc_array(attrs, char *, attrs->ngroups);
+ if (attrs->groups == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (c = 0; c < attrs->ngroups; c++) {
+ attrs->groups[c] = talloc_strdup(attrs->groups,
+ list[c]);
+ if (attrs->groups[c] == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ }
+
+ tag = ber_peek_tag(ber, &ber_len);
+ DEBUG(SSSDBG_TRACE_ALL, "BER tag is [%d]\n", (int) tag);
+ if (tag == LBER_SEQUENCE) {
+ ret = get_extra_attrs(ber, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "get_extra_attrs failed.\n");
+ goto done;
+ }
+ }
+
+
+ ret = EOK;
+
+done:
+ ber_memfree(gecos);
+ ber_memfree(homedir);
+ ber_memfree(shell);
+ ber_memvfree((void **) list);
+
+ return ret;
+}
+
+static errno_t add_v1_group_data(BerElement *ber, struct resp_attrs *attrs)
+{
+ ber_tag_t tag;
+ ber_len_t ber_len;
+ int ret;
+ char **list = NULL;
+ size_t c;
+
+ tag = ber_scanf(ber, "{v}", &list);
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ for (attrs->ngroups = 0; list[attrs->ngroups] != NULL;
+ attrs->ngroups++);
+
+ if (attrs->ngroups > 0) {
+ attrs->a.group.gr_mem = talloc_zero_array(attrs, char *,
+ attrs->ngroups + 1);
+ if (attrs->a.group.gr_mem == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (c = 0; c < attrs->ngroups; c++) {
+ attrs->a.group.gr_mem[c] =
+ talloc_strdup(attrs->a.group.gr_mem,
+ list[c]);
+ if (attrs->a.group.gr_mem[c] == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ }
+
+ tag = ber_peek_tag(ber, &ber_len);
+ DEBUG(SSSDBG_TRACE_ALL, "BER tag is [%d]\n", (int) tag);
+ if (tag == LBER_SEQUENCE) {
+ ret = get_extra_attrs(ber, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "get_extra_attrs failed.\n");
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ ber_memvfree((void **) list);
+
+ return ret;
+}
+
+static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+ struct req_input *req_input,
+ struct resp_attrs *attrs,
+ struct resp_attrs *simple_attrs);
+
static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
char *retoid,
struct berval *retdata,
@@ -428,16 +683,21 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
gid_t gid;
struct resp_attrs *attrs = NULL;
char *sid_str;
+ bool is_v1 = false;
if (retoid == NULL || retdata == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "Missing OID or data.\n");
return EINVAL;
}
- if (strcmp(retoid, EXOP_SID2NAME_OID) != 0) {
+ if (strcmp(retoid, EXOP_SID2NAME_V1_OID) == 0) {
+ is_v1 = true;
+ } else if (strcmp(retoid, EXOP_SID2NAME_OID) == 0) {
+ is_v1 = false;
+ } else {
DEBUG(SSSDBG_OP_FAILURE,
- "Result has wrong OID, expected [%s], got [%s].\n",
- EXOP_SID2NAME_OID, retoid);
+ "Result has wrong OID, expected [%s] or [%s], got [%s].\n",
+ EXOP_SID2NAME_OID, EXOP_SID2NAME_V1_OID, retoid);
return EINVAL;
}
@@ -463,7 +723,8 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
switch (type) {
case RESP_USER:
- tag = ber_scanf(ber, "{aaii}}", &domain_name, &name, &uid, &gid);
+ case RESP_USER_GROUPLIST:
+ tag = ber_scanf(ber, "{aaii", &domain_name, &name, &uid, &gid);
if (tag == LBER_ERROR) {
DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
ret = EINVAL;
@@ -485,9 +746,25 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
attrs->a.user.pw_uid = uid;
attrs->a.user.pw_gid = gid;
+ if (is_v1) {
+ ret = add_v1_user_data(ber, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "add_v1_user_data failed.\n");
+ goto done;
+ }
+ }
+
+ tag = ber_scanf(ber, "}}");
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
break;
case RESP_GROUP:
- tag = ber_scanf(ber, "{aai}}", &domain_name, &name, &gid);
+ case RESP_GROUP_MEMBERS:
+ tag = ber_scanf(ber, "{aai", &domain_name, &name, &gid);
if (tag == LBER_ERROR) {
DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
ret = EINVAL;
@@ -508,6 +785,21 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
attrs->a.group.gr_gid = gid;
+ if (is_v1) {
+ ret = add_v1_group_data(ber, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "add_v1_group_data failed.\n");
+ goto done;
+ }
+ }
+
+ tag = ber_scanf(ber, "}}");
+ if (tag == LBER_ERROR) {
+ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
break;
case RESP_SID:
tag = ber_scanf(ber, "a}", &sid_str);
@@ -572,6 +864,166 @@ done:
return ret;
}
+struct ipa_s2n_get_groups_state {
+ struct tevent_context *ev;
+ struct sss_domain_info *dom;
+ struct sdap_handle *sh;
+ struct req_input req_input;
+ char **group_list;
+ size_t group_idx;
+ int exop_timeout;
+};
+
+static errno_t ipa_s2n_get_groups_step(struct tevent_req *req);
+static void ipa_s2n_get_groups_next(struct tevent_req *subreq);
+
+static struct tevent_req *ipa_s2n_get_groups_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sss_domain_info *dom,
+ struct sdap_handle *sh,
+ int exop_timeout,
+ char **group_list)
+{
+ int ret;
+ struct ipa_s2n_get_groups_state *state;
+ struct tevent_req *req;
+
+ req = tevent_req_create(mem_ctx, &state, struct ipa_s2n_get_groups_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->dom = dom;
+ state->sh = sh;
+ state->group_list = group_list;
+ state->group_idx = 0;
+ state->req_input.type = REQ_INP_NAME;
+ state->req_input.inp.name = NULL;
+ state->exop_timeout = exop_timeout;
+
+ ret = ipa_s2n_get_groups_step(req);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_step failed.\n");
+ goto done;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static errno_t ipa_s2n_get_groups_step(struct tevent_req *req)
+{
+ int ret;
+ struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
+ struct ipa_s2n_get_groups_state);
+ struct berval *bv_req;
+ struct tevent_req *subreq;
+ struct sss_domain_info *obj_domain;
+ struct sss_domain_info *parent_domain;
+ char *group_name = NULL;
+ char *domain_name = NULL;
+
+ parent_domain = get_domains_head(state->dom);
+
+ ret = sss_parse_name(state, parent_domain->names,
+ state->group_list[state->group_idx],
+ &domain_name, &group_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name '%s' [%d]: %s\n",
+ state->group_list[state->group_idx],
+ ret, sss_strerror(ret));
+ return ret;
+ }
+
+ obj_domain = find_domain_by_name(parent_domain, domain_name, true);
+ if (obj_domain == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
+ return ENOMEM;
+ }
+
+ state->req_input.inp.name = group_name;
+
+ ret = s2n_encode_request(state, obj_domain->name, BE_REQ_GROUP,
+ REQ_FULL_WITH_MEMBERS,
+ &state->req_input, &bv_req);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "s2n_encode_request failed.\n");
+ return ret;
+ }
+
+ subreq = ipa_s2n_exop_send(state, state->ev, state->sh, true,
+ state->exop_timeout, bv_req);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_exop_send failed.\n");
+ return ENOMEM;
+ }
+ tevent_req_set_callback(subreq, ipa_s2n_get_groups_next, req);
+
+ return EOK;
+}
+
+static void ipa_s2n_get_groups_next(struct tevent_req *subreq)
+{
+ int ret;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_s2n_get_groups_state *state = tevent_req_data(req,
+ struct ipa_s2n_get_groups_state);
+ char *retoid = NULL;
+ struct berval *retdata = NULL;
+ struct resp_attrs *attrs;
+
+ ret = ipa_s2n_exop_recv(subreq, state, &retoid, &retdata);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "s2n exop request failed.\n");
+ goto fail;
+ }
+
+ ret = s2n_response_to_attrs(state, retoid, retdata, &attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "s2n_response_to_attrs failed.\n");
+ goto fail;
+ }
+
+ ret = ipa_s2n_save_objects(state->dom, &state->req_input, attrs, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
+ goto fail;
+ }
+
+ state->group_idx++;
+ if (state->group_list[state->group_idx] == NULL) {
+ tevent_req_done(req);
+ return;
+ }
+
+ ret = ipa_s2n_get_groups_step(req);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_groups_step failed.\n");
+ goto fail;
+ }
+
+ return;
+
+fail:
+ tevent_req_error(req,ret);
+ return;
+}
+
+static int ipa_s2n_get_groups_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
struct ipa_s2n_get_user_state {
struct tevent_context *ev;
struct sdap_options *opts;
@@ -581,6 +1033,8 @@ struct ipa_s2n_get_user_state {
int entry_type;
enum request_types request_type;
struct resp_attrs *attrs;
+ struct resp_attrs *simple_attrs;
+ int exop_timeout;
};
static void ipa_s2n_get_user_done(struct tevent_req *subreq);
@@ -598,6 +1052,7 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
struct tevent_req *subreq;
struct berval *bv_req = NULL;
int ret = EFAULT;
+ bool is_v1 = false;
req = tevent_req_create(mem_ctx, &state, struct ipa_s2n_get_user_state);
if (req == NULL) {
@@ -610,7 +1065,22 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
state->sh = sh;
state->req_input = req_input;
state->entry_type = entry_type;
- state->request_type = REQ_FULL;
+ state->attrs = NULL;
+ state->simple_attrs = NULL;
+ state->exop_timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT);
+
+ if (sdap_is_extension_supported(sh, EXOP_SID2NAME_V1_OID)) {
+ state->request_type = REQ_FULL_WITH_MEMBERS;
+ is_v1 = true;
+ } else if (sdap_is_extension_supported(sh, EXOP_SID2NAME_OID)) {
+ state->request_type = REQ_FULL;
+ is_v1 = false;
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Extdom not supported on the server, "
+ "cannot resolve objects from trusted domains.\n");
+ ret = EIO;
+ goto fail;
+ }
ret = s2n_encode_request(state, dom->name, entry_type, state->request_type,
req_input, &bv_req);
@@ -618,7 +1088,8 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
goto fail;
}
- subreq = ipa_s2n_exop_send(state, state->ev, state->sh, bv_req);
+ subreq = ipa_s2n_exop_send(state, state->ev, state->sh, is_v1,
+ state->exop_timeout, bv_req);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_exop_send failed.\n");
ret = ENOMEM;
@@ -635,6 +1106,159 @@ fail:
return req;
}
+static errno_t process_members(struct sss_domain_info *domain,
+ struct sysdb_attrs *group_attrs,
+ char **members)
+{
+ int ret;
+ size_t c;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *msg;
+ const char *dn_str;
+ struct sss_domain_info *obj_domain;
+ struct sss_domain_info *parent_domain;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+ return ENOMEM;
+ }
+
+ parent_domain = get_domains_head(domain);
+
+ for (c = 0; members[c] != NULL; c++) {
+ obj_domain = find_domain_by_object_name(parent_domain, members[c]);
+ if (obj_domain == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_object_name failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], NULL,
+ &msg);
+ if (ret == EOK) {
+ dn_str = ldb_dn_get_linearized(msg->dn);
+ if (dn_str == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n");
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n",
+ members[c], dn_str);
+
+ ret = sysdb_attrs_add_string(group_attrs, SYSDB_MEMBER, dn_str);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+ goto done;
+ }
+ } else if (ret == ENOENT) {
+ DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n", members[c]);
+
+ ret = sysdb_attrs_add_string(group_attrs, SYSDB_GHOST, members[c]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+ goto done;
+ }
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
+ goto done;
+ }
+ }
+
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *dom,
+ size_t ngroups, char **groups,
+ struct ldb_dn ***_dn_list,
+ char ***_missing_groups)
+{
+ int ret;
+ size_t c;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn **dn_list = NULL;
+ char **missing_groups = NULL;
+ struct ldb_message *msg = NULL;
+ size_t n_dns = 0;
+ size_t n_missing = 0;
+ struct sss_domain_info *obj_domain;
+ struct sss_domain_info *parent_domain;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+ return ENOMEM;
+ }
+
+ dn_list = talloc_zero_array(tmp_ctx, struct ldb_dn *, ngroups + 1);
+ missing_groups = talloc_zero_array(tmp_ctx, char *, ngroups + 1);
+ if (dn_list == NULL || missing_groups == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_array_zero failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ parent_domain = (dom->parent == NULL) ? dom : dom->parent;
+
+ for (c = 0; c < ngroups; c++) {
+ obj_domain = find_domain_by_object_name(parent_domain, groups[c]);
+ if (obj_domain == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_object_name failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_search_group_by_name(tmp_ctx, obj_domain, groups[c], NULL,
+ &msg);
+ if (ret == EOK) {
+ dn_list[n_dns] = ldb_dn_copy(dn_list, msg->dn);
+ if (dn_list[n_dns] == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ n_dns++;
+ } else if (ret == ENOENT) {
+ missing_groups[n_missing] = talloc_strdup(missing_groups,
+ groups[c]);
+ if (missing_groups[n_missing] == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ n_missing++;
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_group_by_name failed.\n");
+ goto done;
+ }
+ }
+
+ if (n_missing != 0) {
+ *_missing_groups = talloc_steal(mem_ctx, missing_groups);
+ } else {
+ *_missing_groups = NULL;
+ }
+
+ if (n_dns != 0) {
+ *_dn_list = talloc_steal(mem_ctx, dn_list);
+ } else {
+ *dn_list = NULL;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static void ipa_s2n_get_groups_done(struct tevent_req *subreq);
static void ipa_s2n_get_user_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -645,18 +1269,9 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
char *retoid = NULL;
struct berval *retdata = NULL;
struct resp_attrs *attrs = NULL;
- struct resp_attrs *simple_attrs = NULL;
- time_t now;
- uint64_t timeout = 10*60*60; /* FIXME: find a better timeout ! */
- struct sss_nss_homedir_ctx homedir_ctx;
- const char *homedir = NULL;
- struct sysdb_attrs *user_attrs = NULL;
- struct sysdb_attrs *group_attrs = NULL;
- char *name;
- char *realm;
- char *upn;
struct berval *bv_req = NULL;
- gid_t gid;
+ char **missing_groups = NULL;
+ struct ldb_dn **group_dn_list = NULL;
ret = ipa_s2n_exop_recv(subreq, state, &retoid, &retdata);
talloc_zfree(subreq);
@@ -666,6 +1281,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
}
switch (state->request_type) {
+ case REQ_FULL_WITH_MEMBERS:
case REQ_FULL:
ret = s2n_response_to_attrs(state, retoid, retdata, &attrs);
if (ret != EOK) {
@@ -688,7 +1304,34 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
state->attrs = attrs;
- if (state->req_input->type == REQ_INP_SECID) {
+ if (attrs->response_type == RESP_USER_GROUPLIST) {
+ ret = get_group_dn_list(state, state->dom,
+ attrs->ngroups, attrs->groups,
+ &group_dn_list, &missing_groups);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "get_group_dn_list failed.\n");
+ goto done;
+ }
+
+ if (missing_groups != NULL) {
+ subreq = ipa_s2n_get_groups_send(state, state->ev, state->dom,
+ state->sh, state->exop_timeout,
+ missing_groups);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "ipa_s2n_get_groups_send failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ tevent_req_set_callback(subreq, ipa_s2n_get_groups_done,
+ req);
+
+ return;
+ }
+ }
+
+ if (state->req_input->type == REQ_INP_SECID
+ || attrs->response_type == RESP_GROUP_MEMBERS) {
/* We already know the SID, we do not have to read it. */
break;
}
@@ -702,7 +1345,8 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
goto done;
}
- subreq = ipa_s2n_exop_send(state, state->ev, state->sh, bv_req);
+ subreq = ipa_s2n_exop_send(state, state->ev, state->sh, false,
+ state->exop_timeout, bv_req);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_exop_send failed.\n");
ret = ENOMEM;
@@ -713,7 +1357,8 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
return;
case REQ_SIMPLE:
- ret = s2n_response_to_attrs(state, retoid, retdata, &simple_attrs);
+ ret = s2n_response_to_attrs(state, retoid, retdata,
+ &state->simple_attrs);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "s2n_response_to_attrs failed.\n");
goto done;
@@ -730,40 +1375,79 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
DEBUG(SSSDBG_CRIT_FAILURE, "Missing data of full request.\n");
ret = EINVAL;
goto done;
+ }
+
+ ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
+ state->simple_attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
+ goto done;
+ }
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
} else {
- attrs = state->attrs;
+ tevent_req_error(req, ret);
+ }
+ return;
+}
+
+static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+ struct req_input *req_input,
+ struct resp_attrs *attrs,
+ struct resp_attrs *simple_attrs)
+{
+ int ret;
+ time_t now;
+ uint64_t timeout = 10*60*60; /* FIXME: find a better timeout ! */
+ struct sss_nss_homedir_ctx homedir_ctx;
+ char *name;
+ char *realm;
+ char *upn;
+ gid_t gid;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+ return ENOMEM;
}
now = time(NULL);
+ if (attrs->sysdb_attrs == NULL) {
+ attrs->sysdb_attrs = sysdb_new_attrs(attrs);
+ if (attrs->sysdb_attrs == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
switch (attrs->response_type) {
case RESP_USER:
- if (state->dom->subdomain_homedir) {
+ case RESP_USER_GROUPLIST:
+ if (dom->subdomain_homedir
+ && attrs->a.user.pw_dir == NULL) {
ZERO_STRUCT(homedir_ctx);
homedir_ctx.username = attrs->a.user.pw_name;
homedir_ctx.uid = attrs->a.user.pw_uid;
- homedir_ctx.domain = state->dom->name;
- homedir_ctx.flatname = state->dom->flat_name;
- homedir_ctx.config_homedir_substr = state->dom->homedir_substr;
+ homedir_ctx.domain = dom->name;
+ homedir_ctx.flatname = dom->flat_name;
+ homedir_ctx.config_homedir_substr = dom->homedir_substr;
- homedir = expand_homedir_template(state,
- state->dom->subdomain_homedir,
+ attrs->a.user.pw_dir = expand_homedir_template(attrs,
+ dom->subdomain_homedir,
&homedir_ctx);
- if (homedir == NULL) {
+ if (attrs->a.user.pw_dir == NULL) {
ret = ENOMEM;
goto done;
}
}
- user_attrs = sysdb_new_attrs(state);
- if (user_attrs == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
- ret = ENOMEM;
- goto done;
- }
-
/* we always use the fully qualified name for subdomain users */
- name = sss_tc_fqname(state, state->dom->names, state->dom,
+ name = sss_tc_fqname(tmp_ctx, dom->names, dom,
attrs->a.user.pw_name);
if (!name) {
DEBUG(SSSDBG_OP_FAILURE, "failed to format user name.\n");
@@ -771,7 +1455,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
goto done;
}
- ret = sysdb_attrs_add_lc_name_alias(user_attrs, name);
+ ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_add_lc_name_alias failed.\n");
@@ -784,13 +1468,13 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
* access to the regex to deconstruct it */
/* FIXME: The real UPN is available from the PAC, we should get
* it from there. */
- realm = get_uppercase_realm(state, state->dom->name);
+ realm = get_uppercase_realm(tmp_ctx, dom->name);
if (!realm) {
DEBUG(SSSDBG_OP_FAILURE, "failed to get realm.\n");
ret = ENOMEM;
goto done;
}
- upn = talloc_asprintf(state, "%s@%s",
+ upn = talloc_asprintf(tmp_ctx, "%s@%s",
attrs->a.user.pw_name, realm);
if (!upn) {
DEBUG(SSSDBG_OP_FAILURE, "failed to format UPN.\n");
@@ -798,44 +1482,49 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
goto done;
}
- ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);
+ ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_UPN, upn);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
goto done;
}
- if (state->req_input->type == REQ_INP_SECID) {
- ret = sysdb_attrs_add_string(user_attrs, SYSDB_SID_STR,
- state->req_input->inp.secid);
+ if (req_input->type == REQ_INP_SECID) {
+ ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_SID_STR,
+ req_input->inp.secid);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_attrs_add_string failed.\n");
goto done;
}
}
- if (simple_attrs != NULL && simple_attrs->response_type == RESP_SID) {
- ret = sysdb_attrs_add_string(user_attrs, SYSDB_SID_STR,
+ if (simple_attrs != NULL
+ && simple_attrs->response_type == RESP_SID) {
+ ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_SID_STR,
simple_attrs->a.sid_str);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_attrs_add_string failed.\n");
goto done;
}
}
gid = 0;
- if (state->dom->mpg == false) {
+ if (dom->mpg == false) {
gid = attrs->a.user.pw_gid;
}
- ret = sysdb_store_user(state->dom, name, NULL,
+ ret = sysdb_store_user(dom, name, NULL,
attrs->a.user.pw_uid,
- gid, NULL, /* gecos */
- homedir, NULL, NULL, user_attrs, NULL,
+ gid, attrs->a.user.pw_gecos,
+ attrs->a.user.pw_dir, attrs->a.user.pw_shell,
+ NULL, attrs->sysdb_attrs, NULL,
timeout, now);
break;
case RESP_GROUP:
+ case RESP_GROUP_MEMBERS:
/* we always use the fully qualified name for subdomain users */
- name = sss_tc_fqname(state, state->dom->names, state->dom,
+ name = sss_tc_fqname(tmp_ctx, dom->names, dom,
attrs->a.group.gr_name);
if (!name) {
DEBUG(SSSDBG_OP_FAILURE, "failed to format user name,\n");
@@ -843,40 +1532,43 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
goto done;
}
- group_attrs = sysdb_new_attrs(state);
- if (group_attrs == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
- ret = ENOMEM;
- goto done;
- }
-
- ret = sysdb_attrs_add_lc_name_alias(group_attrs, name);
+ ret = sysdb_attrs_add_lc_name_alias(attrs->sysdb_attrs, name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_add_lc_name_alias failed.\n");
goto done;
}
- if (state->req_input->type == REQ_INP_SECID) {
- ret = sysdb_attrs_add_string(group_attrs, SYSDB_SID_STR,
- state->req_input->inp.secid);
+ if (req_input->type == REQ_INP_SECID) {
+ ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_SID_STR,
+ req_input->inp.secid);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_attrs_add_string failed.\n");
goto done;
}
}
- if (simple_attrs != NULL && simple_attrs->response_type == RESP_SID) {
- ret = sysdb_attrs_add_string(group_attrs, SYSDB_SID_STR,
+ if (simple_attrs != NULL
+ && simple_attrs->response_type == RESP_SID) {
+ ret = sysdb_attrs_add_string(attrs->sysdb_attrs, SYSDB_SID_STR,
simple_attrs->a.sid_str);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_attrs_add_string failed.\n");
goto done;
}
}
- ret = sysdb_store_group(state->dom, name, attrs->a.group.gr_gid,
- group_attrs, timeout, now);
+ ret = process_members(dom, attrs->sysdb_attrs,
+ attrs->a.group.gr_mem);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n");
+ goto done;
+ }
+
+ ret = sysdb_store_group(dom, name, attrs->a.group.gr_gid,
+ attrs->sysdb_attrs, timeout, now);
break;
default:
DEBUG(SSSDBG_OP_FAILURE, "Unexpected response type [%d].\n",
@@ -886,13 +1578,36 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
}
done:
- talloc_free(user_attrs);
- talloc_free(group_attrs);
- if (ret == EOK) {
- tevent_req_done(req);
- } else {
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static void ipa_s2n_get_groups_done(struct tevent_req *subreq)
+{
+ int ret;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct ipa_s2n_get_user_state *state = tevent_req_data(req,
+ struct ipa_s2n_get_user_state);
+
+ ret = ipa_s2n_get_groups_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "s2n get_groups request failed.\n");
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs,
+ state->simple_attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n");
tevent_req_error(req, ret);
+ return;
}
+
+ tevent_req_done(req);
return;
}