From 09d5c7b390a18d5cc29a87853dce0c4681e8f153 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 22 Mar 2013 00:12:49 -0500 Subject: [PATCH] Add --noacls options and set dwDesiredAccess more appropriately --- doc/imagex-apply.1.in | 18 ++++--- doc/imagex-capture.1.in | 5 ++ programs/imagex.c | 15 ++++-- src/ntfs-apply.c | 19 ++++--- src/ntfs-capture.c | 54 +++++++++---------- src/wimlib.h | 8 +++ src/win32.c | 112 +++++++++++++++++----------------------- src/win32.h | 2 +- src/write.c | 2 +- 9 files changed, 128 insertions(+), 107 deletions(-) diff --git a/doc/imagex-apply.1.in b/doc/imagex-apply.1.in index 1868100c..4c6a1b45 100644 --- a/doc/imagex-apply.1.in +++ b/doc/imagex-apply.1.in @@ -244,12 +244,18 @@ File glob of additional split WIM parts that are part of the split WIM being applied. See \fBSPLIT_WIMS\fR. .TP \fB--unix-data\fR -This option may only be given in the normal extraction mode (not NTFS). -By default, in the normal extraction mode, \fB@IMAGEX_PROGNAME@ apply\fR will ignore both -Windows-style security descriptors and UNIX-specific file owners, groups, and -modes set when using \fB@IMAGEX_PROGNAME@ capture\fR with the \fB--unix-data\fR flag. By -passing \fB--unix-data\fR to \fB@IMAGEX_PROGNAME@ apply\fR instead, this causes this -UNIX-specific data to be restored when available. +This option may only be given in the normal extraction mode (not NTFS). By +default, in the normal extraction mode on UNIX, \fB@IMAGEX_PROGNAME@ apply\fR +will ignore both Windows-style security descriptors and UNIX-specific file +owners, groups, and modes set when using \fB@IMAGEX_PROGNAME@ capture\fR with +the \fB--unix-data\fR flag. By passing \fB--unix-data\fR to +\fB@IMAGEX_PROGNAME@ apply\fR instead, this causes this UNIX-specific data to be +restored when available. +.TP +\fB--noacls\fR +In the NTFS apply mode, do not apply security descriptors. This flag is also +available in the native Win32 build of wimlib and may be useful when running +\fB@IMAGEX_PROGNAME@\fR as a non-administrator. .SH NOTES diff --git a/doc/imagex-capture.1.in b/doc/imagex-capture.1.in index a599f2ce..95fdd763 100644 --- a/doc/imagex-capture.1.in +++ b/doc/imagex-capture.1.in @@ -234,6 +234,11 @@ for convenience only, in case you want to use \fB@IMAGEX_PROGNAME@\fR to archive UNIX. Microsoft's software will not understand this special information. .TP +\fB--noacls\fR +In the NTFS capture mode, do not capture security descriptors. This flag is +also available in the native Win32 build of wimlib and may be useful when +running \fB@IMAGEX_PROGNAME@\fR as a non-administrator. +.TP \fB--source-list\fR \fB@IMAGEX_PROGNAME@ capture\fR and \fB@IMAGEX_PROGNAME@ append\fR, as of wimlib 1.3.0, support a new option to create a WIM image from multiple files or directories. When diff --git a/programs/imagex.c b/programs/imagex.c index e37b04f1..0d271e43 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -81,17 +81,18 @@ IMAGEX_PROGNAME" append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" " [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n" " [--verbose] [--dereference] [--config=FILE]\n" " [--threads=NUM_THREADS] [--rebuild] [--unix-data]\n" -" [--source-list]\n", +" [--source-list] [--noacls]\n", [APPLY] = IMAGEX_PROGNAME" apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" " (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" -" [--symlink] [--verbose] [--ref=\"GLOB\"] [--unix-data]\n", +" [--symlink] [--verbose] [--ref=\"GLOB\"] [--unix-data]\n" +" [--noacls]\n", [CAPTURE] = IMAGEX_PROGNAME" capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" " [DESCRIPTION] [--boot] [--check] [--compress=TYPE]\n" " [--flags EDITION_ID] [--verbose] [--dereference]\n" " [--config=FILE] [--threads=NUM_THREADS] [--unix-data]\n" -" [--source-list]\n", +" [--source-list] [--noacls]\n", [DELETE] = IMAGEX_PROGNAME" delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft]\n", [DIR] = @@ -130,6 +131,7 @@ static const struct option apply_options[] = { {"verbose", no_argument, NULL, 'v'}, {"ref", required_argument, NULL, 'r'}, {"unix-data", no_argument, NULL, 'U'}, + {"noacls", no_argument, NULL, 'N'}, {NULL, 0, NULL, 0}, }; static const struct option capture_or_append_options[] = { @@ -144,6 +146,7 @@ static const struct option capture_or_append_options[] = { {"rebuild", no_argument, NULL, 'R'}, {"unix-data", no_argument, NULL, 'U'}, {"source-list", no_argument, NULL, 'S'}, + {"noacls", no_argument, NULL, 'N'}, {NULL, 0, NULL, 0}, }; static const struct option delete_options[] = { @@ -841,6 +844,9 @@ static int imagex_apply(int argc, char **argv) case 'U': extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA; break; + case 'N': + extract_flags |= WIMLIB_EXTRACT_FLAG_NOACLS; + break; default: usage(APPLY); return -1; @@ -999,6 +1005,9 @@ static int imagex_capture_or_append(int argc, char **argv) case 'S': source_list = true; break; + case 'N': + add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NO_ACLS; + break; default: usage(cmd); return -1; diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index 8bc6c49b..4d2292b7 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -274,7 +274,8 @@ static int apply_file_attributes_and_security_data(ntfs_inode *ni, ntfs_inode *dir_ni, const struct wim_dentry *dentry, - const WIMStruct *w) + const WIMStruct *w, + int extract_flags) { int ret; struct SECURITY_CONTEXT ctx; @@ -298,7 +299,9 @@ apply_file_attributes_and_security_data(ntfs_inode *ni, dentry->full_path); return WIMLIB_ERR_NTFS_3G; } - if (inode->i_security_id != -1) { + if (inode->i_security_id != -1 && + !(extract_flags & WIMLIB_EXTRACT_FLAG_NOACLS)) + { const char *desc; const struct wim_security_data *sd; @@ -439,7 +442,8 @@ do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, } ret = apply_file_attributes_and_security_data(ni, dir_ni, dentry, - args->w); + args->w, + args->extract_flags); if (ret != 0) goto out_close_dir_ni; @@ -497,7 +501,8 @@ out: static int apply_root_dentry_ntfs(const struct wim_dentry *dentry, - ntfs_volume *vol, const WIMStruct *w) + ntfs_volume *vol, const WIMStruct *w, + int extract_flags) { ntfs_inode *ni; int ret = 0; @@ -507,7 +512,8 @@ apply_root_dentry_ntfs(const struct wim_dentry *dentry, ERROR_WITH_ERRNO("Could not find root NTFS inode"); return WIMLIB_ERR_NTFS_3G; } - ret = apply_file_attributes_and_security_data(ni, ni, dentry, w); + ret = apply_file_attributes_and_security_data(ni, ni, dentry, w, + extract_flags); if (ntfs_inode_close(ni) != 0) { ERROR_WITH_ERRNO("Failed to close NTFS inode for root " "directory"); @@ -529,7 +535,8 @@ apply_dentry_ntfs(struct wim_dentry *dentry, void *arg) /* Treat the root dentry specially. */ if (dentry_is_root(dentry)) - return apply_root_dentry_ntfs(dentry, vol, w); + return apply_root_dentry_ntfs(dentry, vol, w, + args->extract_flags); /* NTFS filename namespaces need careful consideration. A name for a * NTFS file may be in either the POSIX, Win32, DOS, or Win32+DOS diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index da794480..3f036d07 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -602,34 +602,36 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_p, if (ret != 0) return ret; - /* Get security descriptor */ - char _sd[1]; - char *sd = _sd; - errno = 0; - ret = ntfs_xattr_system_getxattr(&ctx, XATTR_NTFS_ACL, - ni, dir_ni, sd, - sizeof(sd)); - if (ret > sizeof(sd)) { - sd = alloca(ret); + if (!(add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS)) { + /* Get security descriptor */ + char _sd[1]; + char *sd = _sd; + errno = 0; ret = ntfs_xattr_system_getxattr(&ctx, XATTR_NTFS_ACL, - ni, dir_ni, sd, ret); - } - if (ret > 0) { - root->d_inode->i_security_id = sd_set_add_sd(sd_set, sd, ret); - if (root->d_inode->i_security_id == -1) { - ERROR("Out of memory"); - return WIMLIB_ERR_NOMEM; + ni, dir_ni, sd, + sizeof(sd)); + if (ret > sizeof(sd)) { + sd = alloca(ret); + ret = ntfs_xattr_system_getxattr(&ctx, XATTR_NTFS_ACL, + ni, dir_ni, sd, ret); + } + if (ret > 0) { + root->d_inode->i_security_id = sd_set_add_sd(sd_set, sd, ret); + if (root->d_inode->i_security_id == -1) { + ERROR("Out of memory"); + return WIMLIB_ERR_NOMEM; + } + DEBUG("Added security ID = %u for `%s'", + root->d_inode->i_security_id, path); + ret = 0; + } else if (ret < 0) { + ERROR_WITH_ERRNO("Failed to get security information from " + "`%s'", path); + ret = WIMLIB_ERR_NTFS_3G; + } else { + root->d_inode->i_security_id = -1; + DEBUG("No security ID for `%s'", path); } - DEBUG("Added security ID = %u for `%s'", - root->d_inode->i_security_id, path); - ret = 0; - } else if (ret < 0) { - ERROR_WITH_ERRNO("Failed to get security information from " - "`%s'", path); - ret = WIMLIB_ERR_NTFS_3G; - } else { - root->d_inode->i_security_id = -1; - DEBUG("No security ID for `%s'", path); } return ret; } diff --git a/src/wimlib.h b/src/wimlib.h index 16f3ecb4..2947e100 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -633,6 +633,10 @@ struct wimlib_capture_source { * This flag cannot be combined with ::WIMLIB_ADD_IMAGE_FLAG_NTFS. */ #define WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA 0x00000010 +/** Do not capture security descriptors. Only has an effect in NTFS capture + * mode, or in Win32 native builds. */ +#define WIMLIB_ADD_IMAGE_FLAG_NO_ACLS 0x00000020 + /****************************** * WIMLIB_EXPORT_FLAG_* * ******************************/ @@ -669,6 +673,10 @@ struct wimlib_capture_source { * Cannot be used with ::WIMLIB_EXTRACT_FLAG_NTFS. */ #define WIMLIB_EXTRACT_FLAG_UNIX_DATA 0x00000020 +/** Do not extract security descriptors. Only has an effect in NTFS apply mode, + * or in Win32 native builds. */ +#define WIMLIB_EXTRACT_FLAG_NOACLS 0x00000040 + /****************************** * WIMLIB_MOUNT_FLAG_* * ******************************/ diff --git a/src/win32.c b/src/win32.c index ba3dc588..8b8620fe 100644 --- a/src/win32.c +++ b/src/win32.c @@ -75,12 +75,9 @@ win32_error_last() } #endif -HANDLE -win32_open_file_readonly(const wchar_t *path, bool data_only) +static HANDLE +win32_open_existing_file(const wchar_t *path, DWORD dwDesiredAccess) { - DWORD dwDesiredAccess = FILE_READ_DATA; - if (!data_only) - dwDesiredAccess |= FILE_READ_ATTRIBUTES | READ_CONTROL | ACCESS_SYSTEM_SECURITY; return CreateFileW(path, dwDesiredAccess, FILE_SHARE_READ, @@ -91,6 +88,12 @@ win32_open_file_readonly(const wchar_t *path, bool data_only) NULL /* hTemplateFile */); } +HANDLE +win32_open_file_data_only(const wchar_t *path) +{ + return win32_open_existing_file(path, FILE_READ_DATA); +} + int win32_read_file(const mbchar *filename, void *handle, u64 offset, size_t size, void *buf) @@ -346,7 +349,7 @@ win32_sha1sum(const wchar_t *path, u8 hash[SHA1_HASH_SIZE]) DWORD bytesRead; int ret; - hFile = win32_open_file_readonly(path, false); + hFile = win32_open_file_data_only(path); if (hFile == INVALID_HANDLE_VALUE) return WIMLIB_ERR_OPEN; @@ -639,7 +642,8 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, goto out_destroy_sd_set; path_utf16_nchars = path_utf16_nbytes / sizeof(wchar_t); - HANDLE hFile = win32_open_file_readonly(path_utf16, false); + HANDLE hFile = win32_open_existing_file(path_utf16, + FILE_READ_DATA | FILE_READ_ATTRIBUTES); if (hFile == INVALID_HANDLE_VALUE) { err = GetLastError(); ERROR("Win32 API: Failed to open \"%s\"", root_disk_path); @@ -678,12 +682,15 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, /* Get DOS name and security descriptor (if any). */ ret = win32_get_short_name(root, path_utf16); - if (ret) - goto out_close_handle; - ret = win32_get_security_descriptor(root, sd_set, path_utf16); if (ret) goto out_close_handle; + if (!(add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS)) { + ret = win32_get_security_descriptor(root, sd_set, path_utf16); + if (ret) + goto out_close_handle; + } + if (inode_is_directory(inode)) { /* Directory (not a reparse point) --- recurse to children */ @@ -842,7 +849,8 @@ static int win32_extract_stream(const struct wim_inode *inode, const wchar_t *path, const wchar_t *stream_name_utf16, - struct wim_lookup_table_entry *lte) + struct wim_lookup_table_entry *lte, + const struct wim_security_data *security_data) { wchar_t *stream_path; HANDLE h; @@ -850,6 +858,17 @@ win32_extract_stream(const struct wim_inode *inode, DWORD err; DWORD creationDisposition = CREATE_ALWAYS; + SECURITY_ATTRIBUTES *secattr; + + if (security_data && inode->i_security_id != -1) { + secattr = alloca(sizeof(*secattr)); + secattr->nLength = sizeof(*secattr); + secattr->lpSecurityDescriptor = security_data->descriptors[inode->i_security_id]; + secattr->bInheritHandle = FALSE; + } else { + secattr = NULL; + } + if (stream_name_utf16) { /* Named stream. Create a buffer that contains the UTF-16LE * string [.\]@path:@stream_name_utf16. This is needed to @@ -888,7 +907,7 @@ win32_extract_stream(const struct wim_inode *inode, * the call to CreateFileW() will merely open the directory that * was already created rather than creating a new file. */ if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) { - if (!CreateDirectoryW(stream_path, NULL)) { + if (!CreateDirectoryW(stream_path, secattr)) { err = GetLastError(); if (err != ERROR_ALREADY_EXISTS) { ERROR("Failed to create directory \"%ls\"", @@ -909,9 +928,9 @@ win32_extract_stream(const struct wim_inode *inode, DEBUG("Opening \"%ls\"", stream_path); h = CreateFileW(stream_path, - GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY, + GENERIC_WRITE, 0, - NULL, + secattr, creationDisposition, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | @@ -972,13 +991,15 @@ out: */ static int win32_extract_streams(const struct wim_inode *inode, - const wchar_t *path, u64 *completed_bytes_p) + const wchar_t *path, u64 *completed_bytes_p, + const struct wim_security_data *security_data) { struct wim_lookup_table_entry *unnamed_lte; int ret; unnamed_lte = inode_unnamed_lte_resolved(inode); - ret = win32_extract_stream(inode, path, NULL, unnamed_lte); + ret = win32_extract_stream(inode, path, NULL, unnamed_lte, + security_data); if (ret) goto out; if (unnamed_lte) @@ -996,7 +1017,8 @@ win32_extract_streams(const struct wim_inode *inode, ret = win32_extract_stream(inode, path, ads_entry->stream_name, - ads_entry->lte); + ads_entry->lte, + NULL); if (ret) break; if (ads_entry->lte) @@ -1007,35 +1029,6 @@ out: return ret; } -/* - * Sets the security descriptor on an extracted file. This is Win32-specific - * code. - * - * @inode: The WIM inode that was extracted and has a security descriptor. - * @path: UTF-16LE external path that the inode was extracted to. - * @sd: Security data for the WIM image. - * - * Returns 0 on success; nonzero on failure. - */ -static int win32_set_security_data(const struct wim_inode *inode, - const wchar_t *path, - const struct wim_security_data *sd) -{ - SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION | - SACL_SECURITY_INFORMATION | - OWNER_SECURITY_INFORMATION | - GROUP_SECURITY_INFORMATION; - if (!SetFileSecurityW(path, securityInformation, - (PSECURITY_DESCRIPTOR)sd->descriptors[inode->i_security_id])) - { - DWORD err = GetLastError(); - ERROR("Can't set security descriptor on \"%ls\"", path); - win32_error(err); - return WIMLIB_ERR_WRITE; - } - return 0; -} - /* Extract a file, directory, reparse point, or hard link to an * already-extracted file using the Win32 API */ int win32_do_apply_dentry(const mbchar *output_path, @@ -1070,21 +1063,18 @@ int win32_do_apply_dentry(const mbchar *output_path, } else { /* Create the file, directory, or reparse point, and extract the * data streams. */ + const struct wim_security_data *security_data; + if (args->extract_flags & WIMLIB_EXTRACT_FLAG_NOACLS) + security_data = NULL; + else + security_data = wim_const_security_data(args->w); + ret = win32_extract_streams(inode, utf16le_path, - &args->progress.extract.completed_bytes); + &args->progress.extract.completed_bytes, + security_data); if (ret) goto out_free_utf16_path; - /* Set security descriptor if present */ - if (inode->i_security_id != -1) { - DEBUG("Setting security descriptor %d on %s", - inode->i_security_id, output_path); - ret = win32_set_security_data(inode, - utf16le_path, - wim_const_security_data(args->w)); - if (ret) - goto out_free_utf16_path; - } if (inode->i_nlink > 1) { /* Save extracted path for a later call to * CreateHardLinkW() if this inode has multiple links. @@ -1120,13 +1110,7 @@ win32_do_apply_dentry_timestamps(const mbchar *output_path, return ret; DEBUG("Opening \"%s\" to set timestamps", output_path); - h = CreateFileW(utf16le_path, - GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, - NULL); + h = win32_open_existing_file(utf16le_path, FILE_WRITE_ATTRIBUTES); if (h == INVALID_HANDLE_VALUE) err = GetLastError(); diff --git a/src/win32.h b/src/win32.h index 518b30e6..139490e6 100644 --- a/src/win32.h +++ b/src/win32.h @@ -20,7 +20,7 @@ win32_read_file(const mbchar *filename, void *handle, u64 offset, size_t size, void *buf); extern HANDLE -win32_open_file_readonly(const wchar_t *path_utf16, bool data_only); +win32_open_file_data_only(const wchar_t *path_utf16); extern void win32_close_file(void *handle); diff --git a/src/write.c b/src/write.c index 8355a283..1982ea0d 100644 --- a/src/write.c +++ b/src/write.c @@ -313,7 +313,7 @@ prepare_resource_for_read(struct wim_lookup_table_entry *lte case RESOURCE_WIN32: if (lte->win32_file_on_disk_fp == INVALID_HANDLE_VALUE) { lte->win32_file_on_disk_fp = - win32_open_file_readonly(lte->win32_file_on_disk, true); + win32_open_file_data_only(lte->win32_file_on_disk); if (lte->win32_file_on_disk_fp == INVALID_HANDLE_VALUE) { ERROR("Win32 API: Can't open %ls", lte->win32_file_on_disk); win32_error_last(); -- 2.43.0