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 <sb...@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 ...
From 1becbaf1c6120618a5dfe47150bf970578d1c8be Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@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

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to