This repository is to contain libraries that will let privilege-demanding application... trunk@12580
Sapan Bhatia [Fri, 20 Mar 2009 14:18:31 +0000 (14:18 +0000)]
a slice.

fuse/Makefile [new file with mode: 0644]
fuse/reroutemount.c [new file with mode: 0644]
fuse/stolen_from_fuse.c [new file with mode: 0644]
fuse/stolen_from_fuse.c.orig [new file with mode: 0644]

diff --git a/fuse/Makefile b/fuse/Makefile
new file mode 100644 (file)
index 0000000..3d0c5eb
--- /dev/null
@@ -0,0 +1,4 @@
+all: reroutemount.c reroutemount_server.c stolen_from_fuse.c
+       gcc -g -c stolen_from_fuse.c -o stolen_from_fuse.o
+       gcc -g stolen_from_fuse.o reroutemount_server.c -o reroutemount_server
+       gcc -g -shared stolen_from_fuse.o reroutemount.c -o reroutemount.so
diff --git a/fuse/reroutemount.c b/fuse/reroutemount.c
new file mode 100644 (file)
index 0000000..4ded3bb
--- /dev/null
@@ -0,0 +1,130 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "stolen_from_fuse.h"
+
+char *socket_name = "/vsys/local_fusemount.control";
+
+int rrm_connect_socket() {
+  int fd = socket( AF_UNIX, SOCK_STREAM, 0 );
+  struct sockaddr_un addr;
+  addr.sun_family = AF_UNIX;
+  strcpy( addr.sun_path, socket_name );
+  int len = strlen(socket_name) + sizeof(addr.sun_family);
+  assert( connect( fd, (struct sockaddr *) &addr, len ) == 0 );
+  return fd;
+}
+
+void rrm_do_umount( char *const argv[], int n, int fd ) {
+
+  // write the length
+  char buf[1024];
+  sprintf( buf, "%08x\n", n );
+  write( fd, buf, strlen(buf) );
+
+  // now write each arg
+  int i;
+  for( i = 0; i < n; i++ ) {
+    assert( strlen(argv[i]) < 1024 );
+    sprintf( buf, "%s\n", argv[i] );
+    write( fd, buf, strlen(buf) );
+  }
+
+  char inbuf[10];
+  int n2 = read( fd, inbuf, 10 );
+  inbuf[n2] = '\0';
+
+  int r = atoi(inbuf);
+
+}
+
+int umount2( const char *mnt, int flags ) {
+  int fd = rrm_connect_socket();
+
+  const char *argv[3];
+  argv[0] = "fusermount";
+  argv[1] = "-u";
+  argv[2] = mnt;
+
+  rrm_do_umount( (char **const) argv, 3, fd );
+
+  close(fd);
+}
+
+int mount(const char *source, const char *target, const char *filesystemtype,
+        unsigned long mountflags, const void *data) {
+
+  int fd = rrm_connect_socket();
+  
+  char buf[1024];
+  sprintf( buf, "%08x\n", 0 );
+  write( fd, buf, strlen(buf) );
+
+  sprintf( buf, "%s\n%s\n%s\n%ld\n%s\n", source, target, filesystemtype,
+          mountflags, data );
+  write( fd, buf, strlen(buf) );
+
+  char inbuf[10];
+  int n = read( fd, inbuf, 9 );
+  inbuf[n] = '\0';
+
+  int r;
+  assert( sscanf( inbuf, "%08x\n", &r ) == 1);
+
+  int fuse_fd = 0;
+  if( r < 0 ) {
+    errno = r;
+    return -1;
+  } else if( r > 0 ) {
+    // get the fd
+    fuse_fd = rrm_receive_fd(fd);
+
+    // what was the old fd?
+    int old_fd;
+    char extra[1024];
+    int s = sscanf( data, "fd=%d,%s", &old_fd, extra );
+    assert( dup2( fuse_fd, old_fd ) == old_fd );
+
+  }
+
+  close(fd);
+  return 0;
+
+}
+
+int execv( const char *path, char *const argv[] ) {
+
+  if( strstr( path, "fusermount" ) == NULL ) {
+    return execv( path, argv );
+  }
+
+  // also make sure this is an unmount . . .
+  int n = 0;
+  char *arg = argv[n];
+  int found_u = 0;
+  while( arg != NULL ) {
+    if( strcmp( arg, "-u" ) == 0 ) {
+      found_u = 1;
+      break;
+    }
+    arg = argv[++n];
+  }
+
+  if( !found_u ) {
+    return execv( path, argv );
+  }
+
+  // Have root do any fusermounts we need done
+  int fd = rrm_connect_socket();
+
+  rrm_do_umount( argv, n, fd );
+
+  exit(0);
+
+}
+
diff --git a/fuse/stolen_from_fuse.c b/fuse/stolen_from_fuse.c
new file mode 100644 (file)
index 0000000..87fef01
--- /dev/null
@@ -0,0 +1,162 @@
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "stolen_from_fuse.h"
+
+// Most of this code is stolen from FUSE 2.7.4
+
+/** Function to pass a file descriptor over a UNIX socket.
+  * 
+  * Sends the file descriptor fd over the channel sock_fd.
+  *
+  ***/
+int rrm_send_fd(int sock_fd, int fd)
+{
+       int retval;
+       struct msghdr msg;
+       struct cmsghdr *p_cmsg;
+       struct iovec vec;
+       size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
+       int *p_fds;
+       char sendchar = 0;
+
+       msg.msg_control = cmsgbuf;
+       msg.msg_controllen = sizeof(cmsgbuf);
+       p_cmsg = CMSG_FIRSTHDR(&msg);
+       p_cmsg->cmsg_level = SOL_SOCKET;
+       p_cmsg->cmsg_type = SCM_RIGHTS;
+       p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+       p_fds = (int *) CMSG_DATA(p_cmsg);
+       *p_fds = fd;
+       msg.msg_controllen = p_cmsg->cmsg_len;
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &vec;
+       msg.msg_iovlen = 1;
+       msg.msg_flags = 0;
+       /* "To pass file descriptors or credentials you need to send/read at
+        * least one byte" (man 7 unix) */
+       vec.iov_base = &sendchar;
+       vec.iov_len = sizeof(sendchar);
+       while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
+       if (retval != 1) {
+               perror("sending file descriptor");
+               return -1;
+       }
+       return 0;
+}
+
+
+/* return value:
+ * >= 0         => fd
+ * -1   => error
+ */
+int rrm_receive_fd(int fd)
+{
+       struct msghdr msg;
+       struct iovec iov;
+       char buf[1];
+       int rv;
+       size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
+       struct cmsghdr *cmsg;
+
+       iov.iov_base = buf;
+       iov.iov_len = 1;
+
+       msg.msg_name = 0;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       /* old BSD implementations should use msg_accrights instead of
+        * msg_control; the interface is different. */
+       msg.msg_control = ccmsg;
+       msg.msg_controllen = sizeof(ccmsg);
+
+       while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
+       if (rv == -1) {
+               perror("recvmsg");
+               return -1;
+       }
+       if(!rv) {
+               /* EOF */
+               return -1;
+       }
+
+       cmsg = CMSG_FIRSTHDR(&msg);
+       if (!cmsg->cmsg_type == SCM_RIGHTS) {
+               fprintf(stderr, "got control message of unknown type %d\n",
+                       cmsg->cmsg_type);
+               return -1;
+       }
+       return *(int*)CMSG_DATA(cmsg);
+}
+
+int rrm_fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
+{
+       int res;
+       int status;
+       
+       res = umount2(mnt, lazy ? 2 : 0);
+       if (res == -1)
+         fprintf(stderr, "%s: failed to unmount %s: %s\n",
+                 progname, mnt, strerror(errno));
+       return res;
+
+}
+
+static int rrm_try_open(const char *dev, char **devp, int silent)
+{
+       int fd = open(dev, O_RDWR);
+       if (fd != -1) {
+               *devp = strdup(dev);
+               if (*devp == NULL) {
+                 fprintf(stderr, "failed to allocate memory\n" );
+                               
+                       close(fd);
+                       fd = -1;
+               }
+       } else if (errno == ENODEV ||
+                  errno == ENOENT)/* check for ENOENT too, for the udev case */
+               return -2;
+       else if (!silent) {
+               fprintf(stderr, "failed to open %s: %s\n", dev,
+                       strerror(errno));
+       }
+       return fd;
+}
+
+static int rrm_try_open_fuse_device(char **devp)
+{
+       int fd;
+       int err;
+
+       //drop_privs();
+       fd = rrm_try_open(FUSE_DEV_NEW, devp, 0);
+       //restore_privs();
+       if (fd >= 0)
+               return fd;
+
+       err = fd;
+       fd = rrm_try_open(FUSE_DEV_OLD, devp, 1);
+       if (fd >= 0)
+               return fd;
+
+       return err;
+}
+
+int rrm_open_fuse_device(char **devp)
+{
+       int fd = rrm_try_open_fuse_device(devp);
+       if (fd >= -1)
+               return fd;
+
+       fprintf(stderr,
+               "fuse device not found, try 'modprobe fuse' first\n");
+
+       return -1;
+}
diff --git a/fuse/stolen_from_fuse.c.orig b/fuse/stolen_from_fuse.c.orig
new file mode 100644 (file)
index 0000000..a96cbd7
--- /dev/null
@@ -0,0 +1,157 @@
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "stolen_from_fuse.h"
+
+// Most of this code is stolen from FUSE 2.7.4
+
+int rrm_send_fd(int sock_fd, int fd)
+{
+       int retval;
+       struct msghdr msg;
+       struct cmsghdr *p_cmsg;
+       struct iovec vec;
+       size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
+       int *p_fds;
+       char sendchar = 0;
+
+       msg.msg_control = cmsgbuf;
+       msg.msg_controllen = sizeof(cmsgbuf);
+       p_cmsg = CMSG_FIRSTHDR(&msg);
+       p_cmsg->cmsg_level = SOL_SOCKET;
+       p_cmsg->cmsg_type = SCM_RIGHTS;
+       p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+       p_fds = (int *) CMSG_DATA(p_cmsg);
+       *p_fds = fd;
+       msg.msg_controllen = p_cmsg->cmsg_len;
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &vec;
+       msg.msg_iovlen = 1;
+       msg.msg_flags = 0;
+       /* "To pass file descriptors or credentials you need to send/read at
+        * least one byte" (man 7 unix) */
+       vec.iov_base = &sendchar;
+       vec.iov_len = sizeof(sendchar);
+       while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
+       if (retval != 1) {
+               perror("sending file descriptor");
+               return -1;
+       }
+       return 0;
+}
+
+
+/* return value:
+ * >= 0         => fd
+ * -1   => error
+ */
+int rrm_receive_fd(int fd)
+{
+       struct msghdr msg;
+       struct iovec iov;
+       char buf[1];
+       int rv;
+       size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
+       struct cmsghdr *cmsg;
+
+       iov.iov_base = buf;
+       iov.iov_len = 1;
+
+       msg.msg_name = 0;
+       msg.msg_namelen = 0;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       /* old BSD implementations should use msg_accrights instead of
+        * msg_control; the interface is different. */
+       msg.msg_control = ccmsg;
+       msg.msg_controllen = sizeof(ccmsg);
+
+       while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
+       if (rv == -1) {
+               perror("recvmsg");
+               return -1;
+       }
+       if(!rv) {
+               /* EOF */
+               return -1;
+       }
+
+       cmsg = CMSG_FIRSTHDR(&msg);
+       if (!cmsg->cmsg_type == SCM_RIGHTS) {
+               fprintf(stderr, "got control message of unknown type %d\n",
+                       cmsg->cmsg_type);
+               return -1;
+       }
+       return *(int*)CMSG_DATA(cmsg);
+}
+
+int rrm_fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
+{
+       int res;
+       int status;
+       
+       res = umount2(mnt, lazy ? 2 : 0);
+       if (res == -1)
+         fprintf(stderr, "%s: failed to unmount %s: %s\n",
+                 progname, mnt, strerror(errno));
+       return res;
+
+}
+
+static int rrm_try_open(const char *dev, char **devp, int silent)
+{
+       int fd = open(dev, O_RDWR);
+       if (fd != -1) {
+               *devp = strdup(dev);
+               if (*devp == NULL) {
+                 fprintf(stderr, "failed to allocate memory\n" );
+                               
+                       close(fd);
+                       fd = -1;
+               }
+       } else if (errno == ENODEV ||
+                  errno == ENOENT)/* check for ENOENT too, for the udev case */
+               return -2;
+       else if (!silent) {
+               fprintf(stderr, "failed to open %s: %s\n", dev,
+                       strerror(errno));
+       }
+       return fd;
+}
+
+static int rrm_try_open_fuse_device(char **devp)
+{
+       int fd;
+       int err;
+
+       //drop_privs();
+       fd = rrm_try_open(FUSE_DEV_NEW, devp, 0);
+       //restore_privs();
+       if (fd >= 0)
+               return fd;
+
+       err = fd;
+       fd = rrm_try_open(FUSE_DEV_OLD, devp, 1);
+       if (fd >= 0)
+               return fd;
+
+       return err;
+}
+
+int rrm_open_fuse_device(char **devp)
+{
+       int fd = rrm_try_open_fuse_device(devp);
+       if (fd >= -1)
+               return fd;
+
+       fprintf(stderr,
+               "fuse device not found, try 'modprobe fuse' first\n");
+
+       return -1;
+}