Blob Blame History Raw
From b2af54f9e327763783f482b3d5b7b3819ce75f82 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 17 Mar 2017 14:48:50 +0100
Subject: [PATCH] extdom: improve cert request

Certificates can be assigned to multiple user so the extdom plugin must
use sss_nss_getlistbycert() instead of sss_nss_getnamebycert() and
return a list of fully-qualified user names.

Due to issues on the SSSD side the current version of lookups by
certificates didn't work at all and the changes here won't break
existing clients.

Related to https://pagure.io/freeipa/issue/6826

Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: David Kupka <dkupka@redhat.com>
---
 .../ipa-extdom-extop/ipa_extdom.h                  |   3 +-
 .../ipa-extdom-extop/ipa_extdom_common.c           | 157 ++++++++++++++++++---
 server.m4                                          |   2 +-
 3 files changed, 143 insertions(+), 19 deletions(-)

diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
index 34e2d3c795e33bbeb9552910d80ddcc828751b93..bc29f069816b0ce13578c9ae14c61edb832d44e4 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
@@ -95,7 +95,8 @@ enum response_types {
     RESP_USER,
     RESP_GROUP,
     RESP_USER_GROUPLIST,
-    RESP_GROUP_MEMBERS
+    RESP_GROUP_MEMBERS,
+    RESP_NAME_LIST
 };
 
 struct extdom_req {
diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
index aa1ff10dfbf51b87a367261202b39d1346bd337a..fe225fa86669a6728bec5014be41d80275f10717 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
@@ -698,6 +698,90 @@ done:
     return ret;
 }
 
+int pack_ber_name_list(struct extdom_req *req, char **fq_name_list,
+                       struct berval **berval)
+{
+    BerElement *ber = NULL;
+    int ret;
+    char *sep;
+    size_t c;
+    size_t len;
+    size_t name_len;
+
+    /* count the names */
+    for (c = 0; fq_name_list[c] != NULL; c++);
+    if (c == 0) {
+        set_err_msg(req, "Empty name list");
+        return LDAP_NO_SUCH_OBJECT;
+    }
+
+    ber = ber_alloc_t( LBER_USE_DER );
+    if (ber == NULL) {
+        set_err_msg(req, "BER alloc failed");
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+
+    ret = ber_printf(ber,"{e{", RESP_NAME_LIST);
+    if (ret == -1) {
+        set_err_msg(req, "BER start failed");
+        ber_free(ber, 1);
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    for (c = 0; fq_name_list[c] != NULL; c++) {
+        len = strlen(fq_name_list[c]);
+        if (len < 3) {
+            set_err_msg(req, "Fully qualified name too short");
+            ber_free(ber, 1);
+            return LDAP_OPERATIONS_ERROR;
+        }
+
+        sep = strrchr(fq_name_list[c], SSSD_DOMAIN_SEPARATOR);
+        if (sep == NULL) {
+            set_err_msg(req, "Failed to split fully qualified name");
+            ber_free(ber, 1);
+            return LDAP_OPERATIONS_ERROR;
+        }
+
+        name_len = sep - fq_name_list[c];
+        if (name_len == 0) {
+            set_err_msg(req, "Missing name.");
+            ber_free(ber, 1);
+            return LDAP_OPERATIONS_ERROR;
+        }
+        if (name_len + 1 == len) {
+            set_err_msg(req, "Missing domain.");
+            ber_free(ber, 1);
+            return LDAP_OPERATIONS_ERROR;
+        }
+
+        ret = ber_printf(ber,"{oo}", (sep + 1),  len - name_len -1,
+                                      fq_name_list[c], name_len);
+        if (ret == -1) {
+        set_err_msg(req, "BER list item failed");
+            ber_free(ber, 1);
+            return LDAP_OPERATIONS_ERROR;
+        }
+    }
+
+    ret = ber_printf(ber,"}}");
+    if (ret == -1) {
+        set_err_msg(req, "BER end failed");
+        ber_free(ber, 1);
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = ber_flatten(ber, berval);
+    ber_free(ber, 1);
+    if (ret == -1) {
+        set_err_msg(req, "BER flatten failed");
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    return LDAP_SUCCESS;
+}
+
 int pack_ber_name(const char *domain_name, const char *name,
                   struct berval **berval)
 {
@@ -867,12 +951,56 @@ done:
     return ret;
 }
 
-static int handle_sid_or_cert_request(struct ipa_extdom_ctx *ctx,
-                                      struct extdom_req *req,
-                                      enum request_types request_type,
-                                      enum input_types input_type,
-                                      const char *input,
-                                      struct berval **berval)
+static int handle_cert_request(struct ipa_extdom_ctx *ctx,
+                               struct extdom_req *req,
+                               enum request_types request_type,
+                               enum input_types input_type,
+                               const char *input,
+                               struct berval **berval)
+{
+    int ret;
+    char **fq_names = NULL;
+    enum sss_id_type *id_types = NULL;
+    size_t c;
+
+    if (request_type != REQ_SIMPLE) {
+        set_err_msg(req, "Only simple request type allowed "
+                         "for lookups by certificate");
+        ret = LDAP_PROTOCOL_ERROR;
+        goto done;
+    }
+
+    ret = sss_nss_getlistbycert(input, &fq_names, &id_types);
+    if (ret != 0) {
+        if (ret == ENOENT) {
+            ret = LDAP_NO_SUCH_OBJECT;
+        } else {
+            set_err_msg(req, "Failed to lookup name by certificate");
+            ret = LDAP_OPERATIONS_ERROR;
+        }
+        goto done;
+    }
+
+    ret = pack_ber_name_list(req, fq_names, berval);
+
+done:
+    if (fq_names != NULL) {
+        for (c = 0; fq_names[c] != NULL; c++) {
+            free(fq_names[c]);
+        }
+        free(fq_names);
+    }
+    free(id_types);
+
+    return ret;
+}
+
+static int handle_sid_request(struct ipa_extdom_ctx *ctx,
+                              struct extdom_req *req,
+                              enum request_types request_type,
+                              enum input_types input_type,
+                              const char *input,
+                              struct berval **berval)
 {
     int ret;
     struct passwd pwd;
@@ -886,11 +1014,7 @@ static int handle_sid_or_cert_request(struct ipa_extdom_ctx *ctx,
     enum sss_id_type id_type;
     struct sss_nss_kv *kv_list = NULL;
 
-    if (input_type == INP_SID) {
-        ret = sss_nss_getnamebysid(input, &fq_name, &id_type);
-    } else {
-        ret = sss_nss_getnamebycert(input, &fq_name, &id_type);
-    }
+    ret = sss_nss_getnamebysid(input, &fq_name, &id_type);
     if (ret != 0) {
         if (ret == ENOENT) {
             ret = LDAP_NO_SUCH_OBJECT;
@@ -1147,13 +1271,12 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
 
         break;
     case INP_SID:
+        ret = handle_sid_request(ctx, req, req->request_type,
+                                 req->input_type, req->data.sid, berval);
+        break;
     case INP_CERT:
-        ret = handle_sid_or_cert_request(ctx, req, req->request_type,
-                                         req->input_type,
-                                         req->input_type == INP_SID ?
-                                                                 req->data.sid :
-                                                                 req->data.cert,
-                                         berval);
+        ret = handle_cert_request(ctx, req, req->request_type,
+                                  req->input_type, req->data.cert, berval);
         break;
     case INP_NAME:
         ret = handle_name_request(ctx, req, req->request_type,
diff --git a/server.m4 b/server.m4
index a4c99195ae535e586445cf5bbe9fef457d224531..5d5333e194cb339d31576f54a70d96becadf9a87 100644
--- a/server.m4
+++ b/server.m4
@@ -28,7 +28,7 @@ DIRSRV_CFLAGS="$DIRSRV_CFLAGS $NSPR_CFLAGS"
 
 dnl -- sss_idmap is needed by the extdom exop --
 PKG_CHECK_MODULES([SSSIDMAP], [sss_idmap])
-PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.13.90])
+PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.15.2])
 
 dnl -- sss_certmap and certauth.h are needed by the IPA KDB certauth plugin --
 PKG_CHECK_EXISTS([sss_certmap],
-- 
2.12.1