summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am13
-rw-r--r--cifsidmap.h45
-rw-r--r--configure.ac9
-rw-r--r--getcifsacl.c98
-rw-r--r--idmap_plugin.c103
-rw-r--r--idmap_plugin.h46
-rw-r--r--idmapwb.c115
7 files changed, 371 insertions, 58 deletions
diff --git a/Makefile.am b/Makefile.am
index 8964b37..bc5e517 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,9 +57,8 @@ endif
if CONFIG_CIFSACL
bin_PROGRAMS += getcifsacl
-getcifsacl_SOURCES = getcifsacl.c
-getcifsacl_LDADD = $(WBCLIENT_LIBS)
-getcifsacl_CFLAGS = $(WBCLIENT_CFLAGS)
+getcifsacl_SOURCES = getcifsacl.c idmap_plugin.c
+getcifsacl_LDADD = -ldl
man_MANS += getcifsacl.1
bin_PROGRAMS += setcifsacl
@@ -69,4 +68,12 @@ setcifsacl_CFLAGS = $(WBCLIENT_CFLAGS)
man_MANS += setcifsacl.1
endif
+if CONFIG_PLUGIN
+plugindir = $(pkglibdir)
+plugin_PROGRAMS = idmapwb.so
+
+idmapwb.so: idmapwb.c
+ $(CC) $(CFLAGS) $(AM_CFLAGS) $(WBCLIENT_CFLAGS) $(LDFLAGS) -shared -fpic -o $@ $+ $(WBCLIENT_LIBS)
+endif
+
SUBDIRS = contrib
diff --git a/cifsidmap.h b/cifsidmap.h
index 9907618..c307333 100644
--- a/cifsidmap.h
+++ b/cifsidmap.h
@@ -34,4 +34,49 @@ struct cifs_sid {
uint32_t sub_auth[SID_MAX_SUB_AUTHORITIES];
} __attribute__((packed));
+/* Plugins should implement the following functions: */
+
+/**
+ * cifs_idmap_init_plugin - Initialize the plugin interface
+ * @handle - return pointer for an opaque handle
+ * @errmsg - pointer to error message pointer
+ *
+ * This function should do whatever is required to establish a context
+ * for later ID mapping operations. The "handle" is an opaque context
+ * cookie that will be passed in on subsequent ID mapping operations.
+ * The errmsg is used to pass back an error string both during the init
+ * and in subsequent idmapping functions. On any error, the plugin
+ * should point *errmsg at a string describing that error. Returns 0
+ * on success and non-zero on error.
+ *
+ * int cifs_idmap_init_plugin(void **handle, const char **errmsg);
+ */
+
+/**
+ * cifs_idmap_exit_plugin - Destroy an idmapping context
+ * @handle - context handle that should be destroyed
+ *
+ * When programs are finished with the idmapping plugin, they'll call
+ * this function to destroy any context that was created during the
+ * init_plugin. The handle passed back in was the one given by the init
+ * routine.
+ *
+ * void cifs_idmap_exit_plugin(void *handle);
+ */
+
+/**
+ * cifs_idmap_sid_to_str - convert cifs_sid to a string
+ * @handle - context handle
+ * @sid - pointer to a cifs_sid
+ * @name - return pointer for the name
+ *
+ * This function should convert the given cifs_sid to a string
+ * representation in a heap-allocated buffer. The caller of this
+ * function is expected to free "name" on success. Returns 0 on
+ * success and non-zero on error.
+ *
+ * int cifs_idmap_sid_to_str(void *handle, const struct cifs_sid *sid,
+ * char **name);
+ */
+
#endif /* _CIFSIDMAP_H */
diff --git a/configure.ac b/configure.ac
index b6791ab..9652ad2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -52,6 +52,14 @@ AC_ARG_ENABLE(systemd,
enable_systemd=$enableval,
enable_systemd="maybe")
+# "with" options
+AC_ARG_WITH(idmap-plugin,
+ [AC_HELP_STRING([--with-idmap-plugin=/path/to/plugin],
+ [Define the path to the plugin that the idmapping infrastructure should use @<:@default=/etc/cifs-utils/idmap-plugin@:>@])],
+ pluginpath=$withval,
+ pluginpath="/etc/cifs-utils/idmap-plugin")
+AC_DEFINE_UNQUOTED(IDMAP_PLUGIN_PATH, "$pluginpath", [Location of plugin that ID mapping infrastructure should use. (usually a symlink to real plugin)])
+
# check for ROOTSBINDIR environment var
if test -z $ROOTSBINDIR; then
ROOTSBINDIR="/sbin"
@@ -230,6 +238,7 @@ AM_CONDITIONAL(CONFIG_CIFSUPCALL, [test "$enable_cifsupcall" != "no"])
AM_CONDITIONAL(CONFIG_CIFSCREDS, [test "$enable_cifscreds" != "no"])
AM_CONDITIONAL(CONFIG_CIFSIDMAP, [test "$enable_cifsidmap" != "no"])
AM_CONDITIONAL(CONFIG_CIFSACL, [test "$enable_cifsacl" != "no"])
+AM_CONDITIONAL(CONFIG_PLUGIN, [test "$enable_cifsidmap" != "no" -o "$enable_cifsacl" != "no"])
LIBCAP_NG_PATH
diff --git a/getcifsacl.c b/getcifsacl.c
index 550429c..b8998ef 100644
--- a/getcifsacl.c
+++ b/getcifsacl.c
@@ -33,10 +33,13 @@
#include <stddef.h>
#include <errno.h>
#include <limits.h>
-#include <wbclient.h>
#include <ctype.h>
#include <sys/xattr.h>
#include "cifsacl.h"
+#include "idmap_plugin.h"
+
+static void *plugin_handle;
+static bool plugin_loaded;
static void
print_each_ace_mask(uint32_t mask)
@@ -169,61 +172,33 @@ print_ace_type(uint8_t acetype, int raw)
}
}
-/*
- * Winbind keeps wbcDomainSid fields in host-endian. Copy fields from the
- * csid to the wsid, while converting the subauthority fields from LE.
- */
static void
-csid_to_wsid(struct wbcDomainSid *wsid, const struct cifs_sid *csid)
+print_sid(struct cifs_sid *csid, int raw)
{
- int i;
- uint8_t num_subauth = (csid->num_subauth <= WBC_MAXSUBAUTHS) ?
- csid->num_subauth : WBC_MAXSUBAUTHS;
-
- wsid->sid_rev_num = csid->revision;
- wsid->num_auths = num_subauth;
- for (i = 0; i < NUM_AUTHS; i++)
- wsid->id_auth[i] = csid->authority[i];
- for (i = 0; i < num_subauth; i++)
- wsid->sub_auths[i] = le32toh(csid->sub_auth[i]);
-}
-
-static void
-print_sid(struct cifs_sid *sidptr, int raw)
-{
- int i;
- wbcErr rc;
- char *domain_name = NULL;
- char *sidname = NULL;
- enum wbcSidType sntype;
+ int i, rc;
+ char *name;
unsigned long long id_auth_val;
- struct wbcDomainSid wsid;
- csid_to_wsid(&wsid, sidptr);
+ if (raw || !plugin_loaded)
+ goto print_sid_raw;
- if (raw)
+ rc = sid_to_str(plugin_handle, csid, &name);
+ if (rc)
goto print_sid_raw;
- rc = wbcLookupSid(&wsid, &domain_name, &sidname, &sntype);
- if (WBC_ERROR_IS_OK(rc)) {
- printf("%s", domain_name);
- if (strlen(domain_name))
- printf("%c", '\\');
- printf("%s", sidname);
- wbcFreeMemory(domain_name);
- wbcFreeMemory(sidname);
- return;
- }
+ printf("%s", name);
+ free(name);
+ return;
print_sid_raw:
- printf("S-%hhu", wsid.sid_rev_num);
+ printf("S-%hhu", csid->revision);
- id_auth_val = (unsigned long long)wsid.id_auth[5];
- id_auth_val += (unsigned long long)wsid.id_auth[4] << 8;
- id_auth_val += (unsigned long long)wsid.id_auth[3] << 16;
- id_auth_val += (unsigned long long)wsid.id_auth[2] << 24;
- id_auth_val += (unsigned long long)wsid.id_auth[1] << 32;
- id_auth_val += (unsigned long long)wsid.id_auth[0] << 48;
+ id_auth_val = (unsigned long long)csid->authority[5];
+ id_auth_val += (unsigned long long)csid->authority[4] << 8;
+ id_auth_val += (unsigned long long)csid->authority[3] << 16;
+ id_auth_val += (unsigned long long)csid->authority[2] << 24;
+ id_auth_val += (unsigned long long)csid->authority[1] << 32;
+ id_auth_val += (unsigned long long)csid->authority[0] << 48;
/*
* MS-DTYP states that if the authority is >= 2^32, then it should be
@@ -234,8 +209,8 @@ print_sid_raw:
else
printf("-0x%llx", id_auth_val);
- for (i = 0; i < wsid.num_auths; i++)
- printf("-%u", wsid.sub_auths[i]);
+ for (i = 0; i < csid->num_subauth; i++)
+ printf("-%u", le32toh(csid->sub_auth[i]));
}
static void
@@ -368,7 +343,8 @@ getcifsacl_usage(const char *prog)
int
main(const int argc, char *const argv[])
{
- int c, raw = 0;
+ int c, ret = 0;
+ bool raw = false;
ssize_t attrlen;
size_t bufsize = BUFSIZE;
char *filename, *attrval;
@@ -379,7 +355,7 @@ main(const int argc, char *const argv[])
printf("Version: %s\n", VERSION);
goto out;
case 'r':
- raw = 1;
+ raw = true;
break;
default:
break;
@@ -392,20 +368,31 @@ main(const int argc, char *const argv[])
filename = argv[1];
else {
getcifsacl_usage(basename(argv[0]));
- return 0;
+ goto out;
+ }
+
+ if (!raw && !plugin_loaded) {
+ ret = init_plugin(&plugin_handle);
+ if (ret)
+ printf("WARNING: unable to initialize idmapping plugin: %s\n",
+ plugin_errmsg);
+ else
+ plugin_loaded = true;
}
cifsacl:
if (bufsize >= XATTR_SIZE_MAX) {
printf("buffer to allocate exceeds max size of %d\n",
XATTR_SIZE_MAX);
- return -1;
+ ret = -1;
+ goto out;
}
attrval = malloc(bufsize * sizeof(char));
if (!attrval) {
printf("error allocating memory for attribute value buffer\n");
- return -1;
+ ret = -1;
+ goto out;
}
attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
@@ -421,7 +408,8 @@ cifsacl:
parse_sec_desc((struct cifs_ntsd *)attrval, attrlen, raw);
free(attrval);
-
out:
- return 0;
+ if (plugin_loaded)
+ exit_plugin(plugin_handle);
+ return ret;
}
diff --git a/idmap_plugin.c b/idmap_plugin.c
new file mode 100644
index 0000000..237c921
--- /dev/null
+++ b/idmap_plugin.c
@@ -0,0 +1,103 @@
+/*
+ * ID Mapping Plugin interface for cifs-utils
+ * Copyright (C) 2012 Jeff Layton (jlayton@samba.org)
+ *
+ * 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "cifsidmap.h"
+
+const char *plugin_errmsg;
+static void *plugin;
+
+static void *
+resolve_symbol(const char *symbol_name)
+{
+ void *symbol;
+
+ dlerror();
+ symbol = dlsym(plugin, symbol_name);
+ if (!symbol)
+ plugin_errmsg = dlerror();
+ return symbol;
+}
+
+/*
+ * open the plugin. Note that we leave it open over the life of the
+ * program. It gets closed on exit.
+ */
+static int
+open_plugin(void)
+{
+ if (plugin)
+ return 0;
+
+ plugin = dlopen(IDMAP_PLUGIN_PATH, RTLD_LAZY);
+ if (!plugin) {
+ plugin_errmsg = dlerror();
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int
+init_plugin(void **handle)
+{
+ int ret;
+ int (*init)(void **, const char **);
+
+ ret = open_plugin();
+ if (ret)
+ return ret;
+
+ init = resolve_symbol("cifs_idmap_init_plugin");
+ if (!init) {
+ plugin_errmsg = "cifs_idmap_init_plugin not implemented";
+ return -ENOSYS;
+ }
+ return (*init)(handle, &plugin_errmsg);
+}
+
+void
+exit_plugin(void *handle)
+{
+ int (*exit)(void *);
+
+ exit = resolve_symbol("cifs_idmap_exit_plugin");
+ if (exit)
+ (*exit)(handle);
+}
+
+int
+sid_to_str(void *handle, const struct cifs_sid *sid, char **name)
+{
+ int (*entry)(void *, const struct cifs_sid *, char **);
+
+ *(void **)(&entry) = resolve_symbol("cifs_idmap_sid_to_str");
+ if (!entry) {
+ plugin_errmsg = "cifs_idmap_sid_to_str not implemented";
+ return -ENOSYS;
+ }
+
+ return (*entry)(handle, sid, name);
+}
diff --git a/idmap_plugin.h b/idmap_plugin.h
new file mode 100644
index 0000000..277bb12
--- /dev/null
+++ b/idmap_plugin.h
@@ -0,0 +1,46 @@
+/*
+ * ID Mapping Plugin interface for cifs-utils
+ * Copyright (C) 2012 Jeff Layton (jlayton@samba.org)
+ *
+ * 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 "cifsidmap.h"
+
+#ifndef _IDMAP_PLUGIN_H
+#define _IDMAP_PLUGIN_H
+
+/*
+ * On error, plugin functions will set this pointer to a string description
+ * of the error. The string should not be freed.
+ */
+extern const char *plugin_errmsg;
+
+/*
+ * External API. Programs should call this to use the plugin functionality.
+ */
+
+/*
+ * Initialize plugin. Returns an opaque handle that should be passed to
+ * other idmapping functions.
+ */
+extern int init_plugin(void **handle);
+
+/* Close out an init'ed handle */
+extern void exit_plugin(void *handle);
+
+/* Convert cifs_sid to a string. Caller must free *name on success */
+extern int sid_to_str(void *handle, const struct cifs_sid *sid, char **name);
+
+#endif /* _IDMAP_PLUGIN_H */
diff --git a/idmapwb.c b/idmapwb.c
new file mode 100644
index 0000000..858028f
--- /dev/null
+++ b/idmapwb.c
@@ -0,0 +1,115 @@
+/*
+ * Winbind ID Mapping Plugin
+ * Copyright (C) 2012 Jeff Layton (jlayton@samba.org)
+ *
+ * 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdint.h>
+#include <endian.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wbclient.h>
+
+#include "cifsidmap.h"
+
+static const char **plugin_errmsg;
+
+/*
+ * Winbind keeps wbcDomainSid fields in host-endian. Copy fields from the
+ * csid to the wsid, while converting the subauthority fields from LE.
+ */
+static void
+csid_to_wsid(struct wbcDomainSid *wsid, const struct cifs_sid *csid)
+{
+ int i;
+ uint8_t num_subauth = (csid->num_subauth <= WBC_MAXSUBAUTHS) ?
+ csid->num_subauth : WBC_MAXSUBAUTHS;
+
+ wsid->sid_rev_num = csid->revision;
+ wsid->num_auths = num_subauth;
+ for (i = 0; i < NUM_AUTHS; i++)
+ wsid->id_auth[i] = csid->authority[i];
+ for (i = 0; i < num_subauth; i++)
+ wsid->sub_auths[i] = le32toh(csid->sub_auth[i]);
+}
+
+int
+cifs_idmap_sid_to_str(void *handle __attribute__ ((unused)),
+ const struct cifs_sid *csid, char **string)
+{
+ int rc;
+ wbcErr wbcrc;
+ char *domain = NULL;
+ char *name = NULL;
+ enum wbcSidType sntype;
+ struct wbcDomainSid wsid;
+ size_t len;
+
+ csid_to_wsid(&wsid, csid);
+
+ wbcrc = wbcLookupSid(&wsid, &domain, &name, &sntype);
+ if (!WBC_ERROR_IS_OK(wbcrc)) {
+ *plugin_errmsg = wbcErrorString(wbcrc);
+ return -EIO;
+ }
+
+ /* +1 for '\\' and +1 for NULL terminator */
+ len = strlen(domain) + 1 + strlen(name) + 1;
+
+ *string = malloc(len);
+ if (!*string) {
+ *plugin_errmsg = "Unable to allocate memory";
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = snprintf(*string, len, "%s\\%s", domain, name);
+ if (rc >= (long)len) {
+ free(*string);
+ *plugin_errmsg = "Resulting string was truncated";
+ *string = NULL;
+ rc = -EIO;
+ } else {
+ rc = 0;
+ }
+out:
+ wbcFreeMemory(domain);
+ wbcFreeMemory(name);
+ return rc;
+}
+
+/*
+ * For the winbind plugin, we don't need to do anything special on
+ * init or exit
+ */
+int
+cifs_idmap_init_plugin(void **handle __attribute__((unused)), const char **errmsg)
+{
+ plugin_errmsg = errmsg;
+ return 0;
+}
+
+void
+cifs_idmap_exit_plugin(void *handle __attribute__((unused)))
+{
+ return;
+}