Add nfs.upcall
This patch adds the nfs.upcall program to nfs-utils. This program is called by
the nfs idmapper through request-keys to map between uid / user name and
gid / group name.
Signed-off-by: Bryan Schumaker <[email protected]>
---
diff --git a/aclocal/keyutils.m4 b/aclocal/keyutils.m4
new file mode 100644
index 0000000..84bc112
--- /dev/null
+++ b/aclocal/keyutils.m4
@@ -0,0 +1,11 @@
+dnl Checks for keyutils library and headers
+dnl
+AC_DEFUN([AC_KEYUTILS], [
+
+ dnl Check for libkeyutils; do not add to LIBS if found
+ AC_CHECK_LIB([keyutils], [keyctl_instantiate], [LIBKEYUTILS=-lkeyutils], ,)
+ AC_SUBST(LIBKEYUTILS)
+
+ AC_CHECK_HEADERS([keyutils.h], ,
+ [AC_MSG_ERROR([keyutils.h header not found.])])
+])dnl
diff --git a/configure.ac b/configure.ac
index 3058be6..a5e8620 100644
--- a/configure.ac
+++ b/configure.ac
@@ -247,6 +247,9 @@ if test "$enable_nfsv4" = yes; then
dnl check for nfsidmap libraries and headers
AC_LIBNFSIDMAP
+ dnl check for the keyutils libraries and headers
+ AC_KEYUTILS
+
dnl librpcsecgss already has a dependency on libgssapi,
dnl but we need to make sure we get the right version
if test "$enable_gss" = yes; then
@@ -435,6 +438,7 @@ AC_CONFIG_FILES([
utils/mountd/Makefile
utils/nfsd/Makefile
utils/nfsstat/Makefile
+ utils/nfs.upcall/Makefile
utils/showmount/Makefile
utils/statd/Makefile
tests/Makefile
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 8665183..0104a6c 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -4,6 +4,7 @@ OPTDIRS =
if CONFIG_NFSV4
OPTDIRS += idmapd
+OPTDIRS += nfs.upcall
endif
if CONFIG_GSS
diff --git a/utils/nfs.upcall/Makefile.am b/utils/nfs.upcall/Makefile.am
new file mode 100644
index 0000000..52afd3d
--- /dev/null
+++ b/utils/nfs.upcall/Makefile.am
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+
+sbin_PROGRAMS = nfs.upcall
+nfs_upcall_SOURCES = nfs.upcall.c
+nfs_upcall_LDADD = -lnfsidmap -lkeyutils
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/nfs.upcall/nfs.upcall.c b/utils/nfs.upcall/nfs.upcall.c
new file mode 100644
index 0000000..37aa5e9
--- /dev/null
+++ b/utils/nfs.upcall/nfs.upcall.c
@@ -0,0 +1,120 @@
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <keyutils.h>
+#include <nfsidmap.h>
+
+#include <syslog.h>
+
+/* gcc nfs.upcall.c -o nfs.upcall -l nfsidmap -l keyutils */
+
+#define MAX_ID_LEN 11
+#define IDMAP_NAMESZ 128
+#define USER 1
+#define GROUP 0
+
+
+/*
+ * Find either a user or group id based on the name@domain string
+ */
+int id_lookup(char *name_at_domain, key_serial_t key, int type)
+{
+ char id[MAX_ID_LEN];
+ uid_t uid = 0;
+ gid_t gid = 0;
+ int rc;
+
+ if (type == USER) {
+ rc = nfs4_owner_to_uid(name_at_domain, &uid);
+ sprintf(id, "%u", uid);
+ } else {
+ rc = nfs4_group_owner_to_gid(name_at_domain, &gid);
+ sprintf(id, "%u", gid);
+ }
+
+ if (rc == 0)
+ rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
+
+ return rc;
+}
+
+/*
+ * Find the name@domain string from either a user or group id
+ */
+int name_lookup(char *id, key_serial_t key, int type)
+{
+ char name[IDMAP_NAMESZ];
+ char domain[NFS4_MAX_DOMAIN_LEN];
+ uid_t uid;
+ gid_t gid;
+ int rc;
+
+ rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN);
+ if (rc != 0) {
+ rc = -1;
+ goto out;
+ }
+
+ if (type == USER) {
+ uid = atoi(id);
+ rc = nfs4_uid_to_name(uid, domain, name, IDMAP_NAMESZ);
+ } else {
+ gid = atoi(id);
+ rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ);
+ }
+
+ if (rc == 0)
+ rc = keyctl_instantiate(key, &name, strlen(name), 0);
+
+out:
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+ char *arg;
+ char *value;
+ char *type;
+ int rc = 1;
+ int timeout = 600;
+ key_serial_t key;
+
+ if (argc < 3)
+ return 1;
+
+ arg = malloc(sizeof(char) * strlen(argv[2]) + 1);
+ strcpy(arg, argv[2]);
+ type = strtok(arg, ":");
+ value = strtok(NULL, ":");
+
+ if (argc == 4) {
+ timeout = atoi(argv[3]);
+ if (timeout < 0)
+ timeout = 0;
+ }
+
+ key = strtol(argv[1], NULL, 10);
+
+ if (strcmp(type, "uid") == 0)
+ rc = id_lookup(value, key, USER);
+ else if (strcmp(type, "gid") == 0)
+ rc = id_lookup(value, key, GROUP);
+ else if (strcmp(type, "user") == 0)
+ rc = name_lookup(value, key, USER);
+ else if (strcmp(type, "group") == 0)
+ rc = name_lookup(value, key, GROUP);
+
+ /* Set timeout to 5 (600 seconds) minutes */
+ if (rc == 0)
+ keyctl_set_timeout(key, timeout);
+ else
+ keyctl_negate(key, timeout, 0);
+
+ free(arg);
+ return rc;
+}
On Thu, 2010-09-30 at 13:30 -0400, Chuck Lever wrote:
> My only concern here is that the new design does not preclude the easy ability to get the TXT record and cache its value locally for a reasonable period of time. Replacing a long-running daemon with a multiple invocation program may change the picture a little, if I understand the new design correctly.
I don't think that is true. Look at the ease with which David adapted
the cifs dns resolver to get the AFSDB resource record.
In fact, if we wanted to get a specific TXT record for the kernel, we
can do that today using the existing dns_query() mechanism, and then
writing a userspace handler. I therefore don't see the need to add that
functionality to the idmapper.
> In the end, we could rely on local caching of DNS results (by, say, nscd) and let libnfsidmap do the DNS search whenever it wants.
>
> >> Finally, if at all possible, it would be better if the kernel could automatically recognize and use nfs.upcall rather than the legacy idmapping mechanism. My experience with CONFIG options is that people will almost always choose the wrong setting no matter how many large neon arrows you add. I know there are likely some technical challenges here.
> >
> > I don't think that is easy to do. The keyring upcall mechanism will
> > almost always succeed, no matter whether or not there is a handler for
> > the type of key requested. Instead, it will result in a negative lookup.
> > Unfortunately, seeing a negative key isn't sufficient to determine that
> > no handler exists.
>
> Yes, I acknowledge it may be difficult. And perhaps using the keyring mechanism as it stands today to detect which mechanism to use might not be trivial. Maybe the keyring mechanism is deficient in this regard and could be fixed?
>
> However, the general principal still holds (based on experience we both have! :-) that having an automated mechanism is better than a build-time CONFIG option. If we consider this for a bit and decide it's too hard, then so be it.
It is hard, because there is more than 1 question that needs to be
answered:
- Does the user have a recent copy of the key-utils package installed?
- Does the user have the latest nfs-utils package installed?
- Does the user have /etc/request-key.conf configured correctly?
The keyring upcall mechanism only really answers the first question.
IOW: This is hard to do in the kernel. OTOH, it is really trivial to do
in the kernel package and nfs-utils package dependency lists...
Cheers
Trond
On Wed, 2010-09-29 at 15:41 -0400, Bryan Schumaker wrote:
> Add nfs.upcall
>
> This patch adds the nfs.upcall program to nfs-utils. This program is called by
> the nfs idmapper through request-keys to map between uid / user name and
> gid / group name.
>
> Signed-off-by: Bryan Schumaker <[email protected]>
> ---
> diff --git a/aclocal/keyutils.m4 b/aclocal/keyutils.m4
> new file mode 100644
> index 0000000..84bc112
> --- /dev/null
> +++ b/aclocal/keyutils.m4
> @@ -0,0 +1,11 @@
> +dnl Checks for keyutils library and headers
> +dnl
> +AC_DEFUN([AC_KEYUTILS], [
> +
> + dnl Check for libkeyutils; do not add to LIBS if found
> + AC_CHECK_LIB([keyutils], [keyctl_instantiate], [LIBKEYUTILS=-lkeyutils], ,)
> + AC_SUBST(LIBKEYUTILS)
> +
> + AC_CHECK_HEADERS([keyutils.h], ,
> + [AC_MSG_ERROR([keyutils.h header not found.])])
> +])dnl
> diff --git a/configure.ac b/configure.ac
> index 3058be6..a5e8620 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -247,6 +247,9 @@ if test "$enable_nfsv4" = yes; then
> dnl check for nfsidmap libraries and headers
> AC_LIBNFSIDMAP
>
> + dnl check for the keyutils libraries and headers
> + AC_KEYUTILS
> +
> dnl librpcsecgss already has a dependency on libgssapi,
> dnl but we need to make sure we get the right version
> if test "$enable_gss" = yes; then
> @@ -435,6 +438,7 @@ AC_CONFIG_FILES([
> utils/mountd/Makefile
> utils/nfsd/Makefile
> utils/nfsstat/Makefile
> + utils/nfs.upcall/Makefile
> utils/showmount/Makefile
> utils/statd/Makefile
> tests/Makefile
> diff --git a/utils/Makefile.am b/utils/Makefile.am
> index 8665183..0104a6c 100644
> --- a/utils/Makefile.am
> +++ b/utils/Makefile.am
> @@ -4,6 +4,7 @@ OPTDIRS =
>
> if CONFIG_NFSV4
> OPTDIRS += idmapd
> +OPTDIRS += nfs.upcall
> endif
>
> if CONFIG_GSS
> diff --git a/utils/nfs.upcall/Makefile.am b/utils/nfs.upcall/Makefile.am
> new file mode 100644
> index 0000000..52afd3d
> --- /dev/null
> +++ b/utils/nfs.upcall/Makefile.am
> @@ -0,0 +1,7 @@
> +## Process this file with automake to produce Makefile.in
> +
> +sbin_PROGRAMS = nfs.upcall
> +nfs_upcall_SOURCES = nfs.upcall.c
> +nfs_upcall_LDADD = -lnfsidmap -lkeyutils
> +
> +MAINTAINERCLEANFILES = Makefile.in
> diff --git a/utils/nfs.upcall/nfs.upcall.c b/utils/nfs.upcall/nfs.upcall.c
> new file mode 100644
> index 0000000..37aa5e9
> --- /dev/null
> +++ b/utils/nfs.upcall/nfs.upcall.c
> @@ -0,0 +1,120 @@
> +
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <pwd.h>
> +#include <grp.h>
> +#include <keyutils.h>
> +#include <nfsidmap.h>
> +
> +#include <syslog.h>
> +
> +/* gcc nfs.upcall.c -o nfs.upcall -l nfsidmap -l keyutils */
> +
> +#define MAX_ID_LEN 11
> +#define IDMAP_NAMESZ 128
> +#define USER 1
> +#define GROUP 0
> +
> +
> +/*
> + * Find either a user or group id based on the name@domain string
> + */
> +int id_lookup(char *name_at_domain, key_serial_t key, int type)
> +{
> + char id[MAX_ID_LEN];
> + uid_t uid = 0;
> + gid_t gid = 0;
> + int rc;
> +
> + if (type == USER) {
> + rc = nfs4_owner_to_uid(name_at_domain, &uid);
> + sprintf(id, "%u", uid);
> + } else {
> + rc = nfs4_group_owner_to_gid(name_at_domain, &gid);
> + sprintf(id, "%u", gid);
> + }
> +
> + if (rc == 0)
> + rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
> +
> + return rc;
> +}
> +
> +/*
> + * Find the name@domain string from either a user or group id
> + */
> +int name_lookup(char *id, key_serial_t key, int type)
> +{
> + char name[IDMAP_NAMESZ];
> + char domain[NFS4_MAX_DOMAIN_LEN];
> + uid_t uid;
> + gid_t gid;
> + int rc;
> +
> + rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN);
> + if (rc != 0) {
> + rc = -1;
> + goto out;
> + }
> +
> + if (type == USER) {
> + uid = atoi(id);
> + rc = nfs4_uid_to_name(uid, domain, name, IDMAP_NAMESZ);
> + } else {
> + gid = atoi(id);
> + rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ);
> + }
> +
> + if (rc == 0)
> + rc = keyctl_instantiate(key, &name, strlen(name), 0);
> +
> +out:
> + return rc;
> +}
> +
> +int main(int argc, char **argv)
> +{
> + char *arg;
> + char *value;
> + char *type;
> + int rc = 1;
> + int timeout = 600;
> + key_serial_t key;
> +
> + if (argc < 3)
> + return 1;
> +
> + arg = malloc(sizeof(char) * strlen(argv[2]) + 1);
> + strcpy(arg, argv[2]);
> + type = strtok(arg, ":");
> + value = strtok(NULL, ":");
> +
> + if (argc == 4) {
> + timeout = atoi(argv[3]);
> + if (timeout < 0)
> + timeout = 0;
> + }
> +
> + key = strtol(argv[1], NULL, 10);
> +
> + if (strcmp(type, "uid") == 0)
> + rc = id_lookup(value, key, USER);
> + else if (strcmp(type, "gid") == 0)
> + rc = id_lookup(value, key, GROUP);
> + else if (strcmp(type, "user") == 0)
> + rc = name_lookup(value, key, USER);
> + else if (strcmp(type, "group") == 0)
> + rc = name_lookup(value, key, GROUP);
> +
> + /* Set timeout to 5 (600 seconds) minutes */
> + if (rc == 0)
> + keyctl_set_timeout(key, timeout);
> + else
> + keyctl_negate(key, timeout, 0);
Hmm... I've been looking more closely at the design of request-key. It
looks as if the idea there is that you are supposed to return without
instantiating the key if you are unable to service the request.
Basically, if your program exits with a non-zero value, then request-key
is supposed to look at the next matching entry in /etc/request-key.conf
(until it hits they very last entry, which is always 'keyctl negate').
Sorry, Bryan. The above line was a result of me bugging you. I should
have checked the sources first...
> + free(arg);
> + return rc;
> +}
Cheers
Trond
On Thu, 2010-09-30 at 13:23 -0400, J. Bruce Fields wrote:
> On Thu, Sep 30, 2010 at 01:07:17PM -0400, Trond Myklebust wrote:
> > On Thu, 2010-09-30 at 11:42 -0400, Chuck Lever wrote:
> > > Finally, if at all possible, it would be better if the kernel could automatically recognize and use nfs.upcall rather than the legacy idmapping mechanism. My experience with CONFIG options is that people will almost always choose the wrong setting no matter how many large neon arrows you add. I know there are likely some technical challenges here.
> >
> > I don't think that is easy to do. The keyring upcall mechanism will
> > almost always succeed, no matter whether or not there is a handler for
> > the type of key requested. Instead, it will result in a negative lookup.
> > Unfortunately, seeing a negative key isn't sufficient to determine that
> > no handler exists.
>
> If we could just find out whether there's an executable at the right
> path, that would be enough to catch most misconfigurations. Would it be
> hard to get back at least that much information?
AFAICS, the lookup can return ENOENT or EACCES if the key-utils package
is missing.
However, as I said above, the fact that the exec succeeds is not
sufficient to determine whether or not the user has installed our upcall
handler in their /etc/request-key.conf.
> I'm inclined to agree with Chuck that this is a likely trap for the
> unwary....
That's why the help text for the config option states explicitly that
you need new tools, and points you to the correct Documentation file...
Cheers
Trond
On 09/29/2010 06:13 PM, Trond Myklebust wrote:
> On Wed, 2010-09-29 at 15:41 -0400, Bryan Schumaker wrote:
>> + else
>> + keyctl_negate(key, timeout, 0);
>
> Hmm... I've been looking more closely at the design of request-key. It
> looks as if the idea there is that you are supposed to return without
> instantiating the key if you are unable to service the request.
>
> Basically, if your program exits with a non-zero value, then request-key
> is supposed to look at the next matching entry in /etc/request-key.conf
> (until it hits they very last entry, which is always 'keyctl negate').
>
> Sorry, Bryan. The above line was a result of me bugging you. I should
> have checked the sources first...
>
>> + free(arg);
>> + return rc;
>> +}
>
> Cheers
> Trond
No problem. Here is an updated patch with the line removed.
Bryan
This patch adds the nfs.upcall program to nfs-utils. This program is called by
the nfs idmapper through request-keys to map between uid / user name and
gid / group name.
Signed-off-by: Bryan Schumaker <[email protected]>
---
diff --git a/aclocal/keyutils.m4 b/aclocal/keyutils.m4
new file mode 100644
index 0000000..84bc112
--- /dev/null
+++ b/aclocal/keyutils.m4
@@ -0,0 +1,11 @@
+dnl Checks for keyutils library and headers
+dnl
+AC_DEFUN([AC_KEYUTILS], [
+
+ dnl Check for libkeyutils; do not add to LIBS if found
+ AC_CHECK_LIB([keyutils], [keyctl_instantiate], [LIBKEYUTILS=-lkeyutils], ,)
+ AC_SUBST(LIBKEYUTILS)
+
+ AC_CHECK_HEADERS([keyutils.h], ,
+ [AC_MSG_ERROR([keyutils.h header not found.])])
+])dnl
diff --git a/configure.ac b/configure.ac
index 3058be6..a5e8620 100644
--- a/configure.ac
+++ b/configure.ac
@@ -247,6 +247,9 @@ if test "$enable_nfsv4" = yes; then
dnl check for nfsidmap libraries and headers
AC_LIBNFSIDMAP
+ dnl check for the keyutils libraries and headers
+ AC_KEYUTILS
+
dnl librpcsecgss already has a dependency on libgssapi,
dnl but we need to make sure we get the right version
if test "$enable_gss" = yes; then
@@ -435,6 +438,7 @@ AC_CONFIG_FILES([
utils/mountd/Makefile
utils/nfsd/Makefile
utils/nfsstat/Makefile
+ utils/nfs.upcall/Makefile
utils/showmount/Makefile
utils/statd/Makefile
tests/Makefile
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 8665183..0104a6c 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -4,6 +4,7 @@ OPTDIRS =
if CONFIG_NFSV4
OPTDIRS += idmapd
+OPTDIRS += nfs.upcall
endif
if CONFIG_GSS
diff --git a/utils/nfs.upcall/Makefile.am b/utils/nfs.upcall/Makefile.am
new file mode 100644
index 0000000..52afd3d
--- /dev/null
+++ b/utils/nfs.upcall/Makefile.am
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+
+sbin_PROGRAMS = nfs.upcall
+nfs_upcall_SOURCES = nfs.upcall.c
+nfs_upcall_LDADD = -lnfsidmap -lkeyutils
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/utils/nfs.upcall/nfs.upcall.c b/utils/nfs.upcall/nfs.upcall.c
new file mode 100644
index 0000000..9200972
--- /dev/null
+++ b/utils/nfs.upcall/nfs.upcall.c
@@ -0,0 +1,118 @@
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <keyutils.h>
+#include <nfsidmap.h>
+
+#include <syslog.h>
+
+/* gcc nfs.upcall.c -o nfs.upcall -l nfsidmap -l keyutils */
+
+#define MAX_ID_LEN 11
+#define IDMAP_NAMESZ 128
+#define USER 1
+#define GROUP 0
+
+
+/*
+ * Find either a user or group id based on the name@domain string
+ */
+int id_lookup(char *name_at_domain, key_serial_t key, int type)
+{
+ char id[MAX_ID_LEN];
+ uid_t uid = 0;
+ gid_t gid = 0;
+ int rc;
+
+ if (type == USER) {
+ rc = nfs4_owner_to_uid(name_at_domain, &uid);
+ sprintf(id, "%u", uid);
+ } else {
+ rc = nfs4_group_owner_to_gid(name_at_domain, &gid);
+ sprintf(id, "%u", gid);
+ }
+
+ if (rc == 0)
+ rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
+
+ return rc;
+}
+
+/*
+ * Find the name@domain string from either a user or group id
+ */
+int name_lookup(char *id, key_serial_t key, int type)
+{
+ char name[IDMAP_NAMESZ];
+ char domain[NFS4_MAX_DOMAIN_LEN];
+ uid_t uid;
+ gid_t gid;
+ int rc;
+
+ rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN);
+ if (rc != 0) {
+ rc = -1;
+ goto out;
+ }
+
+ if (type == USER) {
+ uid = atoi(id);
+ rc = nfs4_uid_to_name(uid, domain, name, IDMAP_NAMESZ);
+ } else {
+ gid = atoi(id);
+ rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ);
+ }
+
+ if (rc == 0)
+ rc = keyctl_instantiate(key, &name, strlen(name), 0);
+
+out:
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+ char *arg;
+ char *value;
+ char *type;
+ int rc = 1;
+ int timeout = 600;
+ key_serial_t key;
+
+ if (argc < 3)
+ return 1;
+
+ arg = malloc(sizeof(char) * strlen(argv[2]) + 1);
+ strcpy(arg, argv[2]);
+ type = strtok(arg, ":");
+ value = strtok(NULL, ":");
+
+ if (argc == 4) {
+ timeout = atoi(argv[3]);
+ if (timeout < 0)
+ timeout = 0;
+ }
+
+ key = strtol(argv[1], NULL, 10);
+
+ if (strcmp(type, "uid") == 0)
+ rc = id_lookup(value, key, USER);
+ else if (strcmp(type, "gid") == 0)
+ rc = id_lookup(value, key, GROUP);
+ else if (strcmp(type, "user") == 0)
+ rc = name_lookup(value, key, USER);
+ else if (strcmp(type, "group") == 0)
+ rc = name_lookup(value, key, GROUP);
+
+ /* Set timeout to 5 (600 seconds) minutes */
+ if (rc == 0)
+ keyctl_set_timeout(key, timeout);
+
+ free(arg);
+ return rc;
+}
On Thu, Sep 30, 2010 at 01:07:17PM -0400, Trond Myklebust wrote:
> On Thu, 2010-09-30 at 11:42 -0400, Chuck Lever wrote:
> > Finally, if at all possible, it would be better if the kernel could automatically recognize and use nfs.upcall rather than the legacy idmapping mechanism. My experience with CONFIG options is that people will almost always choose the wrong setting no matter how many large neon arrows you add. I know there are likely some technical challenges here.
>
> I don't think that is easy to do. The keyring upcall mechanism will
> almost always succeed, no matter whether or not there is a handler for
> the type of key requested. Instead, it will result in a negative lookup.
> Unfortunately, seeing a negative key isn't sufficient to determine that
> no handler exists.
If we could just find out whether there's an executable at the right
path, that would be enough to catch most misconfigurations. Would it be
hard to get back at least that much information?
I'm inclined to agree with Chuck that this is a likely trap for the
unwary....
--b.
On Thu, 2010-09-30 at 11:42 -0400, Chuck Lever wrote:
> I might choose a less generic name for this program, unless there are plans to make it handle all NFS upcalls, eventually. How about nfs.idmap ?
nfs.idmap sounds good.
> Should nfs.upcall have its own man page? My opinion is that it should. That might be a better place for the setup information (needed by mortal system administrators) added under Documentation/ by an earlier patch. Documentation/ is an appropriate place for the upcall design information, though.
Agreed. We do need to help people who want to edit /etc/request-key.conf
themselves.
> Also, I've been looking at the Mesta-Adamson draft that provides NFSv4 domain information via DNS. I'd like to see Linux make use of this TXT record, as Solaris does today. It would help make Linux NFSv4 more automatically configurable, especially in heterogeneous environments.
That looks like something that needs to be added to libnfsidmap. I don't
think we need to make the kernel domain-aware.
> As I understand it, nfs.upcall would obviate rpc.idmapd, correct? In that case, what entity would be responsible for a putative DNS lookup to determine the local NFSv4 domain name? How would this information be cached?
See above.
> Finally, if at all possible, it would be better if the kernel could automatically recognize and use nfs.upcall rather than the legacy idmapping mechanism. My experience with CONFIG options is that people will almost always choose the wrong setting no matter how many large neon arrows you add. I know there are likely some technical challenges here.
I don't think that is easy to do. The keyring upcall mechanism will
almost always succeed, no matter whether or not there is a handler for
the type of key requested. Instead, it will result in a negative lookup.
Unfortunately, seeing a negative key isn't sufficient to determine that
no handler exists.
Cheers
Trond
On Sep 30, 2010, at 1:07 PM, Trond Myklebust wrote:
> On Thu, 2010-09-30 at 11:42 -0400, Chuck Lever wrote:
>
>> I might choose a less generic name for this program, unless there are plans to make it handle all NFS upcalls, eventually. How about nfs.idmap ?
>
> nfs.idmap sounds good.
>
>> Should nfs.upcall have its own man page? My opinion is that it should. That might be a better place for the setup information (needed by mortal system administrators) added under Documentation/ by an earlier patch. Documentation/ is an appropriate place for the upcall design information, though.
>
> Agreed. We do need to help people who want to edit /etc/request-key.conf
> themselves.
>
>> Also, I've been looking at the Mesta-Adamson draft that provides NFSv4 domain information via DNS. I'd like to see Linux make use of this TXT record, as Solaris does today. It would help make Linux NFSv4 more automatically configurable, especially in heterogeneous environments.
>
> That looks like something that needs to be added to libnfsidmap. I don't
> think we need to make the kernel domain-aware.
>
>> As I understand it, nfs.upcall would obviate rpc.idmapd, correct? In that case, what entity would be responsible for a putative DNS lookup to determine the local NFSv4 domain name? How would this information be cached?
>
> See above.
OK, makes sense.
My only concern here is that the new design does not preclude the easy ability to get the TXT record and cache its value locally for a reasonable period of time. Replacing a long-running daemon with a multiple invocation program may change the picture a little, if I understand the new design correctly.
In the end, we could rely on local caching of DNS results (by, say, nscd) and let libnfsidmap do the DNS search whenever it wants.
>> Finally, if at all possible, it would be better if the kernel could automatically recognize and use nfs.upcall rather than the legacy idmapping mechanism. My experience with CONFIG options is that people will almost always choose the wrong setting no matter how many large neon arrows you add. I know there are likely some technical challenges here.
>
> I don't think that is easy to do. The keyring upcall mechanism will
> almost always succeed, no matter whether or not there is a handler for
> the type of key requested. Instead, it will result in a negative lookup.
> Unfortunately, seeing a negative key isn't sufficient to determine that
> no handler exists.
Yes, I acknowledge it may be difficult. And perhaps using the keyring mechanism as it stands today to detect which mechanism to use might not be trivial. Maybe the keyring mechanism is deficient in this regard and could be fixed?
However, the general principal still holds (based on experience we both have! :-) that having an automated mechanism is better than a build-time CONFIG option. If we consider this for a bit and decide it's too hard, then so be it.
--
chuck[dot]lever[at]oracle[dot]com
On Sep 30, 2010, at 9:13 AM, Bryan Schumaker wrote:
> On 09/29/2010 06:13 PM, Trond Myklebust wrote:
>> On Wed, 2010-09-29 at 15:41 -0400, Bryan Schumaker wrote:
>>> + else
>>> + keyctl_negate(key, timeout, 0);
>>
>> Hmm... I've been looking more closely at the design of request-key. It
>> looks as if the idea there is that you are supposed to return without
>> instantiating the key if you are unable to service the request.
>>
>> Basically, if your program exits with a non-zero value, then request-key
>> is supposed to look at the next matching entry in /etc/request-key.conf
>> (until it hits they very last entry, which is always 'keyctl negate').
>>
>> Sorry, Bryan. The above line was a result of me bugging you. I should
>> have checked the sources first...
>>
>>> + free(arg);
>>> + return rc;
>>> +}
>>
>> Cheers
>> Trond
>
>
> No problem. Here is an updated patch with the line removed.
Overall this work seems like a positive direction.
I might choose a less generic name for this program, unless there are plans to make it handle all NFS upcalls, eventually. How about nfs.idmap ?
Should nfs.upcall have its own man page? My opinion is that it should. That might be a better place for the setup information (needed by mortal system administrators) added under Documentation/ by an earlier patch. Documentation/ is an appropriate place for the upcall design information, though.
Also, I've been looking at the Mesta-Adamson draft that provides NFSv4 domain information via DNS. I'd like to see Linux make use of this TXT record, as Solaris does today. It would help make Linux NFSv4 more automatically configurable, especially in heterogeneous environments.
As I understand it, nfs.upcall would obviate rpc.idmapd, correct? In that case, what entity would be responsible for a putative DNS lookup to determine the local NFSv4 domain name? How would this information be cached?
Finally, if at all possible, it would be better if the kernel could automatically recognize and use nfs.upcall rather than the legacy idmapping mechanism. My experience with CONFIG options is that people will almost always choose the wrong setting no matter how many large neon arrows you add. I know there are likely some technical challenges here.
> Bryan
>
>
>
> This patch adds the nfs.upcall program to nfs-utils. This program is called by
> the nfs idmapper through request-keys to map between uid / user name and
> gid / group name.
>
> Signed-off-by: Bryan Schumaker <[email protected]>
> ---
> diff --git a/aclocal/keyutils.m4 b/aclocal/keyutils.m4
> new file mode 100644
> index 0000000..84bc112
> --- /dev/null
> +++ b/aclocal/keyutils.m4
> @@ -0,0 +1,11 @@
> +dnl Checks for keyutils library and headers
> +dnl
> +AC_DEFUN([AC_KEYUTILS], [
> +
> + dnl Check for libkeyutils; do not add to LIBS if found
> + AC_CHECK_LIB([keyutils], [keyctl_instantiate], [LIBKEYUTILS=-lkeyutils], ,)
> + AC_SUBST(LIBKEYUTILS)
> +
> + AC_CHECK_HEADERS([keyutils.h], ,
> + [AC_MSG_ERROR([keyutils.h header not found.])])
> +])dnl
> diff --git a/configure.ac b/configure.ac
> index 3058be6..a5e8620 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -247,6 +247,9 @@ if test "$enable_nfsv4" = yes; then
> dnl check for nfsidmap libraries and headers
> AC_LIBNFSIDMAP
>
> + dnl check for the keyutils libraries and headers
> + AC_KEYUTILS
> +
> dnl librpcsecgss already has a dependency on libgssapi,
> dnl but we need to make sure we get the right version
> if test "$enable_gss" = yes; then
> @@ -435,6 +438,7 @@ AC_CONFIG_FILES([
> utils/mountd/Makefile
> utils/nfsd/Makefile
> utils/nfsstat/Makefile
> + utils/nfs.upcall/Makefile
> utils/showmount/Makefile
> utils/statd/Makefile
> tests/Makefile
> diff --git a/utils/Makefile.am b/utils/Makefile.am
> index 8665183..0104a6c 100644
> --- a/utils/Makefile.am
> +++ b/utils/Makefile.am
> @@ -4,6 +4,7 @@ OPTDIRS =
>
> if CONFIG_NFSV4
> OPTDIRS += idmapd
> +OPTDIRS += nfs.upcall
> endif
>
> if CONFIG_GSS
> diff --git a/utils/nfs.upcall/Makefile.am b/utils/nfs.upcall/Makefile.am
> new file mode 100644
> index 0000000..52afd3d
> --- /dev/null
> +++ b/utils/nfs.upcall/Makefile.am
> @@ -0,0 +1,7 @@
> +## Process this file with automake to produce Makefile.in
> +
> +sbin_PROGRAMS = nfs.upcall
> +nfs_upcall_SOURCES = nfs.upcall.c
> +nfs_upcall_LDADD = -lnfsidmap -lkeyutils
> +
> +MAINTAINERCLEANFILES = Makefile.in
> diff --git a/utils/nfs.upcall/nfs.upcall.c b/utils/nfs.upcall/nfs.upcall.c
> new file mode 100644
> index 0000000..9200972
> --- /dev/null
> +++ b/utils/nfs.upcall/nfs.upcall.c
> @@ -0,0 +1,118 @@
> +
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <pwd.h>
> +#include <grp.h>
> +#include <keyutils.h>
> +#include <nfsidmap.h>
> +
> +#include <syslog.h>
> +
> +/* gcc nfs.upcall.c -o nfs.upcall -l nfsidmap -l keyutils */
> +
> +#define MAX_ID_LEN 11
> +#define IDMAP_NAMESZ 128
> +#define USER 1
> +#define GROUP 0
> +
> +
> +/*
> + * Find either a user or group id based on the name@domain string
> + */
> +int id_lookup(char *name_at_domain, key_serial_t key, int type)
> +{
> + char id[MAX_ID_LEN];
> + uid_t uid = 0;
> + gid_t gid = 0;
> + int rc;
> +
> + if (type == USER) {
> + rc = nfs4_owner_to_uid(name_at_domain, &uid);
> + sprintf(id, "%u", uid);
> + } else {
> + rc = nfs4_group_owner_to_gid(name_at_domain, &gid);
> + sprintf(id, "%u", gid);
> + }
> +
> + if (rc == 0)
> + rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
> +
> + return rc;
> +}
> +
> +/*
> + * Find the name@domain string from either a user or group id
> + */
> +int name_lookup(char *id, key_serial_t key, int type)
> +{
> + char name[IDMAP_NAMESZ];
> + char domain[NFS4_MAX_DOMAIN_LEN];
> + uid_t uid;
> + gid_t gid;
> + int rc;
> +
> + rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN);
> + if (rc != 0) {
> + rc = -1;
> + goto out;
> + }
> +
> + if (type == USER) {
> + uid = atoi(id);
> + rc = nfs4_uid_to_name(uid, domain, name, IDMAP_NAMESZ);
> + } else {
> + gid = atoi(id);
> + rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ);
> + }
> +
> + if (rc == 0)
> + rc = keyctl_instantiate(key, &name, strlen(name), 0);
> +
> +out:
> + return rc;
> +}
> +
> +int main(int argc, char **argv)
> +{
> + char *arg;
> + char *value;
> + char *type;
> + int rc = 1;
> + int timeout = 600;
> + key_serial_t key;
> +
> + if (argc < 3)
> + return 1;
> +
> + arg = malloc(sizeof(char) * strlen(argv[2]) + 1);
> + strcpy(arg, argv[2]);
> + type = strtok(arg, ":");
> + value = strtok(NULL, ":");
> +
> + if (argc == 4) {
> + timeout = atoi(argv[3]);
> + if (timeout < 0)
> + timeout = 0;
> + }
> +
> + key = strtol(argv[1], NULL, 10);
> +
> + if (strcmp(type, "uid") == 0)
> + rc = id_lookup(value, key, USER);
> + else if (strcmp(type, "gid") == 0)
> + rc = id_lookup(value, key, GROUP);
> + else if (strcmp(type, "user") == 0)
> + rc = name_lookup(value, key, USER);
> + else if (strcmp(type, "group") == 0)
> + rc = name_lookup(value, key, GROUP);
> +
> + /* Set timeout to 5 (600 seconds) minutes */
> + if (rc == 0)
> + keyctl_set_timeout(key, timeout);
> +
> + free(arg);
> + return rc;
> +}
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
chuck[dot]lever[at]oracle[dot]com