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

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

Reply via email to