[Freeipa-devel] [PATCH 130] extdom: add support for new version

Sumit Bose sbose at redhat.com
Mon Sep 29 16:16:30 UTC 2014


On Mon, Sep 29, 2014 at 06:15:21PM +0200, Sumit Bose wrote:
> On Thu, Sep 25, 2014 at 01:46:00PM +0200, Sumit Bose wrote:
> > On Wed, Sep 24, 2014 at 03:23:54PM +0200, Jakub Hrozek wrote:
> > > On Tue, Sep 23, 2014 at 05:11:01PM +0200, Sumit Bose wrote:
> > > > Hi,
> > > > 
> > > > this patch should fix https://fedorahosted.org/freeipa/ticket/4031 and
> > > > with the corresponding SSSD part it would be possible to get the full
> > > > list of group memberships with the id command even for user who didn't
> > > > log in before.
> > > > 
> > > > bye,
> > > > Sumit
> > > 
> > > So far I only read the patch, no testing was done yet (I'm installing a
> > > separate VM where I'll keep this new plugin for easy comparison and
> > > backwards-compatibility testing)
> > 
> > Thank you for the review, please see comments below.
> > 
> > > 
> > > First, there are some Coverity warnings:
> > > 
> > > Error: USE_AFTER_FREE (CWE-825):
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:242: alias: Assigning: "groups" = "new_groups". Now both point to the same storage.
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:246: freed_arg: "free(void *)" frees "groups".
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:252: use_after_free: Using freed pointer "groups".
> > 
> > fixed
> > 
> > > 
> > > Error: CONSTANT_EXPRESSION_RESULT (CWE-398):
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:596: missing_parentheses: "!id_type != SSS_ID_TYPE_GID" is always true regardless of the values of its operands. Did you intend to either negate the entire comparison expression, in which case parentheses would be required around the entire comparison expression to force that interpretation, or negate the sense of the comparison (that is, use '==' rather than '!=')? This occurs as the logical second operand of '||'.
> > 
> > fixed
> > 
> > > 
> > > Error: DEADCODE (CWE-561):
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:594: cond_cannot_single: Condition "request_type == 1U", taking false branch. Now the value of "request_type" cannot be equal to 1.
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:594: cond_cannot_set: Condition "request_type == 3U", taking false branch. Now the value of "request_type" cannot be equal to any of {1, 3}.
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:606: cannot_set: At condition "request_type == 1U", the value of "request_type" cannot be equal to any of {1, 3}.
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:606: dead_error_condition: The condition "request_type == 1U" cannot be true.
> > > freeipa-4.0.0GIT2563ea2/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c:607: dead_error_line: Execution cannot reach this statement "ret = pack_ber_sid(sid_str,...".
> > 
> > I thik this is a result of the CONSTANT_EXPRESSION_RESULT issue, since I
> > fixed it this warning should be gone as well.
> > 
> > > 
> > > See some comments inline.
> > > 
> > > > From 23ff38cdea85995b211e73f474bcb4b0d7fb8039 Mon Sep 17 00:00:00 2001
> > > > From: Sumit Bose <sbose at redhat.com>
> > > > Date: Tue, 23 Sep 2014 15:55:43 +0200
> > > > Subject: [PATCH] extdom: add support for new version
> > > > 
> > > > Currently the extdom plugin is basically used to translate SIDs of AD
> > > > users and groups to names and POSIX IDs.
> > > > 
> > > > With this patch a new version is added which will return the full member
> > > > list for groups and the full list of group memberships for a user.
> > > > Additionally the gecos field, the home directory and the login shell of a
> > > > user are returned and an optional list of key-value pairs which
> > > > currently will contain the SID of the requested object if available.
> > > > 
> > > > https://fedorahosted.org/freeipa/ticket/4031
> > > > ---
> > > >  .../ipa-extdom-extop/ipa_extdom.h                  |  29 +-
> > > >  .../ipa-extdom-extop/ipa_extdom_common.c           | 850 +++++++++++++++------
> > > >  .../ipa-extdom-extop/ipa_extdom_extop.c            |  28 +-
> > > >  3 files changed, 640 insertions(+), 267 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 5f834a047a579104cd2589ce417c580c1c5388d3..548ee74f561c474854c049726c4c3e71da5cbbea 100644
> > > > --- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
> > > > +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
> > > > @@ -64,6 +64,7 @@
> > > >  #include <sss_nss_idmap.h>
> > > >  
> > > >  #define EXOP_EXTDOM_OID "2.16.840.1.113730.3.8.10.4"
> > > > +#define EXOP_EXTDOM_V2_OID "2.16.840.1.113730.3.8.10.4.1"
> > > 
> > > It's a bit odd that this control is called V1 in the SSSD tree and V2 in
> > > the IPA tree. It's not wrong, just strange maybe.
> > 
> > you are right, I renamed the versions here.
> > 
> > > 
> > > >  
> > > > -int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
> > > > -                   struct extdom_res **res)
> > > > +int check_request(struct extdom_req *req, enum extdom_version version)
> > > > +{
> > > > +    if (version == EXTDOM_V1) {
> > > > +        if (req->request_type == REQ_FULL_WITH_GROUPS) {
> > > > +            return LDAP_PROTOCOL_ERROR;
> > > > +        }
> > > > +    }
> > > 
> > > Any particular reason why these conditions are nested and not and-ed ?
> > > Did you expect more under the EXTDOM_V1 condition?
> > 
> > I'm not expecting them, but who knows :-) I think this way it is more
> > clear that we are testing features of a specific version here.
> > 
> > > 
> > > > +
> > > > +    return LDAP_SUCCESS;
> > > > +}
> > > > +
> > > > +static int get_buffer(size_t *_buf_len, char **_buf)
> > > >  {
> > > > -    int ret;
> > > > -    char *domain_name = NULL;
> > > > -    char *sid_str = NULL;
> > > > -    size_t buf_len;
> > > > -    char *buf = NULL;
> > > >      long pw_max;
> > > >      long gr_max;
> > > > -    struct pwd_grp pg_data;
> > > > -    struct passwd *pwd_result = NULL;
> > > > -    struct group *grp_result = NULL;
> > > > -    enum sss_id_type id_type;
> > > > -    char *fq_name = NULL;
> > > > -    char *sep;
> > > > -
> > > > +    size_t buf_len;
> > > > +    char *buf;
> > > >  
> > > >      pw_max = sysconf(_SC_GETPW_R_SIZE_MAX);
> > > >      gr_max = sysconf(_SC_GETGR_R_SIZE_MAX);
> > > > @@ -211,302 +212,655 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
> > > >          return LDAP_OPERATIONS_ERROR;
> > > >      }
> > > >  
> > > > -    switch (req->input_type) {
> > > > -    case INP_POSIX_UID:
> > > > -        if (req->request_type == REQ_SIMPLE) {
> > > > -            ret = sss_nss_getsidbyid(req->data.posix_uid.uid, &sid_str,
> > > > -                                     &id_type);
> > > > +    *_buf_len = buf_len;
> > > > +    *_buf = buf;
> > > > +
> > > > +    return LDAP_SUCCESS;
> > > > +}
> > > > +
> > > > +static int get_user_grouplist(const char *name, gid_t gid,
> > > > +                              size_t *_ngroups, gid_t **_groups )
> > > > +{
> > > > +    int ret;
> > > > +    int ngroups;
> > > > +    gid_t *groups;
> > > > +    gid_t *new_groups;
> > > > +
> > > > +    ngroups = 128;
> > > 
> > > I was wondering whether to use _SC_NGROUPS_MAX or NGROUPS_MAX here, but
> > > I guess you're right it's very unlikely that a user will be a member of
> > > more than 128 groups so we'd just clinge to more memory than needed..
> > > 
> > > > +    groups = malloc(ngroups * sizeof(gid_t));
> > > > +    if (groups == NULL) {
> > > > +        return LDAP_OPERATIONS_ERROR;
> > > > +    }
> > > > +
> > > > +    ret = getgrouplist(name, gid, groups, &ngroups);
> > > > +    if (ret == -1) {
> > > > +        new_groups = realloc(groups, ngroups);
> > > > +        if (new_groups == NULL) {
> > > > +            free(groups);
> > > > +            return LDAP_OPERATIONS_ERROR;
> > > > +        }
> > > > +        groups = new_groups;
> > > > +
> > > > +        ret = getgrouplist(name, gid, groups, &ngroups);
> > > > +        if (ret == -1) {
> > > > +            free(groups);
> > > > +            ret = LDAP_OPERATIONS_ERROR;
> > > > +        }
> > > > +    }
> > > > +
> > > > +    *_ngroups = ngroups;
> > > > +    *_groups = groups;
> > > > +
> > > > +    return LDAP_SUCCESS;
> > > > +}
> > > > +
> > > > +static int pack_ber_sid(const char *sid, struct berval **berval)
> > > > +{
> > > > +    BerElement *ber = NULL;
> > > > +    int ret;
> > > > +
> > > > +    ber = ber_alloc_t( LBER_USE_DER );
> > > > +    if (ber == NULL) {
> > > > +        return LDAP_OPERATIONS_ERROR;
> > > > +    }
> > > > +
> > > > +    ret = ber_printf(ber,"{es}", RESP_SID, sid);
> > > > +    if (ret == -1) {
> > > > +        ber_free(ber, 1);
> > > > +        return LDAP_OPERATIONS_ERROR;
> > > > +    }
> > > > +
> > > > +    ret = ber_flatten(ber, berval);
> > > > +    ber_free(ber, 1);
> > > > +    if (ret == -1) {
> > > > +        return LDAP_OPERATIONS_ERROR;
> > > > +    }
> > > > +
> > > > +    return LDAP_SUCCESS;
> > > > +}
> > > > +
> > > > +#define SSSD_SYSDB_SID_STR "objectSIDString"
> > > > +
> > > > +static int pack_ber_user(const char *domain_name, const char *user_name,
> > > > +                         uid_t uid, gid_t gid,
> > > > +                         const char *gecos, const char *homedir,
> > > > +                         const char *shell, const char *sid_str,
> > > > +                         struct berval **berval)
> > > > +{
> > > > +    BerElement *ber = NULL;
> > > > +    int ret;
> > > > +    enum response_types response_type;
> > > > +    size_t ngroups;
> > > > +    gid_t *groups = NULL;
> > > > +    size_t buf_len;
> > > > +    char *buf = NULL;
> > > > +    struct group grp;
> > > > +    struct group *grp_result;
> > > > +    size_t c;
> > > > +    char *locat;
> > > > +    char *short_user_name = NULL;
> > > > +    const char *single_value_string_array[] = {NULL, NULL};
> > > > +
> > > > +    if (gecos == NULL && homedir == NULL && shell == NULL) {
> > > > +        response_type = RESP_USER;
> > > > +    } else {
> > > > +        response_type = RESP_USER_GROUPLIST;
> > > > +    }
> > > > +
> > > > +    short_user_name = strdup(user_name);
> > > > +    if ((locat = strchr(short_user_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
> > > 
> > > Some functions in the code use strchr to fund the at-sign, some use
> > > strrch. Could we standardize on one or the other? Do you expect some
> > > usernames with an at-sign in them?
> > 
> > I think the 'rr' version was just a typo, I changed it to 'r'.
> > 
> > > 
> > > > +        if (strcasecmp(locat+1, domain_name) == 0  ) {
> > > > +            locat[0] = '\0';
> > > >          } else {
> > > > -            id_type = SSS_ID_TYPE_UID;
> > > > -            ret = getpwuid_r(req->data.posix_uid.uid, &pg_data.data.pwd, buf,
> > > > -                             buf_len, &pwd_result);
> > > > +            ret = LDAP_NO_SUCH_OBJECT;
> > > > +            goto done;
> > > >          }
> > > > +    }
> > > >  
> > > > -        domain_name = strdup(req->data.posix_uid.domain_name);
> > > > -        break;
> > > > -    case INP_POSIX_GID:
> > > > -        if (req->request_type == REQ_SIMPLE) {
> > > > -            ret = sss_nss_getsidbyid(req->data.posix_uid.uid, &sid_str,
> > > > -                                     &id_type);
> > > > +    ber = ber_alloc_t( LBER_USE_DER );
> > > > +    if (ber == NULL) {
> > > > +        return LDAP_OPERATIONS_ERROR;
> > > > +    }
> > > > +
> > > > +    ret = ber_printf(ber,"{e{ssii", response_type, domain_name, short_user_name,
> > > > +                                      uid, gid);
> > > > +    if (ret == -1) {
> > > > +        ret = LDAP_OPERATIONS_ERROR;
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    if (response_type == RESP_USER_GROUPLIST) {
> > > > +        ret = get_user_grouplist(user_name, gid, &ngroups, &groups);
> > > > +        if (ret != LDAP_SUCCESS) {
> > > > +            goto done;
> > > > +        }
> > > > +
> > > > +        ret = get_buffer(&buf_len, &buf);
> > > > +        if (ret != LDAP_SUCCESS) {
> > > > +            goto done;
> > > > +        }
> > > > +
> > > > +        ret = ber_printf(ber,"sss", gecos, homedir, shell);
> > > > +        if (ret == -1) {
> > > > +            ret = LDAP_OPERATIONS_ERROR;
> > > > +            goto done;
> > > > +        }
> > > > +
> > > > +        ret = ber_printf(ber,"{");
> > > > +        if (ret == -1) {
> > > > +            ret = LDAP_OPERATIONS_ERROR;
> > > > +            goto done;
> > > > +        }
> > > > +
> > > > +        for (c = 0; c < ngroups; c++) {
> > > > +            ret = getgrgid_r(groups[c], &grp, buf, buf_len, &grp_result);
> > > > +            if (ret != 0) {
> > > > +                ret = LDAP_OPERATIONS_ERROR;
> > > > +                goto done;
> > > > +            }
> > > > +            if (grp_result == NULL) {
> > > > +                ret = LDAP_NO_SUCH_OBJECT;
> > > > +                goto done;
> > > 
> > > I wanted to check if you think it's better to continue or fail here. Did
> > > you opt for failing because you were afraid of missing some deny access
> > > checks in case we couldn't resolv a group?
> > 
> > I think there is a disconnect if getgrouplist() returns a GID that
> > cannot be resolved so I prefer an error in this case.
> > 
> > > 
> > > > +            }
> > > > +
> > > > +            ret = ber_printf(ber, "s", grp.gr_name);
> > > > +            if (ret == -1) {
> > > > +                ret = LDAP_OPERATIONS_ERROR;
> > > > +                goto done;
> > > > +            }
> > > > +        }
> > > > +
> > > > +        ret = ber_printf(ber,"}");
> > > > +        if (ret == -1) {
> > > > +            ret = LDAP_OPERATIONS_ERROR;
> > > > +            goto done;
> > > > +        }
> > > > +
> > > > +        single_value_string_array[0] = sid_str;
> > > > +        ret = ber_printf(ber,"{{s{v}}}", SSSD_SYSDB_SID_STR,
> > > > +                                         single_value_string_array);
> > > > +        if (ret == -1) {
> > > > +            ret = LDAP_OPERATIONS_ERROR;
> > > > +            goto done;
> > > > +        }
> > > > +    }
> > > > +
> > > > +    ret = ber_printf(ber,"}}");
> > > > +    if (ret == -1) {
> > > > +        ret = LDAP_OPERATIONS_ERROR;
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    ret = ber_flatten(ber, berval);
> > > > +    if (ret == -1) {
> > > > +        ret = LDAP_OPERATIONS_ERROR;
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    ret = LDAP_SUCCESS;
> > > > +done:
> > > > +    free(short_user_name);
> > > > +    free(groups);
> > > > +    free(buf);
> > > > +    ber_free(ber, 1);
> > > > +    return ret;
> > > > +}
> > > > +
> > > > +static int pack_ber_group(const char *domain_name, const char *group_name,
> > > > +                          gid_t gid, char **members, const char *sid_str,
> > > > +                          struct berval **berval)
> > > > +{
> > > > +    BerElement *ber = NULL;
> > > > +    int ret;
> > > > +    size_t c;
> > > > +    char *locat;
> > > > +    char *short_group_name = NULL;
> > > > +    const char *single_value_string_array[] = {NULL, NULL};
> > > > +
> > > > +    short_group_name = strdup(group_name);
> > > > +    if ((locat = strchr(short_group_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
> > > > +        if (strcasecmp(locat+1, domain_name) == 0  ) {
> > > > +            locat[0] = '\0';
> > > >          } else {
> > > > -            id_type = SSS_ID_TYPE_GID;
> > > > -            ret = getgrgid_r(req->data.posix_gid.gid, &pg_data.data.grp, buf,
> > > > -                             buf_len, &grp_result);
> > > > +            ret = LDAP_NO_SUCH_OBJECT;
> > > > +            goto done;
> > > >          }
> > > > +    }
> > > >  
> > > > -        domain_name = strdup(req->data.posix_gid.domain_name);
> > > > -        break;
> > > > -    case INP_SID:
> > > > -        ret = sss_nss_getnamebysid(req->data.sid, &fq_name, &id_type);
> > > > -        if (ret != 0) {
> > > > +    ber = ber_alloc_t( LBER_USE_DER );
> > > > +    if (ber == NULL) {
> > > > +        return LDAP_OPERATIONS_ERROR;
> > > > +    }
> > > > +
> > > > +    ret = ber_printf(ber,"{e{ssi", members == NULL ? RESP_GROUP
> > > > +                                                    : RESP_GROUP_MEMBERS,
> > > 
> > > Each pack_ber_group is called like this:
> > > 718         if (request_type == REQ_FULL) {
> > > 719             ret = pack_ber_group(domain_name, grp.gr_name, grp.gr_gid,
> > > 720                                  NULL, NULL, berval);
> > > 721         } else {
> > > 722             ret = pack_ber_group(domain_name, grp.gr_name, grp.gr_gid,
> > > 723                                  grp.gr_mem, sid, berval);
> > > 724         }
> > > 
> > > And then you guess the request_type again based on the parameter
> > > values. Isn't it safer to add the request type parameter avoid the if-else
> > > switch in the callers? Or were you trying to be on the safe side to avoid
> > > checking the validity members array in the pack_ber_group function and have
> > > the array set to NULL by the caller?
> > 
> > You are right, the if-block is odd. Instead of the request_type I added
> > the response_type to the argument list of pack_ber_user() and
> > pack_ber_group() which I think is more natural because it is the
> > response that is packed.
> > 
> > > 
> > > The rest of the file looks to me, just the same "issue" with guessing the
> > > request type is repeated.
> > > 
> > 
> > New version attached.
> > 
> > bye,
> > Sumit
> 
> Hi,
> 
> Jakub found another issue which is fixed with this new version.
> 
> bye,
> Sumit

and now with patch ...
-------------- next part --------------
From 1becbaf1c6120618a5dfe47150bf970578d1c8be Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 23 Sep 2014 15:55:43 +0200
Subject: [PATCH] extdom: add support for new version

Currently the extdom plugin is basically used to translate SIDs of AD
users and groups to names and POSIX IDs.

With this patch a new version is added which will return the full member
list for groups and the full list of group memberships for a user.
Additionally the gecos field, the home directory and the login shell of a
user are returned and an optional list of key-value pairs which
currently will contain the SID of the requested object if available.

https://fedorahosted.org/freeipa/ticket/4031
---
 .../ipa-extdom-extop/ipa_extdom.h                  |  29 +-
 .../ipa-extdom-extop/ipa_extdom_common.c           | 830 ++++++++++++++-------
 .../ipa-extdom-extop/ipa_extdom_extop.c            |  28 +-
 3 files changed, 619 insertions(+), 268 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 5f834a047a579104cd2589ce417c580c1c5388d3..90f8390d871a698dc00ef56c41be0749eaa13424 100644
--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
@@ -64,6 +64,7 @@
 #include <sss_nss_idmap.h>
 
 #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 IPA_EXTDOM_PLUGIN_NAME   "ipa-extdom-extop"
 #define IPA_EXTDOM_FEATURE_DESC  "IPA trusted domain ID mapper"
@@ -71,6 +72,11 @@
 
 #define IPA_PLUGIN_NAME IPA_EXTDOM_PLUGIN_NAME
 
+enum extdom_version {
+    EXTDOM_V0 = 0,
+    EXTDOM_V1
+};
+
 enum input_types {
     INP_SID = 1,
     INP_NAME,
@@ -80,14 +86,17 @@ enum input_types {
 
 enum request_types {
     REQ_SIMPLE = 1,
-    REQ_FULL
+    REQ_FULL,
+    REQ_FULL_WITH_GROUPS
 };
 
 enum response_types {
     RESP_SID = 1,
     RESP_NAME,
     RESP_USER,
-    RESP_GROUP
+    RESP_GROUP,
+    RESP_USER_GROUPLIST,
+    RESP_GROUP_MEMBERS
 };
 
 struct extdom_req {
@@ -123,11 +132,18 @@ struct extdom_res {
             char *user_name;
             uid_t uid;
             gid_t gid;
+            char *gecos;
+            char *home;
+            char *shell;
+            size_t ngroups;
+            char **groups;
         } user;
         struct {
             char *domain_name;
             char *group_name;
             gid_t gid;
+            size_t nmembers;
+            char **members;
         } group;
     } data;
 };
@@ -150,15 +166,14 @@ struct pwd_grp {
         struct passwd pwd;
         struct group grp;
     } data;
+    int ngroups;
+    gid_t *groups;
 };
 
 int parse_request_data(struct berval *req_val, struct extdom_req **_req);
 void free_req_data(struct extdom_req *req);
+int check_request(struct extdom_req *req, enum extdom_version version);
 int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
-                   struct extdom_res **res);
-int create_response(struct extdom_req *req, struct pwd_grp *pg_data,
-                    const char *sid_str, enum sss_id_type id_type,
-                    const char *domain_name, struct extdom_res **_res);
-void free_resp_data(struct extdom_res *res);
+                   struct berval **berval);
 int pack_response(struct extdom_res *res, struct berval **ret_val);
 #endif /* _IPA_EXTDOM_H_ */
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 025d37dc5eda05c8db43d4e8176fd7898ed32fe7..d1d214ae769946a89ffe1702382e5db70035fdac 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
@@ -70,6 +70,7 @@ int parse_request_data(struct berval *req_val, struct extdom_req **_req)
  *    requestType ENUMERATED {
  *        simple (1),
  *        full (2)
+ *        full_with_groups (3)
  *    },
  *    data InputData
  * }
@@ -179,23 +180,23 @@ void free_req_data(struct extdom_req *req)
     free(req);
 }
 
-int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
-                   struct extdom_res **res)
+int check_request(struct extdom_req *req, enum extdom_version version)
+{
+    if (version == EXTDOM_V0) {
+        if (req->request_type == REQ_FULL_WITH_GROUPS) {
+            return LDAP_PROTOCOL_ERROR;
+        }
+    }
+
+    return LDAP_SUCCESS;
+}
+
+static int get_buffer(size_t *_buf_len, char **_buf)
 {
-    int ret;
-    char *domain_name = NULL;
-    char *sid_str = NULL;
-    size_t buf_len;
-    char *buf = NULL;
     long pw_max;
     long gr_max;
-    struct pwd_grp pg_data;
-    struct passwd *pwd_result = NULL;
-    struct group *grp_result = NULL;
-    enum sss_id_type id_type;
-    char *fq_name = NULL;
-    char *sep;
-
+    size_t buf_len;
+    char *buf;
 
     pw_max = sysconf(_SC_GETPW_R_SIZE_MAX);
     gr_max = sysconf(_SC_GETGR_R_SIZE_MAX);
@@ -211,302 +212,633 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
         return LDAP_OPERATIONS_ERROR;
     }
 
-    switch (req->input_type) {
-    case INP_POSIX_UID:
-        if (req->request_type == REQ_SIMPLE) {
-            ret = sss_nss_getsidbyid(req->data.posix_uid.uid, &sid_str,
-                                     &id_type);
-        } else {
-            id_type = SSS_ID_TYPE_UID;
-            ret = getpwuid_r(req->data.posix_uid.uid, &pg_data.data.pwd, buf,
-                             buf_len, &pwd_result);
+    *_buf_len = buf_len;
+    *_buf = buf;
+
+    return LDAP_SUCCESS;
+}
+
+static int get_user_grouplist(const char *name, gid_t gid,
+                              size_t *_ngroups, gid_t **_groups )
+{
+    int ret;
+    int ngroups;
+    gid_t *groups;
+    gid_t *new_groups;
+
+    ngroups = 128;
+    groups = malloc(ngroups * sizeof(gid_t));
+    if (groups == NULL) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = getgrouplist(name, gid, groups, &ngroups);
+    if (ret == -1) {
+        new_groups = realloc(groups, ngroups);
+        if (new_groups == NULL) {
+            free(groups);
+            return LDAP_OPERATIONS_ERROR;
         }
+        groups = new_groups;
 
-        domain_name = strdup(req->data.posix_uid.domain_name);
-        break;
-    case INP_POSIX_GID:
-        if (req->request_type == REQ_SIMPLE) {
-            ret = sss_nss_getsidbyid(req->data.posix_uid.uid, &sid_str,
-                                     &id_type);
+        ret = getgrouplist(name, gid, groups, &ngroups);
+        if (ret == -1) {
+            free(groups);
+            return LDAP_OPERATIONS_ERROR;
+        }
+    }
+
+    *_ngroups = ngroups;
+    *_groups = groups;
+
+    return LDAP_SUCCESS;
+}
+
+static int pack_ber_sid(const char *sid, struct berval **berval)
+{
+    BerElement *ber = NULL;
+    int ret;
+
+    ber = ber_alloc_t( LBER_USE_DER );
+    if (ber == NULL) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = ber_printf(ber,"{es}", RESP_SID, sid);
+    if (ret == -1) {
+        ber_free(ber, 1);
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = ber_flatten(ber, berval);
+    ber_free(ber, 1);
+    if (ret == -1) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    return LDAP_SUCCESS;
+}
+
+#define SSSD_SYSDB_SID_STR "objectSIDString"
+
+static int pack_ber_user(enum response_types response_type,
+                         const char *domain_name, const char *user_name,
+                         uid_t uid, gid_t gid,
+                         const char *gecos, const char *homedir,
+                         const char *shell, const char *sid_str,
+                         struct berval **berval)
+{
+    BerElement *ber = NULL;
+    int ret;
+    size_t ngroups;
+    gid_t *groups = NULL;
+    size_t buf_len;
+    char *buf = NULL;
+    struct group grp;
+    struct group *grp_result;
+    size_t c;
+    char *locat;
+    char *short_user_name = NULL;
+    const char *single_value_string_array[] = {NULL, NULL};
+
+    short_user_name = strdup(user_name);
+    if ((locat = strchr(short_user_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
+        if (strcasecmp(locat+1, domain_name) == 0  ) {
+            locat[0] = '\0';
         } else {
-            id_type = SSS_ID_TYPE_GID;
-            ret = getgrgid_r(req->data.posix_gid.gid, &pg_data.data.grp, buf,
-                             buf_len, &grp_result);
+            ret = LDAP_NO_SUCH_OBJECT;
+            goto done;
         }
+    }
 
-        domain_name = strdup(req->data.posix_gid.domain_name);
-        break;
-    case INP_SID:
-        ret = sss_nss_getnamebysid(req->data.sid, &fq_name, &id_type);
-        if (ret != 0) {
-            ret = LDAP_OPERATIONS_ERROR;
+    ber = ber_alloc_t( LBER_USE_DER );
+    if (ber == NULL) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = ber_printf(ber,"{e{ssii", response_type, domain_name, short_user_name,
+                                      uid, gid);
+    if (ret == -1) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    if (response_type == RESP_USER_GROUPLIST) {
+        ret = get_user_grouplist(user_name, gid, &ngroups, &groups);
+        if (ret != LDAP_SUCCESS) {
             goto done;
         }
 
-        sep = strrchr(fq_name, SSSD_DOMAIN_SEPARATOR);
-        if (sep == NULL) {
+        ret = get_buffer(&buf_len, &buf);
+        if (ret != LDAP_SUCCESS) {
+            goto done;
+        }
+
+        ret = ber_printf(ber,"sss", gecos, homedir, shell);
+        if (ret == -1) {
             ret = LDAP_OPERATIONS_ERROR;
             goto done;
         }
 
-        ret = asprintf(&domain_name, "%s", sep+1);
+        ret = ber_printf(ber,"{");
         if (ret == -1) {
             ret = LDAP_OPERATIONS_ERROR;
-            domain_name = NULL; /* content is undefined according to
-                                   asprintf(3) */
-            goto done;
-        }
-
-        switch(id_type) {
-        case SSS_ID_TYPE_UID:
-        case SSS_ID_TYPE_BOTH:
-            ret = getpwnam_r(fq_name, &pg_data.data.pwd, buf, buf_len,
-                             &pwd_result);
-            break;
-        case SSS_ID_TYPE_GID:
-            ret = getgrnam_r(fq_name, &pg_data.data.grp, buf, buf_len,
-                             &grp_result);
-            break;
-        default:
+            goto done;
+        }
+
+        for (c = 0; c < ngroups; c++) {
+            ret = getgrgid_r(groups[c], &grp, buf, buf_len, &grp_result);
+            if (ret != 0) {
+                ret = LDAP_NO_SUCH_OBJECT;
+                goto done;
+            }
+            if (grp_result == NULL) {
+                ret = LDAP_NO_SUCH_OBJECT;
+                goto done;
+            }
+
+            ret = ber_printf(ber, "s", grp.gr_name);
+            if (ret == -1) {
+                ret = LDAP_OPERATIONS_ERROR;
+                goto done;
+            }
+        }
+
+        ret = ber_printf(ber,"}");
+        if (ret == -1) {
             ret = LDAP_OPERATIONS_ERROR;
             goto done;
         }
-        break;
-    case INP_NAME:
-        ret = asprintf(&fq_name, "%s%c%s", req->data.name.object_name,
-                                           SSSD_DOMAIN_SEPARATOR,
-                                           req->data.name.domain_name);
+
+        single_value_string_array[0] = sid_str;
+        ret = ber_printf(ber,"{{s{v}}}", SSSD_SYSDB_SID_STR,
+                                         single_value_string_array);
         if (ret == -1) {
             ret = LDAP_OPERATIONS_ERROR;
-            fq_name = NULL; /* content is undefined according to
-                               asprintf(3) */
             goto done;
         }
+    }
 
-        if (req->request_type == REQ_SIMPLE) {
-            ret = sss_nss_getsidbyname(fq_name, &sid_str, &id_type);
+    ret = ber_printf(ber,"}}");
+    if (ret == -1) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    ret = ber_flatten(ber, berval);
+    if (ret == -1) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    ret = LDAP_SUCCESS;
+done:
+    free(short_user_name);
+    free(groups);
+    free(buf);
+    ber_free(ber, 1);
+    return ret;
+}
+
+static int pack_ber_group(enum response_types response_type,
+                          const char *domain_name, const char *group_name,
+                          gid_t gid, char **members, const char *sid_str,
+                          struct berval **berval)
+{
+    BerElement *ber = NULL;
+    int ret;
+    size_t c;
+    char *locat;
+    char *short_group_name = NULL;
+    const char *single_value_string_array[] = {NULL, NULL};
+
+    short_group_name = strdup(group_name);
+    if ((locat = strchr(short_group_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
+        if (strcasecmp(locat+1, domain_name) == 0  ) {
+            locat[0] = '\0';
         } else {
-            id_type = SSS_ID_TYPE_UID;
-            ret = getpwnam_r(fq_name, &pg_data.data.pwd, buf, buf_len,
-                             &pwd_result);
-            if (ret == 0 && pwd_result == NULL) { /* no user entry found */
-                id_type = SSS_ID_TYPE_GID;
-                ret = getgrnam_r(fq_name, &pg_data.data.grp, buf, buf_len,
-                                 &grp_result);
+            ret = LDAP_NO_SUCH_OBJECT;
+            goto done;
+        }
+    }
+
+    ber = ber_alloc_t( LBER_USE_DER );
+    if (ber == NULL) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = ber_printf(ber,"{e{ssi", response_type, domain_name, short_group_name,
+                                   gid);
+    if (ret == -1) {
+        ber_free(ber, 1);
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    if (response_type == RESP_GROUP_MEMBERS) {
+        ret = ber_printf(ber,"{");
+        if (ret == -1) {
+            ret = LDAP_OPERATIONS_ERROR;
+            goto done;
+        }
+
+        for (c = 0; members[c] != NULL; c++) {
+            ret = ber_printf(ber, "s", members[c]);
+            if (ret == -1) {
+                ret = LDAP_OPERATIONS_ERROR;
+                goto done;
             }
         }
-        domain_name = strdup(req->data.name.domain_name);
+
+        ret = ber_printf(ber,"}");
+        if (ret == -1) {
+            ret = LDAP_OPERATIONS_ERROR;
+            goto done;
+        }
+
+        single_value_string_array[0] = sid_str;
+        ret = ber_printf(ber,"{{s{v}}}", SSSD_SYSDB_SID_STR,
+                                         single_value_string_array);
+        if (ret == -1) {
+            ret = LDAP_OPERATIONS_ERROR;
+            goto done;
+        }
+
+    }
+
+    ret = ber_printf(ber,"}}");
+    if (ret == -1) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    ret = ber_flatten(ber, berval);
+    if (ret == -1) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    ret = LDAP_SUCCESS;
+
+done:
+    free(short_group_name);
+    ber_free(ber, 1);
+    return ret;
+}
+
+static int pack_ber_name(const char *domain_name, const char *name,
+                         struct berval **berval)
+{
+    BerElement *ber = NULL;
+    int ret;
+
+    ber = ber_alloc_t( LBER_USE_DER );
+    if (ber == NULL) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = ber_printf(ber,"{e{ss}}", RESP_NAME, domain_name, name);
+    if (ret == -1) {
+        ber_free(ber, 1);
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    ret = ber_flatten(ber, berval);
+    ber_free(ber, 1);
+    if (ret == -1) {
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    return LDAP_SUCCESS;
+}
+
+static int handle_uid_request(enum request_types request_type, uid_t uid,
+                              const char *domain_name, struct berval **berval)
+{
+    int ret;
+    struct passwd pwd;
+    struct passwd *pwd_result = NULL;
+    char *sid_str = NULL;
+    enum sss_id_type id_type;
+    size_t buf_len;
+    char *buf = NULL;
+
+    ret = get_buffer(&buf_len, &buf);
+    if (ret != LDAP_SUCCESS) {
+        return ret;
+    }
+
+    if (request_type == REQ_SIMPLE || request_type == REQ_FULL_WITH_GROUPS) {
+        ret = sss_nss_getsidbyid(uid, &sid_str, &id_type);
+        if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
+                            || id_type == SSS_ID_TYPE_BOTH)) {
+            if (ret == ENOENT) {
+                ret = LDAP_NO_SUCH_OBJECT;
+            } else {
+                ret = LDAP_OPERATIONS_ERROR;
+            }
+            goto done;
+        }
+    }
+
+    if (request_type == REQ_SIMPLE) {
+        ret = pack_ber_sid(sid_str, berval);
+    } else {
+        ret = getpwuid_r(uid, &pwd, buf, buf_len, &pwd_result);
+        if (ret != 0) {
+            ret = LDAP_NO_SUCH_OBJECT;
+            goto done;
+        }
+        if (pwd_result == NULL) {
+            ret = LDAP_NO_SUCH_OBJECT;
+            goto done;
+        }
+
+        ret = pack_ber_user((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, sid_str, berval);
+    }
+
+done:
+    free(sid_str);
+    free(buf);
+    return ret;
+}
+
+static int handle_gid_request(enum request_types request_type, gid_t gid,
+                              const char *domain_name, struct berval **berval)
+{
+    int ret;
+    struct group grp;
+    struct group *grp_result = NULL;
+    char *sid_str = NULL;
+    enum sss_id_type id_type;
+    size_t buf_len;
+    char *buf = NULL;
+
+    ret = get_buffer(&buf_len, &buf);
+    if (ret != LDAP_SUCCESS) {
+        return ret;
+    }
+
+    if (request_type == REQ_SIMPLE || request_type == REQ_FULL_WITH_GROUPS) {
+        ret = sss_nss_getsidbyid(gid, &sid_str, &id_type);
+        if (ret != 0 || id_type != SSS_ID_TYPE_GID) {
+            if (ret == ENOENT) {
+                ret = LDAP_NO_SUCH_OBJECT;
+            } else {
+                ret = LDAP_OPERATIONS_ERROR;
+            }
+            goto done;
+        }
+    }
+
+    if (request_type == REQ_SIMPLE) {
+        ret = pack_ber_sid(sid_str, berval);
+    } else {
+        ret = getgrgid_r(gid, &grp, buf, buf_len, &grp_result);
+        if (ret != 0) {
+            ret = LDAP_NO_SUCH_OBJECT;
+            goto done;
+        }
+        if (grp_result == NULL) {
+            ret = LDAP_NO_SUCH_OBJECT;
+            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, sid_str, berval);
+    }
+
+done:
+    free(sid_str);
+    free(buf);
+    return ret;
+}
+
+static int handle_sid_request(enum request_types request_type, const char *sid,
+                              struct berval **berval)
+{
+    int ret;
+    struct passwd pwd;
+    struct passwd *pwd_result = NULL;
+    struct group grp;
+    struct group *grp_result = NULL;
+    char *domain_name = NULL;
+    char *fq_name = NULL;
+    char *object_name = NULL;
+    char *sep;
+    size_t buf_len;
+    char *buf = NULL;
+    enum sss_id_type id_type;
+
+    ret = sss_nss_getnamebysid(sid, &fq_name, &id_type);
+    if (ret != 0) {
+        if (ret == ENOENT) {
+            ret = LDAP_NO_SUCH_OBJECT;
+        } else {
+            ret = LDAP_OPERATIONS_ERROR;
+        }
+        goto done;
+    }
+
+    sep = strchr(fq_name, SSSD_DOMAIN_SEPARATOR);
+    if (sep == NULL) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    object_name = strndup(fq_name, (sep - fq_name));
+    domain_name = strdup(sep + 1);
+    if (object_name == NULL || domain_name == NULL) {
+        ret = LDAP_OPERATIONS_ERROR;
+        goto done;
+    }
+
+    if (request_type == REQ_SIMPLE) {
+        ret = pack_ber_name(domain_name, object_name, berval);
+        goto done;
+    }
+
+    ret = get_buffer(&buf_len, &buf);
+    if (ret != LDAP_SUCCESS) {
+        return ret;
+    }
+
+    switch(id_type) {
+    case SSS_ID_TYPE_UID:
+    case SSS_ID_TYPE_BOTH:
+        ret = getpwnam_r(fq_name, &pwd, buf, buf_len, &pwd_result);
+        if (ret != 0) {
+            ret = LDAP_NO_SUCH_OBJECT;
+            goto done;
+        }
+
+        if (pwd_result == NULL) {
+            ret = LDAP_NO_SUCH_OBJECT;
+            goto done;
+        }
+
+        ret = pack_ber_user((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, sid, berval);
+        break;
+    case SSS_ID_TYPE_GID:
+        ret = getgrnam_r(fq_name, &grp, buf, buf_len, &grp_result);
+        if (ret != 0) {
+            ret = LDAP_NO_SUCH_OBJECT;
+            goto done;
+        }
+
+        if (grp_result == NULL) {
+            ret = LDAP_NO_SUCH_OBJECT;
+            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, sid, berval);
         break;
     default:
-        ret = LDAP_PROTOCOL_ERROR;
-        goto done;
-    }
-
-    if (ret != 0) {
-        ret = LDAP_OPERATIONS_ERROR;
-        goto done;
-    } else if (ret == 0 && pwd_result == NULL && grp_result == NULL &&
-               sid_str == NULL) {
-        ret = LDAP_NO_SUCH_OBJECT;
-        goto done;
-    }
-
-    if (domain_name == NULL) {
-        ret = LDAP_OPERATIONS_ERROR;
-        goto done;
-    }
-
-    ret = create_response(req, &pg_data, sid_str, id_type, domain_name, res);
-    if (ret != 0) {
         ret = LDAP_OPERATIONS_ERROR;
         goto done;
     }
 
-
-    ret = LDAP_SUCCESS;
-
 done:
-    free(buf);
     free(fq_name);
+    free(object_name);
     free(domain_name);
-    free(sid_str);
+    free(buf);
 
     return ret;
 }
 
-int create_response(struct extdom_req *req, struct pwd_grp *pg_data,
-                    const char *sid_str, enum sss_id_type id_type,
-                    const char *domain_name, struct extdom_res **_res)
+static int handle_name_request(enum request_types request_type,
+                               const char *name, const char *domain_name,
+                               struct berval **berval)
 {
-    int ret = EFAULT;
-    char *locat = NULL;
-    struct extdom_res *res;
-
-    res = calloc(1, sizeof(struct extdom_res));
-    if (res == NULL) {
-        return ENOMEM;
+    int ret;
+    char *fq_name = NULL;
+    struct passwd pwd;
+    struct passwd *pwd_result = NULL;
+    struct group grp;
+    struct group *grp_result = NULL;
+    char *sid_str = NULL;
+    enum sss_id_type id_type;
+    size_t buf_len;
+    char *buf = NULL;
+
+    ret = asprintf(&fq_name, "%s%c%s", name, SSSD_DOMAIN_SEPARATOR,
+                                       domain_name);
+    if (ret == -1) {
+        ret = LDAP_OPERATIONS_ERROR;
+        fq_name = NULL; /* content is undefined according to
+                           asprintf(3) */
+        goto done;
     }
 
-    switch (req->request_type) {
-        case REQ_SIMPLE:
-            switch (req->input_type) {
-                case INP_SID:
-                    res->response_type = RESP_NAME;
-                    res->data.name.domain_name = strdup(domain_name);
-                    switch(id_type) {
-                    case SSS_ID_TYPE_UID:
-                    case SSS_ID_TYPE_BOTH:
-                        if ((locat = strchr(pg_data->data.pwd.pw_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
-                            if (strcasecmp(locat+1, domain_name) == 0  ) {
-                                locat[0] = 0;
-                            } else {
-                                ret = LDAP_NO_SUCH_OBJECT;
-                                goto done;
-                            }
-                        }
-                        res->data.name.object_name =
-                                              strdup(pg_data->data.pwd.pw_name);
-                        break;
-                    case SSS_ID_TYPE_GID:
-                        if ((locat = strchr(pg_data->data.grp.gr_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
-                            if (strcasecmp(locat+1, domain_name) == 0) {
-                                locat[0] = 0;
-                            } else {
-                                ret = LDAP_NO_SUCH_OBJECT;
-                                goto done;
-                            }
-                        }
-                        res->data.name.object_name =
-                                              strdup(pg_data->data.grp.gr_name);
-                        break;
-                    default:
-                        ret = EINVAL;
-                        goto done;
-                    }
-
-                    if (res->data.name.domain_name == NULL
-                            || res->data.name.object_name == NULL) {
-                        ret = ENOMEM;
-                        goto done;
-                    }
-                    break;
-                case INP_NAME:
-                case INP_POSIX_UID:
-                case INP_POSIX_GID:
-                    res->response_type = RESP_SID;
-                    res->data.sid = strdup(sid_str);
-                    if (res->data.sid == NULL) {
-                        ret = ENOMEM;
-                        goto done;
-                    }
-                    break;
-                default:
-                    ret = EINVAL;
-                    goto done;
-            }
-            break;
-        case REQ_FULL:
-            switch (id_type) {
-                case SSS_ID_TYPE_UID:
-                case SSS_ID_TYPE_BOTH:
-                    res->response_type = RESP_USER;
-                    res->data.user.domain_name = strdup(domain_name);
-                    if ((locat = strchr(pg_data->data.pwd.pw_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
-                        if (strcasecmp(locat+1, domain_name) == 0) {
-                            locat[0] = 0;
-                        } else {
-                            ret = LDAP_NO_SUCH_OBJECT;
-                            goto done;
-                        }
-                    }
-                    res->data.user.user_name =
-                                              strdup(pg_data->data.pwd.pw_name);
-
-                    if (res->data.user.domain_name == NULL
-                            || res->data.user.user_name == NULL) {
-                        ret = ENOMEM;
-                        goto done;
-                    }
-
-                    res->data.user.uid = pg_data->data.pwd.pw_uid;
-                    res->data.user.gid = pg_data->data.pwd.pw_gid;
-                    break;
-                case SSS_ID_TYPE_GID:
-                    res->response_type = RESP_GROUP;
-                    res->data.group.domain_name = strdup(domain_name);
-                    if ((locat = strchr(pg_data->data.grp.gr_name, SSSD_DOMAIN_SEPARATOR)) != NULL) {
-                        if (strcasecmp(locat+1, domain_name) == 0) {
-                            locat[0] = 0;
-                        } else {
-                            ret = LDAP_NO_SUCH_OBJECT;
-                            goto done;
-                        }
-                    }
-                    res->data.group.group_name =
-                                              strdup(pg_data->data.grp.gr_name);
-
-                    if (res->data.group.domain_name == NULL
-                            || res->data.group.group_name == NULL) {
-                        ret = ENOMEM;
-                        goto done;
-                    }
-
-                    res->data.group.gid = pg_data->data.grp.gr_gid;
-                    break;
-                default:
-                    ret = EINVAL;
-                    goto done;
+    if (request_type == REQ_SIMPLE || request_type == REQ_FULL_WITH_GROUPS) {
+        ret = sss_nss_getsidbyname(fq_name, &sid_str, &id_type);
+        if (ret != 0) {
+            if (ret == ENOENT) {
+                ret = LDAP_NO_SUCH_OBJECT;
+            } else {
+                ret = LDAP_OPERATIONS_ERROR;
             }
-            break;
-        default:
-            ret = EINVAL;
-            goto done;
+           goto done;
+        }
     }
 
-    ret = 0;
-
-done:
-    if (ret == 0) {
-        *_res = res;
+    if (request_type == REQ_SIMPLE) {
+        ret = pack_ber_sid(sid_str, berval);
     } else {
-        free_resp_data(res);
-    }
+        ret = get_buffer(&buf_len, &buf);
+        if (ret != LDAP_SUCCESS) {
+            goto done;
+        }
+
+        ret = getpwnam_r(fq_name, &pwd, buf, buf_len, &pwd_result);
+        if (ret != 0) {
+            /* according to the 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. */
+            pwd_result = NULL;
+        }
+
+        if (pwd_result != NULL) {
+            ret = pack_ber_user((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, sid_str, berval);
+        } else { /* no user entry found */
+            ret = getgrnam_r(fq_name, &grp, buf, buf_len, &grp_result);
+            if (ret != 0) {
+                ret = LDAP_NO_SUCH_OBJECT;
+                goto done;
+            }
 
-    if (locat != NULL) {
-        locat[0] = SSSD_DOMAIN_SEPARATOR;
+            if (grp_result == NULL) {
+                ret = LDAP_NO_SUCH_OBJECT;
+                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, sid_str, berval);
+        }
     }
 
+done:
+    free(fq_name);
+    free(sid_str);
+    free(buf);
+
     return ret;
 }
 
-void free_resp_data(struct extdom_res *res)
+int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
+                   struct berval **berval)
 {
-    if (res == NULL) {
-        return;
-    }
+    int ret;
+
+    switch (req->input_type) {
+    case INP_POSIX_UID:
+        ret = handle_uid_request(req->request_type, req->data.posix_uid.uid,
+                                 req->data.posix_uid.domain_name, berval);
 
-    switch (res->response_type) {
-    case RESP_SID:
-        free(res->data.sid);
         break;
-    case RESP_NAME:
-        free(res->data.name.domain_name);
-        free(res->data.name.object_name);
+    case INP_POSIX_GID:
+        ret = handle_gid_request(req->request_type, req->data.posix_gid.gid,
+                                 req->data.posix_uid.domain_name, berval);
+
         break;
-    case RESP_USER:
-        free(res->data.user.domain_name);
-        free(res->data.user.user_name);
+    case INP_SID:
+        ret = handle_sid_request(req->request_type, req->data.sid, berval);
         break;
-    case RESP_GROUP:
-        free(res->data.group.domain_name);
-        free(res->data.group.group_name);
+    case INP_NAME:
+        ret = handle_name_request(req->request_type, req->data.name.object_name,
+                                  req->data.name.domain_name, berval);
+
         break;
+    default:
+        ret = LDAP_PROTOCOL_ERROR;
+        goto done;
     }
 
-    free(res);
+
+done:
+
+    return ret;
 }
 
-
 int pack_response(struct extdom_res *res, struct berval **ret_val)
 {
     BerElement *ber = NULL;
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 9315da260ee3de660ea8ff708950945110da37e3..aa66c145bc6cf2b77fdfe37be18da67588dc0439 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
@@ -49,6 +49,7 @@ Slapi_PluginDesc ipa_extdom_plugin_desc = {
 
 static char *ipa_extdom_oid_list[] = {
     EXOP_EXTDOM_OID,
+    EXOP_EXTDOM_V1_OID,
     NULL
 };
 
@@ -71,8 +72,8 @@ static int ipa_extdom_extop(Slapi_PBlock *pb)
     struct berval *req_val = NULL;
     struct berval *ret_val = NULL;
     struct extdom_req *req = NULL;
-    struct extdom_res *res = NULL;
     struct ipa_extdom_ctx *ctx;
+    enum extdom_version version;
 
     ret = slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &oid);
     if (ret != 0) {
@@ -82,7 +83,11 @@ static int ipa_extdom_extop(Slapi_PBlock *pb)
     }
     LOG("Received extended operation request with OID %s\n", oid);
 
-    if (strcasecmp(oid, EXOP_EXTDOM_OID) != 0) {
+    if (strcasecmp(oid, EXOP_EXTDOM_OID) == 0) {
+        version = EXTDOM_V0;
+    } else if (strcasecmp(oid, EXOP_EXTDOM_V1_OID) == 0) {
+        version = EXTDOM_V1;
+    } else {
         return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
     }
 
@@ -107,21 +112,21 @@ static int ipa_extdom_extop(Slapi_PBlock *pb)
         goto done;
     }
 
-    ret = handle_request(ctx, req, &res);
+    ret = check_request(req, version);
+    if (ret != LDAP_SUCCESS) {
+        rc = LDAP_UNWILLING_TO_PERFORM;
+        err_msg = "Error in request data.\n";
+        goto done;
+    }
+
+    ret = handle_request(ctx, req, &ret_val);
     if (ret != LDAP_SUCCESS) {
         rc = LDAP_OPERATIONS_ERROR;
         err_msg = "Failed to handle the request.\n";
         goto done;
     }
 
-    ret = pack_response(res, &ret_val);
-    if (ret != LDAP_SUCCESS) {
-        rc = LDAP_OPERATIONS_ERROR;
-        err_msg = "Failed to pack the response.\n";
-        goto done;
-    }
-
-    ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, EXOP_EXTDOM_OID);
+    ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, oid);
     if (ret != 0) {
         rc = LDAP_OPERATIONS_ERROR;
         err_msg = "Failed to set the OID for the response.\n";
@@ -139,7 +144,6 @@ static int ipa_extdom_extop(Slapi_PBlock *pb)
 
 done:
     free_req_data(req);
-    free_resp_data(res);
     if (err_msg != NULL) {
         LOG("%s", err_msg);
     }
-- 
1.8.5.3



More information about the Freeipa-devel mailing list