Support group-id looks for kernels that ask for them.
authorNeil Brown <neilb@suse.de>
Mon, 12 Feb 2007 05:30:23 +0000 (16:30 +1100)
committerNeil Brown <neilb@suse.de>
Mon, 12 Feb 2007 05:30:23 +0000 (16:30 +1100)
With "-g" mountd will listen for uid -> gidlist requests
from the kernel and provide the required mapping.
This is specific to AUTH_USER (aka AUTH_SYS) and is designed
to overcome the 16-gid limit in the AUTH_UNIX protocol.

support/nfs/cacheio.c
utils/mountd/cache.c
utils/mountd/mountd.c
utils/mountd/mountd.man

index 4df80a6..a76915b 100644 (file)
@@ -256,6 +256,7 @@ cache_flush(int force)
         */
        static char *cachelist[] = {
                "auth.unix.ip",
+               "auth.unix.gid",
                "nfsd.fh",
                "nfsd.export",
                NULL
index 6947203..629d567 100644 (file)
@@ -21,6 +21,8 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
 #include "misc.h"
 #include "nfslib.h"
 #include "exportfs.h"
@@ -101,6 +103,53 @@ void auth_unix_ip(FILE *f)
        
 }
 
+void auth_unix_gid(FILE *f)
+{
+       /* Request are
+        *  uid
+        * reply is
+        *  uid expiry count list of group ids
+        */
+       int uid;
+       struct passwd *pw;
+       gid_t glist[100], *groups = glist;
+       int ngroups = 100;
+       int rv, i;
+       char *cp;
+
+       if (readline(fileno(f), &lbuf, &lbuflen) != 1)
+               return;
+
+       cp = lbuf;
+       if (qword_get_int(&cp, &uid) != 0)
+               return;
+
+       pw = getpwuid(uid);
+       if (!pw)
+               rv = -1;
+       else {
+               rv = getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+               if (rv == -1 && ngroups >= 100) {
+                       groups = malloc(sizeof(gid_t)*ngroups);
+                       if (!groups)
+                               rv = -1;
+                       else
+                               rv = getgrouplist(pw->pw_name, pw->pw_gid,
+                                                 groups, &ngroups);
+               }
+       }
+       qword_printint(f, uid);
+       qword_printint(f, time(0)+30*60);
+       if (rv >= 0) {
+               qword_printint(f, ngroups);
+               for (i=0; i<ngroups; i++)
+                       qword_printint(f, groups[i]);
+       }
+       qword_eol(f);
+       if (groups != glist)
+               free(groups);
+}
+
 int get_uuid(char *path, char *uuid, int uuidlen, char *u)
 {
        /* extract hex digits from uuidstr and compose a uuid
@@ -462,16 +511,20 @@ struct {
        FILE *f;
 } cachelist[] = {
        { "auth.unix.ip", auth_unix_ip},
+       { "auth.unix.gid", auth_unix_gid},
        { "nfsd.export", nfsd_export},
        { "nfsd.fh", nfsd_fh},
        { NULL, NULL }
 };
 
+extern int manage_gids;
 void cache_open(void) 
 {
        int i;
-       for (i=0; cachelist[i].cache_name; i++ ){
+       for (i=0; cachelist[i].cache_name; i++ ) {
                char path[100];
+               if (!manage_gids && cachelist[i].f == auth_unix_gid)
+                       continue;
                sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i].cache_name);
                cachelist[i].f = fopen(path, "r+");
        }
@@ -529,7 +582,7 @@ int cache_export(nfs_export *exp)
        if (exp->m_export.e_maptype != CLE_MAP_IDENT) {
                xlog(L_ERROR, "%s: unsupported mapping; kernel supports only 'identity' (default)",
                    exp->m_export.m_path);
-               return;
+               return -1;
        }
 
        f = fopen("/proc/net/rpc/auth.unix.ip/channel", "w");
index 5204faa..fc9a73c 100644 (file)
@@ -39,6 +39,7 @@ static struct nfs_fh_len *get_rootfh(struct svc_req *, dirpath *, mountstat3 *,
 
 int reverse_resolve = 0;
 int new_cache = 0;
+int manage_gids;
 
 /* PRC: a high-availability callout program can be specified with -H
  * When this is done, the program will receive callouts whenever clients
@@ -68,6 +69,7 @@ static struct option longopts[] =
        { "state-directory-path", 1, 0, 's' },
        { "num-threads", 1, 0, 't' },
        { "reverse-lookup", 0, 0, 'r' },
+       { "manage-gids", 0, 0, 'g' },
        { NULL, 0, 0, 0 }
 };
 
@@ -567,8 +569,11 @@ main(int argc, char **argv)
 
        /* Parse the command line options and arguments. */
        opterr = 0;
-       while ((c = getopt_long(argc, argv, "o:nFd:f:p:P:hH:N:V:vrs:t:", longopts, NULL)) != EOF)
+       while ((c = getopt_long(argc, argv, "o:nFd:f:p:P:hH:N:V:vrs:t:g", longopts, NULL)) != EOF)
                switch (c) {
+               case 'g':
+                       manage_gids = 1;
+                       break;
                case 'o':
                        descriptors = atoi(optarg);
                        if (descriptors <= 0) {
@@ -746,6 +751,6 @@ usage(const char *prog, int n)
 "      [-p|--port port] [-V version|--nfs-version version]\n"
 "      [-N version|--no-nfs-version version] [-n|--no-tcp]\n"
 "      [-H ha-callout-prog] [-s|--state-directory-path path]\n"
-"      [-t num|--num-threads=num]\n", prog);
+"      [-g|--manage-gids] [-t num|--num-threads=num]\n", prog);
        exit(n);
 }
index 70166c1..f8646d4 100644 (file)
@@ -143,6 +143,21 @@ can support both NFS version 2 and the newer version 3.
 Print the version of
 .B rpc.mountd
 and exit.
+.TP
+.B \-g " or " \-\-manage-gids
+Accept requests from the kernel to map user id numbers into  lists of
+group id numbers for use in access control.  An NFS request will
+normally (except when using Kerberos or other cryptographic
+authentication) contains a user-id and a list of group-ids.  Due to a
+limitation in the NFS protocol, at most 16 groups ids can be listed.
+If you use the
+.B \-g
+flag, then the list of group ids received from the client will be
+replaced by a list of group ids determined by an appropriate lookup on
+the server. Note that the 'primary' group id is not affected so a
+.I newgroup
+command on the client will still be effective.  This function requires
+a Linux Kernel with version at least 2.6.21.
 
 .SH TCP_WRAPPERS SUPPORT
 This