483b06
From b2af54f9e327763783f482b3d5b7b3819ce75f82 Mon Sep 17 00:00:00 2001
483b06
From: Sumit Bose <sbose@redhat.com>
483b06
Date: Fri, 17 Mar 2017 14:48:50 +0100
483b06
Subject: [PATCH] extdom: improve cert request
483b06
483b06
Certificates can be assigned to multiple user so the extdom plugin must
483b06
use sss_nss_getlistbycert() instead of sss_nss_getnamebycert() and
483b06
return a list of fully-qualified user names.
483b06
483b06
Due to issues on the SSSD side the current version of lookups by
483b06
certificates didn't work at all and the changes here won't break
483b06
existing clients.
483b06
483b06
Related to https://pagure.io/freeipa/issue/6826
483b06
483b06
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
483b06
Reviewed-By: David Kupka <dkupka@redhat.com>
483b06
---
483b06
 .../ipa-extdom-extop/ipa_extdom.h                  |   3 +-
483b06
 .../ipa-extdom-extop/ipa_extdom_common.c           | 157 ++++++++++++++++++---
483b06
 server.m4                                          |   2 +-
483b06
 3 files changed, 143 insertions(+), 19 deletions(-)
483b06
483b06
diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
483b06
index 34e2d3c795e33bbeb9552910d80ddcc828751b93..bc29f069816b0ce13578c9ae14c61edb832d44e4 100644
483b06
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
483b06
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
483b06
@@ -95,7 +95,8 @@ enum response_types {
483b06
     RESP_USER,
483b06
     RESP_GROUP,
483b06
     RESP_USER_GROUPLIST,
483b06
-    RESP_GROUP_MEMBERS
483b06
+    RESP_GROUP_MEMBERS,
483b06
+    RESP_NAME_LIST
483b06
 };
483b06
 
483b06
 struct extdom_req {
483b06
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
483b06
index aa1ff10dfbf51b87a367261202b39d1346bd337a..fe225fa86669a6728bec5014be41d80275f10717 100644
483b06
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
483b06
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
483b06
@@ -698,6 +698,90 @@ done:
483b06
     return ret;
483b06
 }
483b06
 
483b06
+int pack_ber_name_list(struct extdom_req *req, char **fq_name_list,
483b06
+                       struct berval **berval)
483b06
+{
483b06
+    BerElement *ber = NULL;
483b06
+    int ret;
483b06
+    char *sep;
483b06
+    size_t c;
483b06
+    size_t len;
483b06
+    size_t name_len;
483b06
+
483b06
+    /* count the names */
483b06
+    for (c = 0; fq_name_list[c] != NULL; c++);
483b06
+    if (c == 0) {
483b06
+        set_err_msg(req, "Empty name list");
483b06
+        return LDAP_NO_SUCH_OBJECT;
483b06
+    }
483b06
+
483b06
+    ber = ber_alloc_t( LBER_USE_DER );
483b06
+    if (ber == NULL) {
483b06
+        set_err_msg(req, "BER alloc failed");
483b06
+        return LDAP_OPERATIONS_ERROR;
483b06
+    }
483b06
+
483b06
+
483b06
+    ret = ber_printf(ber,"{e{", RESP_NAME_LIST);
483b06
+    if (ret == -1) {
483b06
+        set_err_msg(req, "BER start failed");
483b06
+        ber_free(ber, 1);
483b06
+        return LDAP_OPERATIONS_ERROR;
483b06
+    }
483b06
+
483b06
+    for (c = 0; fq_name_list[c] != NULL; c++) {
483b06
+        len = strlen(fq_name_list[c]);
483b06
+        if (len < 3) {
483b06
+            set_err_msg(req, "Fully qualified name too short");
483b06
+            ber_free(ber, 1);
483b06
+            return LDAP_OPERATIONS_ERROR;
483b06
+        }
483b06
+
483b06
+        sep = strrchr(fq_name_list[c], SSSD_DOMAIN_SEPARATOR);
483b06
+        if (sep == NULL) {
483b06
+            set_err_msg(req, "Failed to split fully qualified name");
483b06
+            ber_free(ber, 1);
483b06
+            return LDAP_OPERATIONS_ERROR;
483b06
+        }
483b06
+
483b06
+        name_len = sep - fq_name_list[c];
483b06
+        if (name_len == 0) {
483b06
+            set_err_msg(req, "Missing name.");
483b06
+            ber_free(ber, 1);
483b06
+            return LDAP_OPERATIONS_ERROR;
483b06
+        }
483b06
+        if (name_len + 1 == len) {
483b06
+            set_err_msg(req, "Missing domain.");
483b06
+            ber_free(ber, 1);
483b06
+            return LDAP_OPERATIONS_ERROR;
483b06
+        }
483b06
+
483b06
+        ret = ber_printf(ber,"{oo}", (sep + 1),  len - name_len -1,
483b06
+                                      fq_name_list[c], name_len);
483b06
+        if (ret == -1) {
483b06
+        set_err_msg(req, "BER list item failed");
483b06
+            ber_free(ber, 1);
483b06
+            return LDAP_OPERATIONS_ERROR;
483b06
+        }
483b06
+    }
483b06
+
483b06
+    ret = ber_printf(ber,"}}");
483b06
+    if (ret == -1) {
483b06
+        set_err_msg(req, "BER end failed");
483b06
+        ber_free(ber, 1);
483b06
+        return LDAP_OPERATIONS_ERROR;
483b06
+    }
483b06
+
483b06
+    ret = ber_flatten(ber, berval);
483b06
+    ber_free(ber, 1);
483b06
+    if (ret == -1) {
483b06
+        set_err_msg(req, "BER flatten failed");
483b06
+        return LDAP_OPERATIONS_ERROR;
483b06
+    }
483b06
+
483b06
+    return LDAP_SUCCESS;
483b06
+}
483b06
+
483b06
 int pack_ber_name(const char *domain_name, const char *name,
483b06
                   struct berval **berval)
483b06
 {
483b06
@@ -867,12 +951,56 @@ done:
483b06
     return ret;
483b06
 }
483b06
 
483b06
-static int handle_sid_or_cert_request(struct ipa_extdom_ctx *ctx,
483b06
-                                      struct extdom_req *req,
483b06
-                                      enum request_types request_type,
483b06
-                                      enum input_types input_type,
483b06
-                                      const char *input,
483b06
-                                      struct berval **berval)
483b06
+static int handle_cert_request(struct ipa_extdom_ctx *ctx,
483b06
+                               struct extdom_req *req,
483b06
+                               enum request_types request_type,
483b06
+                               enum input_types input_type,
483b06
+                               const char *input,
483b06
+                               struct berval **berval)
483b06
+{
483b06
+    int ret;
483b06
+    char **fq_names = NULL;
483b06
+    enum sss_id_type *id_types = NULL;
483b06
+    size_t c;
483b06
+
483b06
+    if (request_type != REQ_SIMPLE) {
483b06
+        set_err_msg(req, "Only simple request type allowed "
483b06
+                         "for lookups by certificate");
483b06
+        ret = LDAP_PROTOCOL_ERROR;
483b06
+        goto done;
483b06
+    }
483b06
+
483b06
+    ret = sss_nss_getlistbycert(input, &fq_names, &id_types);
483b06
+    if (ret != 0) {
483b06
+        if (ret == ENOENT) {
483b06
+            ret = LDAP_NO_SUCH_OBJECT;
483b06
+        } else {
483b06
+            set_err_msg(req, "Failed to lookup name by certificate");
483b06
+            ret = LDAP_OPERATIONS_ERROR;
483b06
+        }
483b06
+        goto done;
483b06
+    }
483b06
+
483b06
+    ret = pack_ber_name_list(req, fq_names, berval);
483b06
+
483b06
+done:
483b06
+    if (fq_names != NULL) {
483b06
+        for (c = 0; fq_names[c] != NULL; c++) {
483b06
+            free(fq_names[c]);
483b06
+        }
483b06
+        free(fq_names);
483b06
+    }
483b06
+    free(id_types);
483b06
+
483b06
+    return ret;
483b06
+}
483b06
+
483b06
+static int handle_sid_request(struct ipa_extdom_ctx *ctx,
483b06
+                              struct extdom_req *req,
483b06
+                              enum request_types request_type,
483b06
+                              enum input_types input_type,
483b06
+                              const char *input,
483b06
+                              struct berval **berval)
483b06
 {
483b06
     int ret;
483b06
     struct passwd pwd;
483b06
@@ -886,11 +1014,7 @@ static int handle_sid_or_cert_request(struct ipa_extdom_ctx *ctx,
483b06
     enum sss_id_type id_type;
483b06
     struct sss_nss_kv *kv_list = NULL;
483b06
 
483b06
-    if (input_type == INP_SID) {
483b06
-        ret = sss_nss_getnamebysid(input, &fq_name, &id_type);
483b06
-    } else {
483b06
-        ret = sss_nss_getnamebycert(input, &fq_name, &id_type);
483b06
-    }
483b06
+    ret = sss_nss_getnamebysid(input, &fq_name, &id_type);
483b06
     if (ret != 0) {
483b06
         if (ret == ENOENT) {
483b06
             ret = LDAP_NO_SUCH_OBJECT;
483b06
@@ -1147,13 +1271,12 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
483b06
 
483b06
         break;
483b06
     case INP_SID:
483b06
+        ret = handle_sid_request(ctx, req, req->request_type,
483b06
+                                 req->input_type, req->data.sid, berval);
483b06
+        break;
483b06
     case INP_CERT:
483b06
-        ret = handle_sid_or_cert_request(ctx, req, req->request_type,
483b06
-                                         req->input_type,
483b06
-                                         req->input_type == INP_SID ?
483b06
-                                                                 req->data.sid :
483b06
-                                                                 req->data.cert,
483b06
-                                         berval);
483b06
+        ret = handle_cert_request(ctx, req, req->request_type,
483b06
+                                  req->input_type, req->data.cert, berval);
483b06
         break;
483b06
     case INP_NAME:
483b06
         ret = handle_name_request(ctx, req, req->request_type,
483b06
diff --git a/server.m4 b/server.m4
483b06
index a4c99195ae535e586445cf5bbe9fef457d224531..5d5333e194cb339d31576f54a70d96becadf9a87 100644
483b06
--- a/server.m4
483b06
+++ b/server.m4
483b06
@@ -28,7 +28,7 @@ DIRSRV_CFLAGS="$DIRSRV_CFLAGS $NSPR_CFLAGS"
483b06
 
483b06
 dnl -- sss_idmap is needed by the extdom exop --
483b06
 PKG_CHECK_MODULES([SSSIDMAP], [sss_idmap])
483b06
-PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.13.90])
483b06
+PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.15.2])
483b06
 
483b06
 dnl -- sss_certmap and certauth.h are needed by the IPA KDB certauth plugin --
483b06
 PKG_CHECK_EXISTS([sss_certmap],
483b06
-- 
483b06
2.12.1
483b06