Implemented an extended attribute interface to get/set NTFS ACLs
parent
31e6a0b734
commit
cb59654f39
|
@ -239,6 +239,8 @@ int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
|
|||
const char *path, ntfs_inode *ni, struct stat*);
|
||||
int ntfs_set_mode(struct SECURITY_CONTEXT *scx,
|
||||
const char *path, ntfs_inode *ni, mode_t mode);
|
||||
BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx,
|
||||
const char *path, ntfs_inode *ni);
|
||||
int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, const char *path,
|
||||
ntfs_inode *ni, int accesstype);
|
||||
BOOL ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
|
||||
|
@ -280,6 +282,12 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|||
ntfs_inode *ni);
|
||||
int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
||||
const char *name, ntfs_inode *ni);
|
||||
int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
||||
const char *name, char *value, size_t size,
|
||||
ntfs_inode *ni);
|
||||
int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
||||
const char *name, const char *value, size_t size,
|
||||
ntfs_inode *ni);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1990,7 +1990,10 @@ static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
|
|||
|
||||
/*
|
||||
* Get a Posix ACL
|
||||
*
|
||||
* returns size or -errno if there is a problem
|
||||
* if size was too small, no copy is done and errno is not set,
|
||||
* the caller is expected to issue a new call
|
||||
*/
|
||||
|
||||
int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
||||
|
@ -2072,26 +2075,35 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|||
if (pxdesc) {
|
||||
if (ntfs_valid_posix(pxdesc)) {
|
||||
if (!strcmp(name,"system.posix_acl_default")) {
|
||||
outsize = sizeof(struct POSIX_ACL)
|
||||
+ pxdesc->defcnt*sizeof(struct POSIX_ACE);
|
||||
if (outsize <= size) {
|
||||
if (ni->mrec->flags
|
||||
& MFT_RECORD_IS_DIRECTORY)
|
||||
outsize = sizeof(struct POSIX_ACL)
|
||||
+ pxdesc->defcnt*sizeof(struct POSIX_ACE);
|
||||
else {
|
||||
/*
|
||||
* getting default ACL from plain file :
|
||||
* return EACCES if size > 0 as
|
||||
* indicated in the man, but return ok
|
||||
* if size == 0, so that ls does not
|
||||
* display an error
|
||||
*/
|
||||
if (size > 0) {
|
||||
outsize = 0;
|
||||
errno = EACCES;
|
||||
} else
|
||||
outsize = sizeof(struct POSIX_ACL);
|
||||
}
|
||||
if (outsize && (outsize <= size)) {
|
||||
memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL));
|
||||
memcpy(&value[sizeof(struct POSIX_ACL)],
|
||||
&pxdesc->acl.ace[pxdesc->firstdef],
|
||||
outsize-sizeof(struct POSIX_ACL));
|
||||
} else {
|
||||
outsize = 0;
|
||||
errno = ENOSPC;
|
||||
}
|
||||
} else {
|
||||
outsize = sizeof(struct POSIX_ACL)
|
||||
+ pxdesc->acccnt*sizeof(struct POSIX_ACE);
|
||||
if (outsize <= size)
|
||||
memcpy(value,&pxdesc->acl,outsize);
|
||||
else {
|
||||
outsize = 0;
|
||||
errno = ENOSPC;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outsize = 0;
|
||||
|
@ -2106,6 +2118,33 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|||
return (outsize ? (int)outsize : -errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get an NTFS ACL
|
||||
*
|
||||
* Returns size or -errno if there is a problem
|
||||
* if size was too small, no copy is done and errno is not set,
|
||||
* the caller is expected to issue a new call
|
||||
*/
|
||||
|
||||
int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
||||
const char *name __attribute__((unused)),
|
||||
char *value, size_t size, ntfs_inode *ni)
|
||||
{
|
||||
char *securattr;
|
||||
size_t outsize;
|
||||
|
||||
outsize = 0; /* default to no data and no error */
|
||||
securattr = getsecurityattr(scx->vol, path, ni);
|
||||
if (securattr) {
|
||||
outsize = ntfs_attr_size(securattr);
|
||||
if (outsize <= size) {
|
||||
memcpy(value,securattr,outsize);
|
||||
}
|
||||
free(securattr);
|
||||
}
|
||||
return (outsize ? (int)outsize : -errno);
|
||||
}
|
||||
|
||||
#endif /* POSIXACLS */
|
||||
|
||||
/*
|
||||
|
@ -2627,12 +2666,64 @@ int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
|||
|
||||
#if POSIXACLS
|
||||
|
||||
/*
|
||||
* Check whether user has ownership rights on a file
|
||||
*
|
||||
* Returns TRUE if allowed
|
||||
* if not, errno tells why
|
||||
*/
|
||||
|
||||
BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx,
|
||||
const char *path, ntfs_inode *ni)
|
||||
{
|
||||
const struct CACHED_PERMISSIONS *cached;
|
||||
char *oldattr;
|
||||
const SID *usid;
|
||||
uid_t processuid;
|
||||
uid_t uid;
|
||||
BOOL gotowner;
|
||||
int allowed;
|
||||
|
||||
gotowner = FALSE; /* default */
|
||||
processuid = scx->uid;
|
||||
/* get the owner, either from cache or from old attribute */
|
||||
cached = fetch_cache(scx, ni);
|
||||
if (cached) {
|
||||
uid = cached->uid;
|
||||
gotowner = TRUE;
|
||||
} else {
|
||||
oldattr = getsecurityattr(scx->vol,path, ni);
|
||||
if (oldattr) {
|
||||
#if OWNERFROMACL
|
||||
usid = ntfs_acl_owner(oldattr);
|
||||
#else
|
||||
const SECURITY_DESCRIPTOR_RELATIVE *phead;
|
||||
|
||||
phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
|
||||
usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
|
||||
#endif
|
||||
uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
|
||||
gotowner = TRUE;
|
||||
free(oldattr);
|
||||
}
|
||||
}
|
||||
allowed = FALSE;
|
||||
if (gotowner) {
|
||||
/* TODO : use CAP_FOWNER process capability */
|
||||
if (!processuid || (processuid == uid))
|
||||
allowed = TRUE;
|
||||
else
|
||||
errno = EPERM;
|
||||
}
|
||||
return (allowed);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a new access or default Posix ACL to a file
|
||||
* (or remove ACL if no input data)
|
||||
* Validity of input data is checked after merging
|
||||
*
|
||||
* Returns 0, or -1 if there is a problem
|
||||
* Returns 0, or -1 if there is a problem which errno describes
|
||||
*/
|
||||
|
||||
int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
||||
|
@ -2664,7 +2755,7 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|||
count = 0;
|
||||
isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
|
||||
newpxdesc = (struct POSIX_SECURITY*)NULL;
|
||||
if (!deflt || isdir) {
|
||||
if (!deflt || isdir || !size) {
|
||||
cached = fetch_cache(scx, ni);
|
||||
if (cached) {
|
||||
uid = cached->uid;
|
||||
|
@ -2703,6 +2794,7 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|||
|
||||
if (newpxdesc) {
|
||||
processuid = scx->uid;
|
||||
/* TODO : use CAP_FOWNER process capability */
|
||||
if (!processuid || (uid == processuid)) {
|
||||
/*
|
||||
* clear setgid if file group does
|
||||
|
@ -2732,6 +2824,65 @@ int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|||
(const char*)NULL, 0, ni));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a new NTFS ACL to a file
|
||||
*
|
||||
* Returns 0, or -1 if there is a problem
|
||||
*/
|
||||
|
||||
int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx,
|
||||
const char *path __attribute__((unused)),
|
||||
const char *name __attribute__((unused)),
|
||||
const char *value, size_t size, ntfs_inode *ni)
|
||||
{
|
||||
char *attr;
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
if ((size > 0)
|
||||
&& ntfs_valid_descr(value,size)
|
||||
&& (ntfs_attr_size(value) == size)) {
|
||||
if (ntfs_allowed_as_owner(scx,path,ni)) {
|
||||
/* need copying in order to write */
|
||||
attr = (char*)ntfs_malloc(size);
|
||||
if (attr) {
|
||||
memcpy(attr,value,size);
|
||||
res = update_secur_descr(scx->vol, attr, ni);
|
||||
/*
|
||||
* No need to invalidate standard caches :
|
||||
* the relation between a securid and
|
||||
* the associated protection is unchanged,
|
||||
* only the relation between a file and
|
||||
* its securid and protection is changed.
|
||||
*/
|
||||
#if CACHE_LEGACY_SIZE
|
||||
/*
|
||||
* we must however invalidate the legacy
|
||||
* cache, which is based on inode numbers.
|
||||
* For safety, invalidate even if updating
|
||||
* failed.
|
||||
*/
|
||||
if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
&& !ni->security_id) {
|
||||
struct CACHED_PERMISSIONS_LEGACY legacy;
|
||||
|
||||
legacy.mft_no = ni->mft_no;
|
||||
legacy.variable = (char*)NULL;
|
||||
legacy.varsize = 0;
|
||||
ntfs_invalidate_cache(scx->vol->legacy_cache,
|
||||
GENERIC(&legacy),
|
||||
(cache_compare)leg_compare);
|
||||
}
|
||||
#endif
|
||||
free(attr);
|
||||
} else
|
||||
errno = ENOMEM;
|
||||
}
|
||||
} else
|
||||
errno = EINVAL;
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -2812,6 +2963,7 @@ int ntfs_set_mode(struct SECURITY_CONTEXT *scx,
|
|||
|
||||
if (!res) {
|
||||
processuid = scx->uid;
|
||||
/* TODO : use CAP_FOWNER process capability */
|
||||
if (!processuid || (uid == processuid)) {
|
||||
/*
|
||||
* clear setgid if file group does
|
||||
|
|
|
@ -1714,6 +1714,7 @@ static const int nf_ns_xattr_preffix_len = 5;
|
|||
|
||||
static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
|
||||
static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
|
||||
static const char nf_ns_xattr_ntfs[] = "system.ntfs_acl";
|
||||
|
||||
/*
|
||||
* Check whether access to an ACL as an extended attribute
|
||||
|
@ -1908,7 +1909,8 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
|||
|
||||
/* hijack Posix/NTFS ACL retrieval */
|
||||
if ((!strcmp(name,nf_ns_xattr_posix_access)
|
||||
|| !strcmp(name,nf_ns_xattr_posix_default)) {
|
||||
|| !strcmp(name,nf_ns_xattr_posix_default)
|
||||
|| !strcmp(name,nf_ns_xattr_ntfs))) {
|
||||
|
||||
ni = ntfs_check_access_xattr(path,&security);
|
||||
if (ni) {
|
||||
|
@ -1918,8 +1920,12 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
|||
* is done, and the caller has to
|
||||
* issue a new call with correct size.
|
||||
*/
|
||||
res = ntfs_get_posix_acl(&security,path,
|
||||
name,value,size,ni);
|
||||
if (!strcmp(name,nf_ns_xattr_ntfs))
|
||||
res = ntfs_get_ntfs_acl(&security,path,
|
||||
name,value,size,ni);
|
||||
else
|
||||
res = ntfs_get_posix_acl(&security,path,
|
||||
name,value,size,ni);
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
} else
|
||||
|
@ -1978,12 +1984,17 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
|||
|
||||
/* hijack Posix/NTFS ACL setting */
|
||||
if (!strcmp(name,nf_ns_xattr_posix_access)
|
||||
|| !strcmp(name,nf_ns_xattr_posix_default)) {
|
||||
|| !strcmp(name,nf_ns_xattr_posix_default)
|
||||
|| !strcmp(name,nf_ns_xattr_ntfs)) {
|
||||
|
||||
ni = ntfs_check_access_xattr(path,&security);
|
||||
if (ni) {
|
||||
res = ntfs_set_posix_acl(&security,path,
|
||||
name,value,size,ni);
|
||||
if (!strcmp(name,nf_ns_xattr_ntfs))
|
||||
res = ntfs_set_ntfs_acl(&security,path,
|
||||
name,value,size,ni);
|
||||
else
|
||||
res = ntfs_set_posix_acl(&security,path,
|
||||
name,value,size,ni);
|
||||
if (res)
|
||||
res = -errno;
|
||||
if (ntfs_inode_close(ni))
|
||||
|
|
Loading…
Reference in New Issue