From e901f5bc2e56a930ac71c545586aaf70b0fd2b56 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 30 Aug 2012 12:59:56 -0500 Subject: [PATCH] new NTFS 3g patches --- Makefile.am | 2 + config.h.in | 3 + configure.ac | 19 ++ src/ntfs-3g_security.c | 465 +++++++++++++---------------------------- src/ntfs-apply.c | 13 +- src/ntfs-capture.c | 12 +- 6 files changed, 187 insertions(+), 327 deletions(-) diff --git a/Makefile.am b/Makefile.am index b789fa41..e7cf2b55 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,8 +54,10 @@ libwim_la_SOURCES = \ src/xpress.h if WITH_NTFS_3G +if !WITH_NEW_NTFS_3G libwim_la_SOURCES += src/ntfs-3g_security.c endif +endif EXTRA_libwim_la_SOURCES = src/sha1-ssse3.asm diff --git a/config.h.in b/config.h.in index db9f0e2d..ecd767d3 100644 --- a/config.h.in +++ b/config.h.in @@ -106,6 +106,9 @@ /* Define to 1 if using libcrypto SHA1 */ #undef WITH_LIBCRYPTO +/* Define to 1 to use patched upstream NTFS-3g instead of version 2012-1-15 */ +#undef WITH_NEW_NTFS_3G + /* Define to 1 to enable support for NTFS-specific information */ #undef WITH_NTFS_3G diff --git a/configure.ac b/configure.ac index c2156614..5dcc2ff1 100644 --- a/configure.ac +++ b/configure.ac @@ -163,6 +163,25 @@ AM_CONDITIONAL([WITH_NTFS_3G], [test "x$WITH_NTFS_3G" = "xyes"]) AC_SUBST([LIBNTFS_3G_LDADD], [$LIBNTFS_3G_LDADD]) AC_SUBST([LIBNTFS_3G_CFLAGS], [$LIBNTFS_3G_CFLAGS]) +AC_MSG_CHECKING([whether to use patched upstream libntfs-3g]) +AC_ARG_WITH([new-ntfs-3g], + [AS_HELP_STRING([--with-new-ntfs-3g], [build using patched upstream + NTFS-3g instead of version 2012-1-15])], + [WITH_NEW_NTFS_3G=$withval], + [WITH_NEW_NTFS_3G=no] + ) + +AC_MSG_RESULT([$WITH_NEW_NTFS_3G]) +if test "x$WITH_NEW_NTFS_3G" = "xyes"; then + if test "x$WITH_NTFS_3G" != "xyes"; then + AC_MSG_ERROR([Cannot use new NTFS-3g if configuring + --without-ntfs-3g]) + fi + AC_DEFINE([WITH_NEW_NTFS_3G], [1], [Define to 1 to use patched upstream + NTFS-3g instead of version 2012-1-15]) +fi +AM_CONDITIONAL([WITH_NEW_NTFS_3G], [test "x$WITH_NEW_NTFS_3G" = "xyes"]) + AC_MSG_CHECKING([whether to include support for mounting WIMs]) AC_ARG_WITH([fuse], AS_HELP_STRING([--without-fuse], [build without libfuse. diff --git a/src/ntfs-3g_security.c b/src/ntfs-3g_security.c index de26d28b..4b26eb2f 100644 --- a/src/ntfs-3g_security.c +++ b/src/ntfs-3g_security.c @@ -22,21 +22,27 @@ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "util.h" - #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include + +/*#ifdef HAVE_STDIO_H*/ #include +/*#endif*/ #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif +/*#ifdef HAVE_ERRNO_H*/ #include +/*#endif*/ +/*#ifdef HAVE_FCNTL_H*/ #include +/*#endif*/ #ifdef HAVE_SETXATTR #include #endif @@ -44,8 +50,6 @@ #include #endif -#include - #include #include #include @@ -4125,6 +4129,77 @@ int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size) return (outsize ? (int)outsize : -errno); } +/* + * Get the ntfs attributes from an inode + * The attributes are returned according to cpu endianness + * + * Returns the attributes if successful (cannot be zero) + * 0 if failed (errno to tell why) + */ + +u32 ntfs_get_inode_attributes(ntfs_inode *ni) +{ + u32 attrib = -1; + + if (ni) { + attrib = le32_to_cpu(ni->flags); + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY); + else + attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY); + if (!attrib) + attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL); + } else + errno = EINVAL; + return (attrib); +} + +/* + * Set the ntfs attributes on an inode + * The attribute is expected according to cpu endianness + * + * Returns 0 if successful + * -1 if failed (errno to tell why) + */ + +int ntfs_set_inode_attributes(ntfs_inode *ni, u32 attrib) +{ + le32 settable; + ATTR_FLAGS dirflags; + int res; + + res = -1; + if (ni) { + settable = FILE_ATTR_SETTABLE; + res = 0; + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { + /* + * Accept changing compression for a directory + * and set index root accordingly + */ + settable |= FILE_ATTR_COMPRESSED; + if ((ni->flags ^ cpu_to_le32(attrib)) + & FILE_ATTR_COMPRESSED) { + if (ni->flags & FILE_ATTR_COMPRESSED) + dirflags = const_cpu_to_le16(0); + else + dirflags = ATTR_IS_COMPRESSED; + res = ntfs_attr_set_flags(ni, AT_INDEX_ROOT, + NTFS_INDEX_I30, 4, dirflags, + ATTR_COMPRESSION_MASK); + } + } + if (!res) { + ni->flags = (ni->flags & ~settable) + | (cpu_to_le32(attrib) & settable); + NInoFileNameSetDirty(ni); + NInoSetDirty(ni); + } + } else + errno = EINVAL; + return (res); +} + /* * Return the ntfs attribute into an extended attribute * The attribute is expected according to cpu endianness @@ -4136,8 +4211,6 @@ int ntfs_set_ntfs_attrib(ntfs_inode *ni, const char *value, size_t size, int flags) { u32 attrib; - le32 settable; - ATTR_FLAGS dirflags; int res; res = -1; @@ -4145,33 +4218,7 @@ int ntfs_set_ntfs_attrib(ntfs_inode *ni, if (!(flags & XATTR_CREATE)) { /* copy to avoid alignment problems */ memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS)); - settable = FILE_ATTR_SETTABLE; - res = 0; - if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { - /* - * Accept changing compression for a directory - * and set index root accordingly - */ - settable |= FILE_ATTR_COMPRESSED; - if ((ni->flags ^ cpu_to_le32(attrib)) - & FILE_ATTR_COMPRESSED) { - if (ni->flags & FILE_ATTR_COMPRESSED) - dirflags = const_cpu_to_le16(0); - else - dirflags = ATTR_IS_COMPRESSED; - res = ntfs_attr_set_flags(ni, - AT_INDEX_ROOT, - NTFS_INDEX_I30, 4, - dirflags, - ATTR_COMPRESSION_MASK); - } - } - if (!res) { - ni->flags = (ni->flags & ~settable) - | (cpu_to_le32(attrib) & settable); - NInoFileNameSetDirty(ni); - NInoSetDirty(ni); - } + res = ntfs_set_inode_attributes(ni, attrib); } else errno = EEXIST; } else @@ -4554,7 +4601,69 @@ static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr, return (ok); } -#if 0 +int ntfs_get_inode_security(ntfs_inode *ni, u32 selection, + char *buf, u32 buflen, u32 *psize) +{ + int res; + char *attr; + + res = 0; + if (ni) { + attr = getsecurityattr(ni->vol, ni); + if (attr) { + if (feedsecurityattr(attr, selection, + buf, buflen, psize)) { + if (test_nino_flag(ni, v3_Extensions) + && ni->security_id) + res = le32_to_cpu( + ni->security_id); + else + res = -1; + } + free(attr); + } + } else + errno = EINVAL; + return (res); +} + +int ntfs_set_inode_security(ntfs_inode *ni, u32 selection, const char *attr) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + int attrsz; + BOOL missing; + char *oldattr; + int res; + + res = -1; /* default return */ + if (ni) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; + attrsz = ntfs_attr_size(attr); + /* if selected, owner and group must be present or defaulted */ + missing = ((selection & OWNER_SECURITY_INFORMATION) + && !phead->owner + && !(phead->control & SE_OWNER_DEFAULTED)) + || ((selection & GROUP_SECURITY_INFORMATION) + && !phead->group + && !(phead->control & SE_GROUP_DEFAULTED)); + if (!missing + && (phead->control & SE_SELF_RELATIVE) + && ntfs_valid_descr(attr, attrsz)) { + oldattr = getsecurityattr(ni->vol, ni); + if (oldattr) { + if (mergesecurityattr(ni->vol, oldattr, attr, + selection, ni)) { + res = 0; + } + free(oldattr); + } + } else + errno = EINVAL; + } else + errno = EINVAL; + return (res); +} + /* * Return the security descriptor of a file * This is intended to be similar to GetFileSecurity() from Win32 @@ -4680,197 +4789,8 @@ int ntfs_set_file_security(struct SECURITY_API *scapi, errno = EINVAL; return (res); } -#endif - -int ntfs_inode_get_security(ntfs_inode *ni, u32 selection, char *buf, - u32 buflen, u32 *psize) -{ - char *attr; - int res = 0; - - attr = getsecurityattr(ni->vol, ni); - if (attr) { - if (feedsecurityattr(attr,selection, - buf,buflen,psize)) { - if (test_nino_flag(ni, v3_Extensions) - && ni->security_id) - res = le32_to_cpu( - ni->security_id); - else - res = -1; - } - free(attr); - } - return (res); -} -/* - * Check the validity of the ACEs in a DACL or SACL - */ - -static BOOL valid_acl(const ACL *pacl, unsigned int end) -{ - const ACCESS_ALLOWED_ACE *pace; - unsigned int offace; - unsigned int acecnt; - unsigned int acesz; - unsigned int nace; - BOOL ok; - - ok = TRUE; - acecnt = le16_to_cpu(pacl->ace_count); - offace = sizeof(ACL); - for (nace = 0; (nace < acecnt) && ok; nace++) { - /* be sure the beginning is within range */ - if ((offace + sizeof(ACCESS_ALLOWED_ACE)) > end) - ok = FALSE; - else { - pace = (const ACCESS_ALLOWED_ACE*) - &((const char*)pacl)[offace]; - acesz = le16_to_cpu(pace->size); - if (((offace + acesz) > end) - || !ntfs_valid_sid(&pace->sid) - || ((ntfs_sid_size(&pace->sid) + 8) != (int)acesz)) - ok = FALSE; - offace += acesz; - } - } - return (ok); -} - -/* - * Do sanity checks on security descriptors read from storage - * basically, we make sure that every field holds within - * allocated storage - * Should not be called with a NULL argument - * returns TRUE if considered safe - * if not, error should be logged by caller - */ -static BOOL _ntfs_valid_descr(const char *securattr, unsigned int attrsz) -{ - const SECURITY_DESCRIPTOR_RELATIVE *phead; - const ACL *pdacl; - const ACL *psacl; - unsigned int offdacl; - unsigned int offsacl; - unsigned int offowner; - unsigned int offgroup; - BOOL ok; - - ok = TRUE; - - /* - * first check overall size if within allocation range - * and a DACL is present - * and owner and group SID are valid - */ - - phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; - offdacl = le32_to_cpu(phead->dacl); - offsacl = le32_to_cpu(phead->sacl); - offowner = le32_to_cpu(phead->owner); - offgroup = le32_to_cpu(phead->group); - pdacl = (const ACL*)&securattr[offdacl]; - psacl = (const ACL*)&securattr[offsacl]; - - /* - * size check occurs before the above pointers are used - * - * "DR Watson" standard directory on WinXP has an - * old revision and no DACL though SE_DACL_PRESENT is set - */ - if ((attrsz >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) - && (phead->revision == SECURITY_DESCRIPTOR_REVISION) - && (offowner >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) - && ((offowner + 2) < attrsz) - && (offgroup >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) - && ((offgroup + 2) < attrsz) - && (!offdacl - || ((offdacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) - && (offdacl+sizeof(ACL) <= attrsz))) - && (!offsacl - || ((offsacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) - && (offsacl+sizeof(ACL) <= attrsz))) - && !(phead->owner & const_cpu_to_le32(3)) - && !(phead->group & const_cpu_to_le32(3)) - && !(phead->dacl & const_cpu_to_le32(3)) - && !(phead->sacl & const_cpu_to_le32(3)) - && (ntfs_attr_size(securattr) <= attrsz) - && ntfs_valid_sid((const SID*)&securattr[offowner]) - && ntfs_valid_sid((const SID*)&securattr[offgroup]) - /* - * if there is an ACL, as indicated by offdacl, - * require SE_DACL_PRESENT - * but "Dr Watson" has SE_DACL_PRESENT though no DACL - */ - && (!offdacl - || ((phead->control & SE_DACL_PRESENT) - && ((pdacl->revision == ACL_REVISION) - || (pdacl->revision == ACL_REVISION_DS)))) - /* same for SACL */ - && (!offsacl - || ((phead->control & SE_SACL_PRESENT) - && ((psacl->revision == ACL_REVISION) - || (psacl->revision == ACL_REVISION_DS))))) { - /* - * Check the DACL and SACL if present - */ - if ((offdacl && !valid_acl(pdacl,attrsz - offdacl)) - || (offsacl && !valid_acl(psacl,attrsz - offsacl))) - ok = FALSE; - } else { - ok = FALSE; - } - return (ok); -} - -/* - * Set security data on a NTFS file given an inode - * - * Returns nonzero on success - */ -int ntfs_inode_set_security(ntfs_inode *ni, u32 selection, const char *attr) -{ - const SECURITY_DESCRIPTOR_RELATIVE *phead; - int attrsz; - BOOL missing; - char *oldattr; - int res; - - res = 0; /* default return */ - phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr; - attrsz = ntfs_attr_size(attr); - /* if selected, owner and group must be present or defaulted */ - missing = ((selection & OWNER_SECURITY_INFORMATION) - && !phead->owner - && !(phead->control & SE_OWNER_DEFAULTED)) - || ((selection & GROUP_SECURITY_INFORMATION) - && !phead->group - && !(phead->control & SE_GROUP_DEFAULTED)); - if (!missing - && (phead->control & SE_SELF_RELATIVE) - && _ntfs_valid_descr(attr, attrsz)) { - oldattr = getsecurityattr(ni->vol, ni); - if (oldattr) { - if (mergesecurityattr( - ni->vol, - oldattr, attr, - selection, ni)) { - if (test_nino_flag(ni, - v3_Extensions)) - res = le32_to_cpu( - ni->security_id); - else - res = -1; - } - free(oldattr); - } - } else - errno = EINVAL; - return (res); -} -#if 0 /* * Return the attributes of a file * This is intended to be similar to GetFileAttributes() from Win32 @@ -4894,14 +4814,7 @@ int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path) if (scapi && (scapi->magic == MAGIC_API) && path) { ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); if (ni) { - attrib = le32_to_cpu(ni->flags); - if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) - attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY); - else - attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY); - if (!attrib) - attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL); - + attrib = ntfs_get_inode_attributes(ni); ntfs_inode_close(ni); } else errno = ENOENT; @@ -4933,105 +4846,24 @@ BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi, const char *path, s32 attrib) { ntfs_inode *ni; - le32 settable; - ATTR_FLAGS dirflags; int res; res = 0; /* default return */ if (scapi && (scapi->magic == MAGIC_API) && path) { ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path); if (ni) { - settable = FILE_ATTR_SETTABLE; - if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { - /* - * Accept changing compression for a directory - * and set index root accordingly - */ - settable |= FILE_ATTR_COMPRESSED; - if ((ni->flags ^ cpu_to_le32(attrib)) - & FILE_ATTR_COMPRESSED) { - if (ni->flags & FILE_ATTR_COMPRESSED) - dirflags = const_cpu_to_le16(0); - else - dirflags = ATTR_IS_COMPRESSED; - res = ntfs_attr_set_flags(ni, - AT_INDEX_ROOT, - NTFS_INDEX_I30, 4, - dirflags, - ATTR_COMPRESSION_MASK); - } - } - if (!res) { - ni->flags = (ni->flags & ~settable) - | (cpu_to_le32(attrib) & settable); - NInoSetDirty(ni); - NInoFileNameSetDirty(ni); - } - if (!ntfs_inode_close(ni)) + /* Win32 convention here : -1 means successful */ + if (!ntfs_set_inode_attributes(ni, attrib)) res = -1; + if (ntfs_inode_close(ni)) + res = 0; } else errno = ENOENT; } return (res); } -#endif - -int ntfs_inode_get_attributes(ntfs_inode *ni) -{ - s32 attrib; - attrib = le32_to_cpu(ni->flags); - if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) - attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY); - else - attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY); - if (!attrib) - attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL); - return (attrib); -} -/* - * Set attributes of a NTFS file given an inode - * - * Returns nonzero on success - */ -int ntfs_inode_set_attributes(ntfs_inode *ni, s32 attrib) -{ - le32 settable = FILE_ATTR_SETTABLE; - ATTR_FLAGS dirflags; - int ret = 0; - - if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { - /* - * Accept changing compression for a directory - * and set index root accordingly - */ - settable |= FILE_ATTR_COMPRESSED; - if ((ni->flags ^ cpu_to_le32(attrib)) - & FILE_ATTR_COMPRESSED) { - if (ni->flags & FILE_ATTR_COMPRESSED) - dirflags = const_cpu_to_le16(0); - else - dirflags = ATTR_IS_COMPRESSED; - ret = ntfs_attr_set_flags(ni, - AT_INDEX_ROOT, - NTFS_INDEX_I30, 4, - dirflags, - ATTR_COMPRESSION_MASK); - } - } - if (ret == 0) { - ni->flags = (ni->flags & ~settable) - | (cpu_to_le32(attrib) & settable); - NInoSetDirty(ni); - NInoFileNameSetDirty(ni); - ret = -1; - } - return ret; -} - - -#if 0 BOOL ntfs_read_directory(struct SECURITY_API *scapi, const char *path, ntfs_filldir_t callback, void *context) { @@ -5335,4 +5167,3 @@ BOOL ntfs_leave_file_security(struct SECURITY_API *scapi) return (ok); } -#endif diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index 47e12c02..1a4cb7dd 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -48,9 +48,12 @@ struct ntfs_apply_args { WIMStruct *w; }; -extern int ntfs_inode_set_security(ntfs_inode *ni, u32 selection, + +#ifndef WITH_NEW_NTFS_3G +extern int ntfs_set_inode_security(ntfs_inode *ni, u32 selection, const char *attr); -extern int ntfs_inode_set_attributes(ntfs_inode *ni, s32 attrib); +extern int ntfs_set_inode_attributes(ntfs_inode *ni, u32 attrib); +#endif /* * Extracts a WIM resource to a NTFS attribute. @@ -239,7 +242,7 @@ apply_file_attributes_and_security_data(ntfs_inode *ni, { DEBUG("Setting NTFS file attributes on `%s' to %#"PRIx32, dentry->full_path_utf8, dentry->attributes); - if (!ntfs_inode_set_attributes(ni, dentry->attributes)) { + if (ntfs_set_inode_attributes(ni, dentry->attributes)) { ERROR("Failed to set NTFS file attributes on `%s'", dentry->full_path_utf8); return WIMLIB_ERR_NTFS_3G; @@ -257,8 +260,8 @@ apply_file_attributes_and_security_data(ntfs_inode *ni, DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION; - if (!ntfs_inode_set_security(ni, selection, - (const char*)sd->descriptors[dentry->security_id])) + if (ntfs_set_inode_security(ni, selection, + (const char*)sd->descriptors[dentry->security_id])) { ERROR_WITH_ERRNO("Failed to set security data on `%s'", dentry->full_path_utf8); diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index 892b5241..4ea23048 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -43,10 +43,12 @@ #include #include -extern int ntfs_inode_get_security(ntfs_inode *ni, u32 selection, char *buf, +#ifndef WITH_NEW_NTFS_3G +extern int ntfs_get_inode_security(ntfs_inode *ni, u32 selection, char *buf, u32 buflen, u32 *psize); -extern int ntfs_inode_get_attributes(ntfs_inode *ni); +extern u32 ntfs_get_inode_attributes(ntfs_inode *ni); +#endif /* Structure that allows searching the security descriptors by SHA1 message * digest. */ @@ -489,7 +491,7 @@ static int build_dentry_tree_ntfs_recursive(struct dentry **root_p, struct dentry *root; mrec_flags = ni->mrec->flags; - attributes = ntfs_inode_get_attributes(ni); + attributes = ntfs_get_inode_attributes(ni); if (exclude_path(path, config, false)) { if (flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE) { @@ -554,14 +556,14 @@ static int build_dentry_tree_ntfs_recursive(struct dentry **root_p, if (ret != 0) return ret; - ret = ntfs_inode_get_security(ni, + ret = ntfs_get_inode_security(ni, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, NULL, 0, &sd_size); char sd[sd_size]; - ret = ntfs_inode_get_security(ni, + ret = ntfs_get_inode_security(ni, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | -- 2.43.0