I have to Nack this one.

I will check the following patches in the next few days, but I am
traveling so it may take a while.

Comments inline.

On Thu, 2014-01-16 at 11:02 +0200, Noam Meltzer wrote:
> Implementation of design document:
> https://fedorahosted.org/sssd/wiki/DesignDocs/rpc.idmapd%20plugin
> ---
>  src/sss_client/common.c             |   5 +
>  src/sss_client/nfs/sss_nfs_client.c | 490 
> ++++++++++++++++++++++++++++++++++++
>  src/sss_client/sss_cli.h            |   2 +
>  3 files changed, 497 insertions(+)
>  create mode 100644 src/sss_client/nfs/sss_nfs_client.c
> 
> diff --git a/src/sss_client/common.c b/src/sss_client/common.c
> index 6044af0..58a9eca 100644
> --- a/src/sss_client/common.c
> +++ b/src/sss_client/common.c
> @@ -936,6 +936,11 @@ int sss_ssh_make_request(enum sss_cli_command cmd,
>      return ret;
>  }
>  
> +int sss_nfs_make_request(enum sss_cli_command cmd, struct sss_cli_req_data 
> *rd,
> +                         uint8_t **rep, size_t *replen, int *errnop)
> +{
> +    return sss_nss_make_request(cmd, rd, rep, replen, errnop);
> +}
>  
>  const char *ssscli_err2string(int err)
>  {
> diff --git a/src/sss_client/nfs/sss_nfs_client.c 
> b/src/sss_client/nfs/sss_nfs_client.c
> new file mode 100644
> index 0000000..9f6e047
> --- /dev/null
> +++ b/src/sss_client/nfs/sss_nfs_client.c
> @@ -0,0 +1,490 @@
> +/*
> +   SSSD
> +
> +   NFS Client
> +
> +   Copyright (C) Noam Meltzer <n...@primarydata.com>    2013
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include <stddef.h>
> +#include <stdlib.h>
> +#include <sys/types.h>
> +#include <errno.h>
> +#include <string.h>
> +
> +#include <nfsidmap.h>
> +#include "nfsidmap_internal.h"
> +#include "cfg.h"
> +
> +#include "sss_client/sss_cli.h"
> +#include "sss_client/nss_mc.h"
> +
> +
> +/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
> .*/
> +#define SSS_NFS_PLUGIN_NAME         "sss_nfs"
> +#define SSS_NFS_CONF_SECTION        "sss_nfs"
> +#define SSS_NFS_CONF_USE_MC         "memcache"
> +#define SSS_NFS_REPLY_ID_OFFSET     (8)
> +#define SSS_NFS_REPLY_NAME_OFFSET   (SSS_NFS_REPLY_ID_OFFSET + 8)
> +#define SSS_NFS_MCBUF_LEN           (4096)
> +#define SSS_NFS_USE_MC_DEFAULT      (1)
> +
> +
> +/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
> .*/
> +static char s_sss_nfs_plugin_name[]     = SSS_NFS_PLUGIN_NAME;
> +static char s_sss_nfs_conf_section[]    = SSS_NFS_CONF_SECTION;
> +static char s_sss_nfs_conf_use_mc[]     = SSS_NFS_CONF_USE_MC;

What does the s_ stand for ?
We use sss_ as a namespacing measure, but it is strictly necessary only
for non static functions or variables.
We do not use s_sss_ for anything though, and we do not use hungarian
notations or similar.

Anyway it is unclear to me what is the point of defining a static string
that contains a const string ?

> +static char *s_mcbuf    = NULL;

You are defining s_mcbuf as a global, then using it liberally in
multiple calls.

This is not reentrant nor thread safe, the client code MUST be thread
safe.

> +static int   s_use_mc   = SSS_NFS_USE_MC_DEFAULT;
> +
> +
> +/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
> .*/
> +/* Forward declarations */
> +static int send_recv(uint8_t **repp, size_t *rep_lenp, enum sss_cli_command 
> cmd,
> +                     const void *req, size_t req_len);
> +static int get_id_from_rep(id_t *idp, uint8_t *rep, size_t rep_len);

Please rename to get_id_from_reply() or reply_to_id()

> +static int get_name_from_rep(char *name, size_t len, uint8_t *rep,
> +                             size_t rep_len);

Please rename to get_name_from_reply() or reply_to_name()

> +/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
> .*/
> +/* get from memcache functions */
> +static int get_uid_from_mc(id_t *uid, const char *name)
> +{
> +    int rc;
> +    struct passwd pwd;
> +    char *buf;

Use char buf[SSS_NFS_MCBUF_LEN]; here instead of a globally allocate
buffer.

It's unlikely a passwd structure will be bigger than 4K but to be
absolutely accurate you may want to do what I suggest later for the
group entries (for those it is mandatory).

> +    size_t len = 0;
> +
> +    if (!s_use_mc) {
> +        return -1;
> +    }
> +
> +    buf = s_mcbuf;
> +    sss_strnlen(name, SSS_NAME_MAX, &len);

Missing error checking here, see _nss_sss_getpwnam_r()

> +    rc = sss_nss_mc_getpwnam(name, len, &pwd, buf, SSS_NFS_MCBUF_LEN);
> +    if (rc == 0) {
> +        IDMAP_LOG(1, ("found user %s in memcache", name));
> +        *uid = pwd.pw_uid;
> +    } else {
> +        IDMAP_LOG(1, ("user %s not in memcache", name));
> +    }
> +
> +    return rc;
> +}
> +
> +static int get_gid_from_mc(id_t *gid, const char *name) {
> +    int rc;
> +    struct group grp;
> +    char *buf;
> +    size_t len;
> +
> +    if (!s_use_mc) {
> +        return -1;
> +    }
> +
> +    buf = s_mcbuf;
> +    sss_strnlen(name, SSS_NAME_MAX, &len);

No error checking as above here ^

For the following call using a fixed size buffer will not do, because
group memberships may be quite large in some environments.

You can use it for a first call, but if ERANGE is returned you must
retry with a bigger, allocated buffer.

You are not doing the retry at all now, which is a bug.

> +    rc = sss_nss_mc_getgrnam(name, len, &grp, buf, SSS_NFS_MCBUF_LEN);
> +    if (rc == 0) {
> +        IDMAP_LOG(1, ("found group %s in memcache", name));
> +        *gid = grp.gr_gid;
> +    } else {
> +        IDMAP_LOG(1, ("group %s not in memcache", name));
> +    }
> +
> +    return rc;
> +}
> +
> +static int get_user_from_mc(char *name, size_t len, uid_t uid)
> +{
> +    int rc;
> +    struct passwd pwd;
> +    char *buf;
> +    size_t cache_len;

Pleas rename to pw_name_len

> +    if (!s_use_mc) {
> +        return -1;
> +    }
> +
> +    buf = s_mcbuf;

Same comments as per get_uid_from_mc()

> +    rc = sss_nss_mc_getpwuid(uid, &pwd, buf, SSS_NFS_MCBUF_LEN);
> +    if (rc == 0) {
> +        cache_len = strlen(pwd.pw_name) + 1;
> +        if (cache_len > len) {
> +            IDMAP_LOG(0, ("%s: reply too long; cache_len=%lu, len=%lu",
> +                          __func__, cache_len, len));
> +            rc = -ENOBUFS;
> +        }
> +        memcpy(name, pwd.pw_name, cache_len);
> +    }
> +
> +    return rc;
> +}
> +
> +static int get_group_from_mc(char *name, size_t len, id_t gid)
> +{
> +    int rc;
> +    struct group grp;
> +    char *buf;
> +    size_t cache_len;
> +
> +    buf = s_mcbuf;

Same comments as per get_gid_from_mc()

> +    rc = sss_nss_mc_getgrgid(gid, &grp, buf, SSS_NFS_MCBUF_LEN);
> +    if (rc == 0) {
> +        cache_len = strlen(grp.gr_name) + 1;
> +        if (cache_len > len) {
> +            IDMAP_LOG(0, ("%s: reply too long; cache_len=%lu, len=%lu",
> +                          __func__, cache_len, len));
> +            rc = -ENOBUFS;
> +        }
> +        memcpy(name, grp.gr_name, cache_len);
> +    }
> +
> +    return rc;
> +}
> +
> +/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
> .*/
> +static int name_to_id(const char *name, id_t *id, enum sss_cli_command cmd)
> +{
> +    int rc;
> +    uint8_t *rep = NULL;
> +    size_t rep_len = 0;
> +    size_t name_len;
> +
> +    sss_strnlen(name, SSS_NAME_MAX, &name_len);

missing error checking

> +    rc = send_recv(&rep, &rep_len, cmd, name, name_len + 1);
> +    if (rc == 0) {
> +        rc = get_id_from_rep(id, rep, rep_len);
> +    }
> +
> +    if (rep != NULL) {

Don't test for rep, just call free() straight, glibc knows to ignore
NULLs.

> +        free(rep);
> +    }
> +
> +    return rc;
> +}
> +
> +static int id_to_name(char *name, size_t len, id_t id,
> +                      enum sss_cli_command cmd)
> +{
> +    int rc;
> +    const void *req = NULL;
> +    uint8_t *rep = NULL;
> +    size_t req_len;
> +    size_t rep_len = 0;
> +
> +    req = (void *)(&id);
> +    req_len = sizeof(id);

This is not safe on some architectures (like ARM).

do this instead:

size_t req_len = sizeof(id_t);
uint8_t req[req_len];

memcpy(req, &id, req_len)

> +    rc = send_recv(&rep, &rep_len, cmd, req, req_len);
> +    if (rc == 0) {
> +        rc = get_name_from_rep(name, len, rep, rep_len);
> +    }
> +
> +    if (rep != NULL) {
> +        free(rep);
> +    }

Just call free() w/o checks.

> +
> +    return rc;
> +}
> +
> +/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
> .*/
> +static int send_recv(uint8_t **repp, size_t *rep_lenp, enum sss_cli_command 
> cmd,


Why send_recv instead of just calling it sss_nfs_make_request() and
avoid the wrapper by the same name that does nothing in common.c ?

If the wrapper needs to stay for some reason, then rename send_recv() to
sss_nfs_request()

Also use rep and rep_len, without the p, we do not change names based on
whether they are pointers or not, the compiler will warn you anyway if
you use them incorrectly.

> +                     const void *req, size_t req_len)
> +{
> +    int err = 0;
> +    enum nss_status req_rc;
> +    struct sss_cli_req_data rd;
> +    uint8_t *rep;
> +    size_t rep_len;
> +
> +    rd.data = req;
> +    rd.len = req_len;
> +
> +    sss_nss_lock();
> +    req_rc = sss_nfs_make_request(cmd, &rd, &rep, &rep_len, &err);
> +    sss_nss_unlock();
> +
> +    if (req_rc == NSS_STATUS_NOTFOUND) {
> +        return -ENOENT;
> +    }
> +    if (req_rc != NSS_STATUS_SUCCESS) {
> +        IDMAP_LOG(0, ("no-make-request; err=%i (%s)", err, strerror(err)));
> +        return -EPIPE;
> +    }

Is -EPIPE really what rpc.idmap expects if a function fails ?

> +    *repp = rep;
> +    *rep_lenp = rep_len;

Why the double assignment here ? Why don't you just pass the function
arguments directly to sss_nfs_make_request() ?
The internal function and it will not assign buffers in case of error,
so you can pass in the arguments directly w/o worry.

> +    return 0;
> +}
> +
> +static int get_id_from_rep(id_t *idp, uint8_t *rep, size_t rep_len)
> +{
> +    int rc = 0;
> +    id_t id;
> +    uint32_t num_results = 0;
> +
> +    if (rep_len < sizeof(uint32_t)) {
> +        IDMAP_LOG(0, ("%s: reply too small; rep_len=%lu", __func__, 
> rep_len));
> +        rc = -EBADMSG;
> +        goto return_rc;
> +    }
> +
> +    SAFEALIGN_COPY_UINT32(&num_results, rep, NULL);
> +    if (num_results > 1) {
> +        IDMAP_LOG(0, ("%s: too many results (%lu)", __func__, num_results));
> +        rc = -EBADMSG;
> +        goto return_rc;
> +    }
> +    if (num_results == 0) {
> +        rc = -ENOENT;
> +        goto return_rc;
> +    }

You need to check that rep_len is >= sizeof(uint32_t) +
SSS_NFS_REPLY_ID_OFFSET before trying to copy or you could segafault if
for some reason it is smaller.

> +    SAFEALIGN_COPY_UINT32(&id, rep + SSS_NFS_REPLY_ID_OFFSET, NULL);
> +    *idp = id;
> +
> +return_rc:

Please use the label 'done' when you want to exit early.

> +    return rc;
> +}
> +
> +static int get_name_from_rep(char *name, size_t len, uint8_t *rep,
> +                             size_t rep_len)
> +{
> +    int rc = 0;
> +    uint32_t num_results = 0;
> +    const char *buf;
> +    size_t buf_len;
> +    size_t offset;
> +
> +    if (rep_len < sizeof(uint32_t)) {
> +        IDMAP_LOG(0, ("%s: reply too small; rep_len=%lu", __func__, 
> rep_len));
> +        rc = -EBADMSG;
> +        goto return_rc;
> +    }
> +
> +    SAFEALIGN_COPY_UINT32(&num_results, rep, NULL);
> +    if (num_results > 1) {
> +        IDMAP_LOG(0, ("%s: too many results (%lu)", __func__, num_results));
> +        rc = -EBADMSG;
> +        goto return_rc;
> +    }
> +    if (num_results == 0) {
> +        rc = -ENOENT;
> +        goto return_rc;
> +    }

As above, please do boundary checks here too.

> +    buf = (const char *)(rep + SSS_NFS_REPLY_NAME_OFFSET);
> +    buf_len = rep_len - SSS_NFS_REPLY_NAME_OFFSET;
> +    offset = 0;
> +    rc = sss_readrep_copy_string(buf, &offset, &buf_len, &len, &name, NULL);
> +    if (rc != 0) {
> +        rc = -rc;
> +    }
> +
> +return_rc:

Use 'done'

> +    return rc;
> +}
> +
> +/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
> .*/
> +/* configuration parsing aids */
> +static int nfs_strcasecmp(const char *s1, const char *s2)

You are changing the semantics of the original function here and
returning a boolean that is true if the strings are equal  and false if
they are not, the origin stncasecmp instead sets -1 0 or 1 depending on
the comparison, by keeping a similar name you provides false
expectations.

Please use instead the following prototype:

static bool str_equal(const char *s1, const char *s2)


> +{
> +    int res = 0;
> +    size_t len1;
> +    size_t len2;
> +
> +    len1 = strlen(s1);
> +    len2 = strlen(s2);
> +
> +    if (len1 == len2) {
> +        res = (strncasecmp(s1, s2, len1) == 0);
> +    }
> +
> +    return res;
> +}


> +static int nfs_conf_get_bool(char *sect, char *attr, int def)
> +{

you are getting a boolean, then please return a 'bool'

> +    int res;
> +    char *val;
> +
> +    res = def;
> +    val = conf_get_str(sect, attr);
> +    if (val) {
> +        res = (nfs_strcasecmp("1", val) ||
> +               nfs_strcasecmp("yes", val) ||
> +               nfs_strcasecmp("true", val) ||
> +               nfs_strcasecmp("on", val));
> +    }
> +
> +    return res;
> +}
> +
> +/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
> .*/
> +/* The external interface */
> +static int sss_nfs_init(void)
> +{
> +    s_mcbuf = malloc(SSS_NFS_MCBUF_LEN);
> +    if (s_mcbuf == NULL) {
> +        return -ENOMEM;
> +    }
> +
> +    s_use_mc = nfs_conf_get_bool(s_sss_nfs_conf_section, 
> s_sss_nfs_conf_use_mc,
> +                                 SSS_NFS_USE_MC_DEFAULT);

In what case would you want to disable using the mmap_cache ?

> +    return 0;
> +}
> +
> +static int sss_nfs_princ_to_ids(char *secname, char *princ, uid_t *uid,
> +                                gid_t *gid, extra_mapping_params **ex)
> +{
> +    (void)secname;
> +    (void)princ;
> +    (void)uid;
> +    (void)gid;
> +    (void)ex;

Why these (void)s ?

> +    IDMAP_LOG(0, ("%s: not implemented", __func__));
> +    return -ENOSYS;
> +}
> +
> +static int sss_nfs_name_to_uid(char *name, uid_t *uid)
> +{
> +    int rc;
> +    size_t name_len = 0;
> +
> +    if (name == NULL) {
> +        IDMAP_LOG(0, ("%s: name is null", __func__));
> +        return -EINVAL;
> +    }
> +    if (uid == NULL) {
> +        IDMAP_LOG(0, ("%s: uid is null", __func__));
> +        return -EINVAL;
> +    }
> +
> +    rc = sss_strnlen(name, SSS_NAME_MAX, &name_len);
> +    if (rc != 0) {
> +        IDMAP_LOG(0, ("%s: no-strnlen; rc=%i (%s)", __func__, rc,
> +                      strerror(rc)));
> +        return -rc;
> +    }
> +
> +    rc = get_uid_from_mc(uid, name);
> +    if (rc != 0) {
> +        rc = name_to_id(name, uid, SSS_NSS_GETPWNAM);
> +    }
> +
> +    return rc;
> +}
> +
> +static int sss_nfs_name_to_gid(char *name, gid_t *gid)
> +{
> +    int rc;
> +    size_t name_len = 0;
> +
> +    if (name == NULL) {
> +        IDMAP_LOG(0, ("%s: name is null", __func__));
> +        return -EINVAL;
> +    }
> +    if (gid == NULL) {
> +        IDMAP_LOG(0, ("%s: gid is null", __func__));
> +        return -EINVAL;
> +    }
> +
> +    rc = sss_strnlen(name, SSS_NAME_MAX, &name_len);
> +    if (rc != 0) {
> +        IDMAP_LOG(0, ("%s: no-strnlen; rc=%i (%s)", __func__, rc,
> +                      strerror(rc)));
> +        return -rc;
> +    }
> +
> +    rc = get_gid_from_mc(gid, name);
> +    if (rc != 0) {
> +        rc = name_to_id(name, gid, SSS_NSS_GETGRNAM);
> +    }
> +
> +    return rc;
> +}
> +
> +static int sss_nfs_uid_to_name(uid_t uid, char *domain, char *name, size_t 
> len)
> +{
> +    int rc;
> +
> +    if (name == NULL) {
> +        IDMAP_LOG(0, ("%s: name is null", __func__));
> +        return -EINVAL;
> +    }
> +
> +    rc = get_user_from_mc(name, len, uid);
> +    if (rc != 0) {
> +        rc = id_to_name(name, len, uid, SSS_NSS_GETPWUID);
> +    }
> +
> +    return rc;
> +}
> +
> +static int sss_nfs_gid_to_name(gid_t gid, char *domain, char *name, size_t 
> len)
> +{
> +    int rc;
> +
> +    if (name == NULL) {
> +        IDMAP_LOG(0, ("%s: name is null", __func__));
> +        return -EINVAL;
> +    }
> +
> +    rc = get_group_from_mc(name, len, gid);
> +    if (rc != 0) {
> +        rc = id_to_name(name, len, gid, SSS_NSS_GETGRGID);
> +    }
> +
> +    return rc;
> +}
> +
> +static int sss_nfs_gss_princ_to_grouplist(
> +    char *secname, char *princ, gid_t *groups, int *ngroups,
> +    extra_mapping_params **ex)
> +{
> +    (void)secname;
> +    (void)princ;
> +    (void)groups;
> +    (void)ngroups;
> +    (void)ex;
> +    IDMAP_LOG(0, ("%s: not implemented", __func__));
> +    return -ENOSYS;
> +}
> +
> +static struct trans_func s_sss_nfs_trans = {
> +    .name = s_sss_nfs_plugin_name,
> +    .init = sss_nfs_init,
> +    .princ_to_ids = sss_nfs_princ_to_ids,
> +    .name_to_uid = sss_nfs_name_to_uid,
> +    .name_to_gid = sss_nfs_name_to_gid,
> +    .uid_to_name = sss_nfs_uid_to_name,
> +    .gid_to_name = sss_nfs_gid_to_name,
> +    .gss_princ_to_grouplist = sss_nfs_gss_princ_to_grouplist,
> +};
> +
> +struct trans_func *libnfsidmap_plugin_init(void)
> +{
> +    return (&s_sss_nfs_trans);
> +}
> diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
> index 285a297..7e488e4 100644
> --- a/src/sss_client/sss_cli.h
> +++ b/src/sss_client/sss_cli.h
> @@ -527,6 +527,8 @@ int sss_ssh_make_request(enum sss_cli_command cmd,
>                           struct sss_cli_req_data *rd,
>                           uint8_t **repbuf, size_t *replen,
>                           int *errnop);
> +int sss_nfs_make_request(enum sss_cli_command cmd, struct sss_cli_req_data 
> *rd,
> +                         uint8_t **rep, size_t *replen, int *errnop);
>  
>  #if 0
>  


-- 
Simo Sorce * Red Hat, Inc * New York

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to