summaryrefslogtreecommitdiffstats
path: root/src/sss_client/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sss_client/nfs')
-rw-r--r--src/sss_client/nfs/nfsidmap_internal.h78
-rw-r--r--src/sss_client/nfs/sss_nfs_client.c589
2 files changed, 667 insertions, 0 deletions
diff --git a/src/sss_client/nfs/nfsidmap_internal.h b/src/sss_client/nfs/nfsidmap_internal.h
new file mode 100644
index 0000000..07547f8
--- /dev/null
+++ b/src/sss_client/nfs/nfsidmap_internal.h
@@ -0,0 +1,78 @@
+/*
+ * nfsidmap_internal.h
+ *
+ * nfs idmapping library, primarily for nfs4 client/server kernel idmapping
+ * and for userland nfs4 idmapping by acl libraries.
+ *
+ * Copyright (c) 2004 The Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Andy Adamson <andros@umich.edu>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+char *get_default_domain(void);
+struct conf_list *get_local_realms(void);
+
+typedef struct trans_func * (*libnfsidmap_plugin_init_t)(void);
+
+struct trans_func {
+ char *name;
+ int (*init)(void);
+ int (*princ_to_ids)(char *secname, char *princ, uid_t *uid, gid_t *gid,
+ extra_mapping_params **ex);
+ int (*name_to_uid)(char *name, uid_t *uid);
+ int (*name_to_gid)(char *name, gid_t *gid);
+ int (*uid_to_name)(uid_t uid, char *domain, char *name, size_t len);
+ int (*gid_to_name)(gid_t gid, char *domain, char *name, size_t len);
+ int (*gss_princ_to_grouplist)(char *secname, char *princ, gid_t *groups,
+ int *ngroups, extra_mapping_params **ex);
+};
+
+struct mapping_plugin {
+ void *dl_handle;
+ struct trans_func *trans;
+};
+
+typedef enum {
+ IDTYPE_USER = 1,
+ IDTYPE_GROUP = 2
+} idtypes;
+
+extern int idmap_verbosity;
+extern nfs4_idmap_log_function_t idmap_log_func;
+/* Level zero always prints, others print depending on verbosity level */
+#define IDMAP_LOG(LVL, MSG) \
+ do { if (LVL <= idmap_verbosity) (*idmap_log_func)MSG; } while (0)
+
+
+/*
+ * from libnfsidmap's cfg.h (same license as above)
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2000, 2003 H�kan Olsson. All rights reserved.
+ */
+extern const char *conf_get_str(const char *, const char *);
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..571256a
--- /dev/null
+++ b/src/sss_client/nfs/sss_nfs_client.c
@@ -0,0 +1,589 @@
+/*
+ SSSD
+
+ NFS Client
+
+ Copyright (C) Noam Meltzer <noam@primarydata.com> 2013-2014
+ Copyright (C) Noam Meltzer <tsnoam@gmail.com> 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/>.
+*/
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+
+#include <nfsidmap.h>
+
+#ifdef HAVE_NFSIDMAP_PLUGIN_H
+#include <nfsidmap_plugin.h>
+#else /* fallback to internal header file with older version of libnfsidmap */
+#include "nfsidmap_internal.h"
+#define nfsidmap_config_get conf_get_str
+#endif
+
+#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 BUF_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;
+ }
+
+ rc = sss_strnlen(name, SSS_NAME_MAX, &len);
+ if (rc != 0) {
+ IDMAP_LOG(0, ("%s: no-strnlen; rc=%i", __func__, rc));
+ return rc;
+ }
+
+ do {
+ buflen += BUF_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;
+ }
+
+ rc = sss_strnlen(name, SSS_NAME_MAX, &len);
+ if (rc != 0) {
+ IDMAP_LOG(0, ("%s: no-strnlen; rc=%i", __func__, rc));
+ return rc;
+ }
+
+ do {
+ buflen += BUF_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 += BUF_LEN;
+ if ((p = realloc(buf, buflen)) == NULL) {
+ rc = ENOMEM;
+ goto done;
+ }
+ buf = p;
+ rc = sss_nss_mc_getpwuid(uid, &pwd, buf, buflen);
+ } 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 += BUF_LEN;
+ if ((p = realloc(buf, buflen)) == NULL) {
+ rc = ENOMEM;
+ goto done;
+ }
+ buf = p;
+ rc = sss_nss_mc_getgrgid(gid, &grp, buf, buflen);
+ } 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;
+
+ 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 = 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_nss_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_NAME_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(const char *sect, const char *attr, int def)
+{
+ int res;
+ const char *val;
+
+ res = def;
+ val = nfsidmap_config_get(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);
+}