mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 10:04:00 +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
|
Jean-Pierre Andre
|
||||||
Alon Bar-Lev
|
Alon Bar-Lev
|
||||||
|
Martin Bene
|
||||||
Dominique L Bouix
|
Dominique L Bouix
|
||||||
Csaba Henk
|
Csaba Henk
|
||||||
Bernhard Kaindl
|
Bernhard Kaindl
|
||||||
|
@ -14,6 +14,7 @@ headers = \
|
|||||||
device.h \
|
device.h \
|
||||||
device_io.h \
|
device_io.h \
|
||||||
dir.h \
|
dir.h \
|
||||||
|
efs.h \
|
||||||
endians.h \
|
endians.h \
|
||||||
index.h \
|
index.h \
|
||||||
inode.h \
|
inode.h \
|
||||||
|
@ -285,7 +285,8 @@ extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
|
|||||||
const ATTR_TYPES type);
|
const ATTR_TYPES type);
|
||||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||||
const ATTR_TYPES type);
|
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_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
|
||||||
|
|
||||||
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
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
|
s64 free_clusters; /* Track the number of free clusters which
|
||||||
greatly improves statfs() performance */
|
greatly improves statfs() performance */
|
||||||
s64 free_mft_records; /* Same for free mft records (see above) */
|
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
|
#if CACHE_INODE_SIZE
|
||||||
struct CACHE_HEADER *xinode_cache;
|
struct CACHE_HEADER *xinode_cache;
|
||||||
|
@ -29,6 +29,7 @@ libntfs_3g_la_SOURCES = \
|
|||||||
debug.c \
|
debug.c \
|
||||||
device.c \
|
device.c \
|
||||||
dir.c \
|
dir.c \
|
||||||
|
efs.c \
|
||||||
index.c \
|
index.c \
|
||||||
inode.c \
|
inode.c \
|
||||||
lcnalloc.c \
|
lcnalloc.c \
|
||||||
@ -37,7 +38,7 @@ libntfs_3g_la_SOURCES = \
|
|||||||
mft.c \
|
mft.c \
|
||||||
misc.c \
|
misc.c \
|
||||||
mst.c \
|
mst.c \
|
||||||
reparse.c \
|
reparse.c \
|
||||||
runlist.c \
|
runlist.c \
|
||||||
security.c \
|
security.c \
|
||||||
unistr.c \
|
unistr.c \
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
#include "efs.h"
|
||||||
|
|
||||||
#define STANDARD_COMPRESSION_UNIT 4
|
#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
|
* directory (for unnamed data streams) or on current
|
||||||
* inode (for named data streams). The compression mark
|
* inode (for named data streams). The compression mark
|
||||||
* may change any time, the compression state can only
|
* 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;
|
a->flags &= ~ATTR_COMPRESSION_MASK;
|
||||||
if (na->ni->flags & FILE_ATTR_COMPRESSED)
|
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)
|
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;
|
ntfs_volume *vol;
|
||||||
runlist_element *rl;
|
runlist_element *rl;
|
||||||
|
u16 efs_padding_length;
|
||||||
|
|
||||||
/* Sanity checking arguments is done in ntfs_attr_pread(). */
|
/* 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
|
* Encrypted non-resident attributes are not supported. We return
|
||||||
* access denied, which is what Windows NT4 does, too.
|
* 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;
|
errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
vol = na->ni->vol;
|
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
/* Truncate reads beyond end of attribute. */
|
/*
|
||||||
if (pos + count > na->data_size) {
|
* Truncate reads beyond end of attribute,
|
||||||
if (pos >= na->data_size)
|
* 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;
|
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 it is a resident attribute, get the value from the mft record. */
|
||||||
if (!NAttrNonResident(na)) {
|
if (!NAttrNonResident(na)) {
|
||||||
@ -868,15 +887,42 @@ res_err_out:
|
|||||||
}
|
}
|
||||||
total = total2 = 0;
|
total = total2 = 0;
|
||||||
/* Zero out reads beyond initialized size. */
|
/* Zero out reads beyond initialized size. */
|
||||||
if (pos + count > na->initialized_size) {
|
if (pos + count > max_init) {
|
||||||
if (pos >= na->initialized_size) {
|
if (pos >= max_init) {
|
||||||
memset(b, 0, count);
|
memset(b, 0, count);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
total2 = pos + count - na->initialized_size;
|
total2 = pos + count - max_init;
|
||||||
count -= total2;
|
count -= total2;
|
||||||
memset((u8*)b + count, 0, 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. */
|
/* Find the runlist element containing the vcn. */
|
||||||
rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
|
rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
|
||||||
if (!rl) {
|
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)
|
compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
|
||||||
!= const_cpu_to_le16(0);
|
!= 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.
|
* 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;
|
errno = EACCES;
|
||||||
goto errno_set;
|
goto errno_set;
|
||||||
}
|
}
|
||||||
@ -3074,7 +3122,7 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
|||||||
ntfs_inode *base_ni;
|
ntfs_inode *base_ni;
|
||||||
|
|
||||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n",
|
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)) {
|
if (!ni || (!name && name_len)) {
|
||||||
errno = EINVAL;
|
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
|
* 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.
|
* 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)
|
ntfs_attr_search_ctx *ctx)
|
||||||
{
|
{
|
||||||
s64 new_allocated_size, bw;
|
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))
|
if (ntfs_attr_can_be_resident(vol, na->type))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (NAttrEncrypted(na)) {
|
if (na->data_flags & ATTR_IS_ENCRYPTED) {
|
||||||
ntfs_log_trace("Making encrypted files resident is not "
|
ntfs_log_trace("Making encrypted streams resident is not "
|
||||||
"implemented yet.\n");
|
"implemented yet.\n");
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
return -1;
|
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,
|
* Encrypted attributes are not supported. We return access denied,
|
||||||
* which is what Windows NT4 does, too.
|
* which is what Windows NT4 does, too.
|
||||||
*/
|
*/
|
||||||
if (NAttrEncrypted(na)) {
|
if (na->data_flags & ATTR_IS_ENCRYPTED) {
|
||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
ntfs_log_perror("Failed to truncate encrypted attribute");
|
ntfs_log_info("Failed to truncate encrypted attribute");
|
||||||
goto out;
|
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 "ntfstime.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
#include "reparse.h"
|
#include "reparse.h"
|
||||||
|
#include "efs.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
@ -122,6 +123,11 @@ typedef enum {
|
|||||||
NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
|
NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
|
||||||
} ntfs_fuse_streams_interface;
|
} ntfs_fuse_streams_interface;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CLOSE_COMPRESSED = 1,
|
||||||
|
CLOSE_ENCRYPTED = 2
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ntfs_volume *vol;
|
ntfs_volume *vol;
|
||||||
unsigned int uid;
|
unsigned int uid;
|
||||||
@ -139,6 +145,7 @@ typedef struct {
|
|||||||
BOOL no_detach;
|
BOOL no_detach;
|
||||||
BOOL blkdev;
|
BOOL blkdev;
|
||||||
BOOL mounted;
|
BOOL mounted;
|
||||||
|
BOOL efs_raw;
|
||||||
struct fuse_chan *fc;
|
struct fuse_chan *fc;
|
||||||
BOOL inherit;
|
BOOL inherit;
|
||||||
unsigned int secure_flags;
|
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. */
|
/* Regular or Interix (INTX) file. */
|
||||||
stbuf->st_mode = S_IFREG;
|
stbuf->st_mode = S_IFREG;
|
||||||
stbuf->st_size = ni->data_size;
|
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.
|
* Temporary fix to make ActiveSync work via Samba 3.0.
|
||||||
* See more on the ntfs-3g-devel list.
|
* 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)
|
if (na->data_size == 1)
|
||||||
stbuf->st_mode = S_IFSOCK;
|
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
|
* Check whether it's Interix symbolic link, block or
|
||||||
* character device.
|
* character device.
|
||||||
@ -793,9 +814,9 @@ static int ntfs_fuse_opendir(const char *path,
|
|||||||
accesstype = S_IWRITE | S_IREAD;
|
accesstype = S_IWRITE | S_IREAD;
|
||||||
else
|
else
|
||||||
accesstype = S_IREAD;
|
accesstype = S_IREAD;
|
||||||
/* JPA directory must be searchable */
|
/* directory must be searchable */
|
||||||
if (!ntfs_allowed_dir_access(&security,path,S_IEXEC)
|
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))
|
|| !ntfs_allowed_access(&security,path,ni,accesstype))
|
||||||
res = -EACCES;
|
res = -EACCES;
|
||||||
}
|
}
|
||||||
@ -865,25 +886,26 @@ static int ntfs_fuse_open(const char *org_path,
|
|||||||
accesstype = S_IWRITE | S_IREAD;
|
accesstype = S_IWRITE | S_IREAD;
|
||||||
else
|
else
|
||||||
accesstype = S_IREAD;
|
accesstype = S_IREAD;
|
||||||
if (NAttrEncrypted(na)
|
|
||||||
/* JPA directory must be searchable */
|
/* 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 */
|
/* JPA check whether requested access is allowed */
|
||||||
|| !ntfs_allowed_access(&security,path,ni,accesstype))
|
|| !ntfs_allowed_access(&security,
|
||||||
res = -EACCES;
|
path,ni,accesstype))
|
||||||
} else {
|
|
||||||
if (NAttrEncrypted(na))
|
|
||||||
res = -EACCES;
|
res = -EACCES;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (NAttrEncrypted(na))
|
|
||||||
res = -EACCES;
|
|
||||||
#endif
|
#endif
|
||||||
/* mark a future need to compress the last chunk */
|
|
||||||
if ((res >= 0)
|
if ((res >= 0)
|
||||||
&& (na->data_flags & ATTR_COMPRESSION_MASK)
|
&& (fi->flags & (O_WRONLY | O_RDWR))) {
|
||||||
&& (fi->flags & (O_WRONLY | O_RDWR)))
|
/* mark a future need to compress the last chunk */
|
||||||
fi->fh |= 1;
|
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);
|
ntfs_attr_close(na);
|
||||||
} else
|
} else
|
||||||
res = -errno;
|
res = -errno;
|
||||||
@ -906,6 +928,7 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
|
|||||||
ntfschar *stream_name;
|
ntfschar *stream_name;
|
||||||
int stream_name_len, res;
|
int stream_name_len, res;
|
||||||
s64 total = 0;
|
s64 total = 0;
|
||||||
|
s64 max_read;
|
||||||
|
|
||||||
if (!size)
|
if (!size)
|
||||||
return 0;
|
return 0;
|
||||||
@ -923,10 +946,16 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
|
|||||||
res = -errno;
|
res = -errno;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
if (offset + (off_t)size > na->data_size) {
|
/* limit reads at next 512 byte boundary for encrypted attributes */
|
||||||
if (na->data_size < offset)
|
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;
|
goto ok;
|
||||||
size = na->data_size - offset;
|
size = max_read - offset;
|
||||||
}
|
}
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
s64 ret = ntfs_attr_pread(na, offset, size, buf);
|
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;
|
int stream_name_len, res;
|
||||||
|
|
||||||
/* Only for marked descriptors there is something to do */
|
/* Only for marked descriptors there is something to do */
|
||||||
if (!(fi->fh & 1)) {
|
if (!(fi->fh & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED))) {
|
||||||
res = 0;
|
res = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1034,7 +1063,11 @@ static int ntfs_fuse_release(const char *org_path,
|
|||||||
res = -errno;
|
res = -errno;
|
||||||
goto exit;
|
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:
|
exit:
|
||||||
if (na)
|
if (na)
|
||||||
ntfs_attr_close(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);
|
set_fuse_error(&res);
|
||||||
#endif
|
#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)) {
|
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);
|
NInoSetDirty(ni);
|
||||||
if (ntfs_inode_close(ni))
|
if (ntfs_inode_close(ni))
|
||||||
set_fuse_error(&res);
|
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))
|
if (ntfs_attr_add(ni, AT_DATA, stream_name, stream_name_len, NULL, 0))
|
||||||
res = -errno;
|
res = -errno;
|
||||||
if ((res >= 0) && (ni->flags & FILE_ATTR_COMPRESSED)
|
|
||||||
&& (fi->flags & (O_WRONLY | O_RDWR)))
|
if ((res >= 0)
|
||||||
fi->fh |= 1;
|
&& (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))
|
if (ntfs_inode_close(ni))
|
||||||
set_fuse_error(&res);
|
set_fuse_error(&res);
|
||||||
return res;
|
return res;
|
||||||
@ -1925,11 +1972,14 @@ static const char xattr_ntfs_3g[] = "ntfs-3g.";
|
|||||||
enum { XATTR_UNMAPPED,
|
enum { XATTR_UNMAPPED,
|
||||||
XATTR_NTFS_ACL,
|
XATTR_NTFS_ACL,
|
||||||
XATTR_NTFS_ATTRIB,
|
XATTR_NTFS_ATTRIB,
|
||||||
|
XATTR_NTFS_EFSINFO,
|
||||||
XATTR_NTFS_REPARSE_DATA,
|
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_ntfs[] = "system.ntfs_acl";
|
||||||
static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
|
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_reparse[] = "system.ntfs_reparse_data";
|
||||||
static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
|
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_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))
|
if (!strcmp(name,nf_ns_xattr_posix_default))
|
||||||
num = XATTR_POSIX_DEF;
|
num = XATTR_POSIX_DEF;
|
||||||
else
|
else
|
||||||
num = XATTR_UNMAPPED;
|
if (ctx->efs_raw
|
||||||
|
&& !strcmp(name,
|
||||||
|
nf_ns_xattr_efsinfo))
|
||||||
|
num = XATTR_NTFS_EFSINFO;
|
||||||
|
else
|
||||||
|
num = XATTR_UNMAPPED;
|
||||||
return (num);
|
return (num);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2093,10 +2148,6 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
|
|||||||
#if POSIXACLS
|
#if POSIXACLS
|
||||||
struct SECURITY_CONTEXT security;
|
struct SECURITY_CONTEXT security;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
|
|
||||||
&& (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR))
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
#if POSIXACLS
|
#if POSIXACLS
|
||||||
/* parent directory must be executable */
|
/* parent directory must be executable */
|
||||||
if (ntfs_fuse_fill_security_context(&security)
|
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);
|
ntfs_inode_close(ni);
|
||||||
goto exit;
|
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)
|
if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR)
|
||||||
continue;
|
|| (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) {
|
||||||
tmp_name_len = ntfs_ucstombs((ntfschar *)((u8*)actx->attr +
|
while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
|
||||||
le16_to_cpu(actx->attr->name_offset)),
|
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);
|
actx->attr->name_length, &tmp_name, 0);
|
||||||
if (tmp_name_len < 0) {
|
if (tmp_name_len < 0) {
|
||||||
ret = -errno;
|
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;
|
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)
|
if (errno != ENOENT)
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
exit:
|
exit:
|
||||||
@ -2263,6 +2332,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
|||||||
ntfs_attr *na = NULL;
|
ntfs_attr *na = NULL;
|
||||||
ntfschar *lename = NULL;
|
ntfschar *lename = NULL;
|
||||||
int res, lename_len;
|
int res, lename_len;
|
||||||
|
s64 rsize;
|
||||||
int attr;
|
int attr;
|
||||||
int namespace;
|
int namespace;
|
||||||
struct SECURITY_CONTEXT security;
|
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,
|
res = ntfs_get_ntfs_attrib(path,
|
||||||
value,size,ni);
|
value,size,ni);
|
||||||
break;
|
break;
|
||||||
|
case XATTR_NTFS_EFSINFO :
|
||||||
|
res = ntfs_get_efs_info(path,
|
||||||
|
value,size,ni);
|
||||||
|
break;
|
||||||
case XATTR_NTFS_REPARSE_DATA :
|
case XATTR_NTFS_REPARSE_DATA :
|
||||||
res = ntfs_get_ntfs_reparse_data(path,
|
res = ntfs_get_ntfs_reparse_data(path,
|
||||||
value,size,ni);
|
value,size,ni);
|
||||||
@ -2305,8 +2379,9 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
|||||||
default : /* not possible */
|
default : /* not possible */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
res = -errno;
|
res = -errno;
|
||||||
|
}
|
||||||
if (ntfs_inode_close(ni))
|
if (ntfs_inode_close(ni))
|
||||||
set_fuse_error(&res);
|
set_fuse_error(&res);
|
||||||
} else
|
} else
|
||||||
@ -2339,6 +2414,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
|||||||
res = ntfs_get_ntfs_attrib(path,
|
res = ntfs_get_ntfs_attrib(path,
|
||||||
value,size,ni);
|
value,size,ni);
|
||||||
break;
|
break;
|
||||||
|
case XATTR_NTFS_EFSINFO :
|
||||||
|
res = ntfs_get_efs_info(path,
|
||||||
|
value,size,ni);
|
||||||
|
break;
|
||||||
case XATTR_NTFS_REPARSE_DATA :
|
case XATTR_NTFS_REPARSE_DATA :
|
||||||
res = ntfs_get_ntfs_reparse_data(path,
|
res = ntfs_get_ntfs_reparse_data(path,
|
||||||
value,size,ni);
|
value,size,ni);
|
||||||
@ -2398,15 +2477,20 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
|||||||
res = -ENODATA;
|
res = -ENODATA;
|
||||||
goto exit;
|
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) {
|
||||||
if (size >= (size_t)na->data_size) {
|
if (size >= (size_t)rsize) {
|
||||||
res = ntfs_attr_pread(na, 0, na->data_size, value);
|
res = ntfs_attr_pread(na, 0, rsize, value);
|
||||||
if (res != na->data_size)
|
if (res != rsize)
|
||||||
res = -errno;
|
res = -errno;
|
||||||
} else
|
} else
|
||||||
res = -ERANGE;
|
res = -ERANGE;
|
||||||
} else
|
} else
|
||||||
res = na->data_size;
|
res = rsize;
|
||||||
exit:
|
exit:
|
||||||
if (na)
|
if (na)
|
||||||
ntfs_attr_close(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,
|
res = ntfs_set_ntfs_attrib(path,
|
||||||
value,size,flags,ni);
|
value,size,flags,ni);
|
||||||
break;
|
break;
|
||||||
|
case XATTR_NTFS_EFSINFO :
|
||||||
|
res = ntfs_set_efs_info(path,
|
||||||
|
value,size,flags,ni);
|
||||||
|
break;
|
||||||
case XATTR_NTFS_REPARSE_DATA :
|
case XATTR_NTFS_REPARSE_DATA :
|
||||||
res = ntfs_set_ntfs_reparse_data(path,
|
res = ntfs_set_ntfs_reparse_data(path,
|
||||||
value,size,flags,ni);
|
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,
|
res = ntfs_set_ntfs_attrib(path,
|
||||||
value,size,flags,ni);
|
value,size,flags,ni);
|
||||||
break;
|
break;
|
||||||
|
case XATTR_NTFS_EFSINFO :
|
||||||
|
res = ntfs_set_efs_info(path,
|
||||||
|
value,size,flags,ni);
|
||||||
|
break;
|
||||||
case XATTR_NTFS_REPARSE_DATA :
|
case XATTR_NTFS_REPARSE_DATA :
|
||||||
res = ntfs_set_ntfs_reparse_data(path,
|
res = ntfs_set_ntfs_reparse_data(path,
|
||||||
value,size,flags,ni);
|
value,size,flags,ni);
|
||||||
@ -2603,10 +2695,14 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
|||||||
if (part > 0)
|
if (part > 0)
|
||||||
total += part;
|
total += part;
|
||||||
} while ((part > 0) && (total < size));
|
} while ((part > 0) && (total < size));
|
||||||
if (total != size)
|
if (total != size)
|
||||||
res = -errno;
|
res = -errno;
|
||||||
else
|
else
|
||||||
res = ntfs_attr_pclose(na);
|
if (!(res = ntfs_attr_pclose(na)))
|
||||||
|
if (ctx->efs_raw
|
||||||
|
&& (ni->flags & FILE_ATTR_ENCRYPTED))
|
||||||
|
res = ntfs_efs_fixup_attribute(NULL,
|
||||||
|
na);
|
||||||
} else
|
} else
|
||||||
res = 0;
|
res = 0;
|
||||||
exit:
|
exit:
|
||||||
@ -2644,6 +2740,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
|
|||||||
*/
|
*/
|
||||||
case XATTR_NTFS_ACL :
|
case XATTR_NTFS_ACL :
|
||||||
case XATTR_NTFS_ATTRIB :
|
case XATTR_NTFS_ATTRIB :
|
||||||
|
case XATTR_NTFS_EFSINFO :
|
||||||
res = -EPERM;
|
res = -EPERM;
|
||||||
break;
|
break;
|
||||||
case XATTR_POSIX_ACC :
|
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_ACL :
|
||||||
case XATTR_NTFS_ATTRIB :
|
case XATTR_NTFS_ATTRIB :
|
||||||
|
case XATTR_NTFS_EFSINFO :
|
||||||
res = -EPERM;
|
res = -EPERM;
|
||||||
break;
|
break;
|
||||||
case XATTR_NTFS_REPARSE_DATA :
|
case XATTR_NTFS_REPARSE_DATA :
|
||||||
@ -2994,6 +3092,7 @@ static char *parse_mount_options(const char *orig_opts)
|
|||||||
int default_permissions = 0;
|
int default_permissions = 0;
|
||||||
|
|
||||||
ctx->secure_flags = 0;
|
ctx->secure_flags = 0;
|
||||||
|
ctx->efs_raw = FALSE;
|
||||||
options = strdup(orig_opts ? orig_opts : "");
|
options = strdup(orig_opts ? orig_opts : "");
|
||||||
if (!options) {
|
if (!options) {
|
||||||
ntfs_log_perror("%s: strdup failed", EXEC_NAME);
|
ntfs_log_perror("%s: strdup failed", EXEC_NAME);
|
||||||
@ -3164,6 +3263,10 @@ static char *parse_mount_options(const char *orig_opts)
|
|||||||
"'usermapping' option.\n");
|
"'usermapping' option.\n");
|
||||||
goto err_exit;
|
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. */
|
} else { /* Probably FUSE option. */
|
||||||
if (strappend(&ret, opt))
|
if (strappend(&ret, opt))
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
@ -3615,6 +3718,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
ctx->security.vol = ctx->vol;
|
ctx->security.vol = ctx->vol;
|
||||||
ctx->vol->secure_flags = ctx->secure_flags;
|
ctx->vol->secure_flags = ctx->secure_flags;
|
||||||
|
ctx->vol->efs_raw = ctx->efs_raw;
|
||||||
if (ctx->secure_flags & (1 << SECURITY_RAW)) {
|
if (ctx->secure_flags & (1 << SECURITY_RAW)) {
|
||||||
ctx->security.uid = ctx->uid;
|
ctx->security.uid = ctx->uid;
|
||||||
ctx->security.gid = ctx->gid;
|
ctx->security.gid = ctx->gid;
|
||||||
|
Loading…
Reference in New Issue
Block a user