diff options
author | Stefan Siegl <stesie@brokenpipe.de> | 2005-12-04 18:20:44 +0000 |
---|---|---|
committer | Stefan Siegl <stesie@brokenpipe.de> | 2005-12-04 18:20:44 +0000 |
commit | 137e7d8686a0f91981d7589c91acdfccf381d139 (patch) | |
tree | c048b9683308d9ea43e49b43ae2af00d67b39c34 | |
parent | 0a013d00e206e5d0e5e44812b0bff2752b9ce872 (diff) |
test_allow_root_or_other: new function, check whether or not to allow filesystem
access according to the allow_root and allow_other flags
netfs_validate_stat: call new test_allow_root_or_other function
netfs_attempt_statfs, netfs_attempt_syncfs: likewise.
netfs_attempt_readlink: check access permission (including
test_allow_root_or_other call) before checking whether the requested
action is supported at all
netfs_attempt_create_file, netfs_attempt_chown, netfs_attempt_mkdir,
netfs_attempt_chmod, netfs_attempt_mkfile, netfs_attempt_sync,
netfs_attempt_unlink, netfs_attempt_set_size, netfs_attempt_mkdev,
netfs_attempt_link, netfs_attempt_rmdir, netfs_attempt_mksymlink,
netfs_attempt_rename, netfs_attempt_write, netfs_attempt_utimes,
netfs_attempt_read, netfs_get_dirents: likewise.
-rw-r--r-- | netfs.c | 304 |
1 files changed, 202 insertions, 102 deletions
@@ -56,16 +56,60 @@ static int fuse_dirent_helper_compat(fuse_dirh_t handle, const char *name, int type); +/* Check whether to allow access to a node, testing the allow_root and + * allow_other flag. This does not check whether default permissions + * are okay to allow access. + * + * Return: 0 if access is to be granted, EPERM otherwise + * + * Sidenote: This function is mainly called from netfs_validate_stat which in + * turn is called by any other of the netfs-operation-functions. This + * is, we don't have to call this from all of the operation-functions + * since netfs_validate_stat is called anyways! + */ +static error_t +test_allow_root_or_other (struct iouser *cred) +{ + FUNC_PROLOGUE("test_allow_root_or_other"); + + /* if allow_other is set, access is okay in any case */ + if(libfuse_params.allow_other) + FUNC_RETURN_FMT(0, "allow_other is set"); + + unsigned int i; + uid_t proc_uid = getuid(); + for(i = 0; i < cred->uids->num; i ++) + { + DEBUG("test_allow", "testing for uid=%d\n", cred->uids->ids[i]); + + if(cred->uids->ids[i] == 0 && libfuse_params.allow_root) + FUNC_RETURN_FMT(0, "allowing access for root"); + + if(cred->uids->ids[i] == proc_uid) + FUNC_RETURN_FMT(0, "allowing access for owner"); + } + + /* iouser is not the "filesystem-owner" and allow_other is not set, + * or iouser is root but allow_root is not set either */ + FUNC_EPILOGUE(EPERM); +} + + + /* Make sure that NP->nn_stat is filled with current information. CRED - identifies the user responsible for the operation. */ + identifies the user responsible for the operation. + + If the user `CRED' is not allowed to perform any operation (considering + the allow_root and allow_other flags), return EPERM. */ error_t netfs_validate_stat (struct node *node, struct iouser *cred) { - (void) cred; - FUNC_PROLOGUE_NODE("netfs_validate_stat", node); error_t err = EOPNOTSUPP; + if(test_allow_root_or_other(cred)) + FUNC_RETURN(EPERM); + if(FUSE_OP_HAVE(getattr)) err = -FUSE_OP_CALL(getattr, node->nn->path, &node->nn_stat); @@ -98,7 +142,7 @@ error_t netfs_attempt_readlink (struct iouser *user, struct node *node, char *buf) { FUNC_PROLOGUE_NODE("netfs_attempt_readlink", node); - error_t err = EOPNOTSUPP; + error_t err; if((err = netfs_validate_stat(node, user)) || (err = fshelp_access(&node->nn_stat, S_IREAD, user))) @@ -106,6 +150,8 @@ error_t netfs_attempt_readlink (struct iouser *user, struct node *node, if(FUSE_OP_HAVE(readlink)) err = -FUSE_OP_CALL(readlink, node->nn->path, buf, INT_MAX); + else + err = EOPNOTSUPP; out: FUNC_EPILOGUE(err); @@ -121,16 +167,19 @@ netfs_attempt_create_file (struct iouser *user, struct node *dir, char *name, mode_t mode, struct node **node) { FUNC_PROLOGUE("netfs_attempt_create_file"); - error_t err = EOPNOTSUPP; + error_t err; char *path = NULL; - if(! FUSE_OP_HAVE(mknod)) - goto out; - if((err = netfs_validate_stat(dir, user)) || (err = fshelp_checkdirmod(&dir->nn_stat, NULL, user))) goto out; + if(! FUSE_OP_HAVE(mknod)) + { + err = EOPNOTSUPP; + goto out; + } + if(! (path = malloc(strlen(dir->nn->path) + strlen(name) + 2))) { err = ENOMEM; @@ -196,15 +245,18 @@ error_t netfs_attempt_chown (struct iouser *cred, struct node *node, uid_t uid, uid_t gid) { FUNC_PROLOGUE_NODE("netfs_attempt_chown", node); - error_t err = EOPNOTSUPP; - - if(! FUSE_OP_HAVE(chown)) - goto out; + error_t err; if((err = netfs_validate_stat(node, cred)) || (err = fshelp_isowner(&node->nn_stat, cred))) goto out; + if(! FUSE_OP_HAVE(chown)) + { + err = EOPNOTSUPP; + goto out; + } + /* FIXME, make sure, that user CRED is not able to change permissions * to somebody who is not. That is, don't allow $unpriv_user to change * owner to e.g. root. @@ -225,14 +277,18 @@ error_t netfs_attempt_statfs (struct iouser *cred, struct node *node, fsys_statfsbuf_t *st) { - (void) cred; - FUNC_PROLOGUE_NODE("netfs_attempt_statfs", node); - error_t err = EOPNOTSUPP; + error_t err; + + if(test_allow_root_or_other(cred)) + err = EPERM; - if(FUSE_OP_HAVE(statfs)) + else if(FUSE_OP_HAVE(statfs)) err = -FUSE_OP_CALL(statfs, node->nn->path, st); + else + err = EOPNOTSUPP; + FUNC_EPILOGUE(err); } @@ -244,16 +300,19 @@ error_t netfs_attempt_mkdir (struct iouser *user, struct node *dir, char *name, mode_t mode) { FUNC_PROLOGUE("netfs_attempt_mkdir"); - error_t err = EOPNOTSUPP; + error_t err; char *path = NULL; - if(! FUSE_OP_HAVE(mkdir)) - goto out; - if((err = netfs_validate_stat(dir, user)) || (err = fshelp_checkdirmod(&dir->nn_stat, NULL, user))) goto out; + if(! FUSE_OP_HAVE(mkdir)) + { + err = EOPNOTSUPP; + goto out; + } + if(! (path = malloc(strlen(dir->nn->path) + strlen(name) + 2))) { err = ENOMEM; @@ -344,15 +403,18 @@ error_t netfs_attempt_chmod (struct iouser *cred, struct node *node, mode_t mode) { FUNC_PROLOGUE_NODE("netfs_attempt_chmod", node); - error_t err = EOPNOTSUPP; - - if(! FUSE_OP_HAVE(chmod)) - goto out; + error_t err; if((err = netfs_validate_stat(node, cred)) || (err = fshelp_isowner(&node->nn_stat, cred))) goto out; + if(! FUSE_OP_HAVE(chmod)) + { + err = EOPNOTSUPP; + goto out; + } + err = -FUSE_OP_CALL(chmod, node->nn->path, mode); node->nn->may_need_sync = 1; @@ -368,13 +430,15 @@ error_t netfs_attempt_mkfile (struct iouser *user, struct node *dir, mode_t mode, struct node **node) { FUNC_PROLOGUE("netfs_attempt_mkfile"); - error_t err = EOPNOTSUPP; + error_t err; char name[20]; static int num = 0; - if(FUSE_OP_HAVE(mknod)) - if(! (err = netfs_validate_stat(dir, user))) - err = fshelp_checkdirmod(&dir->nn_stat, NULL, user); + if(! (err = netfs_validate_stat(dir, user))) + err = fshelp_checkdirmod(&dir->nn_stat, NULL, user); + + if(! err && ! FUSE_OP_HAVE(mknod)) + err = EOPNOTSUPP; if(err) { @@ -423,12 +487,15 @@ error_t netfs_attempt_mkfile (struct iouser *user, struct node *dir, only after sync is completely finished. */ error_t netfs_attempt_syncfs (struct iouser *cred, int wait) { - (void) cred; /* cannot use anything but translator's rights, - * FIXME, maybe setuid/setgid? */ (void) wait; /* there's no such flag in libfuse */ FUNC_PROLOGUE("netfs_attempt_syncfs"); - error_t err = fuse_sync_filesystem(); + error_t err; + + if(test_allow_root_or_other(cred)) + err = EPERM; + else + err = fuse_sync_filesystem(); FUNC_EPILOGUE(err); } @@ -443,15 +510,18 @@ netfs_attempt_sync (struct iouser *cred, struct node *node, int wait) (void) wait; /* there's no such flag in libfuse */ FUNC_PROLOGUE_NODE("netfs_attempt_sync", node); - error_t err = EOPNOTSUPP; - - if(! FUSE_OP_HAVE(fsync)) - goto out; + error_t err; if((err = netfs_validate_stat(node, cred)) || (err = fshelp_access(&node->nn_stat, S_IWRITE, cred))) goto out; + if(! FUSE_OP_HAVE(fsync)) + { + err = EOPNOTSUPP; + goto out; + } + if(fuse_ops) err = -fuse_ops->fsync(node->nn->path, 0, &node->nn->info); else @@ -473,12 +543,9 @@ error_t netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name) { FUNC_PROLOGUE("netfs_attempt_unlink"); - error_t err = EOPNOTSUPP; + error_t err; struct node *node = NULL; - if(! FUSE_OP_HAVE(unlink)) - goto out; - err = netfs_attempt_lookup(user, dir, name, &node); assert(dir != node); mutex_lock(&dir->lock); /* re-lock directory, since netfs_attempt_lookup @@ -494,7 +561,10 @@ error_t netfs_attempt_unlink (struct iouser *user, struct node *dir, || (err = fshelp_checkdirmod(&dir->nn_stat, &node->nn_stat, user))) goto out; - err = -FUSE_OP_CALL(unlink, node->nn->path); + if(FUSE_OP_HAVE(unlink)) + err = -FUSE_OP_CALL(unlink, node->nn->path); + else + err = EOPNOTSUPP; /* TODO free associated netnode. really? * FIXME, make sure nn->may_need_sync is set */ @@ -513,16 +583,16 @@ error_t netfs_attempt_set_size (struct iouser *cred, struct node *node, loff_t size) { FUNC_PROLOGUE_NODE("netfs_attempt_set_size", node); - error_t err = EOPNOTSUPP; - - if(! FUSE_OP_HAVE(truncate)) - goto out; + error_t err; if((err = netfs_validate_stat(node, cred)) || (err = fshelp_access(&node->nn_stat, S_IWRITE, cred))) goto out; - err = -FUSE_OP_CALL(truncate, node->nn->path, size); + if(FUSE_OP_HAVE(truncate)) + err = -FUSE_OP_CALL(truncate, node->nn->path, size); + else + err = EOPNOTSUPP; out: FUNC_EPILOGUE(err); @@ -536,26 +606,32 @@ error_t netfs_attempt_mkdev (struct iouser *cred, struct node *node, mode_t type, dev_t indexes) { FUNC_PROLOGUE_NODE("netfs_attempt_mkdev", node); - error_t err = EOPNOTSUPP; - - if(! FUSE_OP_HAVE(mknod)) - goto out; - - /* we need to unlink the existing node, therefore, if unlink is not - * available, we cannot turn *node into a device. - */ - if(! FUSE_OP_HAVE(unlink)) - goto out; + error_t err; /* check permissions * XXX, shall we check permissions of the parent directory as well, * since we're going to unlink files? */ - if((err = netfs_validate_stat(node, cred)) || (err = fshelp_access(&node->nn_stat, S_IWRITE, cred))) goto out; + /* check whether the operations are available at all */ + if(! FUSE_OP_HAVE(mknod)) + { + err = EOPNOTSUPP; + goto out; + } + + /* we need to unlink the existing node, therefore, if unlink is not + * available, we cannot turn *node into a device. + */ + if(! FUSE_OP_HAVE(unlink)) + { + err = EOPNOTSUPP; + goto out; + } + /* unlink the already existing node, to be able to create the (new) * device file */ @@ -697,12 +773,9 @@ error_t netfs_attempt_link (struct iouser *user, struct node *dir, { FUNC_PROLOGUE_FMT("netfs_attempt_link", "link=%s/%s, to=%s", dir->nn->path, name, file->nn->path); - error_t err = EOPNOTSUPP; + error_t err; struct node *node = NULL; - if(! FUSE_OP_HAVE(link)) - goto out_nounlock; - mutex_lock(&dir->lock); if((err = netfs_attempt_lookup(user, dir, name, &node))) @@ -715,6 +788,11 @@ error_t netfs_attempt_link (struct iouser *user, struct node *dir, || (err = fshelp_checkdirmod(&dir->nn_stat, &node->nn_stat, user))) goto out; + if(! FUSE_OP_HAVE(link)) { + err = EOPNOTSUPP; + goto out; + } + if(! excl && FUSE_OP_HAVE(unlink)) /* EXCL is not set, therefore we may remove the target, i.e. call * unlink on it. Ignoring return value, as it's mostly not interesting, @@ -766,12 +844,9 @@ error_t netfs_attempt_rmdir (struct iouser *user, struct node *dir, char *name) { FUNC_PROLOGUE("netfs_attempt_rmdir"); - error_t err = EOPNOTSUPP; + error_t err; struct node *node = NULL; - if(! FUSE_OP_HAVE(rmdir)) - goto out_nounlock; - err = netfs_attempt_lookup(user, dir, name, &node); assert(dir != node); mutex_lock(&dir->lock); /* netfs_attempt_lookup unlocked dir */ @@ -783,7 +858,11 @@ error_t netfs_attempt_rmdir (struct iouser *user, || (err = fshelp_checkdirmod(&dir->nn_stat, &node->nn_stat, user))) goto out; - err = -FUSE_OP_CALL(rmdir, node->nn->path); + if(FUSE_OP_HAVE(rmdir)) + err = -FUSE_OP_CALL(rmdir, node->nn->path); + else + err = EOPNOTSUPP; + /* TODO free associated netnode. really? * FIXME, make sure nn->may_need_sync is set */ @@ -818,27 +897,32 @@ error_t netfs_attempt_mksymlink (struct iouser *cred, struct node *node, char *name) { FUNC_PROLOGUE_NODE("netfs_attempt_mksymlink", node); - error_t err = EOPNOTSUPP; - - /* we need to unlink the existing node, therefore, if unlink is not - * available, we cannot create symlinks - */ - if(! FUSE_OP_HAVE(unlink)) - goto out; - - /* symlink function available? if not, fail. */ - if(! FUSE_OP_HAVE(symlink)) - goto out; + error_t err; /* check permissions * XXX, shall we check permissions of the parent directory as well, * since we're going to unlink files? */ - if((err = netfs_validate_stat(node, cred)) || (err = fshelp_access(&node->nn_stat, S_IWRITE, cred))) goto out; + /* we need to unlink the existing node, therefore, if unlink is not + * available, we cannot create symlinks + */ + if(! FUSE_OP_HAVE(unlink)) + { + err = EOPNOTSUPP; + goto out; + } + + /* symlink function available? if not, fail. */ + if(! FUSE_OP_HAVE(symlink)) + { + err = EOPNOTSUPP; + goto out; + } + /* try to remove the existing node (probably an anonymous file) */ if((err = -FUSE_OP_CALL(unlink, node->nn->path))) goto out; @@ -863,13 +947,10 @@ error_t netfs_attempt_rename (struct iouser *user, struct node *fromdir, char *toname, int excl) { FUNC_PROLOGUE("netfs_attempt_rename"); - error_t err = EOPNOTSUPP; + error_t err; struct node *fromnode; char *topath = NULL; - if(! FUSE_OP_HAVE(rename)) - goto out_nounlock; - if(! (topath = malloc(strlen(toname) + strlen(todir->nn->path) + 2))) { err = ENOMEM; @@ -896,6 +977,12 @@ error_t netfs_attempt_rename (struct iouser *user, struct node *fromdir, || fshelp_checkdirmod(&todir->nn_stat, NULL, user)) goto out; + if(! FUSE_OP_HAVE(rename)) + { + err = EOPNOTSUPP; + goto out; + } + sprintf(topath, "%s/%s", todir->nn->path, toname); if(! excl && FUSE_OP_HAVE(unlink)) @@ -938,15 +1025,18 @@ error_t netfs_attempt_write (struct iouser *cred, struct node *node, loff_t offset, size_t *len, void *data) { FUNC_PROLOGUE_NODE("netfs_attempt_write", node); - error_t err = EOPNOTSUPP; - - if(! FUSE_OP_HAVE(write)) - goto out; + error_t err; if((err = netfs_validate_stat(node, cred)) || (err = fshelp_access(&node->nn_stat, S_IWRITE, cred))) goto out; + if(! FUSE_OP_HAVE(write)) + { + err = EOPNOTSUPP; + goto out; + } + node->nn->info.writepage = 0; /* cannot distinct on the Hurd :( */ int sz = fuse_ops ? @@ -971,21 +1061,24 @@ netfs_attempt_utimes (struct iouser *cred, struct node *node, struct timespec *atime, struct timespec *mtime) { FUNC_PROLOGUE_NODE("netfs_attempt_utimes", node); - error_t err = EOPNOTSUPP; - - /* prepare utimebuf for FUSE_OP_HAVE(utime) call */ - struct utimbuf utb; - utb.actime = atime ? atime->tv_sec : node->nn_stat.st_atime; - utb.modtime = mtime ? mtime->tv_sec : node->nn_stat.st_mtime; + error_t err; /* test whether operation is supported and permission are sufficient */ - if(! FUSE_OP_HAVE(utime)) - goto out; - if((err = netfs_validate_stat(node, cred)) || (err = fshelp_isowner(&node->nn_stat, cred))) goto out; + if(! FUSE_OP_HAVE(utime)) + { + err = EOPNOTSUPP; + goto out; + } + + /* prepare utimebuf for FUSE_OP_HAVE(utime) call */ + struct utimbuf utb; + utb.actime = atime ? atime->tv_sec : node->nn_stat.st_atime; + utb.modtime = mtime ? mtime->tv_sec : node->nn_stat.st_mtime; + err = -FUSE_OP_CALL(utime, node->nn->path, &utb); if (! err) @@ -1012,15 +1105,19 @@ error_t netfs_attempt_read (struct iouser *cred, struct node *node, loff_t offset, size_t *len, void *data) { FUNC_PROLOGUE_NODE("netfs_attempt_read", node); - error_t err = EOPNOTSUPP; - - if(! FUSE_OP_HAVE(read)) - goto out; + error_t err; if((err = netfs_validate_stat(node, cred)) || (err = fshelp_access(&node->nn_stat, S_IREAD, cred))) goto out; + if(! FUSE_OP_HAVE(read)) + { + err = EOPNOTSUPP; + goto out; + } + + int sz = fuse_ops ? (fuse_ops->read(node->nn->path, data, *len, offset, &node->nn->info)) : (fuse_ops_compat->read(node->nn->path, data, *len, offset)); @@ -1187,17 +1284,20 @@ netfs_get_dirents (struct iouser *cred, struct node *dir, * i.e. never allocate any further memory */ FUNC_PROLOGUE_NODE("netfs_get_dirents", dir); - error_t err = EOPNOTSUPP; + error_t err; fuse_dirh_t handle; - if(! FUSE_OP_HAVE(getdir)) - goto out; - if((err = netfs_validate_stat(dir, cred)) || (err = fshelp_access(&dir->nn_stat, S_IREAD, cred)) || (err = fshelp_access(&dir->nn_stat, S_IEXEC, cred))) goto out; + if(! FUSE_OP_HAVE(getdir)) + { + err = EOPNOTSUPP; + goto out; + } + if(! (handle = malloc(sizeof(struct fuse_dirhandle)))) { err = ENOMEM; /* sorry, translator not available ... */ |