URL: https://github.com/freeipa/freeipa/pull/3654
Author: abbra
 Title: #3654: [Backport][ipa-4-7] extdom: plugin doesn't allow @ in group name
Action: opened

PR body:
"""
This PR was opened automatically because PR #3616 was pushed to master and 
backport to ipa-4-7 is required.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/3654/head:pr3654
git checkout pr3654
From 738f7c7714a45636ad02b260dd53adcd566af414 Mon Sep 17 00:00:00 2001
From: Tomas Halman <[email protected]>
Date: Tue, 3 Sep 2019 16:33:54 +0200
Subject: [PATCH 1/4] extdom: plugin doesn't allow @ in group name

Old implementation handles username and group names with
one common call. Character @ is used in the call to detect UPN.

Group name can legaly contain this character and therefore the
common approach doesn't work in such case.

Also the original call is less efficient because it tries to resolv
username allways then it fallback to group resolution.

Here we implement two new separate calls for resolving users and
groups.

Fixes: https://bugzilla.redhat.com/1746951
---
 .../ipa-extdom-extop/ipa_extdom.h             |   8 +-
 .../ipa-extdom-extop/ipa_extdom_common.c      | 271 ++++++++++++------
 .../ipa-extdom-extop/ipa_extdom_extop.c       |   3 +
 3 files changed, 197 insertions(+), 85 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 e01e74ca59..81691ca1b3 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
@@ -63,6 +63,7 @@
 
 #define EXOP_EXTDOM_OID "2.16.840.1.113730.3.8.10.4"
 #define EXOP_EXTDOM_V1_OID "2.16.840.1.113730.3.8.10.4.1"
+#define EXOP_EXTDOM_V2_OID "2.16.840.1.113730.3.8.10.4.2"
 
 #define IPA_EXTDOM_PLUGIN_NAME   "ipa-extdom-extop"
 #define IPA_EXTDOM_FEATURE_DESC  "IPA trusted domain ID mapper"
@@ -72,7 +73,8 @@
 
 enum extdom_version {
     EXTDOM_V0 = 0,
-    EXTDOM_V1
+    EXTDOM_V1,
+    EXTDOM_V2
 };
 
 enum input_types {
@@ -80,7 +82,9 @@ enum input_types {
     INP_NAME,
     INP_POSIX_UID,
     INP_POSIX_GID,
-    INP_CERT
+    INP_CERT,
+    INP_USERNAME,
+    INP_GROUPNAME
 };
 
 enum request_types {
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 65c723ce65..92a7bea706 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
@@ -271,7 +271,9 @@ int parse_request_data(struct berval *req_val, struct extdom_req **_req)
  *        sid (1),
  *        name (2),
  *        posix uid (3),
- *        posix gid (3)
+ *        posix gid (4),
+ *        username (5),
+ *        groupname (6)
  *    },
  *    requestType ENUMERATED {
  *        simple (1),
@@ -337,6 +339,8 @@ int parse_request_data(struct berval *req_val, struct extdom_req **_req)
 
     switch (req->input_type) {
         case INP_NAME:
+        case INP_USERNAME:
+        case INP_GROUPNAME:
             tag = ber_scanf(ber, "{aa}}", &req->data.name.domain_name,
                                             &req->data.name.object_name);
             break;
@@ -378,6 +382,8 @@ void free_req_data(struct extdom_req *req)
 
     switch (req->input_type) {
     case INP_NAME:
+    case INP_USERNAME:
+    case INP_GROUPNAME:
         ber_memfree(req->data.name.domain_name);
         ber_memfree(req->data.name.object_name);
         break;
@@ -407,6 +413,12 @@ int check_request(struct extdom_req *req, enum extdom_version version)
         }
     }
 
+    if (version == EXTDOM_V0 || version == EXTDOM_V1) {
+        if (req->input_type == INP_USERNAME || req->input_type == INP_GROUPNAME) {
+            return LDAP_PROTOCOL_ERROR;
+        }
+    }
+
     return LDAP_SUCCESS;
 }
 
@@ -1157,17 +1169,46 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
     return ret;
 }
 
-static int handle_name_request(struct ipa_extdom_ctx *ctx,
-                               struct extdom_req *req,
-                               enum request_types request_type,
-                               const char *name, const char *domain_name,
-                               struct berval **berval)
+
+static int handle_simple_request(struct extdom_req *req,
+                                 const char *fq_name,
+                                 struct berval **berval)
+{
+    int ret;
+    char *sid_str = NULL;
+    enum sss_id_type id_type;
+
+    ret = sss_nss_getsidbyname(fq_name, &sid_str, &id_type);
+    switch(ret) {
+    case 0:
+        ret = pack_ber_sid(sid_str, berval);
+        break;
+    case ENOENT:
+        ret = LDAP_NO_SUCH_OBJECT;
+        break;
+    case ETIMEDOUT:
+    case ETIME:
+        ret = LDAP_TIMELIMIT_EXCEEDED;
+        break;
+    default:
+        set_err_msg(req, "Failed to lookup SID by name");
+        ret = LDAP_OPERATIONS_ERROR;
+        break;
+    }
+
+    free(sid_str);
+    return ret;
+}
+
+static int handle_username_request(struct ipa_extdom_ctx *ctx,
+                                   struct extdom_req *req,
+                                   enum request_types request_type,
+                                   const char *name, const char *domain_name,
+                                   struct berval **berval)
 {
     int ret;
     char *fq_name = NULL;
     struct passwd pwd;
-    struct group grp;
-    char *sid_str = NULL;
     enum sss_id_type id_type;
     size_t buf_len;
     char *buf = NULL;
@@ -1189,104 +1230,156 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
     }
 
     if (request_type == REQ_SIMPLE) {
-        ret = sss_nss_getsidbyname(fq_name, &sid_str, &id_type);
-        if (ret != 0) {
-            if (ret == ENOENT) {
-                ret = LDAP_NO_SUCH_OBJECT;
-            } else if (ret == ETIMEDOUT || ret == ETIME) {
-                ret = LDAP_TIMELIMIT_EXCEEDED;
-            } else {
-                set_err_msg(req, "Failed to lookup SID by name");
-                ret = LDAP_OPERATIONS_ERROR;
-            }
-            goto done;
-        }
+        /* REQ_SIMPLE */
+        ret = handle_simple_request(req, fq_name, berval);
+        goto done;
+    }
 
-        ret = pack_ber_sid(sid_str, berval);
-    } else {
-        ret = get_buffer(&buf_len, &buf);
-        if (ret != LDAP_SUCCESS) {
-            goto done;
-        }
+    /* REQ_FULL || REQ_FULL_WITH_GROUPS */
+    ret = get_buffer(&buf_len, &buf);
+    if (ret != LDAP_SUCCESS) {
+        goto done;
+    }
 
-        ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len);
-        if (ret == 0) {
-            if (request_type == REQ_FULL_WITH_GROUPS) {
-                ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type);
-                if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
-                                    || id_type == SSS_ID_TYPE_BOTH)) {
-                    set_err_msg(req, "Failed to read original data");
-                    if (ret == ENOENT) {
-                        ret = LDAP_NO_SUCH_OBJECT;
-                    } else if (ret == ETIMEDOUT || ret == ETIME) {
-                        ret = LDAP_TIMELIMIT_EXCEEDED;
-                    } else {
-                        ret = LDAP_OPERATIONS_ERROR;
-                    }
-                    goto done;
-                }
-            }
-            ret = pack_ber_user(ctx,
-                                (request_type == REQ_FULL ? RESP_USER
-                                                          : RESP_USER_GROUPLIST),
-                                domain_name, pwd.pw_name, pwd.pw_uid,
-                                pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
-                                pwd.pw_shell, kv_list, berval);
-        } else if (ret == ENOMEM || ret == ERANGE) {
-            ret = LDAP_OPERATIONS_ERROR;
-            goto done;
-        } else if (ret == ETIMEDOUT) {
-            ret = LDAP_TIMELIMIT_EXCEEDED;
-            goto done;
-        } else { /* no user entry found */
-            /* according to the getpwnam() man page there are a couple of
-             * error codes which can indicate that the user was not found. To
-             * be on the safe side we fail back to the group lookup on all
-             * errors. */
-            ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len);
-            if (ret != 0) {
+    ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len);
+    switch(ret) {
+    case 0:
+        if (request_type == REQ_FULL_WITH_GROUPS) {
+            ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type);
+            if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
+                              || id_type == SSS_ID_TYPE_BOTH)) {
+                set_err_msg(req, "Failed to read original data");
                 if (ret == ENOENT) {
                     ret = LDAP_NO_SUCH_OBJECT;
-                } else if (ret == ETIMEDOUT) {
+                } else if (ret == ETIMEDOUT || ret == ETIME) {
                     ret = LDAP_TIMELIMIT_EXCEEDED;
                 } else {
                     ret = LDAP_OPERATIONS_ERROR;
                 }
                 goto done;
             }
+        }
+        ret = pack_ber_user(ctx,
+                            (request_type == REQ_FULL ? RESP_USER
+                             : RESP_USER_GROUPLIST),
+                            domain_name, pwd.pw_name, pwd.pw_uid,
+                            pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
+                            pwd.pw_shell, kv_list, berval);
+        break;
+    case ENOMEM:
+    case ERANGE:
+        ret = LDAP_OPERATIONS_ERROR;
+        break;
+    case ETIMEDOUT:
+        ret = LDAP_TIMELIMIT_EXCEEDED;
+        break;
+    default:
+        ret = LDAP_NO_SUCH_OBJECT;
+        break;
+    }
 
-            if (request_type == REQ_FULL_WITH_GROUPS) {
-                ret = sss_nss_getorigbyname(grp.gr_name, &kv_list, &id_type);
-                if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
-                                    || id_type == SSS_ID_TYPE_BOTH)) {
-                    if (ret == ENOENT) {
-                        ret = LDAP_NO_SUCH_OBJECT;
-                    } else if (ret == ETIMEDOUT || ret == ETIME) {
-                        ret = LDAP_TIMELIMIT_EXCEEDED;
-                    } else {
-                        set_err_msg(req, "Failed to read original data");
-                        ret = LDAP_OPERATIONS_ERROR;
-                    }
-                    goto done;
-                }
-            }
+done:
+    sss_nss_free_kv(kv_list);
+    free(fq_name);
+    free(buf);
+
+    return ret;
+}
 
-            ret = pack_ber_group((request_type == REQ_FULL ? RESP_GROUP
-                                                           : RESP_GROUP_MEMBERS),
-                                 domain_name, grp.gr_name, grp.gr_gid,
-                                 grp.gr_mem, kv_list, berval);
+static int handle_groupname_request(struct ipa_extdom_ctx *ctx,
+                                    struct extdom_req *req,
+                                    enum request_types request_type,
+                                    const char *name, const char *domain_name,
+                                    struct berval **berval)
+{
+    int ret;
+    char *fq_name = NULL;
+    struct group grp;
+    enum sss_id_type id_type;
+    size_t buf_len;
+    char *buf = NULL;
+    struct sss_nss_kv *kv_list = NULL;
+
+    /* with groups we can be sure that name doesn't contain the domain_name */
+    ret = asprintf(&fq_name, "%s%c%s", name, SSSD_DOMAIN_SEPARATOR,
+                   domain_name);
+    if (ret == -1) {
+        ret = LDAP_OPERATIONS_ERROR;
+        set_err_msg(req, "Failed to create fully qualified name");
+        fq_name = NULL; /* content is undefined according to
+                           asprintf(3) */
+        goto done;
+    }
+
+    if (request_type == REQ_SIMPLE) {
+        /* REQ_SIMPLE */
+        ret = handle_simple_request(req, fq_name, berval);
+        goto done;
+    }
+
+    /* REQ_FULL || REQ_FULL_WITH_GROUPS */
+    ret = get_buffer(&buf_len, &buf);
+    if (ret != LDAP_SUCCESS) {
+        goto done;
+    }
+
+    ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len);
+    if (ret != 0) {
+        if (ret == ENOMEM || ret == ERANGE) {
+            ret = LDAP_OPERATIONS_ERROR;
+        } else {
+            ret = LDAP_NO_SUCH_OBJECT;
         }
+        goto done;
     }
 
+    if (request_type == REQ_FULL_WITH_GROUPS) {
+        ret = sss_nss_getorigbyname(grp.gr_name, &kv_list, &id_type);
+        if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
+                          || id_type == SSS_ID_TYPE_BOTH)) {
+            if (ret == ENOENT) {
+                ret = LDAP_NO_SUCH_OBJECT;
+            } else {
+                set_err_msg(req, "Failed to read original data");
+                ret = LDAP_OPERATIONS_ERROR;
+            }
+            goto done;
+        }
+    }
+
+    ret = pack_ber_group((request_type == REQ_FULL ? RESP_GROUP
+                          : RESP_GROUP_MEMBERS),
+                         domain_name, grp.gr_name, grp.gr_gid,
+                         grp.gr_mem, kv_list, berval);
+
 done:
     sss_nss_free_kv(kv_list);
     free(fq_name);
-    free(sid_str);
     free(buf);
 
     return ret;
 }
 
+static int handle_name_request(struct ipa_extdom_ctx *ctx,
+                               struct extdom_req *req,
+                               enum request_types request_type,
+                               const char *name, const char *domain_name,
+                               struct berval **berval)
+{
+    int ret;
+
+
+    ret = handle_username_request(ctx, req, request_type,
+                                  name, domain_name, berval);
+    if (ret == LDAP_NO_SUCH_OBJECT) {
+        ret = handle_groupname_request(ctx, req, request_type,
+                                       name, domain_name, berval);
+    }
+
+    return ret;
+}
+
+
 int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
                    struct berval **berval)
 {
@@ -1318,6 +1411,18 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
                                   req->data.name.object_name,
                                   req->data.name.domain_name, berval);
 
+        break;
+    case INP_GROUPNAME:
+        ret = handle_groupname_request(ctx, req, req->request_type,
+                                       req->data.name.object_name,
+                                       req->data.name.domain_name, berval);
+
+        break;
+    case INP_USERNAME:
+        ret = handle_username_request(ctx, req, req->request_type,
+                                      req->data.name.object_name,
+                                      req->data.name.domain_name, berval);
+
         break;
     default:
         set_err_msg(req, "Unknown input type");
diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
index 48fcecc1ee..5f9714f982 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
@@ -54,6 +54,7 @@ Slapi_PluginDesc ipa_extdom_plugin_desc = {
 static char *ipa_extdom_oid_list[] = {
     EXOP_EXTDOM_OID,
     EXOP_EXTDOM_V1_OID,
+    EXOP_EXTDOM_V2_OID,
     NULL
 };
 
@@ -196,6 +197,8 @@ static int ipa_extdom_extop(Slapi_PBlock *pb)
         version = EXTDOM_V0;
     } else if (strcasecmp(oid, EXOP_EXTDOM_V1_OID) == 0) {
         version = EXTDOM_V1;
+    } else if (strcasecmp(oid, EXOP_EXTDOM_V2_OID) == 0) {
+        version = EXTDOM_V2;
     } else {
         return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
     }

From 6092ba2e25420eda395be12a9bfeaa83561b4c71 Mon Sep 17 00:00:00 2001
From: Tomas Halman <[email protected]>
Date: Tue, 10 Sep 2019 13:32:45 +0200
Subject: [PATCH 2/4] extdom: plugin doesn't use timeout in blocking call

Expose nss timeout parameter. Use sss_nss_getorigbyname_timeout
instead of sss_nss_getorigbyname
---
 .../ipa-extdom-extop/back_extdom.h               |  4 ++++
 .../ipa-extdom-extop/back_extdom_nss_sss.c       |  7 +++++--
 .../ipa-extdom-extop/back_extdom_sss_idmap.c     |  9 ++++++++-
 .../ipa-extdom-extop/ipa_extdom.h                |  1 +
 .../ipa-extdom-extop/ipa_extdom_common.c         | 16 ++++++++++++++--
 .../ipa-extdom-extop/ipa_extdom_extop.c          |  1 -
 6 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h
index d2937c8c8e..05292cf93a 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h
@@ -35,6 +35,9 @@ enum nss_status {
     NSS_STATUS_RETURN
 };
 
+/* default NSS operation timeout 10s (ipaExtdomMaxNssTimeout) */
+#define DEFAULT_MAX_NSS_TIMEOUT (10*1000)
+
 /* NSS backend operations implemented using either nss_sss.so.2 or libsss_nss_idmap API */
 struct nss_ops_ctx;
 
@@ -42,6 +45,7 @@ int back_extdom_init_context(struct nss_ops_ctx **nss_context);
 void back_extdom_free_context(struct nss_ops_ctx **nss_context);
 void back_extdom_set_timeout(struct nss_ops_ctx *nss_context,
                              unsigned int timeout);
+unsigned int back_extdom_get_timeout(struct nss_ops_ctx *nss_context);
 void back_extdom_evict_user(struct nss_ops_ctx *nss_context,
                             const char *name);
 void back_extdom_evict_group(struct nss_ops_ctx *nss_context,
diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c
index 55b1030403..c29dc994af 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c
@@ -135,7 +135,7 @@ int back_extdom_init_context(struct nss_ops_ctx **nss_context)
 }
 
 
-/* Following three functions cannot be implemented with nss_sss.so.2
+/* Following four functions cannot be implemented with nss_sss.so.2
  * As result, we simply do nothing here */
 
 void back_extdom_set_timeout(struct nss_ops_ctx *nss_context,
@@ -143,6 +143,10 @@ void back_extdom_set_timeout(struct nss_ops_ctx *nss_context,
         /* no operation */
 }
 
+unsigned int back_extdom_get_timeout(struct nss_ops_ctx *nss_context) {
+    return DEFAULT_MAX_NSS_TIMEOUT;
+}
+
 void back_extdom_evict_user(struct nss_ops_ctx *nss_context,
                             const char *name) {
         /* no operation */
@@ -288,4 +292,3 @@ enum nss_status back_extdom_getgrouplist(struct nss_ops_ctx *nss_context,
 
     return ret;
 }
-
diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
index 163e8e1371..8064f871e0 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
@@ -111,6 +111,14 @@ void back_extdom_set_timeout(struct nss_ops_ctx *nss_context,
     nss_context->timeout = timeout;
 }
 
+unsigned int back_extdom_get_timeout(struct nss_ops_ctx *nss_context) {
+    if (nss_context == NULL) {
+        return DEFAULT_MAX_NSS_TIMEOUT;
+    }
+
+    return nss_context->timeout;
+}
+
 void back_extdom_evict_user(struct nss_ops_ctx *nss_context,
                             const char *name) {
     if (nss_context == NULL) {
@@ -272,4 +280,3 @@ enum nss_status back_extdom_getgrouplist(struct nss_ops_ctx *nss_context,
     }
     return __convert_sss_nss2nss_status(ret);
 }
-
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 81691ca1b3..beb4eedd5a 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
@@ -59,6 +59,7 @@
 #include <lber.h>
 #include <time.h>
 
+#define IPA_389DS_PLUGIN_HELPER_CALLS
 #include <sss_nss_idmap.h>
 
 #define EXOP_EXTDOM_OID "2.16.840.1.113730.3.8.10.4"
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 92a7bea706..853f49fa7e 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
@@ -114,6 +114,13 @@ int __nss_to_err(enum nss_status errcode)
     }
 }
 
+static int get_timeout(struct ipa_extdom_ctx *ctx) {
+    if (ctx == NULL || ctx->nss_ctx == NULL) {
+        return DEFAULT_MAX_NSS_TIMEOUT;
+    }
+    return back_extdom_get_timeout(ctx->nss_ctx);
+}
+
 int getpwnam_r_wrapper(struct ipa_extdom_ctx *ctx, const char *name,
                        struct passwd *pwd, char **buf, size_t *buf_len)
 {
@@ -1245,7 +1252,9 @@ static int handle_username_request(struct ipa_extdom_ctx *ctx,
     switch(ret) {
     case 0:
         if (request_type == REQ_FULL_WITH_GROUPS) {
-            ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type);
+            ret = sss_nss_getorigbyname_timeout(pwd.pw_name,
+                                                get_timeout(ctx),
+                                                &kv_list, &id_type);
             if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
                               || id_type == SSS_ID_TYPE_BOTH)) {
                 set_err_msg(req, "Failed to read original data");
@@ -1334,7 +1343,10 @@ static int handle_groupname_request(struct ipa_extdom_ctx *ctx,
     }
 
     if (request_type == REQ_FULL_WITH_GROUPS) {
-        ret = sss_nss_getorigbyname(grp.gr_name, &kv_list, &id_type);
+        ret = sss_nss_getorigbyname_timeout(grp.gr_name,
+                                            get_timeout(ctx),
+                                            &kv_list,
+                                            &id_type);
         if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
                           || id_type == SSS_ID_TYPE_BOTH)) {
             if (ret == ENOENT) {
diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
index 5f9714f982..5d22f9f2d5 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
@@ -42,7 +42,6 @@
 #include "util.h"
 
 #define DEFAULT_MAX_NSS_BUFFER (128*1024*1024)
-#define DEFAULT_MAX_NSS_TIMEOUT (10*1000)
 
 Slapi_PluginDesc ipa_extdom_plugin_desc = {
     IPA_EXTDOM_FEATURE_DESC,

From cf1c0894e14c1f9a1aa5c1ddc5b7912dcc335cb5 Mon Sep 17 00:00:00 2001
From: Tomas Halman <[email protected]>
Date: Tue, 10 Sep 2019 13:46:08 +0200
Subject: [PATCH 3/4] extdom: use sss_nss_*_timeout calls

Use nss calls with timeout in extdom plugin
---
 .../ipa-extdom-extop/ipa_extdom_common.c      | 40 +++++++++++--------
 1 file changed, 24 insertions(+), 16 deletions(-)

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 853f49fa7e..5d97ff6137 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
@@ -852,7 +852,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
     }
 
     if (request_type == REQ_SIMPLE) {
-        ret = sss_nss_getsidbyid(uid, &sid_str, &id_type);
+        ret = sss_nss_getsidbyid_timeout(uid, get_timeout(ctx),
+                                         &sid_str, &id_type);
         if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
                             || id_type == SSS_ID_TYPE_BOTH)) {
             if (ret == ENOENT) {
@@ -881,7 +882,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
         }
 
         if (request_type == REQ_FULL_WITH_GROUPS) {
-            ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type);
+            ret = sss_nss_getorigbyname_timeout(pwd.pw_name, get_timeout(ctx),
+                                                &kv_list, &id_type);
             if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
                                 || id_type == SSS_ID_TYPE_BOTH)) {
                 set_err_msg(req, "Failed to read original data");
@@ -930,7 +932,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
     }
 
     if (request_type == REQ_SIMPLE) {
-        ret = sss_nss_getsidbyid(gid, &sid_str, &id_type);
+        ret = sss_nss_getsidbyid_timeout(gid, get_timeout(ctx),
+                                         &sid_str, &id_type);
         if (ret != 0 || id_type != SSS_ID_TYPE_GID) {
             if (ret == ENOENT) {
                 ret = LDAP_NO_SUCH_OBJECT;
@@ -958,7 +961,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
         }
 
         if (request_type == REQ_FULL_WITH_GROUPS) {
-            ret = sss_nss_getorigbyname(grp.gr_name, &kv_list, &id_type);
+            ret = sss_nss_getorigbyname_timeout(grp.gr_name, get_timeout(ctx),
+                                                &kv_list, &id_type);
             if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
                                 || id_type == SSS_ID_TYPE_BOTH)) {
                 set_err_msg(req, "Failed to read original data");
@@ -1005,7 +1009,8 @@ static int handle_cert_request(struct ipa_extdom_ctx *ctx,
         goto done;
     }
 
-    ret = sss_nss_getlistbycert(input, &fq_names, &id_types);
+    ret = sss_nss_getlistbycert_timeout(input, get_timeout(ctx),
+                                        &fq_names, &id_types);
     if (ret != 0) {
         if (ret == ENOENT) {
             ret = LDAP_NO_SUCH_OBJECT;
@@ -1051,7 +1056,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
     enum sss_id_type id_type;
     struct sss_nss_kv *kv_list = NULL;
 
-    ret = sss_nss_getnamebysid(input, &fq_name, &id_type);
+    ret = sss_nss_getnamebysid_timeout(input, get_timeout(ctx),
+                                       &fq_name, &id_type);
     if (ret != 0) {
         if (ret == ENOENT) {
             ret = LDAP_NO_SUCH_OBJECT;
@@ -1105,7 +1111,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
         }
 
         if (request_type == REQ_FULL_WITH_GROUPS) {
-            ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type);
+            ret = sss_nss_getorigbyname_timeout(pwd.pw_name, get_timeout(ctx),
+                                                &kv_list, &id_type);
             if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
                                 || id_type == SSS_ID_TYPE_BOTH)) {
                 set_err_msg(req, "Failed to read original data");
@@ -1141,7 +1148,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
         }
 
         if (request_type == REQ_FULL_WITH_GROUPS) {
-            ret = sss_nss_getorigbyname(grp.gr_name, &kv_list, &id_type);
+            ret = sss_nss_getorigbyname_timeout(grp.gr_name, get_timeout(ctx),
+                                                &kv_list, &id_type);
             if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
                                 || id_type == SSS_ID_TYPE_BOTH)) {
                 set_err_msg(req, "Failed to read original data");
@@ -1177,7 +1185,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
 }
 
 
-static int handle_simple_request(struct extdom_req *req,
+static int handle_simple_request(struct ipa_extdom_ctx *ctx,
+                                 struct extdom_req *req,
                                  const char *fq_name,
                                  struct berval **berval)
 {
@@ -1185,7 +1194,8 @@ static int handle_simple_request(struct extdom_req *req,
     char *sid_str = NULL;
     enum sss_id_type id_type;
 
-    ret = sss_nss_getsidbyname(fq_name, &sid_str, &id_type);
+    ret = sss_nss_getsidbyname_timeout(fq_name, get_timeout(ctx),
+                                       &sid_str, &id_type);
     switch(ret) {
     case 0:
         ret = pack_ber_sid(sid_str, berval);
@@ -1238,7 +1248,7 @@ static int handle_username_request(struct ipa_extdom_ctx *ctx,
 
     if (request_type == REQ_SIMPLE) {
         /* REQ_SIMPLE */
-        ret = handle_simple_request(req, fq_name, berval);
+        ret = handle_simple_request(ctx, req, fq_name, berval);
         goto done;
     }
 
@@ -1322,7 +1332,7 @@ static int handle_groupname_request(struct ipa_extdom_ctx *ctx,
 
     if (request_type == REQ_SIMPLE) {
         /* REQ_SIMPLE */
-        ret = handle_simple_request(req, fq_name, berval);
+        ret = handle_simple_request(ctx, req, fq_name, berval);
         goto done;
     }
 
@@ -1343,10 +1353,8 @@ static int handle_groupname_request(struct ipa_extdom_ctx *ctx,
     }
 
     if (request_type == REQ_FULL_WITH_GROUPS) {
-        ret = sss_nss_getorigbyname_timeout(grp.gr_name,
-                                            get_timeout(ctx),
-                                            &kv_list,
-                                            &id_type);
+        ret = sss_nss_getorigbyname_timeout(grp.gr_name, get_timeout(ctx),
+                                            &kv_list, &id_type);
         if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
                           || id_type == SSS_ID_TYPE_BOTH)) {
             if (ret == ENOENT) {

From f982b4115525738243041b57d6c79bb67375d5fc Mon Sep 17 00:00:00 2001
From: Tomas Halman <[email protected]>
Date: Wed, 11 Sep 2019 10:15:48 +0200
Subject: [PATCH 4/4] extdom: add extdom protocol documentation

Add the description of extdom protocol and its versions
---
 doc/designs/extdom-plugin-protocol.md | 242 ++++++++++++++++++++++++++
 1 file changed, 242 insertions(+)
 create mode 100644 doc/designs/extdom-plugin-protocol.md

diff --git a/doc/designs/extdom-plugin-protocol.md b/doc/designs/extdom-plugin-protocol.md
new file mode 100644
index 0000000000..cd2e9e2ffd
--- /dev/null
+++ b/doc/designs/extdom-plugin-protocol.md
@@ -0,0 +1,242 @@
+# Extdom plugin protocol
+
+SSSD on ipa client uses extdom plugin to translate SID to names and POSIX IDs. It can
+also return secondary groups for any user.
+
+## EXTDOM V0 (2.16.840.1.113730.3.8.10.4)
+
+### V0 request
+
+    /*
+     * ExtdomRequestValue ::= SEQUENCE {
+     *    inputType ENUMERATED {
+     *        sid (1),
+     *        name (2),
+     *        posix uid (3),
+     *        posix gid (4)
+     *    },
+     *    requestType ENUMERATED {
+     *        simple (1),
+     *        full (2)
+     *    },
+     *    data InputData
+     * }
+     *
+     * InputData ::= CHOICE {
+     *    sid OCTET STRING,
+     *    name NameDomainData
+     *    uid PosixUid,
+     *    gid PosixGid
+     * }
+     *
+     * NameDomainData ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    object_name OCTET STRING
+     * }
+     *
+     * PosixUid ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    uid INTEGER
+     * }
+     *
+     * PosixGid ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    gid INTEGER
+     * }
+     */
+
+### V0 reply
+
+    /*
+     * ExtdomResponseValue ::= SEQUENCE {
+     *    responseType ENUMERATED {
+     *        sid (1),
+     *        name (2),
+     *        posix_user (3),
+     *        posix_group (4)
+     *    },
+     *    data OutputData
+     * }
+     *
+     * OutputData ::= CHOICE {
+     *    sid OCTET STRING,
+     *    name NameDomainData,
+     *    user PosixUser,
+     *    group PosixGroup
+     * }
+     *
+     * NameDomainData ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    object_name OCTET STRING
+     * }
+     *
+     * PosixUser ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    user_name OCTET STRING,
+     *    uid INTEGER
+     *    gid INTEGER
+     * }
+     *
+     * PosixGroup ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    group_name OCTET STRING,
+     *    gid INTEGER
+     * }
+     */
+
+## EXTDOM V1 (2.16.840.1.113730.3.8.10.4.1)
+
+In V1 version the requestType is extended of `full_with_groups`.
+The response introduces new type `posix_user_grouplist` containing
+the list of groups
+
+### V1 request
+
+    /*
+     * ExtdomRequestValue ::= SEQUENCE {
+     *    inputType ENUMERATED {
+     *        sid (1),
+     *        name (2),
+     *        posix uid (3),
+     *        posix gid (4),
+     *    },
+     *    requestType ENUMERATED {
+     *        simple (1),
+     *        full (2),
+     *        full_with_groups (3)
+     *    },
+     *    data InputData
+     * }
+     *
+     * InputData ::= CHOICE {
+     *    sid OCTET STRING,
+     *    name NameDomainData
+     *    uid PosixUid,
+     *    gid PosixGid
+     * }
+     *
+     * NameDomainData ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    object_name OCTET STRING
+     * }
+     *
+     * PosixUid ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    uid INTEGER
+     * }
+     *
+     * PosixGid ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    gid INTEGER
+     * }
+     */
+
+### V1 reply
+
+    /*
+     * ExtdomResponseValue ::= SEQUENCE {
+     *    responseType ENUMERATED {
+     *        sid (1),
+     *        name (2),
+     *        posix_user (3),
+     *        posix_group (4),
+     *        posix_user_grouplist (5)
+     *    },
+     *    data OutputData
+     * }
+     *
+     * OutputData ::= CHOICE {
+     *    sid OCTET STRING,
+     *    name NameDomainData,
+     *    user PosixUser,
+     *    group PosixGroup,
+     *    user_grouplist PosixUserGrouplist
+     * }
+     *
+     * NameDomainData ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    object_name OCTET STRING
+     * }
+     *
+     * PosixUser ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    user_name OCTET STRING,
+     *    uid INTEGER
+     *    gid INTEGER
+     * }
+     *
+     * GroupNameList ::= SEQUENCE OF groupname OCTET STRING
+     *
+     * PosixGroup ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    group_name OCTET STRING,
+     *    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 groupname OCTET STRING
+     *
+     */
+
+## EXTDOM V2 (2.16.840.1.113730.3.8.10.4.2)
+
+The `name` request tries to translate name to ID. It first tries translate it
+as if it is a user and when it fails, it tries to resolve is as group.
+
+To make it more efficient when SSSD knows the type of requested object, two new
+inputTypes are defined - username and groupname.
+
+The response is the same as in V1
+
+### V2 request
+
+    /*
+     * ExtdomRequestValue ::= SEQUENCE {
+     *    inputType ENUMERATED {
+     *        sid (1),
+     *        name (2),
+     *        posix uid (3),
+     *        posix gid (4),
+     *        username (5),
+     *        groupname (6)
+     *    },
+     *    requestType ENUMERATED {
+     *        simple (1),
+     *        full (2),
+     *        full_with_groups (3)
+     *    },
+     *    data InputData
+     * }
+     *
+     * InputData ::= CHOICE {
+     *    sid OCTET STRING,
+     *    name NameDomainData
+     *    uid PosixUid,
+     *    gid PosixGid
+     * }
+     *
+     * NameDomainData ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    object_name OCTET STRING
+     * }
+     *
+     * PosixUid ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    uid INTEGER
+     * }
+     *
+     * PosixGid ::= SEQUENCE {
+     *    domain_name OCTET STRING,
+     *    gid INTEGER
+     * }
+     */
_______________________________________________
FreeIPA-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/[email protected]

Reply via email to