mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 01:53:45 +08:00
Implemented backup/restoring of encrypted files (by Martin Bene)
This commit is contained in:
parent
1cd46c2241
commit
c79b3777ca
1
AUTHORS
1
AUTHORS
@ -3,6 +3,7 @@ Present authors of ntfs-3g in alphabetical order:
|
||||
|
||||
Jean-Pierre Andre
|
||||
Alon Bar-Lev
|
||||
Martin Bene
|
||||
Dominique L Bouix
|
||||
Csaba Henk
|
||||
Bernhard Kaindl
|
||||
|
@ -14,6 +14,7 @@ headers = \
|
||||
device.h \
|
||||
device_io.h \
|
||||
dir.h \
|
||||
efs.h \
|
||||
endians.h \
|
||||
index.h \
|
||||
inode.h \
|
||||
|
@ -285,7 +285,8 @@ extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
|
||||
int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
extern int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
|
||||
|
||||
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
|
31
include/ntfs-3g/efs.h
Normal file
31
include/ntfs-3g/efs.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2009 Martin Bene
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the NTFS-3G
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef EFS_H
|
||||
#define EFS_H
|
||||
|
||||
int ntfs_get_efs_info(const char *path,
|
||||
char *value, size_t size, ntfs_inode *ni);
|
||||
int ntfs_set_efs_info(const char *path,
|
||||
const char *value, size_t size, int flags,
|
||||
ntfs_inode *ni);
|
||||
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na);
|
||||
|
||||
#endif /* EFS_H */
|
@ -228,6 +228,8 @@ struct _ntfs_volume {
|
||||
s64 free_clusters; /* Track the number of free clusters which
|
||||
greatly improves statfs() performance */
|
||||
s64 free_mft_records; /* Same for free mft records (see above) */
|
||||
BOOL efs_raw; /* volume is mounted for raw access to
|
||||
efs-encrypted files */
|
||||
|
||||
#if CACHE_INODE_SIZE
|
||||
struct CACHE_HEADER *xinode_cache;
|
||||
|
@ -29,6 +29,7 @@ libntfs_3g_la_SOURCES = \
|
||||
debug.c \
|
||||
device.c \
|
||||
dir.c \
|
||||
efs.c \
|
||||
index.c \
|
||||
inode.c \
|
||||
lcnalloc.c \
|
||||
@ -37,7 +38,7 @@ libntfs_3g_la_SOURCES = \
|
||||
mft.c \
|
||||
misc.c \
|
||||
mst.c \
|
||||
reparse.c \
|
||||
reparse.c \
|
||||
runlist.c \
|
||||
security.c \
|
||||
unistr.c \
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include "bitmap.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "efs.h"
|
||||
|
||||
#define STANDARD_COMPRESSION_UNIT 4
|
||||
|
||||
@ -446,7 +447,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
* directory (for unnamed data streams) or on current
|
||||
* inode (for named data streams). The compression mark
|
||||
* may change any time, the compression state can only
|
||||
* change when stream is void.
|
||||
* change when stream is wiped out.
|
||||
*/
|
||||
a->flags &= ~ATTR_COMPRESSION_MASK;
|
||||
if (na->ni->flags & FILE_ATTR_COMPRESSED)
|
||||
@ -806,9 +807,10 @@ map_rl:
|
||||
*/
|
||||
static s64 ntfs_attr_pread_i(ntfs_attr *na, const s64 pos, s64 count, void *b)
|
||||
{
|
||||
s64 br, to_read, ofs, total, total2;
|
||||
s64 br, to_read, ofs, total, total2, max_read, max_init;
|
||||
ntfs_volume *vol;
|
||||
runlist_element *rl;
|
||||
u16 efs_padding_length;
|
||||
|
||||
/* Sanity checking arguments is done in ntfs_attr_pread(). */
|
||||
|
||||
@ -825,20 +827,37 @@ static s64 ntfs_attr_pread_i(ntfs_attr *na, const s64 pos, s64 count, void *b)
|
||||
/*
|
||||
* Encrypted non-resident attributes are not supported. We return
|
||||
* access denied, which is what Windows NT4 does, too.
|
||||
* However, allow if mounted with efs_raw option
|
||||
*/
|
||||
if (NAttrEncrypted(na) && NAttrNonResident(na)) {
|
||||
vol = na->ni->vol;
|
||||
if (!vol->efs_raw && NAttrEncrypted(na) && NAttrNonResident(na)) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
vol = na->ni->vol;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
/* Truncate reads beyond end of attribute. */
|
||||
if (pos + count > na->data_size) {
|
||||
if (pos >= na->data_size)
|
||||
/*
|
||||
* Truncate reads beyond end of attribute,
|
||||
* but round to next 512 byte boundary for encrypted
|
||||
* attributes with efs_raw mount option
|
||||
*/
|
||||
max_read = na->data_size;
|
||||
max_init = na->initialized_size;
|
||||
if (na->ni->vol->efs_raw
|
||||
&& (na->data_flags & ATTR_IS_ENCRYPTED)
|
||||
&& NAttrNonResident(na)) {
|
||||
if (na->data_size != na->initialized_size) {
|
||||
ntfs_log_error("uninitialized encrypted file not supported\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
max_init = max_read = ((na->data_size + 511) & ~511) + 2;
|
||||
}
|
||||
if (pos + count > max_read) {
|
||||
if (pos >= max_read)
|
||||
return 0;
|
||||
count = na->data_size - pos;
|
||||
count = max_read - pos;
|
||||
}
|
||||
/* If it is a resident attribute, get the value from the mft record. */
|
||||
if (!NAttrNonResident(na)) {
|
||||
@ -868,15 +887,42 @@ res_err_out:
|
||||
}
|
||||
total = total2 = 0;
|
||||
/* Zero out reads beyond initialized size. */
|
||||
if (pos + count > na->initialized_size) {
|
||||
if (pos >= na->initialized_size) {
|
||||
if (pos + count > max_init) {
|
||||
if (pos >= max_init) {
|
||||
memset(b, 0, count);
|
||||
return count;
|
||||
}
|
||||
total2 = pos + count - na->initialized_size;
|
||||
total2 = pos + count - max_init;
|
||||
count -= total2;
|
||||
memset((u8*)b + count, 0, total2);
|
||||
}
|
||||
/*
|
||||
* for encrypted non-resident attributes with efs_raw set
|
||||
* the last two bytes aren't read from disk but contain
|
||||
* the number of padding bytes so original size can be
|
||||
* restored
|
||||
*/
|
||||
if (na->ni->vol->efs_raw &&
|
||||
(na->data_flags & ATTR_IS_ENCRYPTED) &&
|
||||
((pos + count) > max_init-2)) {
|
||||
efs_padding_length = 511 - ((na->data_size - 1) & 511);
|
||||
if (pos+count == max_init) {
|
||||
if (count == 1) {
|
||||
*((u8*)b+count-1) = (u8)(efs_padding_length >> 8);
|
||||
count--;
|
||||
total2++;
|
||||
} else {
|
||||
*(u16*)((u8*)b+count-2) = cpu_to_le16(efs_padding_length);
|
||||
count -= 2;
|
||||
total2 +=2;
|
||||
}
|
||||
} else {
|
||||
*((u8*)b+count-1) = (u8)(efs_padding_length & 0xff);
|
||||
count--;
|
||||
total2++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the runlist element containing the vcn. */
|
||||
rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
|
||||
if (!rl) {
|
||||
@ -1255,10 +1301,12 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
||||
compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
|
||||
!= const_cpu_to_le16(0);
|
||||
/*
|
||||
* Encrypted non-resident attributes are not supported. We return
|
||||
* Encrypted attributes are only supported in raw mode. We return
|
||||
* access denied, which is what Windows NT4 does, too.
|
||||
* Moreover a file cannot be both encrypted and compressed.
|
||||
*/
|
||||
if (NAttrEncrypted(na) && NAttrNonResident(na)) {
|
||||
if ((na->data_flags & ATTR_IS_ENCRYPTED)
|
||||
&& (compressed || !vol->efs_raw)) {
|
||||
errno = EACCES;
|
||||
goto errno_set;
|
||||
}
|
||||
@ -3074,7 +3122,7 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfs_inode *base_ni;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n",
|
||||
(long long) ni->mft_no, (unsigned) type, (unsigned) flags);
|
||||
(long long) ni->mft_no, (unsigned) type, (unsigned) data_flags);
|
||||
|
||||
if (!ni || (!name && name_len)) {
|
||||
errno = EINVAL;
|
||||
@ -4051,7 +4099,7 @@ int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra)
|
||||
* We expect the caller to do this as this is a fairly low level
|
||||
* function and it is likely there will be further changes made.
|
||||
*/
|
||||
static int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
s64 new_allocated_size, bw;
|
||||
@ -4504,8 +4552,8 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
|
||||
if (ntfs_attr_can_be_resident(vol, na->type))
|
||||
return -1;
|
||||
|
||||
if (NAttrEncrypted(na)) {
|
||||
ntfs_log_trace("Making encrypted files resident is not "
|
||||
if (na->data_flags & ATTR_IS_ENCRYPTED) {
|
||||
ntfs_log_trace("Making encrypted streams resident is not "
|
||||
"implemented yet.\n");
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
@ -5476,9 +5524,9 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
|
||||
* Encrypted attributes are not supported. We return access denied,
|
||||
* which is what Windows NT4 does, too.
|
||||
*/
|
||||
if (NAttrEncrypted(na)) {
|
||||
if (na->data_flags & ATTR_IS_ENCRYPTED) {
|
||||
errno = EACCES;
|
||||
ntfs_log_perror("Failed to truncate encrypted attribute");
|
||||
ntfs_log_info("Failed to truncate encrypted attribute");
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
|
339
libntfs-3g/efs.c
Normal file
339
libntfs-3g/efs.c
Normal file
@ -0,0 +1,339 @@
|
||||
/**
|
||||
* efs.c - Limited processing of encrypted files
|
||||
*
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2009 Martin Bene
|
||||
* Copyright (c) 2009 Jean-Pierre Andre
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the NTFS-3G
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "attrib.h"
|
||||
#include "inode.h"
|
||||
#include "dir.h"
|
||||
#include "efs.h"
|
||||
#include "index.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "efs.h"
|
||||
|
||||
static ntfschar logged_utility_stream_name[] = {
|
||||
const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('E'),
|
||||
const_cpu_to_le16('F'),
|
||||
const_cpu_to_le16('S'),
|
||||
const_cpu_to_le16(0)
|
||||
} ;
|
||||
|
||||
|
||||
/*
|
||||
* Get the ntfs EFS info into an extended attribute
|
||||
*/
|
||||
|
||||
int ntfs_get_efs_info(const char *path,
|
||||
char *value, size_t size, ntfs_inode *ni)
|
||||
{
|
||||
EFS_ATTR_HEADER *efs_info;
|
||||
s64 attr_size = 0;
|
||||
|
||||
if (ni) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
|
||||
AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
|
||||
&attr_size);
|
||||
if (efs_info
|
||||
&& (le32_to_cpu(efs_info->length) == attr_size)) {
|
||||
if (attr_size <= (s64)size) {
|
||||
if (value)
|
||||
memcpy(value,efs_info,attr_size);
|
||||
else {
|
||||
errno = EFAULT;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else
|
||||
if (size) {
|
||||
errno = ERANGE;
|
||||
attr_size = 0;
|
||||
}
|
||||
free (efs_info);
|
||||
} else {
|
||||
if (efs_info) {
|
||||
free(efs_info);
|
||||
ntfs_log_info("Bad efs_info for file %s\n",path);
|
||||
} else {
|
||||
ntfs_log_info("Could not get efsinfo"
|
||||
" for file %s\n", path);
|
||||
}
|
||||
errno = EIO;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
ntfs_log_info("File %s is not encrypted",path);
|
||||
}
|
||||
}
|
||||
return (attr_size ? (int)attr_size : -errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the efs data from an extended attribute
|
||||
* Warning : the new data is not checked
|
||||
* Returns 0, or -1 if there is a problem
|
||||
*/
|
||||
|
||||
int ntfs_set_efs_info(const char *path __attribute__((unused)),
|
||||
const char *value, size_t size, int flags,
|
||||
ntfs_inode *ni)
|
||||
{
|
||||
int res;
|
||||
int written;
|
||||
ntfs_attr *na;
|
||||
const EFS_ATTR_HEADER *info_header;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
res = 0;
|
||||
if (ni && value && size) {
|
||||
if (ni->flags && (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
|
||||
if (ni->flags && FILE_ATTR_ENCRYPTED) {
|
||||
ntfs_log_info("File %s already encrypted",path);
|
||||
errno = EEXIST;
|
||||
} else {
|
||||
/*
|
||||
* Possible problem : if encrypted file was
|
||||
* restored in a compressed directory, it was
|
||||
* restored as compressed.
|
||||
* TODO : decompress first.
|
||||
*/
|
||||
ntfs_log_error("File %s cannot be encrypted and compressed\n",
|
||||
path);
|
||||
errno = EIO;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
info_header = (const EFS_ATTR_HEADER*)value;
|
||||
/* make sure we get a likely efsinfo */
|
||||
if (le32_to_cpu(info_header->length) != size) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
|
||||
(ntfschar*)NULL,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
/*
|
||||
* no logged_utility_stream attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
*/
|
||||
res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name,4,
|
||||
(u8*)NULL,(s64)size);
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
/*
|
||||
* open and update the existing efs data
|
||||
*/
|
||||
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4);
|
||||
if (na) {
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate(na, (s64)size);
|
||||
/* overwrite value if any */
|
||||
if (!res && value) {
|
||||
written = (int)ntfs_attr_pwrite(na,
|
||||
(s64)0, (s64)size, value);
|
||||
if (written != (s64)size) {
|
||||
ntfs_log_error("Failed to "
|
||||
"update efs data\n");
|
||||
errno = EIO;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
/* iterate over AT_DATA attributes */
|
||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
return (-1);
|
||||
}
|
||||
while (!ntfs_attr_lookup(AT_DATA, NULL, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
if (ntfs_efs_fixup_attribute(ctx, NULL)) {
|
||||
ntfs_log_error("Error in efs fixup of AT_DATA Attribute");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
}
|
||||
ni->flags |= FILE_ATTR_ENCRYPTED;
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
}
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fixup raw encrypted AT_DATA Attribute
|
||||
* read padding length from last two bytes
|
||||
* truncate attribute, make non-resident,
|
||||
* set data size to match padding length
|
||||
* set ATTR_IS_ENCRYPTED flag on attribute
|
||||
*
|
||||
* Return 0 if successful
|
||||
* -1 if failed (errno tells why)
|
||||
*/
|
||||
|
||||
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
{
|
||||
u64 newsize;
|
||||
le16 appended_bytes;
|
||||
u16 padding_length;
|
||||
ATTR_RECORD *a;
|
||||
ntfs_inode *ni;
|
||||
BOOL close_na = FALSE;
|
||||
BOOL close_ctx = FALSE;
|
||||
|
||||
if (!ctx && !na) {
|
||||
ntfs_log_error("neither ctx nor na specified for efs_fixup_attribute\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (!ctx) {
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
goto err_out;
|
||||
}
|
||||
close_ctx=TRUE;
|
||||
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
a = ctx->attr;
|
||||
if (!na) {
|
||||
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
|
||||
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
|
||||
a->name_length);
|
||||
if (!na) {
|
||||
ntfs_log_error("can't open DATA Attribute\n");
|
||||
return (-1);
|
||||
}
|
||||
close_na = TRUE;
|
||||
}
|
||||
/* make sure size is valid for a raw encrypted stream */
|
||||
if ((na->data_size & 511) != 2) {
|
||||
ntfs_log_error("Bad raw encrypted stream");
|
||||
goto err_out;
|
||||
}
|
||||
/* read padding length from last two bytes of attribute */
|
||||
if (ntfs_attr_pread(na, na->data_size-2, 2, &appended_bytes) != 2) {
|
||||
ntfs_log_error("Error reading padding length\n");
|
||||
goto err_out;
|
||||
}
|
||||
padding_length = le16_to_cpu(appended_bytes);
|
||||
if (padding_length > 511 || padding_length > na->data_size-2) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_error("invalid padding length %d for data_size %lld\n",
|
||||
padding_length, (long long)na->data_size);
|
||||
goto err_out;
|
||||
}
|
||||
newsize = na->data_size - padding_length - 2;
|
||||
/* truncate attribute to possibly free clusters allocated
|
||||
for the last two bytes */
|
||||
if (ntfs_attr_truncate(na, na->data_size-2)) {
|
||||
ntfs_log_error("Error truncating attribute\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Encrypted AT_DATA Attributes MUST be non-resident */
|
||||
if (!NAttrNonResident(na)
|
||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||
ntfs_log_error("Error making DATA attribute non-resident\n");
|
||||
goto err_out;
|
||||
}
|
||||
ni = na->ni;
|
||||
if (!na->name_len) {
|
||||
ni->data_size = newsize;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
}
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
if (close_na)
|
||||
ntfs_attr_close(na);
|
||||
|
||||
ctx->attr->data_size = cpu_to_le64(newsize);
|
||||
if (le64_to_cpu(ctx->attr->initialized_size) > newsize)
|
||||
ctx->attr->initialized_size = ctx->attr->data_size;
|
||||
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
|
||||
if (close_ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
|
||||
return (0);
|
||||
err_out:
|
||||
if (close_na && na)
|
||||
ntfs_attr_close(na);
|
||||
if (close_ctx && ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (-1);
|
||||
}
|
266
src/ntfs-3g.c
266
src/ntfs-3g.c
@ -94,6 +94,7 @@
|
||||
#include "ntfstime.h"
|
||||
#include "security.h"
|
||||
#include "reparse.h"
|
||||
#include "efs.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
@ -122,6 +123,11 @@ typedef enum {
|
||||
NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
|
||||
} ntfs_fuse_streams_interface;
|
||||
|
||||
enum {
|
||||
CLOSE_COMPRESSED = 1,
|
||||
CLOSE_ENCRYPTED = 2
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ntfs_volume *vol;
|
||||
unsigned int uid;
|
||||
@ -139,6 +145,7 @@ typedef struct {
|
||||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
BOOL mounted;
|
||||
BOOL efs_raw;
|
||||
struct fuse_chan *fc;
|
||||
BOOL inherit;
|
||||
unsigned int secure_flags;
|
||||
@ -532,6 +539,14 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
||||
/* Regular or Interix (INTX) file. */
|
||||
stbuf->st_mode = S_IFREG;
|
||||
stbuf->st_size = ni->data_size;
|
||||
/*
|
||||
* return data size rounded to next 512 byte boundary for
|
||||
* encrypted files to include padding required for decryption
|
||||
* also include 2 bytes for padding info
|
||||
*/
|
||||
if (ctx->efs_raw && ni->flags & FILE_ATTR_ENCRYPTED)
|
||||
stbuf->st_size = ((ni->data_size + 511) & ~511) + 2;
|
||||
|
||||
/*
|
||||
* Temporary fix to make ActiveSync work via Samba 3.0.
|
||||
* See more on the ntfs-3g-devel list.
|
||||
@ -560,6 +575,12 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
||||
if (na->data_size == 1)
|
||||
stbuf->st_mode = S_IFSOCK;
|
||||
}
|
||||
/* encrypted named stream */
|
||||
/* round size up to next 512 byte boundary */
|
||||
if (ctx->efs_raw && stream_name_len &&
|
||||
(na->data_flags & ATTR_IS_ENCRYPTED) &&
|
||||
NAttrNonResident(na))
|
||||
stbuf->st_size = ((na->data_size+511) & ~511)+2;
|
||||
/*
|
||||
* Check whether it's Interix symbolic link, block or
|
||||
* character device.
|
||||
@ -793,9 +814,9 @@ static int ntfs_fuse_opendir(const char *path,
|
||||
accesstype = S_IWRITE | S_IREAD;
|
||||
else
|
||||
accesstype = S_IREAD;
|
||||
/* JPA directory must be searchable */
|
||||
/* directory must be searchable */
|
||||
if (!ntfs_allowed_dir_access(&security,path,S_IEXEC)
|
||||
/* JPA check whether requested access is allowed */
|
||||
/* check whether requested access is allowed */
|
||||
|| !ntfs_allowed_access(&security,path,ni,accesstype))
|
||||
res = -EACCES;
|
||||
}
|
||||
@ -865,25 +886,26 @@ static int ntfs_fuse_open(const char *org_path,
|
||||
accesstype = S_IWRITE | S_IREAD;
|
||||
else
|
||||
accesstype = S_IREAD;
|
||||
if (NAttrEncrypted(na)
|
||||
/* JPA directory must be searchable */
|
||||
|| !ntfs_allowed_dir_access(&security,path,S_IEXEC)
|
||||
if (!ntfs_allowed_dir_access(&security,
|
||||
path,S_IEXEC)
|
||||
/* JPA check whether requested access is allowed */
|
||||
|| !ntfs_allowed_access(&security,path,ni,accesstype))
|
||||
res = -EACCES;
|
||||
} else {
|
||||
if (NAttrEncrypted(na))
|
||||
|| !ntfs_allowed_access(&security,
|
||||
path,ni,accesstype))
|
||||
res = -EACCES;
|
||||
}
|
||||
#else
|
||||
if (NAttrEncrypted(na))
|
||||
res = -EACCES;
|
||||
#endif
|
||||
/* mark a future need to compress the last chunk */
|
||||
if ((res >= 0)
|
||||
&& (na->data_flags & ATTR_COMPRESSION_MASK)
|
||||
&& (fi->flags & (O_WRONLY | O_RDWR)))
|
||||
fi->fh |= 1;
|
||||
&& (fi->flags & (O_WRONLY | O_RDWR))) {
|
||||
/* mark a future need to compress the last chunk */
|
||||
if (na->data_flags & ATTR_COMPRESSION_MASK)
|
||||
fi->fh |= CLOSE_COMPRESSED;
|
||||
/* mark a future need to fixup encrypted inode */
|
||||
if (ctx->efs_raw
|
||||
&& !(na->data_flags & ATTR_IS_ENCRYPTED)
|
||||
&& (ni->flags & FILE_ATTR_ENCRYPTED))
|
||||
fi->fh |= CLOSE_ENCRYPTED;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
res = -errno;
|
||||
@ -906,6 +928,7 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
|
||||
ntfschar *stream_name;
|
||||
int stream_name_len, res;
|
||||
s64 total = 0;
|
||||
s64 max_read;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
@ -923,10 +946,16 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
if (offset + (off_t)size > na->data_size) {
|
||||
if (na->data_size < offset)
|
||||
/* limit reads at next 512 byte boundary for encrypted attributes */
|
||||
max_read = na->data_size;
|
||||
if (ctx->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) &&
|
||||
NAttrNonResident(na)) {
|
||||
max_read = ((na->data_size+511) & ~511) + 2;
|
||||
}
|
||||
if (offset + (off_t)size > max_read) {
|
||||
if (max_read < offset)
|
||||
goto ok;
|
||||
size = na->data_size - offset;
|
||||
size = max_read - offset;
|
||||
}
|
||||
while (size > 0) {
|
||||
s64 ret = ntfs_attr_pread(na, offset, size, buf);
|
||||
@ -1015,7 +1044,7 @@ static int ntfs_fuse_release(const char *org_path,
|
||||
int stream_name_len, res;
|
||||
|
||||
/* Only for marked descriptors there is something to do */
|
||||
if (!(fi->fh & 1)) {
|
||||
if (!(fi->fh & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED))) {
|
||||
res = 0;
|
||||
goto out;
|
||||
}
|
||||
@ -1034,7 +1063,11 @@ static int ntfs_fuse_release(const char *org_path,
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
res = ntfs_attr_pclose(na);
|
||||
res = 0;
|
||||
if (fi->fh & CLOSE_COMPRESSED)
|
||||
res = ntfs_attr_pclose(na);
|
||||
if (fi->fh & CLOSE_ENCRYPTED)
|
||||
res = ntfs_efs_fixup_attribute(NULL, na);
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
@ -1372,10 +1405,15 @@ static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev,
|
||||
set_fuse_error(&res);
|
||||
#endif
|
||||
}
|
||||
/* mark a need to compress the end of file */
|
||||
/* mark a need to compress the end of file */
|
||||
if (fi && (ni->flags & FILE_ATTR_COMPRESSED)) {
|
||||
fi->fh |= 1;
|
||||
fi->fh |= CLOSE_COMPRESSED;
|
||||
}
|
||||
/* mark a future need to fixup encrypted inode */
|
||||
if (fi
|
||||
&& ctx->efs_raw
|
||||
&& (ni->flags & FILE_ATTR_ENCRYPTED))
|
||||
fi->fh |= CLOSE_ENCRYPTED;
|
||||
NInoSetDirty(ni);
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
@ -1426,9 +1464,18 @@ static int ntfs_fuse_create_stream(const char *path,
|
||||
}
|
||||
if (ntfs_attr_add(ni, AT_DATA, stream_name, stream_name_len, NULL, 0))
|
||||
res = -errno;
|
||||
if ((res >= 0) && (ni->flags & FILE_ATTR_COMPRESSED)
|
||||
&& (fi->flags & (O_WRONLY | O_RDWR)))
|
||||
fi->fh |= 1;
|
||||
|
||||
if ((res >= 0)
|
||||
&& (fi->flags & (O_WRONLY | O_RDWR))) {
|
||||
/* mark a future need to compress the last block */
|
||||
if (ni->flags & FILE_ATTR_COMPRESSED)
|
||||
fi->fh |= CLOSE_COMPRESSED;
|
||||
/* mark a future need to fixup encrypted inode */
|
||||
if (ctx->efs_raw
|
||||
&& (ni->flags & FILE_ATTR_ENCRYPTED))
|
||||
fi->fh |= CLOSE_ENCRYPTED;
|
||||
}
|
||||
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
return res;
|
||||
@ -1925,11 +1972,14 @@ static const char xattr_ntfs_3g[] = "ntfs-3g.";
|
||||
enum { XATTR_UNMAPPED,
|
||||
XATTR_NTFS_ACL,
|
||||
XATTR_NTFS_ATTRIB,
|
||||
XATTR_NTFS_EFSINFO,
|
||||
XATTR_NTFS_REPARSE_DATA,
|
||||
XATTR_POSIX_ACC, XATTR_POSIX_DEF } ;
|
||||
XATTR_POSIX_ACC,
|
||||
XATTR_POSIX_DEF } ;
|
||||
|
||||
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_efsinfo[] = "user.ntfs.efsinfo";
|
||||
static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
|
||||
static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
|
||||
static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
|
||||
@ -2003,7 +2053,12 @@ static int mapped_xattr_system(const char *name)
|
||||
if (!strcmp(name,nf_ns_xattr_posix_default))
|
||||
num = XATTR_POSIX_DEF;
|
||||
else
|
||||
num = XATTR_UNMAPPED;
|
||||
if (ctx->efs_raw
|
||||
&& !strcmp(name,
|
||||
nf_ns_xattr_efsinfo))
|
||||
num = XATTR_NTFS_EFSINFO;
|
||||
else
|
||||
num = XATTR_UNMAPPED;
|
||||
return (num);
|
||||
}
|
||||
|
||||
@ -2093,10 +2148,6 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
|
||||
#if POSIXACLS
|
||||
struct SECURITY_CONTEXT security;
|
||||
#endif
|
||||
|
||||
if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
|
||||
&& (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR))
|
||||
return -EOPNOTSUPP;
|
||||
#if POSIXACLS
|
||||
/* parent directory must be executable */
|
||||
if (ntfs_fuse_fill_security_context(&security)
|
||||
@ -2121,53 +2172,71 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
|
||||
ntfs_inode_close(ni);
|
||||
goto exit;
|
||||
}
|
||||
while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
|
||||
0, NULL, 0, actx)) {
|
||||
char *tmp_name = NULL;
|
||||
int tmp_name_len;
|
||||
|
||||
if (!actx->attr->name_length)
|
||||
continue;
|
||||
tmp_name_len = ntfs_ucstombs((ntfschar *)((u8*)actx->attr +
|
||||
le16_to_cpu(actx->attr->name_offset)),
|
||||
if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR)
|
||||
|| (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) {
|
||||
while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
|
||||
0, NULL, 0, actx)) {
|
||||
char *tmp_name = NULL;
|
||||
int tmp_name_len;
|
||||
|
||||
if (!actx->attr->name_length)
|
||||
continue;
|
||||
tmp_name_len = ntfs_ucstombs(
|
||||
(ntfschar *)((u8*)actx->attr +
|
||||
le16_to_cpu(actx->attr->name_offset)),
|
||||
actx->attr->name_length, &tmp_name, 0);
|
||||
if (tmp_name_len < 0) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
/*
|
||||
* When using name spaces, do not return
|
||||
* security, trusted nor system attributes
|
||||
* (filtered elsewhere anyway)
|
||||
* otherwise insert "user." prefix
|
||||
*/
|
||||
if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
|
||||
if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g))
|
||||
&& !strncmp(tmp_name,xattr_ntfs_3g,
|
||||
sizeof(xattr_ntfs_3g)-1))
|
||||
tmp_name_len = 0;
|
||||
else
|
||||
ret += tmp_name_len + nf_ns_user_prefix_len + 1;
|
||||
} else
|
||||
ret += tmp_name_len + 1;
|
||||
if (size && tmp_name_len) {
|
||||
if ((size_t)ret <= size) {
|
||||
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;
|
||||
to++;
|
||||
} else {
|
||||
free(tmp_name);
|
||||
ret = -ERANGE;
|
||||
if (tmp_name_len < 0) {
|
||||
ret = -errno;
|
||||
goto exit;
|
||||
}
|
||||
/*
|
||||
* When using name spaces, do not return
|
||||
* security, trusted nor system attributes
|
||||
* (filtered elsewhere anyway)
|
||||
* otherwise insert "user." prefix
|
||||
*/
|
||||
if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
|
||||
if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g))
|
||||
&& !strncmp(tmp_name,xattr_ntfs_3g,
|
||||
sizeof(xattr_ntfs_3g)-1))
|
||||
tmp_name_len = 0;
|
||||
else
|
||||
ret += tmp_name_len
|
||||
+ nf_ns_user_prefix_len + 1;
|
||||
} else
|
||||
ret += tmp_name_len + 1;
|
||||
if (size && tmp_name_len) {
|
||||
if ((size_t)ret <= size) {
|
||||
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;
|
||||
to++;
|
||||
} else {
|
||||
free(tmp_name);
|
||||
ret = -ERANGE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
free(tmp_name);
|
||||
}
|
||||
free(tmp_name);
|
||||
}
|
||||
|
||||
/* List efs info xattr for encrypted files */
|
||||
if (ctx->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
|
||||
ret += sizeof(nf_ns_xattr_efsinfo);
|
||||
if ((size_t)ret <= size) {
|
||||
memcpy(to, nf_ns_xattr_efsinfo,
|
||||
sizeof(nf_ns_xattr_efsinfo));
|
||||
to += sizeof(nf_ns_xattr_efsinfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (errno != ENOENT)
|
||||
ret = -errno;
|
||||
exit:
|
||||
@ -2263,6 +2332,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
||||
ntfs_attr *na = NULL;
|
||||
ntfschar *lename = NULL;
|
||||
int res, lename_len;
|
||||
s64 rsize;
|
||||
int attr;
|
||||
int namespace;
|
||||
struct SECURITY_CONTEXT security;
|
||||
@ -2298,6 +2368,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
||||
res = ntfs_get_ntfs_attrib(path,
|
||||
value,size,ni);
|
||||
break;
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
res = ntfs_get_efs_info(path,
|
||||
value,size,ni);
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
res = ntfs_get_ntfs_reparse_data(path,
|
||||
value,size,ni);
|
||||
@ -2305,8 +2379,9 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
||||
default : /* not possible */
|
||||
break;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
res = -errno;
|
||||
}
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
} else
|
||||
@ -2339,6 +2414,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
||||
res = ntfs_get_ntfs_attrib(path,
|
||||
value,size,ni);
|
||||
break;
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
res = ntfs_get_efs_info(path,
|
||||
value,size,ni);
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
res = ntfs_get_ntfs_reparse_data(path,
|
||||
value,size,ni);
|
||||
@ -2398,15 +2477,20 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
||||
res = -ENODATA;
|
||||
goto exit;
|
||||
}
|
||||
rsize = na->data_size;
|
||||
if (ctx->efs_raw &&
|
||||
(na->data_flags & ATTR_IS_ENCRYPTED) &&
|
||||
NAttrNonResident(na))
|
||||
rsize = ((na->data_size + 511) & ~511)+2;
|
||||
if (size) {
|
||||
if (size >= (size_t)na->data_size) {
|
||||
res = ntfs_attr_pread(na, 0, na->data_size, value);
|
||||
if (res != na->data_size)
|
||||
if (size >= (size_t)rsize) {
|
||||
res = ntfs_attr_pread(na, 0, rsize, value);
|
||||
if (res != rsize)
|
||||
res = -errno;
|
||||
} else
|
||||
res = -ERANGE;
|
||||
} else
|
||||
res = na->data_size;
|
||||
res = rsize;
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
@ -2454,6 +2538,10 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
||||
res = ntfs_set_ntfs_attrib(path,
|
||||
value,size,flags,ni);
|
||||
break;
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
res = ntfs_set_efs_info(path,
|
||||
value,size,flags,ni);
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
res = ntfs_set_ntfs_reparse_data(path,
|
||||
value,size,flags,ni);
|
||||
@ -2495,6 +2583,10 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
||||
res = ntfs_set_ntfs_attrib(path,
|
||||
value,size,flags,ni);
|
||||
break;
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
res = ntfs_set_efs_info(path,
|
||||
value,size,flags,ni);
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
res = ntfs_set_ntfs_reparse_data(path,
|
||||
value,size,flags,ni);
|
||||
@ -2603,10 +2695,14 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
||||
if (part > 0)
|
||||
total += part;
|
||||
} while ((part > 0) && (total < size));
|
||||
if (total != size)
|
||||
res = -errno;
|
||||
else
|
||||
res = ntfs_attr_pclose(na);
|
||||
if (total != size)
|
||||
res = -errno;
|
||||
else
|
||||
if (!(res = ntfs_attr_pclose(na)))
|
||||
if (ctx->efs_raw
|
||||
&& (ni->flags & FILE_ATTR_ENCRYPTED))
|
||||
res = ntfs_efs_fixup_attribute(NULL,
|
||||
na);
|
||||
} else
|
||||
res = 0;
|
||||
exit:
|
||||
@ -2644,6 +2740,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
|
||||
*/
|
||||
case XATTR_NTFS_ACL :
|
||||
case XATTR_NTFS_ATTRIB :
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
res = -EPERM;
|
||||
break;
|
||||
case XATTR_POSIX_ACC :
|
||||
@ -2688,6 +2785,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
|
||||
*/
|
||||
case XATTR_NTFS_ACL :
|
||||
case XATTR_NTFS_ATTRIB :
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
res = -EPERM;
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
@ -2994,6 +3092,7 @@ static char *parse_mount_options(const char *orig_opts)
|
||||
int default_permissions = 0;
|
||||
|
||||
ctx->secure_flags = 0;
|
||||
ctx->efs_raw = FALSE;
|
||||
options = strdup(orig_opts ? orig_opts : "");
|
||||
if (!options) {
|
||||
ntfs_log_perror("%s: strdup failed", EXEC_NAME);
|
||||
@ -3164,6 +3263,10 @@ static char *parse_mount_options(const char *orig_opts)
|
||||
"'usermapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
} else if (!strcmp(opt, "efs_raw")) {
|
||||
if (bogus_option_value(val, "efs_raw"))
|
||||
goto err_exit;
|
||||
ctx->efs_raw = TRUE;
|
||||
} else { /* Probably FUSE option. */
|
||||
if (strappend(&ret, opt))
|
||||
goto err_exit;
|
||||
@ -3615,6 +3718,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
ctx->security.vol = ctx->vol;
|
||||
ctx->vol->secure_flags = ctx->secure_flags;
|
||||
ctx->vol->efs_raw = ctx->efs_raw;
|
||||
if (ctx->secure_flags & (1 << SECURITY_RAW)) {
|
||||
ctx->security.uid = ctx->uid;
|
||||
ctx->security.gid = ctx->gid;
|
||||
|
Loading…
Reference in New Issue
Block a user