aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--README.md8
-rw-r--r--src/bindfs.114
-rw-r--r--src/bindfs.c50
-rwxr-xr-xtests/test_bindfs.rb14
5 files changed, 57 insertions, 33 deletions
diff --git a/ChangeLog b/ChangeLog
index 71e0017..ddd4ac4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2017-11-30 Martin Pärtel <martin dot partel at gmail dot com>
+
+ * Added options --delete-deny and --rename-deny as suggested by @roojs.
+
2017-10-26 Martin Pärtel <martin dot partel at gmail dot com>
* Released 1.13.8
diff --git a/README.md b/README.md
index e5f654f..582325d 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,4 @@
-## slightly modified ##
-
-Just added block-delete,block-rename
-
-So you can use it with sftp and disable delete/rename ....
-
-
-
## Overview ##
bindfs - https://bindfs.org/
diff --git a/src/bindfs.1 b/src/bindfs.1
index e20fc0f..d47720f 100644
--- a/src/bindfs.1
+++ b/src/bindfs.1
@@ -219,6 +219,20 @@ The read/write permissions are checked against the (possibly modified)
file permissions inside the mount.
+.SH OTHER FILE OPERATIONS
+
+.TP
+.B \-\-delete\-deny, \-o delete\-deny
+Makes all file delete operations fail with a 'permission denied'.
+By default, files can still be modified if they have write permission,
+and renamed if the directory has write permission.
+
+.TP
+.B \-\-rename\-deny, \-o rename\-deny
+Makes all file rename/move operations \fBwithin the mountpoint\fP fail with
+a 'permission denied'. Programs that move files out of a mountpoint do so
+by copying and deleting the original.
+
.SH RATE LIMITS
Reads and writes through the mount point can be throttled. Throttling works
by sleeping the required amount of time on each read or write request.
diff --git a/src/bindfs.c b/src/bindfs.c
index b208c36..6cd7c60 100644
--- a/src/bindfs.c
+++ b/src/bindfs.c
@@ -159,6 +159,9 @@ static struct Settings {
XATTR_READ_WRITE
} xattr_policy;
+ int delete_deny;
+ int rename_deny;
+
int mirrored_users_only;
uid_t *mirrored_users;
int num_mirrored_users;
@@ -184,10 +187,6 @@ static struct Settings {
int enable_lock_forwarding;
int enable_ioctl;
-
- /* should probably be handled with enum... */
- int block_delete;
- int block_rename;
uid_t uid_offset;
gid_t gid_offset;
@@ -480,10 +479,9 @@ static int delete_file(const char *path, int (*target_delete_func)(const char *)
char *unlink_first = NULL;
int (*main_delete_func)(const char*) = target_delete_func;
- if (settings.block_delete)
+ if (settings.delete_deny)
return -EPERM;
-
real_path = process_path(path, false);
if (real_path == NULL)
return -errno;
@@ -824,8 +822,8 @@ static int bindfs_rename(const char *from, const char *to)
{
int res;
char *real_from, *real_to;
-
- if (settings.block_rename)
+
+ if (settings.rename_deny)
return -EPERM;
real_from = process_path(from, false);
@@ -1469,6 +1467,10 @@ static void print_usage(const char *progname)
" --xattr-ro Read-only xattr operations.\n"
" --xattr-rw Read-write xattr operations (the default).\n"
"\n"
+ "Other file operations:\n"
+ " --delete-deny Disallow deleting files.\n"
+ " --rename-deny Disallow renaming files (within the mount).\n"
+ "\n"
"Rate limits:\n"
" --read-rate=... Limit to bytes/sec that can be read.\n"
" --write-rate=... Limit to bytes/sec that can be written.\n"
@@ -1519,6 +1521,8 @@ enum OptionKey {
OPTKEY_XATTR_NONE,
OPTKEY_XATTR_READ_ONLY,
OPTKEY_XATTR_READ_WRITE,
+ OPTKEY_DELETE_DENY,
+ OPTKEY_RENAME_DENY,
OPTKEY_REALISTIC_PERMISSIONS,
OPTKEY_CTIME_FROM_MTIME,
OPTKEY_ENABLE_LOCK_FORWARDING,
@@ -1526,9 +1530,7 @@ enum OptionKey {
OPTKEY_ENABLE_IOCTL,
OPTKEY_HIDE_HARD_LINKS,
OPTKEY_RESOLVE_SYMLINKS,
- OPTKEY_BLOCK_DEVICES_AS_FILES,
- OPTKEY_BLOCK_DELETE,
- OPTKEY_BLOCK_RENAME
+ OPTKEY_BLOCK_DEVICES_AS_FILES
};
static int process_option(void *data, const char *arg, int key,
@@ -1600,6 +1602,13 @@ static int process_option(void *data, const char *arg, int key,
settings.xattr_policy = XATTR_READ_WRITE;
return 0;
+ case OPTKEY_DELETE_DENY:
+ settings.delete_deny = 1;
+ return 0;
+ case OPTKEY_RENAME_DENY:
+ settings.rename_deny= 1;
+ return 0;
+
case OPTKEY_REALISTIC_PERMISSIONS:
settings.realistic_permissions = 1;
return 0;
@@ -1625,14 +1634,6 @@ static int process_option(void *data, const char *arg, int key,
settings.block_devices_as_files = 1;
return 0;
- case OPTKEY_BLOCK_DELETE:
- settings.block_delete = 1;
- return 0;
-
- case OPTKEY_BLOCK_RENAME:
- settings.block_rename = 1;
- return 0;
-
case OPTKEY_NONOPTION:
if (!settings.mntsrc) {
settings.mntsrc = realpath(arg, NULL);
@@ -1960,6 +1961,9 @@ int main(int argc, char *argv[])
OPT2("--xattr-ro", "xattr-ro", OPTKEY_XATTR_READ_ONLY),
OPT2("--xattr-rw", "xattr-rw", OPTKEY_XATTR_READ_WRITE),
+ OPT2("--delete-deny", "delete-deny", OPTKEY_DELETE_DENY),
+ OPT2("--rename-deny", "rename-deny", OPTKEY_RENAME_DENY),
+
OPT2("--hide-hard-links", "hide-hard-links", OPTKEY_HIDE_HARD_LINKS),
OPT2("--resolve-symlinks", "resolve-symlinks", OPTKEY_RESOLVE_SYMLINKS),
OPT_OFFSET2("--resolved-symlink-deletion=%s", "resolved-symlink-deletion=%s", resolved_symlink_deletion, -1),
@@ -1974,9 +1978,6 @@ int main(int argc, char *argv[])
OPT_OFFSET2("--uid-offset=%s", "uid-offset=%s", uid_offset, 0),
OPT_OFFSET2("--gid-offset=%s", "gid-offset=%s", gid_offset, 0),
- OPT2("--block-delete", "block-delete", OPTKEY_BLOCK_DELETE),
- OPT2("--block-rename", "block-rename", OPTKEY_BLOCK_RENAME),
-
@@ -2010,6 +2011,8 @@ int main(int argc, char *argv[])
settings.chmod_allow_x = 0;
settings.chmod_permchain = permchain_create();
settings.xattr_policy = XATTR_READ_WRITE;
+ settings.delete_deny = 0;
+ settings.rename_deny = 0;
settings.mirrored_users_only = 0;
settings.mirrored_users = NULL;
settings.num_mirrored_users = 0;
@@ -2025,9 +2028,6 @@ int main(int argc, char *argv[])
settings.enable_ioctl = 0;
settings.uid_offset = 0;
settings.gid_offset = 0;
-
- settings.block_delete = 0;
- settings.block_rename = 0;
atexit(&atexit_func);
diff --git a/tests/test_bindfs.rb b/tests/test_bindfs.rb
index d3f54b9..33eaaa4 100755
--- a/tests/test_bindfs.rb
+++ b/tests/test_bindfs.rb
@@ -293,6 +293,20 @@ testenv("--chmod-filter=g-w,o-rwx") do
assert { File.stat('src/file').mode & 0777 == 0640 }
end
+testenv("--delete-deny") do
+ touch('src/file')
+ mkdir('src/dir')
+ assert_exception(EPERM) { rm('mnt/file') }
+ assert_exception(EPERM) { rmdir('mnt/dir') }
+end
+
+testenv("--rename-deny") do
+ touch('src/file')
+ mkdir('src/dir')
+ assert_exception(EPERM) { mv('mnt/file', 'mnt/file2') }
+ assert_exception(EPERM) { mv('mnt/dir', 'mnt/dir2') }
+end
+
root_testenv("--map=nobody/root:@#{nobody_group}/@#{root_group}") do
touch('src/file')
chown('nobody', nobody_group, 'src/file')