All of lore.kernel.org
 help / color / mirror / Atom feed
From: Noam Meltzer <noam@primarydata.com>
To: noam@primarydata.com, linux-nfs@vger.kernel.org,
	sssd-devel@lists.fedorahosted.org
Subject: [PATCH v2 1/5] NEW CLIENT: plugin for NFSv4 rpc.idmapd
Date: Tue,  4 Mar 2014 09:37:52 +0200	[thread overview]
Message-ID: <1393918676-20865-2-git-send-email-noam@primarydata.com> (raw)
In-Reply-To: <1393918676-20865-1-git-send-email-noam@primarydata.com>

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 | 569 ++++++++++++++++++++++++++++++++++++
 src/sss_client/sss_cli.h            |   2 +
 3 files changed, 576 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..7b23eab
--- /dev/null
+++ b/src/sss_client/nfs/sss_nfs_client.c
@@ -0,0 +1,569 @@
+/*
+   SSSD
+
+   NFS Client
+
+   Copyright (C) Noam Meltzer <noam@primarydata.com>    2013-2014
+
+   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/>.
+*/
+
+#define _GNU_SOURCE
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+
+#include <nfsidmap.h>
+#include "nfsidmap_internal.h"
+
+#include "sss_client/sss_cli.h"
+#include "sss_client/nss_mc.h"
+
+
+/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+#define PLUGIN_NAME                 "sss_nfs"
+#define CONF_SECTION                "sss_nfs"
+#define CONF_USE_MC                 "memcache"
+#define REPLY_ID_OFFSET             (8)
+#define REPLY_NAME_OFFSET           (REPLY_ID_OFFSET + 8)
+#define MCBUF_LEN                   (4096)
+#define USE_MC_DEFAULT              true
+
+
+/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+static char sss_nfs_plugin_name[]   = PLUGIN_NAME;
+static char nfs_conf_sect[]         = CONF_SECTION;
+static char nfs_conf_use_mc[]       = CONF_USE_MC;
+
+static bool nfs_use_mc              = 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 reply_to_id(id_t *idp, uint8_t *rep, size_t rep_len);
+static int reply_to_name(char *name, size_t len, uint8_t *rep, size_t rep_len);
+
+
+/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+/* get from memcache functions */
+static int get_uid_from_mc(id_t *uid, const char *name)
+{
+    int rc = 0;
+    struct passwd pwd;
+    char *buf = NULL;
+    char *p = NULL;
+    size_t buflen = 0;
+    size_t len = 0;
+
+    if (!nfs_use_mc) {
+        return -1;
+    }
+
+    sss_strnlen(name, SSS_NAME_MAX, &len);
+
+    do {
+        buflen += MCBUF_LEN;
+        if ((p = realloc(buf, buflen)) == NULL) {
+            rc = ENOMEM;
+            goto done;
+        }
+        buf = p;
+        rc = sss_nss_mc_getpwnam(name, len, &pwd, buf, buflen);
+    } while (rc == ERANGE);
+
+    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));
+    }
+
+done:
+    free(buf);
+    return rc;
+}
+
+static int get_gid_from_mc(id_t *gid, const char *name) {
+    int rc = 0;
+    struct group grp;
+    char *buf = NULL;
+    char *p = NULL;
+    size_t buflen = 0;
+    size_t len;
+
+    if (!nfs_use_mc) {
+        return -1;
+    }
+
+    sss_strnlen(name, SSS_NAME_MAX, &len);
+
+    do {
+        buflen += MCBUF_LEN;
+        if ((p = realloc(buf, buflen)) == NULL) {
+            rc = ENOMEM;
+            goto done;
+        }
+        buf = p;
+        rc = sss_nss_mc_getgrnam(name, len, &grp, buf, buflen);
+    } while (rc == ERANGE);
+
+    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));
+    }
+
+done:
+    free(buf);
+    return rc;
+}
+
+static int get_user_from_mc(char *name, size_t len, uid_t uid)
+{
+    int rc;
+    struct passwd pwd;
+    char *buf = NULL;
+    char *p = NULL;
+    size_t buflen = 0;
+    size_t pw_name_len;
+
+    if (!nfs_use_mc) {
+        return -1;
+    }
+
+    do {
+        buflen += MCBUF_LEN;
+        if ((p = realloc(buf, buflen)) == NULL) {
+            rc = ENOMEM;
+            goto done;
+        }
+        buf = p;
+        rc = sss_nss_mc_getpwuid(uid, &pwd, buf, MCBUF_LEN);
+    } while (rc == ERANGE);
+
+    if (rc == 0) {
+        pw_name_len = strlen(pwd.pw_name) + 1;
+        if (pw_name_len > len) {
+            IDMAP_LOG(0, ("%s: reply too long; pw_name_len=%lu, len=%lu",
+                          __func__, pw_name_len, len));
+            rc = ENOBUFS;
+        }
+        IDMAP_LOG(1, ("found uid %i in memcache", uid));
+        memcpy(name, pwd.pw_name, pw_name_len);
+    } else {
+        IDMAP_LOG(1, ("uid %i not in memcache", uid));
+    }
+
+done:
+    free(buf);
+    return rc;
+}
+
+static int get_group_from_mc(char *name, size_t len, id_t gid)
+{
+    int rc;
+    struct group grp;
+    char *buf = NULL;
+    char *p = NULL;
+    size_t buflen = 0;
+    size_t gr_name_len;
+
+    if (!nfs_use_mc) {
+        return -1;
+    }
+
+    do {
+        buflen += MCBUF_LEN;
+        if ((p = realloc(buf, buflen)) == NULL) {
+            rc = ENOMEM;
+            goto done;
+        }
+        buf = p;
+        rc = sss_nss_mc_getgrgid(gid, &grp, buf, MCBUF_LEN);
+    } while (rc == ERANGE);
+
+    if (rc == 0) {
+        gr_name_len = strlen(grp.gr_name) + 1;
+        if (gr_name_len > len) {
+            IDMAP_LOG(0, ("%s: reply too long; gr_name_len=%lu, len=%lu",
+                          __func__, gr_name_len, len));
+            rc = ENOBUFS;
+        }
+        IDMAP_LOG(1, ("found gid %i in memcache", gid));
+        memcpy(name, grp.gr_name, gr_name_len);
+    } else {
+        IDMAP_LOG(1, ("gid %i not in memcache", gid));
+    }
+
+done:
+    free(buf);
+    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);
+
+    rc = send_recv(&rep, &rep_len, cmd, name, name_len + 1);
+    if (rc == 0) {
+        rc = reply_to_id(id, rep, rep_len);
+    }
+
+    free(rep);
+
+    return rc;
+}
+
+static int id_to_name(char *name, size_t len, id_t id,
+                      enum sss_cli_command cmd)
+{
+    int rc;
+    size_t rep_len = 0;
+    size_t req_len = sizeof(id_t);
+    uint8_t *rep = NULL;
+    uint8_t req[req_len];
+
+    memcpy(req, &id, req_len);
+    rc = send_recv(&rep, &rep_len, cmd, &req, req_len);
+    if (rc == 0) {
+        rc = reply_to_name(name, len, rep, rep_len);
+    }
+
+    free(rep);
+
+    return rc;
+}
+
+/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+static int send_recv(uint8_t **rep, size_t *rep_len, enum sss_cli_command cmd,
+                     const void *req, size_t req_len)
+{
+    int err = 0;
+    enum nss_status req_rc;
+    struct sss_cli_req_data rd;
+
+    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", err));
+        return EPIPE;
+    }
+
+    return 0;
+}
+
+static int reply_to_id(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 done;
+    }
+
+    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 done;
+    }
+    if (num_results == 0) {
+        rc = ENOENT;
+        goto done;
+    }
+    if (rep_len < sizeof(uint32_t) + REPLY_ID_OFFSET) {
+        IDMAP_LOG(0, ("%s: reply too small(2); rep_len=%lu", __func__,
+                      rep_len));
+        rc = EBADMSG;
+        goto done;
+    }
+
+    SAFEALIGN_COPY_UINT32(&id, rep + REPLY_ID_OFFSET, NULL);
+    *idp = id;
+
+done:
+    return rc;
+}
+
+static int reply_to_name(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 done;
+    }
+
+    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 done;
+    }
+    if (num_results == 0) {
+        rc = ENOENT;
+        goto done;
+    }
+    if (rep_len < sizeof(uint32_t) + REPLY_ID_OFFSET) {
+        IDMAP_LOG(0, ("%s: reply too small(2); rep_len=%lu", __func__,
+                      rep_len));
+        rc = EBADMSG;
+        goto done;
+    }
+
+    buf = (const char *)(rep + REPLY_NAME_OFFSET);
+    buf_len = rep_len - REPLY_NAME_OFFSET;
+    offset = 0;
+    rc = sss_readrep_copy_string(buf, &offset, &buf_len, &len, &name, NULL);
+    if (rc != 0) {
+        rc = -rc;
+    }
+
+done:
+    return rc;
+}
+
+/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+/* configuration parsing aids */
+static bool str_equal(const char *s1, const char *s2)
+{
+    bool res = false;
+    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)
+{
+    int res;
+    char *val;
+
+    res = def;
+    val = conf_get_str(sect, attr);
+    if (val) {
+        res = (str_equal("1", val) ||
+               str_equal("yes", val) ||
+               str_equal("true", val) ||
+               str_equal("on", val));
+    }
+
+    return res;
+}
+
+
+/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+/* libnfsidmap return-code aids */
+
+/*
+ * we only want to return 0 or ENOENT; otherwise libnfsidmap will stop
+ * translation instead of proceeding to the next translation plugin
+ */
+int normalise_rc(int rc) {
+    int res;
+
+    res = rc;
+    if (res != 0 && res != ENOENT) {
+        res = ENOENT;
+    }
+
+    return res;
+}
+
+/* log the actual rc from our code (to be used before normalising the rc) */
+void log_actual_rc(const char *trans_name, int rc) {
+    char tmp[80];
+    IDMAP_LOG(1, ("%s: rc=%i msg=%s", trans_name, rc,
+                  strerror_r(rc, tmp, sizeof(tmp))));
+}
+
+
+/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+/* The external interface */
+static int sss_nfs_init(void)
+{
+    nfs_use_mc = nfs_conf_get_bool(nfs_conf_sect, nfs_conf_use_mc,
+                                   USE_MC_DEFAULT);
+    IDMAP_LOG(1, ("%s: use memcache: %i", __func__, nfs_use_mc));
+
+    return 0;
+}
+
+static int sss_nfs_princ_to_ids(char *secname, char *princ, uid_t *uid,
+                                gid_t *gid, extra_mapping_params **ex)
+{
+    IDMAP_LOG(0, ("%s: not implemented", __func__));
+    return -ENOENT;
+}
+
+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", __func__, rc));
+        return -rc;
+    }
+
+    rc = get_uid_from_mc(uid, name);
+    if (rc != 0) {
+        rc = name_to_id(name, uid, SSS_NSS_GETPWNAM);
+    }
+
+    log_actual_rc(__func__, rc);
+    rc = normalise_rc(rc);
+
+    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", __func__, rc));
+        return -rc;
+    }
+
+    rc = get_gid_from_mc(gid, name);
+    if (rc != 0) {
+        rc = name_to_id(name, gid, SSS_NSS_GETGRNAM);
+    }
+
+    log_actual_rc(__func__, rc);
+    rc = normalise_rc(rc);
+
+    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);
+    }
+
+    log_actual_rc(__func__, rc);
+    rc = normalise_rc(rc);
+
+    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);
+    }
+
+    log_actual_rc(__func__, rc);
+    rc = normalise_rc(rc);
+
+    return -rc;
+}
+
+static int sss_nfs_gss_princ_to_grouplist(
+    char *secname, char *princ, gid_t *groups, int *ngroups,
+    extra_mapping_params **ex)
+{
+    IDMAP_LOG(0, ("%s: not implemented", __func__));
+    return -ENOENT;
+}
+
+static struct trans_func s_sss_nfs_trans = {
+    .name = 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
 
-- 
1.8.5.3


  reply	other threads:[~2014-03-04  7:38 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-04  7:37 [PATCH v2 0/5] NFSv4 rpc.idmapd plugin Noam Meltzer
2014-03-04  7:37 ` Noam Meltzer [this message]
2014-03-04  7:37 ` [PATCH v2 2/5] NFSv4 client: (private) headers from libnfsidmap Noam Meltzer
2014-03-04  7:37 ` [PATCH v2 3/5] NFSv4 client: add to build system Noam Meltzer
2014-03-04  7:37 ` [PATCH v2 4/5] NFSv4 client: man page Noam Meltzer
2014-03-04  7:37 ` [PATCH v2 5/5] NFSv4 client: add to RPM spec Noam Meltzer
2014-03-13 15:24 ` [PATCH v2 0/5] NFSv4 rpc.idmapd plugin Steve Dickson
2014-03-13 16:58   ` Simo Sorce
2014-03-13 17:25     ` J. Bruce Fields
2014-03-13 17:41       ` Simo Sorce
     [not found]         ` <1394732462.32465.235.camel-Hs+ccMQdwurzDu64bZtGtWD2FQJk+8+b@public.gmane.org>
2014-03-20  7:33           ` Noam Meltzer
2014-03-20 13:49             ` Steve Dickson
2014-05-27 19:46               ` [SSSD] " Jakub Hrozek
2014-05-27 20:02                 ` Simo Sorce
2014-03-20  7:36         ` Noam Meltzer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1393918676-20865-2-git-send-email-noam@primarydata.com \
    --to=noam@primarydata.com \
    --cc=linux-nfs@vger.kernel.org \
    --cc=sssd-devel@lists.fedorahosted.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.