]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
Correctly handle "user" and "users" mount options.
authorNeil Brown <neilb@suse.de>
Fri, 16 Mar 2007 07:07:41 +0000 (18:07 +1100)
committerNeil Brown <neilb@suse.de>
Fri, 16 Mar 2007 07:07:41 +0000 (18:07 +1100)
If "user" or "users" is given, then allow mount.nfs to be run
by a non-root user providing that the mountpoint, filesystem, and options
exactly match what is found in fstab.

For "user", record the user name in mtab so they can unmount the
filesystem later.

Also alwasys ignore auto, owner, group and their negations as well
as "_netdev", "comment" and "loop".

support/include/fstab.h
support/nfs/fstab.c
utils/mount/mount.c

index 8053066b0ce43b64eee746d2e9dcdd5901c2e659..ab30c5a7fa9d1f1f85dd460917f7b1e8f988eea5 100644 (file)
@@ -3,6 +3,10 @@
 
 #include "nfs_mntent.h"
 
+#ifndef _PATH_FSTAB
+#define _PATH_FSTAB "/etc/fstab"
+#endif
+
 int mtab_is_writable(void);
 int mtab_does_not_exist(void);
 
@@ -15,6 +19,9 @@ struct mntentchn *getmntoptfile (const char *file);
 struct mntentchn *getmntdirbackward (const char *dir, struct mntentchn *mc);
 struct mntentchn *getmntdevbackward (const char *dev, struct mntentchn *mc);
 
+struct mntentchn *getfsfile (const char *file);
+struct mntentchn *getfsspec (const char *spec);
+
 void lock_mtab (void);
 void unlock_mtab (void);
 void update_mtab (const char *special, nfs_mntent_t *with);
index 23ea927cc8b80624463345679a18fe5bda16db6c..ba7e580eb08f97978bee156a9e81ecc6dc4b0120 100644 (file)
@@ -80,8 +80,11 @@ mtab_is_writable() {
 
 struct mntentchn mounttable;
 static int got_mtab = 0;
+struct mntentchn fstab;
+static int got_fstab = 0;
 
 static void read_mounttable(void);
+static void read_fstab(void);
 
 static struct mntentchn *
 mtab_head() {
@@ -90,6 +93,14 @@ mtab_head() {
        return &mounttable;
 }
 
+static struct mntentchn *
+fstab_head()
+{
+       if (!got_fstab)
+               read_fstab();
+       return &fstab;
+}
+
 static void
 my_free(const void *s) {
        if (s)
@@ -167,6 +178,27 @@ read_mounttable() {
         read_mntentchn(mfp, fnam, mc);
 }
 
+static void
+read_fstab()
+{
+       mntFILE *mfp = NULL;
+       const char *fnam;
+       struct mntentchn *mc = &fstab;
+
+       got_fstab = 1;
+       mc->nxt = mc->prev = NULL;
+
+       fnam = _PATH_FSTAB;
+       mfp = nfs_setmntent (fnam, "r");
+       if (mfp == NULL || mfp->mntent_fp == NULL) {
+               int errsv = errno;
+               error(_("warning: can't open %s: %s"),
+                       _PATH_FSTAB, strerror (errsv));
+               return;
+       }
+       read_mntentchn(mfp, fnam, mc);
+}
+
 /*
  * Given the directory name NAME, and the place MCPREV we found it last time,
  * try to find more occurrences.
@@ -201,6 +233,32 @@ getmntdevbackward (const char *name, struct mntentchn *mcprev) {
        return NULL;
 }
 
+/* Find the dir FILE in fstab.  */
+struct mntentchn *
+getfsfile (const char *file)
+{
+       struct mntentchn *mc, *mc0;
+
+       mc0 = fstab_head();
+       for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+               if (streq(mc->m.mnt_dir, file))
+                       return mc;
+       return NULL;
+}
+
+/* Find the device SPEC in fstab.  */
+struct mntentchn *
+getfsspec (const char *spec)
+{
+       struct mntentchn *mc, *mc0;
+
+       mc0 = fstab_head();
+       for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+               if (streq(mc->m.mnt_fsname, spec))
+                       return mc;
+       return NULL;
+}
+
 /* Updating mtab ----------------------------------------------*/
 
 /* Flag for already existing lock file. */
index 0edcc1a2565f444263376ced71f127d4e2e07b9c..cdccfe894778a957245242c1657c87629c4659b9 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/mount.h>
 #include <getopt.h>
 #include <mntent.h>
+#include <pwd.h>
 
 #include "fstab.h"
 #include "xcommon.h"
@@ -75,6 +76,11 @@ struct opt_map {
   int  mask;                    /* flag mask value */
 };
 
+/* Custom mount options for our own purposes.  */
+#define MS_DUMMY       0x00000000
+#define MS_USERS       0x40000000
+#define MS_USER                0x80000000
+
 static const struct opt_map opt_map[] = {
   { "defaults", 0, 0, 0         },      /* default options */
   { "ro",       1, 0, MS_RDONLY },      /* read-only */
@@ -91,6 +97,20 @@ static const struct opt_map opt_map[] = {
   { "remount",  0, 0, MS_REMOUNT},      /* Alter flags of mounted FS */
   { "bind",     0, 0, MS_BIND   },      /* Remount part of tree elsewhere */
   { "rbind",    0, 0, MS_BIND|MS_REC }, /* Idem, plus mounted subtrees */
+  { "auto",     0, 0, MS_DUMMY },       /* Can be mounted using -a */
+  { "noauto",   0, 0, MS_DUMMY },       /* Can  only be mounted explicitly */
+  { "users",    1, 0, MS_USERS|MS_NOEXEC|MS_NOSUID|MS_NODEV  },
+                                       /* Allow ordinary user to mount */
+  { "nousers",  0, 1, MS_DUMMY  },      /* Forbid ordinary user to mount */
+  { "user",     1, 0, MS_USER|MS_NOEXEC|MS_NOSUID|MS_NODEV  },
+                                       /* Allow ordinary user to mount */
+  { "nouser",   0, 1, MS_DUMMY   },     /* Forbid ordinary user to mount */
+  { "owner",    0, 0, MS_DUMMY  },      /* Let the owner of the device mount */
+  { "noowner",  0, 0, MS_DUMMY  },      /* Device owner has no special privs */
+  { "group",    0, 0, MS_DUMMY  },      /* Let the group of the device mount */
+  { "nogroup",  0, 0, MS_DUMMY  },      /* Device group has no special privs */
+  { "_netdev",  0, 0, MS_DUMMY},        /* Device requires network */
+  { "comment",  0, 0, MS_DUMMY},        /* fstab comment only (kudzu,_netdev)*/
 
   /* add new options here */
 #ifdef MS_NOSUB
@@ -105,6 +125,7 @@ static const struct opt_map opt_map[] = {
   { "mand",     0, 0, MS_MANDLOCK },    /* Allow mandatory locks on this FS */
   { "nomand",   0, 1, MS_MANDLOCK },    /* Forbid mandatory locks on this FS */
 #endif
+  { "loop",     1, 0, MS_DUMMY   },      /* use a loop device */
 #ifdef MS_NOATIME
   { "atime",    0, 1, MS_NOATIME },     /* Update access time */
   { "noatime",  0, 0, MS_NOATIME },     /* Do not update access time */
@@ -122,6 +143,15 @@ static char * fix_opts_string (int flags, const char *extra_opts) {
        char *new_opts;
 
        new_opts = xstrdup((flags & MS_RDONLY) ? "ro" : "rw");
+       if (flags & MS_USER) {
+               /* record who mounted this so they can unmount */
+               struct passwd *pw = getpwuid(getuid());
+               if(pw)
+                       new_opts = xstrconcat3(new_opts, ",user=", pw->pw_name);
+       }
+       if (flags & MS_USERS)
+               new_opts = xstrconcat3(new_opts, ",users", "");
+       
        for (om = opt_map; om->opt != NULL; om++) {
                if (om->skip)
                        continue;
@@ -282,16 +312,12 @@ int main(int argc, char *argv[])
        int c, flags = 0, nfs_mount_vers = 0, mnt_err = 1, fake = 0;
        char *spec, *mount_point, *extra_opts = NULL;
        char *mount_opts = NULL, *p;
+       uid_t uid = getuid();
 
        progname = argv[0];
        if ((p = strrchr(progname, '/')) != NULL)
                progname = p+1;
 
-       if (getuid() != 0) {
-               printf("%s: only root can do that.\n", progname);
-               exit(1);
-       }
-
        if(!strncmp(progname, "umount", strlen("umount"))) {
                if(argc < 2) {
                        umount_usage();
@@ -375,10 +401,35 @@ int main(int argc, char *argv[])
        }
 
        spec = argv[1];
-       mount_point = canonicalize(argv[2]);
+       mount_point = argv[2];
+
+       if (uid != 0) {
+               /* don't even think about it unless options exactly
+                * make fstab
+                */
+               struct mntentchn *mc;
+
+               if ((mc = getfsfile(mount_point)) == NULL ||
+                   strcmp(mc->m.mnt_fsname, spec) != 0 ||
+                   strcmp(mc->m.mnt_opts, mount_opts) != 0) {
+                       fprintf(stderr, "%s: permission died - no match for fstab\n",
+                               progname);
+                       exit(1);
+               }
+               mounttype = 0;
+       }
+
+       mount_point = canonicalize(mount_point);
        
        parse_opts(mount_opts, &flags, &extra_opts);
 
+       if (uid != 0) {
+           if (! (flags & (MS_USERS | MS_USER))) {
+                   fprintf(stderr, "%s: permission denied\n", progname);
+                   exit(1);
+           }
+       }
+
        if (!strcmp(progname, "mount.nfs4") || nfs_mount_vers == 4) {
                nfs_mount_vers = 4;
                mnt_err = nfs4mount(spec, mount_point, &flags, &extra_opts, &mount_opts, 0);