[hackers] [skvm] It is now possible for a normal user to unmount a drive without having root privileges. || Dimitrios Papastamos

From: <hg_AT_suckless.org>
Date: Thu, 14 May 2009 19:53:26 +0000 (UTC)

changeset: 13:56c21f2aa16a
tag: tip
user: Dimitrios Papastamos <stateless [at] archlinux.us>
date: Thu May 14 20:52:13 2009 -0700
files: README skvm.c
description:
It is now possible for a normal user to unmount a drive without having root privileges.
This is still experimental, therefore it is advisable to backup your /etc/fstab before
testing this commit.

diff -r 749c5d4b4f0e -r 56c21f2aa16a README
--- a/README Wed May 13 20:45:33 2009 -0700
+++ b/README Thu May 14 20:52:13 2009 -0700
@@ -6,6 +6,10 @@
 It is meant to be simple to use, efficient and functional. It has
 been tested and working on Arch linux and Debian, however the init script
 needs to be adapted when used on Debian.
+
+Warning
+=======
+Make sure you back up your /etc/fstab.
 
 Installation
 ============
@@ -22,6 +26,8 @@
 * sudo /etc/rc.d/skvm restart
 * sudo /etc/rc.d/skvm stop
 
+Info
+====
 If you want to unmount the drives, you will have to be root. If you
 cold eject a drive, skvm will unmount it and delete the mountpoint.
 That is probably not a good idea.
diff -r 749c5d4b4f0e -r 56c21f2aa16a skvm.c
--- a/skvm.c Wed May 13 20:45:33 2009 -0700
+++ b/skvm.c Thu May 14 20:52:13 2009 -0700
@@ -37,7 +37,7 @@
  */
 #define MOUNT_CMD_PATH "/bin/mount"
 #define UMOUNT_CMD_PATH "/bin/umount"
-#define DEFAULT_MNT_OPTIONS "noexec,nosuid"
+#define DEFAULT_MNT_OPTIONS "noexec,nosuid,nodev,users"
 #define BASE_MNT_DIR "/media/"
 
 /* not user controlled */
@@ -74,13 +74,16 @@
  */
 
 struct device_t {
- char *args[8]; /* arguments to mount for this device */
    char *mountp; /* mount point */
    char *did; /* volume's unique id */
    char *dev; /* device associated with this volume */
    char *label; /* volume's label */
    char *fstype; /* filesystem type */
    char *opt; /* mount options */
+ int use_fstab; /* true if this device has an fstab entry
+ before inserting the device */
+ int should_remove_entry; /* true if upon removal of the device
+ an entry in fstab needs to be removed */
    LibHalVolume *volume;
    LibHalDrive *drive;
    struct device_t *next;
@@ -137,9 +140,10 @@
 static char *get_mount_point(const char *dev, const char *label);
 static int resolve_symlink(const char *symlnk, char *d, size_t d_len);
 static void consider_fstab(struct device_t *device);
-static void do_args(struct device_t *device);
-static int do_mount(struct device_t *device);
+static int do_mount(const struct device_t *device);
 static int do_umount(const struct device_t *device);
+static int add_fstab_entry(const struct device_t *device);
+static int remove_fstab_entry(const struct device_t *device);
 
 /* general function helpers */
 static inline int file_exists(const char *path);
@@ -314,8 +318,12 @@
       mkdir(device->mountp, 0750);
    do_mount(device) < 0 ? free_device(device) : add_to_device_list(device);
 
- if (debug_mode_flag && device)
- debug_dump_device(device);
+ if (device) {
+ if (!add_fstab_entry(device))
+ device->should_remove_entry = 1;
+ if (debug_mode_flag)
+ debug_dump_device(device);
+ }
 
 out:
    if (mountable)
@@ -337,11 +345,14 @@
          if (!file_exists(mountp)) {
             if (!is_mounted(iter->dev))
                if (do_umount(iter))
- syslog(LOG_WARNING, "%s:%d: %s", __FILE__, __LINE__,
+ syslog(LOG_ERR, "%s:%d: %s", __FILE__, __LINE__,
                          strerror(errno));
             if (rmdir(mountp) < 0)
- syslog(LOG_WARNING, "%s:%d: %s", __FILE__, __LINE__,
+ syslog(LOG_ERR, "%s:%d: %s", __FILE__, __LINE__,
                       strerror(errno));
+ if (iter->should_remove_entry && remove_fstab_entry(iter))
+ syslog(LOG_ERR, "%s:%d: %s", __FILE__, __LINE__,
+ "cannot remove fstab entry");
             remove_from_device_list(prev, iter);
          }
          return;
@@ -366,6 +377,8 @@
       device->volume = volume;
       device->drive = drive;
       device->next = NULL;
+ device->use_fstab = 0;
+ device->should_remove_entry = 0;
       if (!device->did || !device->label || !device->fstype) {
          free_device(device);
          device = NULL;
@@ -568,6 +581,7 @@
             ++str;
             if (!(mtab = setmntent("/etc/mtab", "r")))
                goto out;
+ device->use_fstab = 1;
             len = strlen(str) + 1 + strlen(BASE_MNT_DIR);
             tmp = device->mountp;
             while ((i = getmntent(mtab))) {
@@ -591,31 +605,22 @@
    endmntent(fp);
 }
 
-/* TODO: might actually remove this one */
-static void
-do_args(struct device_t *device) {
- int i = 0;
-
- if (!device)
- return;
-
- device->args[i++] = MOUNT_CMD_PATH;
- device->args[i++] = "-t";
- device->args[i++] = device->fstype;
- device->args[i++] = "-o";
- device->args[i++] = (!device->opt) ? DEFAULT_MNT_OPTIONS : device->opt;
- device->args[i++] = device->dev;
- device->args[i++] = device->mountp;
- device->args[i] = (char *)NULL;
-}
-
 static int
-do_mount(struct device_t *device) {
+do_mount(const struct device_t *device) {
    if (!device)
       return -1;
 
- do_args(device);
- return EXEC_CMD(device->args) ? 0 : -1;
+ return EXEC_CMD(
+ ((char *[]) {
+ MOUNT_CMD_PATH,
+ "-t",
+ device->fstype,
+ "-o",
+ (!device->opt) ? DEFAULT_MNT_OPTIONS : device->opt,
+ device->dev,
+ device->mountp,
+ (char *)NULL
+ })) ? 0 : -1;
 }
 
 static int
@@ -627,6 +632,72 @@
    ((char *[]) {
       UMOUNT_CMD_PATH, device->dev, (char *)NULL
    })) ? 0 : -1;
+}
+
+static int
+add_fstab_entry(const struct device_t *device) {
+ FILE *fstab;
+ struct mntent entry;
+
+ if (!device || device->use_fstab)
+ return -1;
+ fstab = setmntent("/etc/fstab", "a");
+ if (!fstab)
+ return -1;
+
+ entry.mnt_fsname = device->dev;
+ entry.mnt_dir = device->mountp;
+ entry.mnt_type = device->fstype;
+ entry.mnt_opts = (!device->opt) ? DEFAULT_MNT_OPTIONS : device->opt;
+ entry.mnt_freq = 0;
+ entry.mnt_passno = 0;
+
+ addmntent(fstab, &entry);
+ endmntent(fstab);
+ return 0;
+}
+
+static int
+remove_fstab_entry(const struct device_t *device) {
+ FILE *fstab, *line_pp;
+ char buf[BUFSIZ];
+ int lines = 0, i = 0;
+
+ if (!device || device->use_fstab)
+ return -1;
+
+ line_pp = popen("wc -l /etc/fstab | awk '{print $1}'", "r");
+ if (!line_pp)
+ return -1;
+ if (!fgets(buf, sizeof buf, line_pp))
+ return -1;
+ pclose(line_pp);
+ lines = atoi(buf);
+
+ fstab = fopen("/etc/fstab", "r+");
+ if (!fstab)
+ return -1;
+
+ char tmp[lines][BUFSIZ];
+ while (!feof(fstab) && fgets(tmp[i], BUFSIZ, fstab))
+ ++i;
+
+ rewind(fstab);
+ if (ftruncate(fileno(fstab), 0) < 0) {
+ syslog(LOG_ERR, "%s:%d: %s", __FILE__, __LINE__,
+ strerror(errno));
+ return -1;
+ }
+
+ i = 0;
+ while (i < lines) {
+ if (!strstr(tmp[i], device->dev))
+ fprintf(fstab, "%s", tmp[i]);
+ ++i;
+ }
+
+ fclose(fstab);
+ return 0;
 }
 
 static inline int
@@ -676,7 +747,6 @@
    if (!device)
       return;
 
- printf("~~~ Device dump ~~~\n");
    printf("Volume info: %s\n", (!device->did) ? "(null)" : device->did);
    printf("Device: %s\n", (!device->dev) ? "(null)" : device->dev);
    printf("Label: %s\n", (!device->label) ? "(null)" : device->label);
@@ -686,6 +756,7 @@
           (!device->opt) ? DEFAULT_MNT_OPTIONS : device->opt);
    printf("Mount point: %s\n",
           (!device->mountp) ? "(null)" : device->mountp);
- printf("~~~~~~~~~~~~~~~~~~~\n");
+ printf("Uses /etc/fstab: %d\n", device->use_fstab);
+ printf("Cleanup after /etc/fstab: %d\n", device->should_remove_entry);
 }
 
Received on Thu May 14 2009 - 19:53:26 UTC

This archive was generated by hypermail 2.2.0 : Thu May 14 2009 - 20:00:06 UTC