From 767b4d075c6af58450704d93562c6716d5856ea5 Mon Sep 17 00:00:00 2001 From: jpandre Date: Mon, 2 Jun 2008 10:56:23 +0000 Subject: [PATCH] Fixed deletions from a sticky directory (on kernels >= 2.6.25) --- libntfs-3g/security.c | 21 ++++++++++++++------- posixacls.patch | 28 ++++++++++++++-------------- src/ntfs-3g.c | 33 +++++++++++++++++++++++++++------ 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c index a8cc2dbd..d305fab0 100644 --- a/libntfs-3g/security.c +++ b/libntfs-3g/security.c @@ -3747,6 +3747,7 @@ int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, int perm; int res; int allow; + struct stat stbuf; /* * Always allow for root. From the user's point of view, @@ -3784,9 +3785,13 @@ int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0); break; case S_IWRITE + S_IEXEC + S_ISVTX: - if (perm & S_ISVTX) - allow = 2; - else + if (perm & S_ISVTX) { + if ((ntfs_get_owner_mode(scx,path,ni,&stbuf) >= 0) + && (stbuf.st_uid == scx->uid)) + allow = 1; + else + allow = 2; + } else allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); break; @@ -3821,6 +3826,7 @@ BOOL ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, char *name; ntfs_inode *ni; ntfs_inode *dir_ni; + struct stat stbuf; allow = 0; dirpath = strdup(path); @@ -3835,16 +3841,17 @@ BOOL ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, dir_ni, accesstype); ntfs_inode_close(dir_ni); /* - * for a sticky directory, have to retry - * and check whether file itself is writeable + * for an not-owned sticky directory, have to + * check whether file itself is owned */ if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX)) && (allow == 2)) { ni = ntfs_pathname_to_inode(scx->vol, NULL, path); + allow = FALSE; if (ni) { - allow = ntfs_allowed_access(scx,path, - ni, S_IWRITE); + allow = (ntfs_get_owner_mode(scx,path,ni,&stbuf) >= 0) + && (stbuf.st_uid == scx->uid); ntfs_inode_close(ni); } } diff --git a/posixacls.patch b/posixacls.patch index 9bdbbb15..c0376422 100644 --- a/posixacls.patch +++ b/posixacls.patch @@ -1,5 +1,5 @@ ---- ntfsdev/ntfs-3g/src/ntfs-3g.c 2008-04-17 10:12:03.000000000 +0200 -+++ ntfsacls/ntfs-3g/src/ntfs-3g.c 2008-04-20 12:26:51.000000000 +0200 +--- ntfsdev/ntfs-3g/src/ntfs-3g.c 2008-06-02 10:13:23.000000000 +0200 ++++ ntfsacls/ntfs-3g/src/ntfs-3g.c 2008-06-02 11:06:46.000000000 +0200 @@ -1069,9 +1069,15 @@ securid = ntfs_inherited_id(&security, dir_path, dir_ni, S_ISDIR(type)); @@ -35,7 +35,7 @@ else { /* Adjust read-only (for Windows) */ if (perm & S_IWUSR) -@@ -1729,6 +1743,38 @@ +@@ -1750,6 +1764,38 @@ ntfschar *lename = NULL; int res, lename_len; @@ -74,7 +74,7 @@ if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) return ntfs_fuse_getxattr_windows(path, name, value, size); if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) -@@ -1779,6 +1825,37 @@ +@@ -1800,6 +1846,37 @@ ntfschar *lename = NULL; int res, lename_len; @@ -112,7 +112,7 @@ if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) return -EOPNOTSUPP; if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || -@@ -1837,6 +1914,37 @@ +@@ -1858,6 +1935,37 @@ int res = 0, lename_len; @@ -150,7 +150,7 @@ if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) return -EOPNOTSUPP; if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || ---- ntfsdev/ntfs-3g/include/ntfs-3g/security.h 2008-04-17 15:02:46.000000000 +0200 +--- ntfsdev/ntfs-3g/include/ntfs-3g/security.h 2008-05-30 08:53:07.000000000 +0200 +++ ntfsacls/ntfs-3g/include/ntfs-3g/security.h 2008-04-20 11:37:48.000000000 +0200 @@ -30,6 +30,8 @@ #include "inode.h" @@ -285,8 +285,8 @@ /* * Security API for direct access to security descriptors * based on Win32 API ---- ntfsdev/ntfs-3g/libntfs-3g/security.c 2008-04-21 15:52:57.000000000 +0200 -+++ ntfsacls/ntfs-3g/libntfs-3g/security.c 2008-04-23 10:15:26.000000000 +0200 +--- ntfsdev/ntfs-3g/libntfs-3g/security.c 2008-06-02 10:19:12.000000000 +0200 ++++ ntfsacls/ntfs-3g/libntfs-3g/security.c 2008-06-02 10:26:10.000000000 +0200 @@ -526,6 +526,673 @@ return (ok); } @@ -3493,7 +3493,7 @@ } else { errno = EPERM; res = -1; /* neither owner nor root */ -@@ -3758,7 +6474,11 @@ +@@ -3759,7 +6475,11 @@ if (!scx->usermapping || !scx->uid) allow = 1; else { @@ -3506,7 +3506,7 @@ if (perm >= 0) { res = EACCES; switch (accesstype) { -@@ -3873,6 +6593,10 @@ +@@ -3880,6 +6600,10 @@ mode_t mode; int perm; int res; @@ -3517,7 +3517,7 @@ res = 0; /* get the current owner and mode from cache or security attributes */ -@@ -3882,10 +6606,23 @@ +@@ -3889,10 +6613,23 @@ fileuid = cached->uid; filegid = cached->gid; mode = cached->mode; @@ -3541,7 +3541,7 @@ oldattr = getsecurityattr(scx->vol, path, ni); if (oldattr) { phead = (const SECURITY_DESCRIPTOR_RELATIVE*) -@@ -3898,6 +6635,21 @@ +@@ -3905,6 +6642,21 @@ usid = (const SID*) &oldattr[le32_to_cpu(phead->owner)]; #endif @@ -3563,7 +3563,7 @@ mode = perm = build_permissions(oldattr, usid, gsid, ni); if (perm >= 0) { -@@ -3905,6 +6657,7 @@ +@@ -3912,6 +6664,7 @@ filegid = findgroup(scx,gsid); } else res = -1; @@ -3571,7 +3571,7 @@ free(oldattr); } else res = -1; -@@ -3926,11 +6679,19 @@ +@@ -3933,11 +6686,19 @@ /* unless request originated by root */ if (uid && (fileuid != uid)) mode &= 01777; diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index b5f530b7..e9f2e75e 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -1321,7 +1321,7 @@ static int ntfs_fuse_rm(const char *org_path) } /* JPA deny unlinking if directory is not writable and executable */ if (!ntfs_fuse_fill_security_context(&security) - || ntfs_allowed_access(&security, path, dir_ni, + || ntfs_allowed_dir_access(&security, org_path, S_IEXEC + S_IWRITE + S_ISVTX)) { if (ntfs_delete(ctx->vol, org_path, ni, dir_ni, @@ -1379,7 +1379,7 @@ static int ntfs_fuse_unlink(const char *org_path) */ if (!ntfs_fuse_fill_security_context(&security) || ntfs_allowed_dir_access(&security, path, - S_IEXEC + S_IWRITE)) + S_IEXEC + S_IWRITE + S_ISVTX)) res = ntfs_fuse_rm_stream(path, stream_name, stream_name_len); else res = -errno; @@ -1425,7 +1425,15 @@ err: "to '%s'", new_path, tmp); } else { cleanup: - ntfs_fuse_unlink(tmp); + /* + * Condition for this unlink has already been checked in + * "ntfs_fuse_rename_existing_dest()", so it should never + * fail (unless concurrent access to directories when fuse + * is multithreaded) + */ + if (ntfs_fuse_unlink(tmp) < 0) + ntfs_log_perror("Rename failed. Existing file '%s' still present " + "as '%s'", new_path, tmp); } return ret; } @@ -1434,6 +1442,7 @@ static int ntfs_fuse_rename_existing_dest(const char *old_path, const char *new_ { int ret, len; char *tmp; + struct SECURITY_CONTEXT security; const char *ext = ".ntfs-3g-"; ntfs_log_trace("Entering\n"); @@ -1447,9 +1456,21 @@ static int ntfs_fuse_rename_existing_dest(const char *old_path, const char *new_ if (ret != len - 1) { ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1); ret = -EOVERFLOW; - } else - ret = ntfs_fuse_safe_rename(old_path, new_path, tmp); - + } else { + /* + * Make sure existing dest can be removed. + * This is only needed if parent directory is + * sticky, because in this situation condition + * for unlinking is different from condition for + * linking + */ + if (!ntfs_fuse_fill_security_context(&security) + || ntfs_allowed_dir_access(&security, new_path, + S_IEXEC + S_IWRITE + S_ISVTX)) + ret = ntfs_fuse_safe_rename(old_path, new_path, tmp); + else + ret = -EACCES; + } free(tmp); return ret; }