Blob Blame History Raw
From 537e057ef3bd140e418381f2ce74397ab8c34a73 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 24 Mar 2017 15:40:41 +0100
Subject: [PATCH 59/60] IPA: lookup AD users by certificates on IPA clients

Get a list of users mapped to a certificate back from the IPA server,
look them up and store them together with the certificate used for the
search as mapped attribute to the cache.

Related to https://pagure.io/SSSD/sssd/issue/3050

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
 src/providers/ipa/ipa_s2n_exop.c | 109 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 4 deletions(-)

diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 05c32a24d61947e62884f460069083fb81f40fe0..8a3391b4093f1547d84fe44a0f24b1d063d1e28c 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -52,7 +52,8 @@ enum response_types {
     RESP_USER,
     RESP_GROUP,
     RESP_USER_GROUPLIST,
-    RESP_GROUP_MEMBERS
+    RESP_GROUP_MEMBERS,
+    RESP_NAME_LIST
 };
 
 /* ==Sid2Name Extended Operation============================================= */
@@ -366,8 +367,8 @@ static errno_t s2n_encode_request(TALLOC_CTX *mem_ctx,
             break;
         case BE_REQ_BY_CERT:
             if (req_input->type == REQ_INP_CERT) {
-            ret = ber_printf(ber, "{ees}", INP_CERT, request_type,
-                                           req_input->inp.cert);
+                ret = ber_printf(ber, "{ees}", INP_CERT, request_type,
+                                               req_input->inp.cert);
             } else {
                 DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n",
                                           req_input->type);
@@ -463,6 +464,11 @@ done:
  * GroupMemberList ::= SEQUENCE OF OCTET STRING
  */
 
+struct name_list {
+    char *domain_name;
+    char *name;
+};
+
 struct resp_attrs {
     enum response_types response_type;
     char *domain_name;
@@ -475,6 +481,7 @@ struct resp_attrs {
     size_t ngroups;
     char **groups;
     struct sysdb_attrs *sysdb_attrs;
+    char **name_list;
 };
 
 static errno_t get_extra_attrs(BerElement *ber, struct resp_attrs *resp_attrs)
@@ -782,6 +789,9 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
     struct resp_attrs *attrs = NULL;
     char *sid_str;
     bool is_v1 = false;
+    char **name_list = NULL;
+    ber_len_t ber_len;
+    char *fq_name = NULL;
 
     if (retoid == NULL || retdata == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "Missing OID or data.\n");
@@ -947,6 +957,53 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
                 goto done;
             }
             break;
+        case RESP_NAME_LIST:
+            tag = ber_scanf(ber, "{");
+            if (tag == LBER_ERROR) {
+                DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+                ret = EINVAL;
+                goto done;
+            }
+
+            while (ber_peek_tag(ber, &ber_len) ==  LBER_SEQUENCE) {
+                tag = ber_scanf(ber, "{aa}", &domain_name, &name);
+                if (tag == LBER_ERROR) {
+                    DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+                    ret = EINVAL;
+                    goto done;
+                }
+
+                fq_name = sss_create_internal_fqname(attrs, name, domain_name);
+                if (fq_name == NULL) {
+                    DEBUG(SSSDBG_OP_FAILURE,
+                          "sss_create_internal_fqname failed.\n");
+                    ret = ENOMEM;
+                    goto done;
+                }
+                DEBUG(SSSDBG_TRACE_ALL, "[%s][%s][%s].\n", domain_name, name,
+                                                           fq_name);
+
+                ret = add_string_to_list(attrs, fq_name, &name_list);
+                ber_memfree(domain_name);
+                ber_memfree(name);
+                talloc_free(fq_name);
+                domain_name = NULL;
+                name = NULL;
+                fq_name = NULL;
+                if (ret != EOK) {
+                    DEBUG(SSSDBG_OP_FAILURE, "add_to_name_list failed.\n");
+                    goto done;
+                }
+            }
+
+            tag = ber_scanf(ber, "}}");
+            if (tag == LBER_ERROR) {
+                DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n");
+                ret = EINVAL;
+                goto done;
+            }
+            attrs->name_list = name_list;
+            break;
         default:
             DEBUG(SSSDBG_OP_FAILURE, "Unexpected response type [%d].\n",
                                       type);
@@ -955,7 +1012,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
     }
 
     attrs->response_type = type;
-    if (type != RESP_SID) {
+    if (type != RESP_SID && type != RESP_NAME_LIST) {
         attrs->domain_name = talloc_strdup(attrs, domain_name);
         if (attrs->domain_name == NULL) {
             DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
@@ -969,6 +1026,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx,
 done:
     ber_memfree(domain_name);
     ber_memfree(name);
+    talloc_free(fq_name);
     ber_free(ber, 1);
 
     if (ret == EOK) {
@@ -1332,6 +1390,7 @@ struct ipa_s2n_get_user_state {
     struct resp_attrs *attrs;
     struct resp_attrs *simple_attrs;
     struct sysdb_attrs *override_attrs;
+    struct sysdb_attrs *mapped_attrs;
     int exop_timeout;
 };
 
@@ -1384,6 +1443,11 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
+    if (entry_type == BE_REQ_BY_CERT) {
+        /* Only REQ_SIMPLE is supported for BE_REQ_BY_CERT */
+        state->request_type = REQ_SIMPLE;
+    }
+
     ret = s2n_encode_request(state, dom->name, entry_type, state->request_type,
                              req_input, &bv_req);
     if (ret != EOK) {
@@ -1785,6 +1849,43 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
             goto done;
         }
 
+        if (state->simple_attrs->response_type == RESP_NAME_LIST
+                && state->req_input->type == REQ_INP_CERT) {
+            state->mapped_attrs = sysdb_new_attrs(state);
+            if (state->mapped_attrs == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+                ret = ENOMEM;
+                goto done;
+            }
+
+            ret = sysdb_attrs_add_base64_blob(state->mapped_attrs,
+                                              SYSDB_USER_MAPPED_CERT,
+                                              state->req_input->inp.cert);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n");
+                goto done;
+            }
+
+            subreq = ipa_s2n_get_list_send(state, state->ev,
+                                           state->ipa_ctx, state->dom,
+                                           state->sh, state->exop_timeout,
+                                           BE_REQ_USER,
+                                           REQ_FULL_WITH_MEMBERS,
+                                           REQ_INP_NAME,
+                                           state->simple_attrs->name_list,
+                                           state->mapped_attrs);
+            if (subreq == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "ipa_s2n_get_list_send failed.\n");
+                ret = ENOMEM;
+                goto done;
+            }
+            tevent_req_set_callback(subreq, ipa_s2n_get_list_done,
+                                    req);
+
+            return;
+        }
+
         break;
     default:
         DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected request type.\n");
-- 
2.9.3