mirror of
https://github.com/libfuse/libfuse.git
synced 2024-11-27 06:04:27 +08:00
x
This commit is contained in:
parent
8cffdb9707
commit
0a7077f536
34
README
34
README
@ -11,11 +11,11 @@ You can download the source code releases from
|
||||
http://sourceforge.net/projects/avf
|
||||
|
||||
or alternatively you can use CVS to get the very latest development
|
||||
version: set the cvsroot to
|
||||
version by setting the cvsroot to
|
||||
|
||||
:pserver:anonymous@cvs.avf.sourceforge.net:/cvsroot/avf
|
||||
|
||||
and check out the 'fuse' module.
|
||||
and checking out the 'fuse' module.
|
||||
|
||||
Installation
|
||||
============
|
||||
@ -49,13 +49,10 @@ steps:
|
||||
|
||||
4) ls -al /mnt/whatever
|
||||
|
||||
5) Be glad!
|
||||
5) Be glad
|
||||
|
||||
If it doesn't work out, you can ask the me. (Oh yeah, and you need to
|
||||
do 'insmod kernel/fuse.o' before running your program, in case you
|
||||
forgot).
|
||||
|
||||
See the file 'include/fuse.h' for documentation of the library interface.
|
||||
If it doesn't work out, please ask! Also see the file 'include/fuse.h' for
|
||||
detailed documentation of the library interface.
|
||||
|
||||
|
||||
Security
|
||||
@ -65,9 +62,8 @@ If you run 'make install', the fusermount program is installed
|
||||
set-user-id to root. This is done to allow normal users to mount
|
||||
their own filesystem implementations.
|
||||
|
||||
There must however be some limitations to forbid the Bad User to do
|
||||
Naughty Things with your Beautiful system. Currently those
|
||||
limitations are:
|
||||
There must however be some limitations, in order to prevent Bad User from
|
||||
doing nasty things. Currently those limitations are:
|
||||
|
||||
- The user can only mount on a mountpoint, for which it has write
|
||||
permission
|
||||
@ -75,16 +71,15 @@ limitations are:
|
||||
- The mountpoint is not a sticky directory which isn't owned by the
|
||||
user (like /tmp usually is)
|
||||
|
||||
- If the user doing the mount is not root, then no other user
|
||||
(including root) can access the contents of the mounted
|
||||
- No other user (including root) can access the contents of the mounted
|
||||
filesystem.
|
||||
|
||||
When linux will have private namespaces (as soon as version 2.5 comes
|
||||
out) then this third condition is useless and can be gotten rid of.
|
||||
When linux will have private namespaces (as soon as version 2.5 comes out
|
||||
hopefully) then this third condition is useless and can be gotten rid of.
|
||||
|
||||
Currently the first two conditions are checked by the fusermount
|
||||
program before doing the mount. This has the nice feature, that it's
|
||||
totally useless. Here's why:
|
||||
Currently the first two conditions are checked by the fusermount program
|
||||
before doing the mount. This has the nice feature, that it's totally
|
||||
useless. Here's why:
|
||||
|
||||
- user creates /tmp/mydir
|
||||
- user starts fusermount
|
||||
@ -96,6 +91,5 @@ totally useless. Here's why:
|
||||
So to make this secure, the checks must be done by the kernel. And so
|
||||
there is a patch (patch/ms_permission.patch) which does exactly this.
|
||||
This is against 2.4.14, but applies to some earlier kernels (not too
|
||||
much earlier though), and possibly some later (I couldn't know, could
|
||||
I?).
|
||||
much earlier though), and possibly some later.
|
||||
|
||||
|
11
TODO
Normal file
11
TODO
Normal file
@ -0,0 +1,11 @@
|
||||
- Better (but not too complex) library interface for open/read/write/close
|
||||
|
||||
- Permission checking for users other then the owner of the mount
|
||||
|
||||
- Improve efficiency of read and write operations
|
||||
|
||||
- Integrate (parts of) fusermount into mount(8)
|
||||
|
||||
- Statfs operation
|
||||
|
||||
- Etc, etc...
|
@ -15,58 +15,25 @@
|
||||
#include <signal.h>
|
||||
#include <utime.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <sys/fsuid.h>
|
||||
|
||||
static char *mount_point;
|
||||
static char *unmount_cmd;
|
||||
|
||||
static int set_creds(struct fuse_cred *cred)
|
||||
static int xmp_getattr(const char *path, struct stat *stbuf)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = setfsuid(cred->uid);
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
res = setfsgid(cred->gid);
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void restore_creds()
|
||||
{
|
||||
setfsuid(getuid());
|
||||
setfsgid(getgid());
|
||||
}
|
||||
|
||||
static int xmp_getattr(struct fuse_cred *cred, const char *path,
|
||||
struct stat *stbuf)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = lstat(path, stbuf);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_readlink(struct fuse_cred *cred, const char *path, char *buf,
|
||||
size_t size)
|
||||
static int xmp_readlink(const char *path, char *buf, size_t size)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = readlink(path, buf, size - 1);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
@ -75,18 +42,13 @@ static int xmp_readlink(struct fuse_cred *cred, const char *path, char *buf,
|
||||
}
|
||||
|
||||
|
||||
static int xmp_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h,
|
||||
fuse_dirfil_t filler)
|
||||
static int xmp_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *de;
|
||||
int res;
|
||||
int res = 0;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
dp = opendir(path);
|
||||
restore_creds();
|
||||
if(dp == NULL)
|
||||
return -errno;
|
||||
|
||||
@ -100,169 +62,121 @@ static int xmp_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h,
|
||||
return res;
|
||||
}
|
||||
|
||||
static int xmp_mknod(struct fuse_cred *cred, const char *path, mode_t mode,
|
||||
dev_t rdev)
|
||||
static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = mknod(path, mode, rdev);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_mkdir(struct fuse_cred *cred, const char *path, mode_t mode)
|
||||
static int xmp_mkdir(const char *path, mode_t mode)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = mkdir(path, mode);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_unlink(struct fuse_cred *cred, const char *path)
|
||||
static int xmp_unlink(const char *path)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = unlink(path);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_rmdir(struct fuse_cred *cred, const char *path)
|
||||
static int xmp_rmdir(const char *path)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = rmdir(path);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_symlink(struct fuse_cred *cred, const char *from,
|
||||
const char *to)
|
||||
static int xmp_symlink(const char *from, const char *to)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = symlink(from, to);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_rename(struct fuse_cred *cred, const char *from, const char *to)
|
||||
static int xmp_rename(const char *from, const char *to)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = rename(from, to);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_link(struct fuse_cred *cred, const char *from, const char *to)
|
||||
static int xmp_link(const char *from, const char *to)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = link(from, to);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_chmod(struct fuse_cred *cred, const char *path, mode_t mode)
|
||||
static int xmp_chmod(const char *path, mode_t mode)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = chmod(path, mode);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_chown(struct fuse_cred *cred, const char *path, uid_t uid,
|
||||
gid_t gid)
|
||||
static int xmp_chown(const char *path, uid_t uid, gid_t gid)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = lchown(path, uid, gid);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_truncate(struct fuse_cred *cred, const char *path, off_t size)
|
||||
static int xmp_truncate(const char *path, off_t size)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = truncate(path, size);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_utime(struct fuse_cred *cred, const char *path,
|
||||
struct utimbuf *buf)
|
||||
static int xmp_utime(const char *path, struct utimbuf *buf)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = utime(path, buf);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
@ -270,15 +184,11 @@ static int xmp_utime(struct fuse_cred *cred, const char *path,
|
||||
}
|
||||
|
||||
|
||||
static int xmp_open(struct fuse_cred *cred, const char *path, int flags)
|
||||
static int xmp_open(const char *path, int flags)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
res = open(path, flags);
|
||||
restore_creds();
|
||||
if(res == -1)
|
||||
return -errno;
|
||||
|
||||
@ -286,17 +196,12 @@ static int xmp_open(struct fuse_cred *cred, const char *path, int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xmp_read(struct fuse_cred *cred, const char *path, char *buf,
|
||||
size_t size, off_t offset)
|
||||
static int xmp_read(const char *path, char *buf, size_t size, off_t offset)
|
||||
{
|
||||
int fd;
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
fd = open(path, O_RDONLY);
|
||||
restore_creds();
|
||||
if(fd == -1)
|
||||
return -errno;
|
||||
|
||||
@ -308,17 +213,13 @@ static int xmp_read(struct fuse_cred *cred, const char *path, char *buf,
|
||||
return res;
|
||||
}
|
||||
|
||||
static int xmp_write(struct fuse_cred *cred, const char *path, const char *buf,
|
||||
size_t size, off_t offset)
|
||||
static int xmp_write(const char *path, const char *buf, size_t size,
|
||||
off_t offset)
|
||||
{
|
||||
int fd;
|
||||
int res;
|
||||
|
||||
res = set_creds(cred);
|
||||
if(res)
|
||||
return res;
|
||||
fd = open(path, O_WRONLY);
|
||||
restore_creds();
|
||||
if(fd == -1)
|
||||
return -errno;
|
||||
|
||||
@ -381,10 +282,8 @@ static struct fuse_operations xmp_oper = {
|
||||
|
||||
static void cleanup()
|
||||
{
|
||||
char *buf = (char *) malloc(strlen(mount_point) + 128);
|
||||
sprintf(buf, "fusermount -u %s", mount_point);
|
||||
system(buf);
|
||||
free(buf);
|
||||
close(0);
|
||||
system(unmount_cmd);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -395,7 +294,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if(argc < 2) {
|
||||
fprintf(stderr,
|
||||
"usage: %s mount_dir [options] \n"
|
||||
"usage: %s unmount_cmd [options] \n"
|
||||
"Options:\n"
|
||||
" -d enable debug output\n"
|
||||
" -s disable multithreaded operation\n",
|
||||
@ -404,7 +303,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
argctr = 1;
|
||||
mount_point = argv[argctr++];
|
||||
unmount_cmd = argv[argctr++];
|
||||
|
||||
set_signal_handlers();
|
||||
atexit(cleanup);
|
||||
@ -430,8 +329,6 @@ int main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
setgroups(0, NULL);
|
||||
|
||||
fuse = fuse_new(0, flags);
|
||||
fuse_set_operations(fuse, &xmp_oper);
|
||||
fuse_loop(fuse);
|
||||
|
@ -21,32 +21,19 @@ typedef struct fuse_dirhandle *fuse_dirh_t;
|
||||
/** Function to add an entry in a getdir() operation */
|
||||
typedef int (*fuse_dirfil_t) (fuse_dirh_t, const char *, int type);
|
||||
|
||||
/** Credentials for an operation, these are determined by the fsuid
|
||||
and fsgid of the calling process */
|
||||
struct fuse_cred {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
/* FIXME: supplementary groups should also be included */
|
||||
/* (And capabilities???) */
|
||||
};
|
||||
|
||||
/**
|
||||
* The file system operations:
|
||||
*
|
||||
* Most of these should work very similarly to the well known UNIX
|
||||
* file system operations. Exceptions are:
|
||||
*
|
||||
* - All operations get a fuse_cred structure by which the filesystem
|
||||
* implementation can check, whether the operation is permitted or
|
||||
* not.
|
||||
*
|
||||
* - All operations should return the negated error value (-errno) on
|
||||
* error.
|
||||
*
|
||||
* - readlink() should fill the buffer with a null terminated string.
|
||||
* The buffer size argument includes the space for the terminating
|
||||
* null character. If the linkname is too long to fit in the buffer,
|
||||
* it should be truncated. The return value should be 0 for success.
|
||||
* - readlink() should fill the buffer with a null terminated string. The
|
||||
* buffer size argument includes the space for the terminating null
|
||||
* character. If the linkname is too long to fit in the buffer, it should
|
||||
* be truncated. The return value should be 0 for success.
|
||||
*
|
||||
* - getdir() is the opendir(), readdir(), ..., closedir() sequence
|
||||
* in one call. For each directory entry the filldir parameter should
|
||||
@ -62,25 +49,26 @@ struct fuse_cred {
|
||||
*
|
||||
* - read(), write() are not passed a filehandle, but rather a
|
||||
* pathname. The offset of the read and write is passed as the last
|
||||
* argument, like the pread() and pwrite() system calls. */
|
||||
* argument, like the pread() and pwrite() system calls.
|
||||
*/
|
||||
struct fuse_operations {
|
||||
int (*getattr) (struct fuse_cred *, const char *, struct stat *);
|
||||
int (*readlink) (struct fuse_cred *, const char *, char *, size_t);
|
||||
int (*getdir) (struct fuse_cred *, const char *, fuse_dirh_t, fuse_dirfil_t);
|
||||
int (*mknod) (struct fuse_cred *, const char *, mode_t, dev_t);
|
||||
int (*mkdir) (struct fuse_cred *, const char *, mode_t);
|
||||
int (*unlink) (struct fuse_cred *, const char *);
|
||||
int (*rmdir) (struct fuse_cred *, const char *);
|
||||
int (*symlink) (struct fuse_cred *, const char *, const char *);
|
||||
int (*rename) (struct fuse_cred *, const char *, const char *);
|
||||
int (*link) (struct fuse_cred *, const char *, const char *);
|
||||
int (*chmod) (struct fuse_cred *, const char *, mode_t);
|
||||
int (*chown) (struct fuse_cred *, const char *, uid_t, gid_t);
|
||||
int (*truncate) (struct fuse_cred *, const char *, off_t);
|
||||
int (*utime) (struct fuse_cred *, const char *, struct utimbuf *);
|
||||
int (*open) (struct fuse_cred *, const char *, int);
|
||||
int (*read) (struct fuse_cred *, const char *, char *, size_t, off_t);
|
||||
int (*write) (struct fuse_cred *, const char *, const char *, size_t, off_t);
|
||||
int (*getattr) (const char *, struct stat *);
|
||||
int (*readlink) (const char *, char *, size_t);
|
||||
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
|
||||
int (*mknod) (const char *, mode_t, dev_t);
|
||||
int (*mkdir) (const char *, mode_t);
|
||||
int (*unlink) (const char *);
|
||||
int (*rmdir) (const char *);
|
||||
int (*symlink) (const char *, const char *);
|
||||
int (*rename) (const char *, const char *);
|
||||
int (*link) (const char *, const char *);
|
||||
int (*chmod) (const char *, mode_t);
|
||||
int (*chown) (const char *, uid_t, gid_t);
|
||||
int (*truncate) (const char *, off_t);
|
||||
int (*utime) (const char *, struct utimbuf *);
|
||||
int (*open) (const char *, int);
|
||||
int (*read) (const char *, char *, size_t, off_t);
|
||||
int (*write) (const char *, const char *, size_t, off_t);
|
||||
};
|
||||
|
||||
/* FUSE flags: */
|
||||
|
@ -149,8 +149,6 @@ struct fuse_in_header {
|
||||
int unique;
|
||||
enum fuse_opcode opcode;
|
||||
unsigned long ino;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
};
|
||||
|
||||
struct fuse_out_header {
|
||||
|
@ -18,6 +18,10 @@ install-exec-local: fuse.o
|
||||
$(INSTALL) -m 644 fuse.o $(DESTDIR)$(fusemoduledir)/fuse.o
|
||||
/sbin/depmod -a
|
||||
|
||||
uninstall-local:
|
||||
rm -f $(DESTDIR)$(fusemoduledir)/fuse.o
|
||||
/sbin/depmod -a
|
||||
|
||||
clean-local:
|
||||
rm -f *.o *.s
|
||||
|
||||
|
16
kernel/dir.c
16
kernel/dir.c
@ -117,7 +117,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* create needs to return a positive entry, so this also does a lookup */
|
||||
/* create needs to return a positive entry, so this is actually an
|
||||
mknod+lookup */
|
||||
static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
|
||||
int rdev)
|
||||
{
|
||||
@ -305,14 +306,11 @@ static int fuse_permission(struct inode *inode, int mask)
|
||||
{
|
||||
struct fuse_conn *fc = INO_FC(inode);
|
||||
|
||||
/* (too) simple protection for non-privileged mounts */
|
||||
if(fc->uid) {
|
||||
if(current->fsuid == fc->uid)
|
||||
return 0;
|
||||
else
|
||||
return -EACCES;
|
||||
}
|
||||
return 0;
|
||||
/* (too) simple protection */
|
||||
if(current->fsuid == fc->uid)
|
||||
return 0;
|
||||
else
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
static int fuse_revalidate(struct dentry *entry)
|
||||
|
@ -95,7 +95,7 @@ struct fuse_out {
|
||||
void *arg;
|
||||
};
|
||||
|
||||
#define FUSE_IN_INIT { {0, 0, 0, current->fsuid, current->fsgid}, 0, 0 }
|
||||
#define FUSE_IN_INIT { {0, 0, 0}, 0, 0 }
|
||||
#define FUSE_OUT_INIT { {0, 0}, 0, 0, 0 }
|
||||
|
||||
|
||||
|
108
lib/fuse.c
108
lib/fuse.c
@ -354,33 +354,28 @@ static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
|
||||
}
|
||||
|
||||
res = write(f->fd, outbuf, outsize);
|
||||
if(res == -1)
|
||||
perror("writing fuse device");
|
||||
if(res == -1) {
|
||||
/* ENOENT means the operation was interrupted */
|
||||
if(errno != ENOENT)
|
||||
perror("writing fuse device");
|
||||
}
|
||||
|
||||
free(outbuf);
|
||||
}
|
||||
|
||||
static void fill_cred(struct fuse_in_header *in, struct fuse_cred *cred)
|
||||
{
|
||||
cred->uid = in->uid;
|
||||
cred->gid = in->gid;
|
||||
}
|
||||
|
||||
static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
|
||||
{
|
||||
int res;
|
||||
char *path;
|
||||
struct stat buf;
|
||||
struct fuse_lookup_out arg;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path_name(f, in->ino, name);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.getattr)
|
||||
res = f->op.getattr(&cred, path, &buf);
|
||||
res = f->op.getattr(path, &buf);
|
||||
free(path);
|
||||
}
|
||||
if(res == 0) {
|
||||
@ -402,15 +397,13 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
|
||||
char *path;
|
||||
struct stat buf;
|
||||
struct fuse_getattr_out arg;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path(f, in->ino);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.getattr)
|
||||
res = f->op.getattr(&cred, path, &buf);
|
||||
res = f->op.getattr(path, &buf);
|
||||
free(path);
|
||||
}
|
||||
if(res == 0)
|
||||
@ -419,20 +412,19 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
|
||||
send_reply(f, in, res, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
int do_chmod(struct fuse *f, struct fuse_cred *cred, const char *path,
|
||||
struct fuse_attr *attr)
|
||||
int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = -ENOSYS;
|
||||
if(f->op.chmod)
|
||||
res = f->op.chmod(cred, path, attr->mode);
|
||||
res = f->op.chmod(path, attr->mode);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int do_chown(struct fuse *f, struct fuse_cred *cred, const char *path,
|
||||
struct fuse_attr *attr, int valid)
|
||||
int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
|
||||
int valid)
|
||||
{
|
||||
int res;
|
||||
uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
|
||||
@ -440,25 +432,23 @@ int do_chown(struct fuse *f, struct fuse_cred *cred, const char *path,
|
||||
|
||||
res = -ENOSYS;
|
||||
if(f->op.chown)
|
||||
res = f->op.chown(cred, path, uid, gid);
|
||||
res = f->op.chown(path, uid, gid);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int do_truncate(struct fuse *f, struct fuse_cred *cred, const char *path,
|
||||
struct fuse_attr *attr)
|
||||
int do_truncate(struct fuse *f, const char *path, struct fuse_attr *attr)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = -ENOSYS;
|
||||
if(f->op.truncate)
|
||||
res = f->op.truncate(cred, path, attr->size);
|
||||
res = f->op.truncate(path, attr->size);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int do_utime(struct fuse *f, struct fuse_cred *cred, const char *path,
|
||||
struct fuse_attr *attr)
|
||||
int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
|
||||
{
|
||||
int res;
|
||||
struct utimbuf buf;
|
||||
@ -466,7 +456,7 @@ int do_utime(struct fuse *f, struct fuse_cred *cred, const char *path,
|
||||
buf.modtime = attr->mtime;
|
||||
res = -ENOSYS;
|
||||
if(f->op.utime)
|
||||
res = f->op.utime(cred, path, &buf);
|
||||
res = f->op.utime(path, &buf);
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -479,9 +469,7 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in,
|
||||
int valid = arg->valid;
|
||||
struct fuse_attr *attr = &arg->attr;
|
||||
struct fuse_setattr_out outarg;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path(f, in->ino);
|
||||
if(path != NULL) {
|
||||
@ -489,16 +477,16 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in,
|
||||
if(f->op.getattr) {
|
||||
res = 0;
|
||||
if(!res && (valid & FATTR_MODE))
|
||||
res = do_chmod(f, &cred, path, attr);
|
||||
res = do_chmod(f, path, attr);
|
||||
if(!res && (valid & (FATTR_UID | FATTR_GID)))
|
||||
res = do_chown(f, &cred, path, attr, valid);
|
||||
res = do_chown(f, path, attr, valid);
|
||||
if(!res && (valid & FATTR_SIZE))
|
||||
res = do_truncate(f, &cred, path, attr);
|
||||
res = do_truncate(f, path, attr);
|
||||
if(!res && (valid & FATTR_UTIME))
|
||||
res = do_utime(f, &cred, path, attr);
|
||||
res = do_utime(f, path, attr);
|
||||
if(!res) {
|
||||
struct stat buf;
|
||||
res = f->op.getattr(&cred, path, &buf);
|
||||
res = f->op.getattr(path, &buf);
|
||||
if(!res)
|
||||
convert_stat(&buf, &outarg.attr);
|
||||
}
|
||||
@ -513,15 +501,13 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in)
|
||||
int res;
|
||||
char link[PATH_MAX + 1];
|
||||
char *path;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path(f, in->ino);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.readlink)
|
||||
res = f->op.readlink(&cred, path, link, sizeof(link));
|
||||
res = f->op.readlink(path, link, sizeof(link));
|
||||
free(path);
|
||||
}
|
||||
link[PATH_MAX] = '\0';
|
||||
@ -534,9 +520,7 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in)
|
||||
struct fuse_getdir_out arg;
|
||||
struct fuse_dirhandle dh;
|
||||
char *path;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
dh.fuse = f;
|
||||
dh.fp = tmpfile();
|
||||
dh.dir = in->ino;
|
||||
@ -545,7 +529,7 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in)
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.getdir)
|
||||
res = f->op.getdir(&cred, path, &dh, (fuse_dirfil_t) fill_dir);
|
||||
res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
|
||||
free(path);
|
||||
}
|
||||
fflush(dh.fp);
|
||||
@ -561,17 +545,15 @@ static void do_mknod(struct fuse *f, struct fuse_in_header *in,
|
||||
char *path;
|
||||
struct fuse_mknod_out outarg;
|
||||
struct stat buf;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path_name(f, in->ino, inarg->name);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.mknod && f->op.getattr) {
|
||||
res = f->op.mknod(&cred, path, inarg->mode, inarg->rdev);
|
||||
res = f->op.mknod(path, inarg->mode, inarg->rdev);
|
||||
if(res == 0)
|
||||
res = f->op.getattr(&cred, path, &buf);
|
||||
res = f->op.getattr(path, &buf);
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
@ -589,15 +571,13 @@ static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
|
||||
{
|
||||
int res;
|
||||
char *path;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path_name(f, in->ino, inarg->name);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.mkdir)
|
||||
res = f->op.mkdir(&cred, path, inarg->mode);
|
||||
res = f->op.mkdir(path, inarg->mode);
|
||||
free(path);
|
||||
}
|
||||
send_reply(f, in, res, NULL, 0);
|
||||
@ -607,20 +587,18 @@ static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
|
||||
{
|
||||
int res;
|
||||
char *path;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path_name(f, in->ino, name);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(in->opcode == FUSE_UNLINK) {
|
||||
if(f->op.unlink)
|
||||
res = f->op.unlink(&cred, path);
|
||||
res = f->op.unlink(path);
|
||||
}
|
||||
else {
|
||||
if(f->op.rmdir)
|
||||
res = f->op.rmdir(&cred, path);
|
||||
res = f->op.rmdir(path);
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
@ -634,15 +612,13 @@ static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
|
||||
{
|
||||
int res;
|
||||
char *path;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path_name(f, in->ino, name);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.symlink)
|
||||
res = f->op.symlink(&cred, link, path);
|
||||
res = f->op.symlink(link, path);
|
||||
free(path);
|
||||
}
|
||||
send_reply(f, in, res, NULL, 0);
|
||||
@ -658,9 +634,7 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
|
||||
char *newname = inarg->names + strlen(oldname) + 1;
|
||||
char *oldpath;
|
||||
char *newpath;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
oldpath = get_path_name(f, olddir, oldname);
|
||||
if(oldpath != NULL) {
|
||||
@ -668,7 +642,7 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
|
||||
if(newpath != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.rename)
|
||||
res = f->op.rename(&cred, oldpath, newpath);
|
||||
res = f->op.rename(oldpath, newpath);
|
||||
if(res == 0)
|
||||
rename_node(f, olddir, oldname, newdir, newname);
|
||||
free(newpath);
|
||||
@ -684,9 +658,7 @@ static void do_link(struct fuse *f, struct fuse_in_header *in,
|
||||
int res;
|
||||
char *oldpath;
|
||||
char *newpath;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
oldpath = get_path(f, in->ino);
|
||||
if(oldpath != NULL) {
|
||||
@ -694,7 +666,7 @@ static void do_link(struct fuse *f, struct fuse_in_header *in,
|
||||
if(newpath != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.link)
|
||||
res = f->op.link(&cred, oldpath, newpath);
|
||||
res = f->op.link(oldpath, newpath);
|
||||
free(newpath);
|
||||
}
|
||||
free(oldpath);
|
||||
@ -707,15 +679,13 @@ static void do_open(struct fuse *f, struct fuse_in_header *in,
|
||||
{
|
||||
int res;
|
||||
char *path;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path(f, in->ino);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.open)
|
||||
res = f->op.open(&cred, path, arg->flags);
|
||||
res = f->op.open(path, arg->flags);
|
||||
free(path);
|
||||
}
|
||||
send_reply(f, in, res, NULL, 0);
|
||||
@ -728,15 +698,13 @@ static void do_read(struct fuse *f, struct fuse_in_header *in,
|
||||
char *path;
|
||||
char *buf = (char *) malloc(arg->size);
|
||||
size_t size;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path(f, in->ino);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.read)
|
||||
res = f->op.read(&cred, path, buf, arg->size, arg->offset);
|
||||
res = f->op.read(path, buf, arg->size, arg->offset);
|
||||
free(path);
|
||||
}
|
||||
|
||||
@ -755,15 +723,13 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
|
||||
{
|
||||
int res;
|
||||
char *path;
|
||||
struct fuse_cred cred;
|
||||
|
||||
fill_cred(in, &cred);
|
||||
res = -ENOENT;
|
||||
path = get_path(f, in->ino);
|
||||
if(path != NULL) {
|
||||
res = -ENOSYS;
|
||||
if(f->op.write)
|
||||
res = f->op.write(&cred, path, arg->buf, arg->size, arg->offset);
|
||||
res = f->op.write(path, arg->buf, arg->size, arg->offset);
|
||||
free(path);
|
||||
}
|
||||
|
||||
@ -905,11 +871,13 @@ void fuse_loop(struct fuse *f)
|
||||
res = read(f->fd, inbuf, sizeof(inbuf));
|
||||
if(res == -1) {
|
||||
perror("reading fuse device");
|
||||
continue;
|
||||
/* BAD... This will happen again */
|
||||
exit(1);
|
||||
}
|
||||
if((size_t) res < sizeof(struct fuse_in_header)) {
|
||||
fprintf(stderr, "short read on fuse device\n");
|
||||
continue;
|
||||
/* Cannot happen */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cmd = (struct cmd *) malloc(sizeof(struct cmd));
|
||||
|
@ -5,6 +5,17 @@
|
||||
This program can be distributed under the terms of the GNU GPL.
|
||||
See the file COPYING.
|
||||
*/
|
||||
/* This program does the mounting and unmounting of FUSE filesystems */
|
||||
|
||||
/*
|
||||
* NOTE: This program should be part of (or be called from) /bin/mount
|
||||
*
|
||||
* Unless that is done, operations on /etc/mtab are not under lock, and so
|
||||
* data in it may be lost. (I will _not_ reimplement that locking, and
|
||||
* anyway that should be done in libc, if possible. But probably it is
|
||||
* not).
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -13,6 +24,8 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <mntent.h>
|
||||
#include <limits.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
@ -28,12 +41,6 @@
|
||||
#define FUSE_DEV "/proc/fs/fuse/dev"
|
||||
|
||||
const char *progname;
|
||||
const char *fusermnt = "/etc/fusermnt";
|
||||
const char *fusermnt_temp = "/etc/fusermnt~";
|
||||
|
||||
#define FUSE_USERNAME_MAX 256
|
||||
#define FUSE_PATH_MAX 4096
|
||||
#define FUSEMNT_LINE_MAX (FUSE_USERNAME_MAX + 1 + FUSE_PATH_MAX + 1)
|
||||
|
||||
static const char *get_user_name()
|
||||
{
|
||||
@ -46,152 +53,136 @@ static const char *get_user_name()
|
||||
}
|
||||
}
|
||||
|
||||
static int fusermnt_lock()
|
||||
static int add_mount(const char *dev, const char *mnt, const char *type)
|
||||
{
|
||||
int res;
|
||||
const char *lockfile = fusermnt;
|
||||
int fd = open(lockfile, O_WRONLY | O_CREAT, 0644);
|
||||
if(fd == -1) {
|
||||
fprintf(stderr, "%s: failed to open lockfile %s: %s\n", progname,
|
||||
lockfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
res = lockf(fd, F_LOCK, 0);
|
||||
if(res == -1) {
|
||||
fprintf(stderr, "%s: failed to lock file %s: %s\n", progname,
|
||||
lockfile, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void fusermnt_unlock(int fd)
|
||||
{
|
||||
lockf(fd, F_UNLCK, 0);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
static int add_mount(const char *mnt)
|
||||
{
|
||||
const char *mtab = _PATH_MOUNTED;
|
||||
struct mntent ent;
|
||||
FILE *fp;
|
||||
int lockfd;
|
||||
const char *user = get_user_name();
|
||||
if(user == NULL)
|
||||
return -1;
|
||||
char *opts;
|
||||
|
||||
lockfd = fusermnt_lock();
|
||||
if(lockfd == -1)
|
||||
return -1;
|
||||
|
||||
fp = fopen(fusermnt, "a");
|
||||
fp = setmntent(mtab, "a");
|
||||
if(fp == NULL) {
|
||||
fprintf(stderr, "%s: could not open %s for writing: %s\n", progname,
|
||||
fusermnt, strerror(errno));
|
||||
fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(getuid() != 0) {
|
||||
const char *user = get_user_name();
|
||||
if(user == NULL)
|
||||
return -1;
|
||||
|
||||
opts = malloc(strlen(user) + 128);
|
||||
if(opts != NULL)
|
||||
sprintf(opts, "rw,nosuid,nodev,user=%s", user);
|
||||
}
|
||||
else
|
||||
opts = strdup("rw,nosuid,nodev");
|
||||
|
||||
if(opts == NULL)
|
||||
return -1;
|
||||
|
||||
ent.mnt_fsname = (char *) dev;
|
||||
ent.mnt_dir = (char *) mnt;
|
||||
ent.mnt_type = (char *) type;
|
||||
ent.mnt_opts = opts;
|
||||
ent.mnt_freq = 0;
|
||||
ent.mnt_passno = 0;
|
||||
res = addmntent(fp, &ent);
|
||||
if(res != 0) {
|
||||
fprintf(stderr, "%s: failed to add entry to %s: %s\n", progname,
|
||||
mtab, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
fprintf(fp, "%s %s\n", user, mnt);
|
||||
fclose(fp);
|
||||
|
||||
fusermnt_unlock(lockfd);
|
||||
|
||||
endmntent(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remove_mount(const char *mnt)
|
||||
{
|
||||
int res;
|
||||
const char *mtab = _PATH_MOUNTED;
|
||||
const char *mtab_new = _PATH_MOUNTED "~";
|
||||
struct mntent *entp;
|
||||
FILE *fp;
|
||||
FILE *newfp;
|
||||
int lockfd;
|
||||
const char *user = NULL;
|
||||
int found;
|
||||
char buf[FUSEMNT_LINE_MAX + 1];
|
||||
const char *user = get_user_name();
|
||||
if(user == NULL)
|
||||
return -1;
|
||||
|
||||
lockfd = fusermnt_lock();
|
||||
if(lockfd == -1)
|
||||
return -1;
|
||||
|
||||
fp = fopen(fusermnt, "r");
|
||||
fp = setmntent(mtab, "r");
|
||||
if(fp == NULL) {
|
||||
fprintf(stderr, "%s: could not open %s for reading: %s\n", progname,
|
||||
fusermnt, strerror(errno));
|
||||
fusermnt_unlock(lockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
newfp = fopen(fusermnt_temp, "w");
|
||||
if(newfp == NULL) {
|
||||
fprintf(stderr, "%s: could not open %s for writing: %s\n", progname,
|
||||
fusermnt_temp, strerror(errno));
|
||||
fclose(fp);
|
||||
fusermnt_unlock(lockfd);
|
||||
return -1;
|
||||
fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
while(fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
char *end = buf + strlen(buf) - 1;
|
||||
char *p;
|
||||
if(*end != '\n') {
|
||||
fprintf(stderr, "%s: line too long in file %s\n", progname,
|
||||
fusermnt);
|
||||
while(fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
char *end = buf + strlen(buf) - 1;
|
||||
if(*end == '\n')
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*end = '\0';
|
||||
newfp = setmntent(mtab_new, "w");
|
||||
if(newfp == NULL) {
|
||||
fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab_new,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(getuid() != 0) {
|
||||
user = get_user_name();
|
||||
if(user == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(p = buf; *p != '\0' && *p != ' '; p++);
|
||||
if(*p == '\0') {
|
||||
fprintf(stderr, "%s: malformed line in file %s\n", progname,
|
||||
fusermnt);
|
||||
continue;
|
||||
found = 0;
|
||||
while((entp = getmntent(fp)) != NULL) {
|
||||
int remove = 0;
|
||||
if(!found && strcmp(entp->mnt_dir, mnt) == 0 &&
|
||||
strcmp(entp->mnt_type, "fuse") == 0) {
|
||||
if(user == NULL)
|
||||
remove = 1;
|
||||
else {
|
||||
char *p = strstr(entp->mnt_opts, "user=");
|
||||
if(p != NULL && strcmp(p + 5, user) == 0)
|
||||
remove = 1;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
p++;
|
||||
if(!found && strcmp(user, buf) == 0 && strcmp(mnt, p) == 0) {
|
||||
int res = umount(mnt);
|
||||
if(remove) {
|
||||
res = umount(mnt);
|
||||
if(res == -1) {
|
||||
found = -1;
|
||||
fprintf(stderr, "%s: umount of %s failed: %s\n", progname,
|
||||
fprintf(stderr, "%s: failed to unmount %s: %s\n", progname,
|
||||
mnt, strerror(errno));
|
||||
found = -1;
|
||||
break;
|
||||
}
|
||||
found = 1;
|
||||
}
|
||||
else
|
||||
fprintf(newfp, "%s %s\n", buf, p);
|
||||
else {
|
||||
res = addmntent(newfp, entp);
|
||||
if(res != 0) {
|
||||
fprintf(stderr, "%s: failed to add entry to %s: %s", progname,
|
||||
mtab_new, strerror(errno));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fclose(newfp);
|
||||
|
||||
endmntent(fp);
|
||||
endmntent(newfp);
|
||||
|
||||
if(found == 1) {
|
||||
int res;
|
||||
res = rename(fusermnt_temp, fusermnt);
|
||||
res = rename(mtab_new, mtab);
|
||||
if(res == -1) {
|
||||
fprintf(stderr, "%s: failed to rename %s to %s: %s\n",
|
||||
progname, fusermnt_temp, fusermnt, strerror(errno));
|
||||
fusermnt_unlock(lockfd);
|
||||
fprintf(stderr, "%s: failed to rename %s to %s: %s\n", progname,
|
||||
mtab_new, mtab, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!found)
|
||||
fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
|
||||
mnt, fusermnt);
|
||||
unlink(fusermnt_temp);
|
||||
fusermnt_unlock(lockfd);
|
||||
mnt, mtab);
|
||||
unlink(mtab_new);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fusermnt_unlock(lockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -347,6 +338,19 @@ static int mount_fuse(const char *mnt)
|
||||
return -1;
|
||||
|
||||
fd = open(dev, O_RDWR);
|
||||
if(fd == -1) {
|
||||
int status;
|
||||
pid_t pid = fork();
|
||||
if(pid == 0) {
|
||||
setuid(0);
|
||||
execl("/sbin/modprobe", "modprobe", "fuse", NULL);
|
||||
exit(1);
|
||||
}
|
||||
if(pid != -1)
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
fd = open(dev, O_RDWR);
|
||||
}
|
||||
if(fd == -1) {
|
||||
fprintf(stderr, "%s: unable to open fuse device %s: %s\n", progname,
|
||||
dev, strerror(errno));
|
||||
@ -357,7 +361,7 @@ static int mount_fuse(const char *mnt)
|
||||
if(res == -1)
|
||||
return -1;
|
||||
|
||||
res = add_mount(mnt);
|
||||
res = add_mount(dev, mnt, type);
|
||||
if(res == -1) {
|
||||
umount(mnt);
|
||||
return -1;
|
||||
@ -366,16 +370,22 @@ static int mount_fuse(const char *mnt)
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int do_umount(const char *mnt)
|
||||
static char *resolve_path(const char *orig, int unmount)
|
||||
{
|
||||
int res;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
res = remove_mount(mnt);
|
||||
if(res == -1)
|
||||
return -1;
|
||||
/* Resolving at unmount can only be done very carefully, not touching
|
||||
the mountpoint... So for the moment it's not done. */
|
||||
if(unmount)
|
||||
return strdup(orig);
|
||||
|
||||
umount(mnt);
|
||||
return 0;
|
||||
if(realpath(orig, buf) == NULL) {
|
||||
fprintf(stderr, "%s: Bad mount point %s: %s\n", progname, orig,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
static void usage()
|
||||
@ -384,7 +394,7 @@ static void usage()
|
||||
"%s: [options] mountpoint [program [args ...]]\n"
|
||||
"Options:\n"
|
||||
" -h print help\n"
|
||||
" -u umount\n",
|
||||
" -u unmount\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
@ -394,11 +404,14 @@ int main(int argc, char *argv[])
|
||||
int a;
|
||||
int fd;
|
||||
int res;
|
||||
char *mnt = NULL;
|
||||
int umount = 0;
|
||||
char *origmnt;
|
||||
char *mnt;
|
||||
int unmount = 0;
|
||||
char **userprog;
|
||||
int numargs;
|
||||
char **newargv;
|
||||
char mypath[PATH_MAX];
|
||||
char *unmount_cmd;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
@ -412,7 +425,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
umount = 1;
|
||||
unmount = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -426,10 +439,20 @@ int main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mnt = argv[a++];
|
||||
origmnt = argv[a++];
|
||||
|
||||
if(getpid() != 0)
|
||||
drop_privs();
|
||||
|
||||
mnt = resolve_path(origmnt, unmount);
|
||||
if(mnt == NULL)
|
||||
exit(1);
|
||||
|
||||
if(getpid() != 0)
|
||||
restore_privs();
|
||||
|
||||
if(umount) {
|
||||
res = do_umount(mnt);
|
||||
if(unmount) {
|
||||
res = remove_mount(mnt);
|
||||
if(res == -1)
|
||||
exit(1);
|
||||
|
||||
@ -454,23 +477,36 @@ int main(int argc, char *argv[])
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* Strangely this doesn't work after dropping permissions... */
|
||||
res = readlink("/proc/self/exe", mypath, sizeof(mypath) - 1);
|
||||
if(res == -1) {
|
||||
fprintf(stderr, "%s: failed to determine self path: %s\n",
|
||||
progname, strerror(errno));
|
||||
strcpy(mypath, "fusermount");
|
||||
fprintf(stderr, "using %s as the default\n", mypath);
|
||||
}
|
||||
else
|
||||
mypath[res] = '\0';
|
||||
|
||||
/* Drop setuid/setgid permissions */
|
||||
setuid(getuid());
|
||||
setgid(getgid());
|
||||
|
||||
|
||||
unmount_cmd = (char *) malloc(strlen(mypath) + strlen(mnt) + 64);
|
||||
sprintf(unmount_cmd, "%s -u %s", mypath, mnt);
|
||||
|
||||
newargv = (char **) malloc(sizeof(char *) * (numargs + 2));
|
||||
newargv[0] = userprog[0];
|
||||
newargv[1] = mnt;
|
||||
newargv[1] = unmount_cmd;
|
||||
for(a = 1; a < numargs; a++)
|
||||
newargv[a+1] = userprog[a];
|
||||
newargv[numargs+1] = NULL;
|
||||
|
||||
execv(userprog[0], newargv);
|
||||
execvp(userprog[0], newargv);
|
||||
fprintf(stderr, "%s: failed to exec %s: %s\n", progname, userprog[0],
|
||||
strerror(errno));
|
||||
|
||||
execl("/proc/self/exe", progname, "-u", mnt, NULL);
|
||||
fprintf(stderr, "%s: failed to exec self: %s\n", progname,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
close(0);
|
||||
system(unmount_cmd);
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user