Implemented security, trusted and open name spaces for extended attributes

N2009_11_14_FIXES
jpandre 2009-01-23 11:02:34 +00:00
parent 3787dcad77
commit 638228121d
1 changed files with 178 additions and 27 deletions

View File

@ -121,6 +121,7 @@ typedef struct {
typedef enum {
NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */
NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */
NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */
NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
} ntfs_fuse_streams_interface;
@ -1754,14 +1755,38 @@ close_inode:
#ifdef HAVE_SETXATTR
/*
* Name space identifications and prefixes
*/
enum { XATTRNS_NONE,
XATTRNS_USER,
XATTRNS_SYSTEM,
XATTRNS_SECURITY,
XATTRNS_TRUSTED,
XATTRNS_OPEN } ;
static const char nf_ns_user_prefix[] = "user.";
static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
static const char nf_ns_system_prefix[] = "system.";
static const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
static const char nf_ns_security_prefix[] = "security.";
static const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
static const char nf_ns_trusted_prefix[] = "trusted.";
static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
static const char xattr_ntfs_3g[] = "ntfs-3g.";
/*
* Identification of data mapped to the system name space
*/
enum { XATTR_UNMAPPED,
XATTR_NTFS_ACL,
XATTR_NTFS_ATTRIB,
XATTR_NTFS_REPARSE_DATA,
XATTR_POSIX_ACC, XATTR_POSIX_DEF } ;
static const char nf_ns_xattr_preffix[] = "user.";
static const int nf_ns_xattr_preffix_len = 5;
static const char nf_ns_xattr_ntfs[] = "system.ntfs_acl";
static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
@ -1809,7 +1834,12 @@ static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security,
#endif
static int mapped_xattr(const char *name)
/*
* Determine whether an extended attribute is in the system
* name space and mapped to internal data
*/
static int mapped_xattr_system(const char *name)
{
int num;
@ -1835,6 +1865,83 @@ static int mapped_xattr(const char *name)
return (num);
}
/*
* Determine the name space of an extended attribute
*/
static int xattr_namespace(const char *name)
{
int namespace;
if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
namespace = XATTRNS_NONE;
if (!strncmp(name, nf_ns_user_prefix,
nf_ns_user_prefix_len)
&& (strlen(name) != (size_t)nf_ns_user_prefix_len))
namespace = XATTRNS_USER;
else if (!strncmp(name, nf_ns_system_prefix,
nf_ns_system_prefix_len)
&& (strlen(name) != (size_t)nf_ns_system_prefix_len))
namespace = XATTRNS_SYSTEM;
else if (!strncmp(name, nf_ns_security_prefix,
nf_ns_security_prefix_len)
&& (strlen(name) != (size_t)nf_ns_security_prefix_len))
namespace = XATTRNS_SECURITY;
else if (!strncmp(name, nf_ns_trusted_prefix,
nf_ns_trusted_prefix_len)
&& (strlen(name) != (size_t)nf_ns_trusted_prefix_len))
namespace = XATTRNS_TRUSTED;
} else
namespace = XATTRNS_OPEN;
return (namespace);
}
/*
* Fix the prefix of an extended attribute
*/
static int fix_xattr_prefix(const char *name, int namespace, ntfschar **lename)
{
int len;
char *prefixed;
*lename = (ntfschar*)NULL;
switch (namespace) {
case XATTRNS_USER :
/*
* user name space : remove user prefix
*/
len = ntfs_mbstoucs(name + nf_ns_user_prefix_len, lename);
break;
case XATTRNS_SYSTEM :
case XATTRNS_SECURITY :
case XATTRNS_TRUSTED :
/*
* security, trusted and unmapped system name spaces :
* insert ntfs-3g prefix
*/
prefixed = ntfs_malloc(strlen(xattr_ntfs_3g)
+ strlen(name) + 1);
if (prefixed) {
strcpy(prefixed,xattr_ntfs_3g);
strcat(prefixed,name);
len = ntfs_mbstoucs(prefixed, lename);
free(prefixed);
} else
len = -1;
break;
case XATTRNS_OPEN :
/*
* in open name space mode : do no fix prefix
*/
len = ntfs_mbstoucs(name, lename);
break;
default :
len = -1;
}
return (len);
}
static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
{
ntfs_attr_search_ctx *actx = NULL;
@ -1845,7 +1952,8 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
struct SECURITY_CONTEXT security;
#endif
if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
&& (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR))
return -EOPNOTSUPP;
#if POSIXACLS
/* parent directory must be executable */
@ -1877,11 +1985,16 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
ret = -errno;
goto exit;
}
ret += tmp_name_len + nf_ns_xattr_preffix_len + 1;
if (ctx->streams == NF_STREAMS_INTERFACE_XATTR)
ret += tmp_name_len + nf_ns_user_prefix_len + 1;
else
ret += tmp_name_len + 1;
if (size) {
if ((size_t)ret <= size) {
strcpy(to, nf_ns_xattr_preffix);
to += nf_ns_xattr_preffix_len;
if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
strcpy(to, nf_ns_user_prefix);
to += nf_ns_user_prefix_len;
}
strncpy(to, tmp_name, tmp_name_len);
to += tmp_name_len;
*to = 0;
@ -1985,9 +2098,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
ntfschar *lename = NULL;
int res, lename_len;
int attr;
int namespace;
struct SECURITY_CONTEXT security;
attr = mapped_xattr(name);
attr = mapped_xattr_system(name);
if (attr != XATTR_UNMAPPED) {
#if POSIXACLS
/*
@ -2059,7 +2173,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
case XATTR_NTFS_REPARSE_DATA :
res = ntfs_get_ntfs_reparse_data(path,
value,size,ni);
break;
break;
default : /* not possible */
break;
}
@ -2073,15 +2187,26 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
}
if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS)
return ntfs_fuse_getxattr_windows(path, name, value, size);
if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
if (ctx->streams == NF_STREAMS_INTERFACE_NONE)
return -EOPNOTSUPP;
if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) ||
strlen(name) == (size_t)nf_ns_xattr_preffix_len)
namespace = xattr_namespace(name);
if (namespace == XATTRNS_NONE)
return -ENODATA;
#if POSIXACLS
/* parent directory must be executable */
if (ntfs_fuse_fill_security_context(&security)
&& !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
return (-errno);
}
/* trusted only readable by root */
if ((namespace == XATTRNS_TRUSTED)
&& security.uid)
return -EACCES;
#endif
ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
if (!ni)
return -errno;
lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename);
lename_len = fix_xattr_prefix(name, namespace, &lename);
if (lename_len == -1) {
res = -errno;
goto exit;
@ -2117,9 +2242,10 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
ntfschar *lename = NULL;
int res, lename_len;
int attr;
int namespace;
struct SECURITY_CONTEXT security;
attr = mapped_xattr(name);
attr = mapped_xattr_system(name);
if (attr != XATTR_UNMAPPED) {
#if POSIXACLS
/*
@ -2205,29 +2331,37 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
#endif
return (res);
}
if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
&& (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR))
return -EOPNOTSUPP;
if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) ||
strlen(name) == (size_t)nf_ns_xattr_preffix_len)
return -EACCES;
namespace = xattr_namespace(name);
if (namespace == XATTRNS_NONE)
return -ENODATA;
#if POSIXACLS
/* parent directory must be executable */
if (ntfs_fuse_fill_security_context(&security)
&& !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
return (-errno);
}
/* security and trusted only settable by root */
if (((namespace == XATTRNS_SECURITY)
|| (namespace == XATTRNS_TRUSTED))
&& security.uid)
return -EACCES;
#endif
ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
if (!ni)
return -errno;
#if POSIXACLS
if (!ntfs_allowed_as_owner(&security,path,ni)) {
if (((namespace == XATTRNS_SECURITY)
|| (namespace == XATTRNS_TRUSTED))
&& !ntfs_allowed_as_owner(&security,path,ni)) {
res = -errno;
ntfs_inode_close(ni);
return (res);
}
#endif
lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename);
lename_len = fix_xattr_prefix(name, namespace, &lename);
if (lename_len == -1) {
res = -errno;
goto exit;
@ -2251,6 +2385,11 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
res = -errno;
goto exit;
}
} else {
if (ntfs_attr_truncate(na, (s64)size)) {
res = -errno;
goto exit;
}
}
res = ntfs_attr_pwrite(na, 0, size, value);
if (res != (s64) size)
@ -2272,9 +2411,10 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
ntfschar *lename = NULL;
int res = 0, lename_len;
int attr;
int namespace;
struct SECURITY_CONTEXT security;
attr = mapped_xattr(name);
attr = mapped_xattr_system(name);
if (attr != XATTR_UNMAPPED) {
#if POSIXACLS
@ -2360,10 +2500,11 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
#endif
return (res);
}
if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
&& (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR))
return -EOPNOTSUPP;
if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) ||
strlen(name) == (size_t)nf_ns_xattr_preffix_len)
namespace = xattr_namespace(name);
if (namespace == XATTRNS_NONE)
return -ENODATA;
#if POSIXACLS
/* parent directory must be executable */
@ -2371,18 +2512,25 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
&& !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
return (-errno);
}
/* security and trusted only settable by root */
if (((namespace == XATTRNS_SECURITY)
|| (namespace == XATTRNS_TRUSTED))
&& security.uid)
return -EACCES;
#endif
ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
if (!ni)
return -errno;
#if POSIXACLS
if (!ntfs_allowed_as_owner(&security,path,ni)) {
if (((namespace == XATTRNS_SECURITY)
|| (namespace == XATTRNS_TRUSTED))
&& !ntfs_allowed_as_owner(&security,path,ni)) {
res = -errno;
ntfs_inode_close(ni);
return (res);
}
#endif
lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename);
lename_len = fix_xattr_prefix(name, namespace, &lename);
if (lename_len == -1) {
res = -errno;
goto exit;
@ -2696,7 +2844,6 @@ static char *parse_mount_options(const char *orig_opts)
goto err_exit;
ctx->hiberfile = TRUE;
} else if (!strcmp(opt, "locale")) {
/* option "locale" kept undocumented */
if (missing_option_value(val, "locale"))
goto err_exit;
ntfs_set_char_encoding(val);
@ -2707,6 +2854,8 @@ static char *parse_mount_options(const char *orig_opts)
ctx->streams = NF_STREAMS_INTERFACE_NONE;
else if (!strcmp(val, "xattr"))
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
else if (!strcmp(val, "openxattr"))
ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
else if (!strcmp(val, "windows"))
ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
else {
@ -2714,6 +2863,8 @@ static char *parse_mount_options(const char *orig_opts)
"access interface.\n");
goto err_exit;
}
} else if (!strcmp(opt, "user_xattr")) {
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
} else if (!strcmp(opt, "noauto")) {
/* Don't pass noauto option to fuse. */
} else if (!strcmp(opt, "debug")) {