From 8e4a9a0129dabaddef33ee0a99f7f8b221bdf483 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 20 May 2012 10:08:20 -0500 Subject: [PATCH] Support for copying security data Previous versions of wimlib had preliminary support for copying security data, before it was removed. This version reintroduces this support, enabled by default but configurable by the configure script. Also various documentation fixes. Allow reading WIMs with security data total length = 0 (it defaults to 8 if it says 0) --- README | 7 ++ config.h.in | 3 + config.h.in~ | 3 - configure | 21 +++++ configure.ac | 14 +++ doc/imagex-info.1.in | 3 +- doc/imagex-split.1.in | 6 +- doc/imagex.1.in | 28 +++--- src/Makefile.am | 1 + src/Makefile.in | 6 +- src/dentry.c | 22 +++-- src/dentry.h | 6 +- src/modify.c | 15 ++-- src/resource.c | 32 ++++--- src/security.c | 193 +++++++++++++++++++++++------------------- src/wim.c | 18 ++-- src/wimlib.h | 14 +-- src/wimlib_internal.h | 52 ++++++------ 18 files changed, 270 insertions(+), 174 deletions(-) diff --git a/README b/README index c210fce9..a5cacf67 100644 --- a/README +++ b/README @@ -86,6 +86,12 @@ wimlib's `configure' script: program if an assertion fails. An assertion failure should only occur if there is a bug in wimlib. +--disable-security-data + Wimlib cannot create or modify WIM security data, but by default it will + copy existing security data when modifying a WIM or exporting an image. + Passing this flag will disable this support; then wimlib will always + write WIMs without security data. + --enable-debug Include debugging messages. Only use this option if you have found a bug in the library. @@ -94,6 +100,7 @@ wimlib's `configure' script: Include more debugging messages. Only use this option if you have found a bug in the library. + ------------------------------------------------------------------------------- DEPENDENCIES diff --git a/config.h.in b/config.h.in index 390b9e35..65f41d9c 100644 --- a/config.h.in +++ b/config.h.in @@ -18,6 +18,9 @@ /* Define to 1 if including even more debug messages. */ #undef ENABLE_MORE_DEBUG +/* Define to 1 to enable support for copying security data */ +#undef ENABLE_SECURITY_DATA + /* Define to 1 if using vectorized implementation of SHA1 */ #undef ENABLE_SSSE3_SHA1 diff --git a/config.h.in~ b/config.h.in~ index e9ff6e4b..390b9e35 100644 --- a/config.h.in~ +++ b/config.h.in~ @@ -108,6 +108,3 @@ # undef WORDS_BIGENDIAN # endif #endif - -/* Define to `int' if does not define. */ -#undef ssize_t diff --git a/configure b/configure index 36c8ae3c..118ae850 100755 --- a/configure +++ b/configure @@ -777,6 +777,7 @@ enable_error_messages enable_custom_memory_allocator enable_assertions enable_verify_compression +enable_security_data with_fuse enable_ssse3_sha1 with_libcrypto @@ -1429,6 +1430,8 @@ Optional Features: --disable-verify-compression disable checking if blocks we compress can be correctly decompressed + --disable-security-data disable the ability to retain the security data of + existing WIMs --enable-ssse3-sha1 use assembly language implementation of SHA1 from Intel, accelerated with vector instructions (SSSE3-enabled CPU required) @@ -13436,6 +13439,24 @@ $as_echo "#define ENABLE_VERIFY_COMPRESSION 1" >>confdefs.h fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for copying security data" >&5 +$as_echo_n "checking whether to include support for copying security data... " >&6; } +# Check whether --enable-security_data was given. +if test "${enable_security_data+set}" = set; then : + enableval=$enable_security_data; ENABLE_SECURITY_DATA=$enableval +else + ENABLE_SECURITY_DATA=yes + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENABLE_SECURITY_DATA" >&5 +$as_echo "$ENABLE_SECURITY_DATA" >&6; } +if test "x$ENABLE_SECURITY_DATA" = "xyes"; then + +$as_echo "#define ENABLE_SECURITY_DATA 1" >>confdefs.h + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for mounting WIMs" >&5 $as_echo_n "checking whether to include support for mounting WIMs... " >&6; } diff --git a/configure.ac b/configure.ac index 0e2db09e..4c1d99cf 100644 --- a/configure.ac +++ b/configure.ac @@ -132,6 +132,20 @@ if test "x$ENABLE_VERIFY_COMPRESSION" = "xyes"; then compressed data]) fi +AC_MSG_CHECKING([whether to include support for copying security data]) +AC_ARG_ENABLE([security_data], + AS_HELP_STRING([--disable-security-data], [disable + the ability to retain the security data of + existing WIMs]), + [ENABLE_SECURITY_DATA=$enableval], + [ENABLE_SECURITY_DATA=yes] + ) +AC_MSG_RESULT([$ENABLE_SECURITY_DATA]) +if test "x$ENABLE_SECURITY_DATA" = "xyes"; then + AC_DEFINE([ENABLE_SECURITY_DATA], [1], [Define to 1 to enable support + for copying security data]) +fi + 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/doc/imagex-info.1.in b/doc/imagex-info.1.in index 547de7af..132ec4e7 100644 --- a/doc/imagex-info.1.in +++ b/doc/imagex-info.1.in @@ -53,7 +53,8 @@ Shows detailed information from the WIM header. Prints all the entries in the lookup table of the WIM. .TP \fB--metadata\fR -Prints the metadata for the directory tree for the specified image. +Prints the metadata, including the security data and the directory entry tree, +for the specified image. .TP \fB--xml\fR Prints the XML data for the WIM. diff --git a/doc/imagex-split.1.in b/doc/imagex-split.1.in index 270d4bb2..a1356df3 100644 --- a/doc/imagex-split.1.in +++ b/doc/imagex-split.1.in @@ -8,7 +8,7 @@ imagex split \- Split a WIM into multiple parts .SH DESCRIPTION .PP -Splits \fIWIMFILE\fR into parts with size at most \fIPART_SIZE\fR megabytes, +Splits \fIWIMFILE\fR into parts with size at most \fIPART_SIZE\fR mebibytes, with the first part having the name \fISPLIT_WIMFILE\fR and the other parts having names numbered in order of the parts. @@ -34,8 +34,8 @@ This is impossible to avoid and Microsoft's program has this problem as well because the WIM file format provides no way to divide a single file resource in the WIM among multiple split WIM parts. So if you, for example, have a file inside the WIM that is 100 MiB, then an uncompressed split WIM will have at -least one part that is 100 MiB in size to contain that file. If the WIM -resources are compressed then less space would be needed. +least one part that is 100 MiB in size to contain that file. However, if the +WIM resources are compressed then less space would be needed. .SH SEE ALSO .BR imagex (1) diff --git a/doc/imagex.1.in b/doc/imagex.1.in index d526ff7f..7fee130d 100644 --- a/doc/imagex.1.in +++ b/doc/imagex.1.in @@ -77,11 +77,12 @@ XML data (parsed and written using \fBlibxml\fR(3)) .SH UNSUPPORTED FEATURES The following features are currently unsupported: .IP \[bu] 2 -File permissions and security descriptors are ignored. The information -contained in them in an existing WIM will be lost when wimlib writes a WIM file. -This does not seem to matter for Windows PE, but this means that you should not -use this program to image a drive containing Windows Vista/7/8 and expect it to -be applied with the correct file permissions. +Wimlib cannot add security data when it captures a WIM file, although it will +preserve security data for existing WIM files. New files added to a mounted +WIM will be added without security data. This does not seem to matter for +Windows PE, but this means that you should not use this program to image a drive +containing Windows Vista/7/8 and expect it to be applied with the correct file +permissions. .IP \[bu] 2 Alternate file streams are unsupported and will be lost when wimlib writes a WIM file. Note that you shouldn't really have these on your Windows system anyway @@ -92,11 +93,13 @@ them together with \fBimagex join\fR first. .IP \[bu] 2 The \fB--verify\fR option, for all commands that use it is unsupported. Without this option, there theoretically could be a SHA1 hash collision between two -files, although it's very unlikely. +files, although it's very unlikely. You can still verify a WIM manually by +capturing it, then applying it to a different location, then running a recursive +diff on the two directory trees. .IP \[bu] 2 -The \fB--config\fR option, for all commands that use it +The \fB--config\fR option, for all commands that use it. .IP \[bu] 2 -Different versions of the WIM file format (if different versions even exist) +Different versions of the WIM file format (if different versions even exist). Also see the Doxygen documentation for Wimlib. @@ -106,10 +109,11 @@ See \fBUNSUPPORTED FEATURES\fR. The most important difference is that this version of \fBimagex\fR cannot capture and restore Windows images losslessly because file permissions and -alternate file streams are ignored. This is because Microsoft designed the WIM -format to be specific to their NTFS filesystem and the Windows security -model/API, which is difficult to support in a non-Windows program. You can -still create images of Windows PE, however. +alternate file streams cannot be captured. This is because Microsoft designed +the WIM format to be specific to their NTFS filesystem and the Windows security +model/API, which is difficult to support in a non-Windows program. However, you +can still create images of Windows PE, even from a directory tree on a non-NTFS +filesystem. See the documentation for each subcommand of \fBimagex\fR; in some cases they do not do exactly the same thing as imagex.exe. diff --git a/src/Makefile.am b/src/Makefile.am index 28471ef2..b1851ec8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,6 +36,7 @@ other_srcs = \ modify.c \ mount.c \ resource.c \ + security.c \ sha1.c \ sha1.h \ split.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 896fbbd4..dcf56f6e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -103,8 +103,8 @@ libwim_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ am__objects_1 = comp.lo decomp.lo huffman.lo lz.lo lzx-common.lo \ lzx-comp.lo lzx-decomp.lo xpress-comp.lo xpress-decomp.lo am__objects_2 = dentry.lo extract.lo header.lo integrity.lo join.lo \ - lookup_table.lo modify.lo mount.lo resource.lo sha1.lo \ - split.lo util.lo wim.lo write.lo xml.lo + lookup_table.lo modify.lo mount.lo resource.lo security.lo \ + sha1.lo split.lo util.lo wim.lo write.lo xml.lo am_libwim_la_OBJECTS = $(am__objects_1) $(am__objects_2) libwim_la_OBJECTS = $(am_libwim_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) @@ -293,6 +293,7 @@ other_srcs = \ modify.c \ mount.c \ resource.c \ + security.c \ sha1.c \ sha1.h \ split.c \ @@ -408,6 +409,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modify.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mount.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resource.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/security.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/split.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Plo@am__quote@ diff --git a/src/dentry.c b/src/dentry.c index c389652e..6f6822ed 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -311,10 +311,12 @@ int print_dentry_full_path(struct dentry *dentry, void *ignore) int print_dentry(struct dentry *dentry, void *lookup_table) { struct lookup_table_entry *lte; - + printf("[DENTRY]\n"); printf("Length = %"PRIu64"\n", dentry->length); printf("Attributes = 0x%x\n", dentry->attributes); - /*printf("Security ID = %d\n", dentry->security_id);*/ +#ifdef ENABLE_SECURITY_DATA + printf("Security ID = %d\n", dentry->security_id); +#endif printf("Subdir offset = %"PRIu64"\n", dentry->subdir_offset); /*printf("Unused1 = %"PRIu64"\n", dentry->unused1);*/ /*printf("Unused2 = %"PRIu64"\n", dentry->unused2);*/ @@ -355,8 +357,9 @@ static inline void dentry_common_init(struct dentry *dentry) { memset(dentry, 0, sizeof(struct dentry)); dentry->refcnt = 1; - /* We are currently ignoring the security data. */ - /*dentry->security_id = -1;*/ +#ifdef ENABLE_SECURITY_DATA + dentry->security_id = -1; +#endif } /* @@ -634,8 +637,11 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, } p = get_u32(p, &dentry->attributes); - /* Currently ignoring security ID. */ +#ifdef ENABLE_SECURITY_DATA + p = get_u32(p, &dentry->security_id); +#else p += sizeof(u32); +#endif p = get_u64(p, &dentry->subdir_offset); /* 2 unused fields */ @@ -733,7 +739,11 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p) memset(p, 0, dentry->length); p = put_u64(p, dentry->length); p = put_u32(p, dentry->attributes); - p = put_u32(p, (u32)(-1)); /* security id */ +#ifdef ENABLE_SECURITY_DATA + p = put_u32(p, dentry->security_id); +#else + p = put_u32(p, (u32)(-1)); +#endif p = put_u64(p, dentry->subdir_offset); p = put_u64(p, 0); /* unused1 */ p = put_u64(p, 0); /* unused2 */ diff --git a/src/dentry.h b/src/dentry.h index faa44d39..dc80a14b 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -35,8 +35,10 @@ struct dentry { /* The index of the node in the security table that contains this file's * security information. If -1, no security information exists for this - * file. Currently ignoring this field.*/ - //int32_t security_id; + * file. */ +#ifdef ENABLE_SECURITY_DATA + int32_t security_id; +#endif /* The offset, from the start of the metadata section, of this directory * entry's child files. 0 if the directory entry has no children. */ diff --git a/src/modify.c b/src/modify.c index e438db9e..60149f8b 100644 --- a/src/modify.c +++ b/src/modify.c @@ -239,10 +239,6 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) w->hdr.image_count++; new_imd = &imd[w->hdr.image_count - 1]; - -#if 0 - init_security_data(&new_imd->security_data); -#endif new_imd->lookup_table_entry = imd_lookup_entry; new_imd->modified = true; new_imd->root_dentry = root_dentry; @@ -343,6 +339,13 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, wims.dest_wim = dest_wim; for_dentry_in_tree(root, add_lookup_table_entry_to_dest_wim, &wims); ret = add_new_dentry_tree(dest_wim, root); +#ifdef ENABLE_SECURITY_DATA + struct wim_security_data *sd = wim_security_data(src_wim); + struct image_metadata *new_imd = wim_get_current_image_metadata(dest_wim); + new_imd->security_data = sd; + if (sd) + sd->refcnt++; +#endif if (ret != 0) return ret; @@ -390,8 +393,8 @@ WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image) * refcnt decremented to 0, and the security data. */ imd = wim_get_current_image_metadata(w); free_dentry_tree(imd->root_dentry, w->lookup_table, true); -#if 0 - destroy_security_data(&imd->security_data); +#ifdef ENABLE_SECURITY_DATA + free_security_data(imd->security_data); #endif /* Get rid of the lookup table entry for this image's metadata resource diff --git a/src/resource.c b/src/resource.c index e315d335..369ac453 100644 --- a/src/resource.c +++ b/src/resource.c @@ -916,13 +916,13 @@ static int transfer_file_resource(FILE *in, u64 size, u64 original_size, * @return: True on success, false on failure. */ int read_metadata_resource(FILE *fp, const struct resource_entry *res_entry, - int wim_ctype, struct dentry **root_dentry_p) + int wim_ctype, struct image_metadata *image_metadata) { u8 *buf; int ctype; u32 dentry_offset; int ret; - struct dentry *dentry; + struct dentry *dentry = NULL; DEBUG("Reading metadata resource: length = %lu, offset = %lu\n", res_entry->original_size, res_entry->offset); @@ -955,11 +955,6 @@ int read_metadata_resource(FILE *fp, const struct resource_entry *res_entry, DEBUG("Finished reading metadata resource into memory.\n"); -#if 0 - /* Read the security data into a WIMSecurityData structure. */ - if (!read_security_data(buf, res_entry->original_size, sd)) - goto err1; -#endif dentry = MALLOC(sizeof(struct dentry)); if (!dentry) { @@ -974,7 +969,17 @@ int read_metadata_resource(FILE *fp, const struct resource_entry *res_entry, * * The security data starts with a 4-byte integer giving its total * length. */ + + /* Read the security data into a WIMSecurityData structure. */ +#ifdef ENABLE_SECURITY_DATA + ret = read_security_data(buf, res_entry->original_size, + &image_metadata->security_data); + if (ret != 0) + goto err1; +#endif get_u32(buf, &dentry_offset); + if (dentry_offset == 0) + dentry_offset = 8; dentry_offset += (8 - dentry_offset % 8) % 8; ret = read_dentry(buf, res_entry->original_size, dentry_offset, dentry); @@ -996,7 +1001,7 @@ int read_metadata_resource(FILE *fp, const struct resource_entry *res_entry, if (ret != 0) goto err2; - *root_dentry_p = dentry; + image_metadata->root_dentry = dentry; FREE(buf); return ret; err2: @@ -1032,7 +1037,11 @@ int write_metadata_resource(WIMStruct *w) if (metadata_offset == -1) return WIMLIB_ERR_WRITE; + #ifdef ENABLE_SECURITY_DATA + subdir_offset = wim_security_data(w)->total_length + root->length + 8; + #else subdir_offset = 8 + root->length + 8; + #endif calculate_subdir_offsets(root, &subdir_offset); metadata_original_size = subdir_offset; buf = MALLOC(metadata_original_size); @@ -1041,12 +1050,11 @@ int write_metadata_resource(WIMStruct *w) "metadata resource\n", metadata_original_size); return WIMLIB_ERR_NOMEM; } - p = buf; - #if 0 + #ifdef ENABLE_SECURITY_DATA /* Write the security data. */ - p = write_security_data(wim_security_data(w), p); + p = write_security_data(wim_security_data(w), buf); #else - p = put_u32(p, 8); /* Total length of security data. */ + p = put_u32(buf, 8); /* Total length of security data. */ p = put_u32(p, 0); /* Number of security data entries. */ #endif diff --git a/src/security.c b/src/security.c index cbf7fe00..cfc6fbd1 100644 --- a/src/security.c +++ b/src/security.c @@ -26,134 +26,144 @@ #include "io.h" #include "security.h" +#ifdef ENABLE_SECURITY_DATA + /* * Reads the security data from the metadata resource. * * @metadata_resource: An array that contains the uncompressed metadata * resource for the WIM file. * @metadata_resource_len: The length of @metadata_resource. - * @sd: A pointer to a WIMSecurityData structure that is filled in with - * the security data. - * @return: True on success, false on failure. + * @sd_p: A pointer to a pointer wim_security_data structure that will be filled + * in with a pointer to a new wim_security_data structure on success. * * Note: There is no `offset' argument because the security data is located at * the beginning of the metadata resource. */ -bool read_security_data(const u8 metadata_resource[], - u64 metadata_resource_len, WIMSecurityData *sd) +int read_security_data(const u8 metadata_resource[], + u64 metadata_resource_len, struct wim_security_data **sd_p) { - sd->num_entries = 0; - sd->descriptors = NULL; - sd->sizes = NULL; + struct wim_security_data *sd; + const u8 *p; + u64 sizes_size; if (metadata_resource_len < 8) { ERROR("Not enough space in %"PRIu64"-byte file resource for " "security data!\n", metadata_resource_len); - return false; + return WIMLIB_ERR_INVALID_RESOURCE_SIZE; } - const u8 *p = metadata_resource; - p = get_u32(p, &sd->total_length); + sd = MALLOC(sizeof(struct wim_security_data)); + if (!sd) + return WIMLIB_ERR_NOMEM; + p = get_u32(metadata_resource, &sd->total_length); p = get_u32(p, &sd->num_entries); /* Verify the listed total length of the security data is big enough to * include the sizes array, verify that the file data is big enough to * include it as well, then allocate the array of sizes. */ - u64 sizes_size = sd->num_entries * sizeof(u64); + sizes_size = sd->num_entries * sizeof(u64); DEBUG("Reading security data with %u entries\n", sd->num_entries); if (sd->num_entries == 0) { - sd->sizes = NULL; - sd->descriptors = NULL; - return true; + FREE(sd); + return 0; } u64 size_no_descriptors = 8 + sizes_size; if (size_no_descriptors > sd->total_length) { - ERROR("Security data total length of %"PRIu64" is too short " - "because there must be at least %"PRIu64" bytes of security " + ERROR("Security data total length of %"PRIu64" is too short because\n" + "there must be at least %"PRIu64" bytes of security " "data!\n", sd->total_length, 8 + sizes_size); - return false; + FREE(sd); + return WIMLIB_ERR_INVALID_RESOURCE_SIZE; } if (size_no_descriptors > metadata_resource_len) { - ERROR("File resource of %"PRIu64" bytes is not big enough " + ERROR("File resource of %"PRIu64" bytes is not big enough\n" "to hold security data of at least %"PRIu64" " "bytes!\n", metadata_resource_len, size_no_descriptors); - return false; + FREE(sd); + return WIMLIB_ERR_INVALID_RESOURCE_SIZE; + } + sd->sizes = MALLOC(sizes_size); + if (!sd->sizes) { + FREE(sd); + return WIMLIB_ERR_NOMEM; } - sd->sizes = xmalloc(sizes_size); /* Copy the sizes array in from the file data. */ p = get_bytes(p, sizes_size, sd->sizes); array_to_le64(sd->sizes, sd->num_entries); /* Allocate the array of pointers to descriptors, and read them in. */ - sd->descriptors = xmalloc(sd->num_entries * sizeof(u8*)); + sd->descriptors = CALLOC(sd->num_entries, sizeof(u8*)); + if (!sd->descriptors) { + FREE(sd); + FREE(sd->sizes); + return WIMLIB_ERR_NOMEM; + } u64 total_len = size_no_descriptors; for (uint i = 0; i < sd->num_entries; i++) { - total_len += sd->sizes[i]; if (total_len > sd->total_length) { ERROR("Security data total length of %"PRIu64" is too " "short because there are at least %"PRIu64" " "bytes of security data!\n", sd->total_length, total_len); - sd->num_entries = i; - return false; + free_security_data(sd); + return WIMLIB_ERR_INVALID_RESOURCE_SIZE; } if (total_len > metadata_resource_len) { - sd->num_entries = i; ERROR("File resource of %"PRIu64" bytes is not big enough " "to hold security data of at least %"PRIu64" " "bytes!\n", metadata_resource_len, total_len); - return false; + free_security_data(sd); + return WIMLIB_ERR_INVALID_RESOURCE_SIZE; + } + sd->descriptors[i] = MALLOC(sd->sizes[i]); + if (!sd->descriptors[i]) { + free_security_data(sd); + return WIMLIB_ERR_NOMEM; } - sd->descriptors[i] = xmalloc(sd->sizes[i]); p = get_bytes(p, sd->sizes[i], sd->descriptors[i]); } - - /* The total_length field seems to take into account padding for - * quadword alignment of the dentry following it, so we can ignore the - * case where the actual length read so far is less than the specified - * total length of the security data. */ - #if 0 - if (total_len < sd->total_length) { - /*ERROR("Warning: security data was actually %"PRIu64" bytes, but "*/ - /*"it says its length is %"PRIu64" bytes!\n",*/ - /*total_len, sd->total_length);*/ - } - #endif - - return true; + sd->refcnt = 1; + *sd_p = sd; + return 0; } /* - * Writes the security data to the output file. - * - * @sd: The security data structure. - * @out: The FILE* for the output file. - * @return: True on success, false on failure. + * Writes security data to an in-memory buffer. */ -u8 *write_security_data(const WIMSecurityData *sd, u8 *p) +u8 *write_security_data(const struct wim_security_data *sd, u8 *p) { - DEBUG("Writing security data (total_length = %u, num_entries = %u)\n", - sd->total_length, sd->num_entries); - u8 *orig_p = p; - p = put_u32(p, sd->total_length); - p = put_u32(p, sd->num_entries); + if (sd) { + DEBUG("Writing security data (total_length = %u, " + "num_entries = %u)\n", sd->total_length, + sd->num_entries); + u8 *orig_p = p; + p = put_u32(p, sd->total_length); + p = put_u32(p, sd->num_entries); + + for (uint i = 0; i < sd->num_entries; i++) + p = put_u64(p, sd->sizes[i]); - for (uint i = 0; i < sd->num_entries; i++) - p = put_u64(p, sd->sizes[i]); + for (uint i = 0; i < sd->num_entries; i++) + p = put_bytes(p, sd->sizes[i], sd->descriptors[i]); - for (uint i = 0; i < sd->num_entries; i++) - p = put_bytes(p, sd->sizes[i], sd->descriptors[i]); + wimlib_assert(p - orig_p <= sd->total_length); - wimlib_assert(p - orig_p <= sd->total_length); + DEBUG("Successfully wrote security data.\n"); + return orig_p + sd->total_length; + } else { + DEBUG("Writing security data (total_length = 8, " + "num_entries = 0)\n"); + p = put_u32(p, 8); + return put_u32(p, 0); - DEBUG("Successfully wrote security data.\n"); - return orig_p + sd->total_length; + } } /* XXX We don't actually do anything with the ACL's yet besides being able to @@ -225,44 +235,49 @@ static void print_security_descriptor(const u8 *p, u64 size) /* * Prints the security data for a WIM file. - * - * @sd: A pointer to the WIMSecurityData structure. */ -void print_security_data(const WIMSecurityData *sd) +void print_security_data(const struct wim_security_data *sd) { puts("[SECURITY DATA]"); - printf("Length = %u bytes\n", sd->total_length); - printf("Number of Entries = %u\n", sd->num_entries); + if (sd) { + printf("Length = %u bytes\n", sd->total_length); + printf("Number of Entries = %u\n", sd->num_entries); - u64 num_entries = (u64)sd->num_entries; - for (u64 i = 0; i < num_entries; i++) { - printf("[SecurityDescriptor %"PRIu64", length = %"PRIu64"]\n", i, - sd->sizes[i]); - print_security_descriptor(sd->descriptors[i], sd->sizes[i]); - putchar('\n'); + u64 num_entries = (u64)sd->num_entries; + for (u64 i = 0; i < num_entries; i++) { + printf("[SecurityDescriptor %"PRIu64", " + "length = %"PRIu64"]\n", + i, sd->sizes[i]); + print_security_descriptor(sd->descriptors[i], + sd->sizes[i]); + putchar('\n'); + } + } else { + puts("Length = 8 bytes\n" + "Number of Entries = 0"); + return; } putchar('\n'); } -void init_security_data(WIMSecurityData *sd) +void free_security_data(struct wim_security_data *sd) { - sd->total_length = 8; - sd->num_entries = 0; - sd->sizes = NULL; - sd->descriptors = NULL; - /* XXX figure out what the security descriptors actually do */ -} + if (!sd) + return; + wimlib_assert(sd->refcnt >= 1); + if (sd->refcnt == 1) { + u8 **descriptors = sd->descriptors; + u32 num_entries = sd->num_entries; -void destroy_security_data(WIMSecurityData *sd) -{ - u8 **descriptors = sd->descriptors; - u32 num_entries = sd->num_entries; - while (num_entries--) - FREE(*descriptors++); - sd->num_entries = 0; - FREE(sd->sizes); - sd->sizes = NULL; - FREE(sd->descriptors); - sd->descriptors = NULL; + if (descriptors) + while (num_entries--) + FREE(*descriptors++); + FREE(sd->sizes); + FREE(sd->descriptors); + FREE(sd); + } else { + sd->refcnt--; + } } +#endif diff --git a/src/wim.c b/src/wim.c index eb33bd39..f9a6851c 100644 --- a/src/wim.c +++ b/src/wim.c @@ -29,7 +29,7 @@ static int print_metadata(WIMStruct *w) { -#if 0 +#ifdef ENABLE_SECURITY_DATA print_security_data(wim_security_data(w)); #endif return for_dentry_in_tree(wim_root_dentry(w), print_dentry, @@ -220,10 +220,11 @@ int wimlib_select_image(WIMStruct *w, int image) DEBUG("Freeing image %u\n", w->current_image); imd = wim_get_current_image_metadata(w); free_dentry_tree(imd->root_dentry, NULL, false); -#if 0 - destroy_security_data(&imd->security_data); -#endif imd->root_dentry = NULL; +#ifdef ENABLE_SECURITY_DATA + free_security_data(imd->security_data); + imd->security_data = NULL; +#endif } w->current_image = image; @@ -239,8 +240,7 @@ int wimlib_select_image(WIMStruct *w, int image) return read_metadata_resource(w->fp, wim_metadata_resource_entry(w), wimlib_get_compression_type(w), - /*wim_security_data(w), */ - wim_root_dentry_p(w)); + wim_get_current_image_metadata(w)); } } @@ -579,9 +579,13 @@ WIMLIBAPI void wimlib_free(WIMStruct *w) FREE(w->xml_data); free_wim_info(w->wim_info); if (w->image_metadata) { - for (i = 0; i < w->hdr.image_count; i++) + for (i = 0; i < w->hdr.image_count; i++) { free_dentry_tree(w->image_metadata[i].root_dentry, NULL, false); + #ifdef ENABLE_SECURITY_DATA + free_security_data(w->image_metadata[i].security_data); + #endif + } FREE(w->image_metadata); } FREE(w); diff --git a/src/wimlib.h b/src/wimlib.h index 14a38264..fa27fc1c 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -134,12 +134,13 @@ * * While wimlib supports the main features of WIM files, wimlib currently has * the following limitations: - * - wimlib does not support "security data", which describes the access rights - * of the files in the WIM. This data is very Windows-specific, and it would - * be difficult to do anything with it. Microsoft's software can still read a - * WIM without security data, including a boot.wim for Windows PE, but do - * not expect to be able to use wimlib to image a Windows installation and - * preserve file attributes. + * - wimlib does not support modifying or creating "security data", which + * describes the access rights of the files in the WIM. This data is very + * Windows-specific, and it would be difficult to do anything with it. + * Microsoft's software can still read a WIM without security data, including + * a boot.wim for Windows PE, but do not expect to be able to use wimlib to + * image a Windows installation and preserve file attributes. However, by + * default, wimlib will preserve security data for existing WIMs. * - There is no way to directly extract or mount split WIMs. * - There is not yet any code to verify that there are no collisions between * different files that happen to have the same SHA1 message digest. @@ -291,6 +292,7 @@ enum wimlib_error_code { WIMLIB_ERR_INVALID_INTEGRITY_TABLE, WIMLIB_ERR_INVALID_PARAM, WIMLIB_ERR_INVALID_RESOURCE_SIZE, + WIMLIB_ERR_INVALID_SECURITY_DATA, WIMLIB_ERR_LINK, WIMLIB_ERR_MKDIR, WIMLIB_ERR_MQUEUE, diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 02b96b33..86b22f76 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -181,10 +181,10 @@ struct wim_header { #define WIM_HDR_FLAG_COMPRESS_LZX 0x00040000 -#if 0 +#ifdef ENABLE_SECURITY_DATA /* Structure for security data. Each image in the WIM file has its own security * data. */ -typedef struct WIMSecurityData { +struct wim_security_data { /* The total length of the security data, in bytes. A typical size is * 2048 bytes. If there is no security data, though (as in the WIMs * that wimlib writes, currently), it will be 8 bytes. */ @@ -198,28 +198,31 @@ typedef struct WIMSecurityData { /* Array of descriptors. */ u8 **descriptors; + + /* keep track of how many WIMs reference this security data (used when + * exporting images between WIMs) */ + u32 refcnt; } WIMSecurityData; #endif /* Metadata resource for an image. */ struct image_metadata { + /* Pointer to the root dentry for the image. */ + struct dentry *root_dentry; -#if 0 - /* The security data for the image. */ - WIMSecurityData security_data; +#ifdef ENABLE_SECURITY_DATA + /* Pointer to the security data for the image. */ + struct wim_security_data *security_data; #endif - - /* The root dentry for the image. */ - struct dentry *root_dentry; + /* A pointer to the lookup table entry for this image's metadata + * resource. */ + struct lookup_table_entry *lookup_table_entry; /* True if the filesystem of the image has been modified. If this is * the case, the memory for the filesystem is not freed when switching * to a different WIM image. */ bool modified; - /* A pointer to the lookup table entry for this image's metadata - * resource. */ - struct lookup_table_entry *lookup_table_entry; }; /* The opaque structure exposed to the wimlib API. */ @@ -288,10 +291,10 @@ static inline struct dentry **wim_root_dentry_p(WIMStruct *w) return &w->image_metadata[w->current_image - 1].root_dentry; } -#if 0 -static inline WIMSecurityData *wim_security_data(WIMStruct *w) +#ifdef ENABLE_SECURITY_DATA +static inline struct wim_security_data *wim_security_data(WIMStruct *w) { - return &w->image_metadata[w->current_image - 1].security_data; + return w->image_metadata[w->current_image - 1].security_data; } #endif @@ -358,9 +361,10 @@ extern int extract_full_resource_to_fd(WIMStruct *w, const struct resource_entry *entry, int fd); -extern int read_metadata_resource(FILE *fp, const struct resource_entry *metadata, - int wim_ctype, /* WIMSecurityData *sd, */ - struct dentry **root_dentry_p); +extern int read_metadata_resource(FILE *fp, + const struct resource_entry *metadata, + int wim_ctype, + struct image_metadata *image_metadata); extern int resource_compression_type(int wim_ctype, int reshdr_flags); @@ -382,15 +386,13 @@ extern int write_resource_from_memory(const u8 resource[], int out_ctype, u64 *resource_size_ret); extern int write_metadata_resource(WIMStruct *w); -#if 0 -/* security.c */ -bool read_security_data(const u8 metadata_resource[], - u64 metadata_resource_len, WIMSecurityData *sd); +#ifdef ENABLE_SECURITY_DATA +int read_security_data(const u8 metadata_resource[], + u64 metadata_resource_len, struct wim_security_data **sd_p); -void print_security_data(const WIMSecurityData *sd); -u8 *write_security_data(const WIMSecurityData *sd, u8 *p); -void init_security_data(WIMSecurityData *sd); -void destroy_security_data(WIMSecurityData *sd); +void print_security_data(const struct wim_security_data *sd); +u8 *write_security_data(const struct wim_security_data *sd, u8 *p); +void free_security_data(struct wim_security_data *sd); #endif /* wim.c */ -- 2.43.0