From ebd6c0ec0ff47ac18af4ef918fd78fb8d9f19540 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 9 Mar 2013 23:44:35 -0600 Subject: [PATCH] Win32 capture --- src/add_image.c | 583 +++++++++++++++++++++++++++++++++++++++++- src/lookup_table.c | 6 + src/lookup_table.h | 4 + src/ntfs-capture.c | 135 +--------- src/resource.c | 12 +- src/security.c | 345 +++++++++++++++++++++++++ src/security.h | 229 +---------------- src/wim.c | 3 +- src/wimlib_internal.h | 12 + src/write.c | 86 ++++--- 10 files changed, 1017 insertions(+), 398 deletions(-) diff --git a/src/add_image.c b/src/add_image.c index fc2f6a20..fa3e77b0 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -21,6 +21,19 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ + +#if defined(__CYGWIN__) || defined(__WIN32__) +# include +# include +# include +# include +# include +# ifdef ERROR +# undef ERROR +# endif +# include "security.h" +#endif + #include "wimlib_internal.h" #include "dentry.h" #include "timestamp.h" @@ -35,6 +48,21 @@ #include #include +#if defined(__CYGWIN__) || defined(__WIN32__) +/*#define ERROR_WIN32_SAFE(format, ...) \*/ +/*{( \*/ + /*DWORD err = GetLastError(); \*/ + /*ERROR(format, ##__VA_ARGS__); \*/ + /*SetLastError(err); \*/ +/*)}*/ +#define DEBUG_WIN32_SAFE(format, ...) \ +({ \ + DWORD err = GetLastError(); \ + DEBUG(format, ##__VA_ARGS__); \ + SetLastError(err); \ +}) +#endif + #define WIMLIB_ADD_IMAGE_FLAG_ROOT 0x80000000 #define WIMLIB_ADD_IMAGE_FLAG_SOURCE 0x40000000 @@ -89,6 +117,412 @@ err: } +#if defined(__CYGWIN__) || defined(__WIN32__) +static u64 FILETIME_to_u64(const FILETIME *ft) +{ + return ((u64)ft->dwHighDateTime << 32) | (u64)ft->dwLowDateTime; +} + +#ifdef ENABLE_ERROR_MESSAGES +static void win32_error(DWORD err_code) +{ + char *buffer; + DWORD nchars; + nchars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, err_code, 0, + (char*)&buffer, 0, NULL); + if (nchars == 0) { + ERROR("Error printing error message! " + "Computer will self-destruct in 3 seconds."); + } else { + ERROR("Win32 error: %s", buffer); + LocalFree(buffer); + } +} +#else +#define win32_error(err_code) +#endif + +static HANDLE win32_open_file(const wchar_t *path) +{ + return CreateFileW(path, + GENERIC_READ | READ_CONTROL, + FILE_SHARE_READ, + NULL, /* lpSecurityAttributes */ + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT, + NULL /* hTemplateFile */); +} + +int win32_read_file(const char *filename, + void *handle, u64 offset, size_t size, u8 *buf) +{ + HANDLE h = handle; + DWORD err; + DWORD bytesRead; + LARGE_INTEGER liOffset = {.QuadPart = offset}; + + wimlib_assert(size <= 0xffffffff); + + if (SetFilePointerEx(h, liOffset, NULL, FILE_BEGIN)) + if (ReadFile(h, buf, size, &bytesRead, NULL) && bytesRead == size) + return 0; + err = GetLastError(); + ERROR("Error reading \"%s\"", filename); + win32_error(err); + return WIMLIB_ERR_READ; +} + +void win32_close_handle(void *handle) +{ + CloseHandle((HANDLE)handle); +} + +void *win32_open_handle(const char *path_utf16) +{ + return (void*)win32_open_file((const wchar_t*)path_utf16); +} + +static int build_dentry_tree(struct wim_dentry **root_ret, + const char *root_disk_path, + struct wim_lookup_table *lookup_table, + struct wim_security_data *sd, + const struct capture_config *config, + int add_image_flags, + wimlib_progress_func_t progress_func, + void *extra_arg); + +static int win32_get_short_name(struct wim_dentry *dentry, + const wchar_t *path_utf16) +{ + WIN32_FIND_DATAW dat; + if (FindFirstFileW(path_utf16, &dat) && + dat.cAlternateFileName[0] != L'\0') + { + size_t short_name_len = wcslen(dat.cAlternateFileName) * 2; + size_t n = short_name_len + sizeof(wchar_t); + dentry->short_name = MALLOC(n); + if (!dentry->short_name) + return WIMLIB_ERR_NOMEM; + memcpy(dentry->short_name, dat.cAlternateFileName, n); + dentry->short_name_len = short_name_len; + } + return 0; +} + +static int win32_get_security_descriptor(struct wim_dentry *dentry, + struct sd_set *sd_set, + const wchar_t *path_utf16, + const char *path) +{ + SECURITY_INFORMATION requestedInformation; + DWORD lenNeeded = 0; + BOOL status; + DWORD err; + +#ifdef BACKUP_SECURITY_INFORMATION + requestedInformation = BACKUP_SECURITY_INFORMATION; +#else + requestedInformation = DACL_SECURITY_INFORMATION | + SACL_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION; +#endif + /* Request length of security descriptor */ + status = GetFileSecurityW(path_utf16, requestedInformation, + NULL, 0, &lenNeeded); + err = GetLastError(); + + /* Error code appears to be ERROR_INSUFFICIENT_BUFFER but + * GetFileSecurity is poorly documented... */ + if (err == ERROR_INSUFFICIENT_BUFFER || err == NO_ERROR) { + DWORD len = lenNeeded; + char buf[len]; + if (GetFileSecurityW(path_utf16, requestedInformation, + buf, len, &lenNeeded)) + { + int security_id = sd_set_add_sd(sd_set, buf, len); + if (security_id < 0) + return WIMLIB_ERR_NOMEM; + else { + dentry->d_inode->i_security_id = security_id; + return 0; + } + } else { + err = GetLastError(); + } + } + ERROR("Win32 API: Failed to read security descriptor of \"%s\"", + path); + win32_error(err); + return WIMLIB_ERR_READ; +} + + +static int win32_recurse_directory(struct wim_dentry *root, + const char *root_disk_path, + struct wim_lookup_table *lookup_table, + struct wim_security_data *sd, + const struct capture_config *config, + int add_image_flags, + wimlib_progress_func_t progress_func, + struct sd_set *sd_set, + const wchar_t *path_utf16, + size_t path_utf16_nchars) +{ + WIN32_FIND_DATAW dat; + HANDLE hFind; + DWORD err; + int ret; + + { + wchar_t pattern_buf[path_utf16_nchars + 3]; + memcpy(pattern_buf, path_utf16, + path_utf16_nchars * sizeof(wchar_t)); + pattern_buf[path_utf16_nchars] = L'/'; + pattern_buf[path_utf16_nchars + 1] = L'*'; + pattern_buf[path_utf16_nchars + 2] = L'\0'; + hFind = FindFirstFileW(pattern_buf, &dat); + } + if (hFind == INVALID_HANDLE_VALUE) { + err = GetLastError(); + if (err == ERROR_FILE_NOT_FOUND) { + return 0; + } else { + ERROR("Win32 API: Failed to read directory \"%s\"", + root_disk_path); + win32_error(err); + return WIMLIB_ERR_READ; + } + } + ret = 0; + do { + if (!(dat.cFileName[0] == L'.' && + (dat.cFileName[1] == L'\0' || + (dat.cFileName[1] == L'.' && dat.cFileName[2] == L'\0')))) + { + struct wim_dentry *child; + + char *utf8_name; + size_t utf8_name_nbytes; + ret = utf16_to_utf8((const char*)dat.cFileName, + wcslen(dat.cFileName) * sizeof(wchar_t), + &utf8_name, + &utf8_name_nbytes); + if (ret) + goto out_find_close; + + char name[strlen(root_disk_path) + utf8_name_nbytes + 1]; + sprintf(name, "%s/%s", root_disk_path, utf8_name); + FREE(utf8_name); + ret = build_dentry_tree(&child, name, lookup_table, + sd, config, add_image_flags, + progress_func, sd_set); + if (ret) + goto out_find_close; + if (child) + dentry_add_child(root, child); + } + } while (FindNextFileW(hFind, &dat)); + err = GetLastError(); + if (err != ERROR_NO_MORE_FILES) { + ERROR("Win32 API: Failed to read directory \"%s\"", root_disk_path); + win32_error(err); + if (ret == 0) + ret = WIMLIB_ERR_READ; + } +out_find_close: + FindClose(hFind); + return ret; +} + +static int win32_capture_reparse_point(const char *path, + HANDLE hFile, + struct wim_inode *inode, + struct wim_lookup_table *lookup_table) +{ + /* "Reparse point data, including the tag and optional GUID, + * cannot exceed 16 kilobytes." - MSDN */ + char reparse_point_buf[16 * 1024]; + DWORD bytesReturned; + const REPARSE_DATA_BUFFER *buf; + + if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, + NULL, 0, reparse_point_buf, + sizeof(reparse_point_buf), &bytesReturned, NULL)) + { + ERROR("Win32 API: Failed to get reparse data of \"%s\"", path); + return WIMLIB_ERR_READ; + } + buf = (const REPARSE_DATA_BUFFER*)reparse_point_buf; + inode->i_reparse_tag = buf->ReparseTag; + return inode_add_ads_with_data(inode, "", (const u8*)buf + 8, + bytesReturned - 8, lookup_table); +} + +static int win32_sha1sum(const wchar_t *path, u8 hash[SHA1_HASH_SIZE]) +{ + HANDLE hFile; + SHA_CTX ctx; + u8 buf[32768]; + DWORD bytesRead; + int ret; + + hFile = win32_open_file(path); + if (hFile == INVALID_HANDLE_VALUE) + return WIMLIB_ERR_OPEN; + + sha1_init(&ctx); + for (;;) { + if (!ReadFile(hFile, buf, sizeof(buf), &bytesRead, NULL)) { + ret = WIMLIB_ERR_READ; + goto out_close_handle; + } + if (bytesRead == 0) + break; + sha1_update(&ctx, buf, bytesRead); + } + ret = 0; + sha1_final(hash, &ctx); +out_close_handle: + CloseHandle(hFile); + return ret; +} + +static int win32_capture_stream(const char *path, + const wchar_t *path_utf16, + size_t path_utf16_nchars, + struct wim_inode *inode, + struct wim_lookup_table *lookup_table, + WIN32_FIND_STREAM_DATA *dat) +{ + struct wim_ads_entry *ads_entry; + u8 hash[SHA1_HASH_SIZE]; + struct wim_lookup_table_entry *lte; + int ret; + wchar_t *p, *colon; + bool is_named_stream; + wchar_t *spath; + size_t spath_nchars; + DWORD err; + + p = dat->cStreamName; + wimlib_assert(*p == L':'); + p += 1; + colon = wcschr(p, L':'); + wimlib_assert(colon != NULL); + + if (wcscmp(colon + 1, L"$DATA")) { + /* Not a DATA stream */ + ret = 0; + goto out; + } + + is_named_stream = (p != colon); + + if (is_named_stream) { + char *utf8_stream_name; + size_t utf8_stream_name_len; + ret = utf16_to_utf8((const char *)p, + colon - p, + &utf8_stream_name, + &utf8_stream_name_len); + if (ret) + goto out; + DEBUG_WIN32_SAFE("Add alternate data stream %s:%s", path, utf8_stream_name); + ads_entry = inode_add_ads(inode, utf8_stream_name); + FREE(utf8_stream_name); + if (!ads_entry) { + ret = WIMLIB_ERR_NOMEM; + goto out; + } + } + + *colon = '\0'; + spath_nchars = path_utf16_nchars; + if (is_named_stream) + spath_nchars += colon - p + 1; + + spath = MALLOC((spath_nchars + 1) * sizeof(wchar_t)); + memcpy(spath, path_utf16, path_utf16_nchars * sizeof(wchar_t)); + if (is_named_stream) { + spath[path_utf16_nchars] = L':'; + memcpy(&spath[path_utf16_nchars + 1], p, (colon - p) * sizeof(wchar_t)); + } + spath[spath_nchars] = L'\0'; + + ret = win32_sha1sum(spath, hash); + if (ret) { + err = GetLastError(); + ERROR("Win32 API: Failed to read \"%s\" to calculate SHA1sum", path); + win32_error(err); + goto out_free_spath; + } + + lte = __lookup_resource(lookup_table, hash); + if (lte) { + lte->refcnt++; + } else { + lte = new_lookup_table_entry(); + if (!lte) { + ret = WIMLIB_ERR_NOMEM; + goto out_free_spath; + } + lte->file_on_disk = (char*)spath; + spath = NULL; + lte->resource_location = RESOURCE_WIN32; + lte->resource_entry.original_size = (uint64_t)dat->StreamSize.QuadPart; + lte->resource_entry.size = (uint64_t)dat->StreamSize.QuadPart; + copy_hash(lte->hash, hash); + lookup_table_insert(lookup_table, lte); + } + if (is_named_stream) + ads_entry->lte = lte; + else + inode->i_lte = lte; +out_free_spath: + FREE(spath); +out: + return ret; +} + +static int win32_capture_streams(const char *path, + const wchar_t *path_utf16, + size_t path_utf16_nchars, + struct wim_inode *inode, + struct wim_lookup_table *lookup_table) +{ + WIN32_FIND_STREAM_DATA dat; + int ret; + HANDLE hFind; + DWORD err; + + hFind = FindFirstStreamW(path_utf16, FindStreamInfoStandard, &dat, 0); + if (hFind == INVALID_HANDLE_VALUE) { + ERROR("Win32 API: Failed to look up data streams of \"%s\"", + path); + return WIMLIB_ERR_READ; + } + do { + ret = win32_capture_stream(path, path_utf16, + path_utf16_nchars, + inode, lookup_table, + &dat); + if (ret) + goto out_find_close; + } while (FindNextStreamW(hFind, &dat)); + err = GetLastError(); + if (err != ERROR_HANDLE_EOF) { + ERROR("Win32 API: Error reading data streams from \"%s\"", path); + win32_error(err); + ret = WIMLIB_ERR_READ; + } +out_find_close: + FindClose(hFind); + return ret; +} +#endif /* * build_dentry_tree(): @@ -132,16 +566,15 @@ static int build_dentry_tree(struct wim_dentry **root_ret, wimlib_progress_func_t progress_func, void *extra_arg) { - struct stat root_stbuf; + struct wim_dentry *root = NULL; int ret = 0; - int (*stat_fn)(const char *restrict, struct stat *restrict); - struct wim_dentry *root; struct wim_inode *inode; if (exclude_path(root_disk_path, config, true)) { if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) { ERROR("Cannot exclude the root directory from capture"); - return WIMLIB_ERR_INVALID_CAPTURE_CONFIG; + ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG; + goto out; } if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE) && progress_func) @@ -151,8 +584,7 @@ static int build_dentry_tree(struct wim_dentry **root_ret, info.scan.excluded = true; progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info); } - *root_ret = NULL; - return 0; + goto out; } if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE) @@ -164,6 +596,10 @@ static int build_dentry_tree(struct wim_dentry **root_ret, progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info); } +#if !defined(__CYGWIN__) && !defined(__WIN32__) + /* UNIX version of capturing a directory tree */ + struct stat root_stbuf; + int (*stat_fn)(const char *restrict, struct stat *restrict); if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) stat_fn = stat; else @@ -172,7 +608,7 @@ static int build_dentry_tree(struct wim_dentry **root_ret, ret = (*stat_fn)(root_disk_path, &root_stbuf); if (ret != 0) { ERROR_WITH_ERRNO("Failed to stat `%s'", root_disk_path); - return WIMLIB_ERR_STAT; + goto out; } if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) && @@ -184,28 +620,32 @@ static int build_dentry_tree(struct wim_dentry **root_ret, ret = stat(root_disk_path, &root_stbuf); if (ret != 0) { ERROR_WITH_ERRNO("Failed to stat `%s'", root_disk_path); - return WIMLIB_ERR_STAT; + ret = WIMLIB_ERR_STAT; + goto out; } if (!S_ISDIR(root_stbuf.st_mode)) { ERROR("`%s' is not a directory", root_disk_path); - return WIMLIB_ERR_NOTDIR; + ret = WIMLIB_ERR_NOTDIR; + goto out; } } if (!S_ISREG(root_stbuf.st_mode) && !S_ISDIR(root_stbuf.st_mode) && !S_ISLNK(root_stbuf.st_mode)) { ERROR("`%s' is not a regular file, directory, or symbolic link.", root_disk_path); - return WIMLIB_ERR_SPECIAL_FILE; + ret = WIMLIB_ERR_SPECIAL_FILE; + goto out; } root = new_dentry_with_timeless_inode(path_basename(root_disk_path)); if (!root) { if (errno == EILSEQ) - return WIMLIB_ERR_INVALID_UTF8_STRING; + ret = WIMLIB_ERR_INVALID_UTF8_STRING; else if (errno == ENOMEM) - return WIMLIB_ERR_NOMEM; + ret = WIMLIB_ERR_NOMEM; else - return WIMLIB_ERR_ICONV_NOT_AVAILABLE; + ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE; + goto out; } inode = root->d_inode; @@ -373,6 +813,122 @@ static int build_dentry_tree(struct wim_dentry **root_ret, ret = WIMLIB_ERR_READLINK; } } +#else + /* Win32 version of capturing a directory tree */ + + wchar_t *path_utf16; + size_t path_utf16_nchars; + struct sd_set *sd_set; + DWORD err; + + if (extra_arg == NULL) { + sd_set = alloca(sizeof(struct sd_set)); + sd_set->rb_root.rb_node = NULL, + sd_set->sd = sd; + } else { + sd_set = extra_arg; + } + + DEBUG_WIN32_SAFE("root_disk_path=\"%s\"", root_disk_path); + ret = utf8_to_utf16(root_disk_path, strlen(root_disk_path), + (char**)&path_utf16, &path_utf16_nchars); + if (ret) + goto out_destroy_sd_set; + path_utf16_nchars /= sizeof(wchar_t); + + DEBUG_WIN32_SAFE("Win32: Opening file `%s'", root_disk_path); + HANDLE hFile = win32_open_file(path_utf16); + if (hFile == INVALID_HANDLE_VALUE) { + err = GetLastError(); + ERROR("Win32 API: Failed to open \"%s\"", root_disk_path); + win32_error(err); + ret = WIMLIB_ERR_OPEN; + goto out_free_path_utf16; + } + + BY_HANDLE_FILE_INFORMATION file_info; + if (!GetFileInformationByHandle(hFile, &file_info)) { + err = GetLastError(); + ERROR("Win32 API: Failed to get file information for \"%s\"", + root_disk_path); + win32_error(err); + ret = WIMLIB_ERR_STAT; + goto out_close_handle; + } + + /* Create a WIM dentry */ + root = new_dentry_with_timeless_inode(path_basename(root_disk_path)); + if (!root) { + if (errno == EILSEQ) + ret = WIMLIB_ERR_INVALID_UTF8_STRING; + else if (errno == ENOMEM) + ret = WIMLIB_ERR_NOMEM; + else + ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE; + goto out_free_path_utf16; + } + + /* Start preparing the associated WIM inode */ + inode = root->d_inode; + + inode->i_attributes = file_info.dwFileAttributes; + inode->i_creation_time = FILETIME_to_u64(&file_info.ftCreationTime); + inode->i_last_write_time = FILETIME_to_u64(&file_info.ftLastWriteTime); + inode->i_last_access_time = FILETIME_to_u64(&file_info.ftLastAccessTime); + inode->i_ino = ((u64)file_info.nFileIndexHigh << 32) | + (u64)file_info.nFileIndexLow; + + inode->i_resolved = 1; + add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE); + + /* 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, + root_disk_path); + if (ret) + goto out_close_handle; + + if (inode_is_directory(inode)) { + /* Directory (not a reparse point) --- recurse to children */ + DEBUG_WIN32_SAFE("Recursing to directory \"%s\"", root_disk_path); + ret = win32_recurse_directory(root, + root_disk_path, + lookup_table, + sd, + config, + add_image_flags, + progress_func, + sd_set, + path_utf16, + path_utf16_nchars); + } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* Reparse point: save the reparse tag and data */ + + DEBUG_WIN32_SAFE("Capturing reparse point `%s'", root_disk_path); + ret = win32_capture_reparse_point(root_disk_path, + hFile, + inode, + lookup_table); + + } else { + DEBUG_WIN32_SAFE("Capturing streams of \"%s\"", root_disk_path); + /* Not a directory, not a reparse point */ + ret = win32_capture_streams(root_disk_path, + path_utf16, + path_utf16_nchars, + inode, + lookup_table); + } +out_close_handle: + CloseHandle(hFile); +out_destroy_sd_set: + if (extra_arg == NULL) + destroy_sd_set(sd_set); +out_free_path_utf16: + FREE(path_utf16); +#endif out: if (ret == 0) *root_ret = root; @@ -381,7 +937,6 @@ out: return ret; } - enum pattern_type { NONE = 0, EXCLUSION_LIST, diff --git a/src/lookup_table.c b/src/lookup_table.c index 2c3278a9..fee69cbb 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -86,6 +86,9 @@ clone_lookup_table_entry(const struct wim_lookup_table_entry *old) switch (new->resource_location) { case RESOURCE_IN_STAGING_FILE: case RESOURCE_IN_FILE_ON_DISK: +#if defined(__CYGWIN__) || defined(__WIN32__) + case RESOURCE_WIN32: +#endif BUILD_BUG_ON((void*)&old->file_on_disk != (void*)&old->staging_file_name); new->staging_file_name = STRDUP(old->staging_file_name); @@ -138,6 +141,9 @@ void free_lookup_table_entry(struct wim_lookup_table_entry *lte) case RESOURCE_IN_STAGING_FILE: case RESOURCE_IN_ATTACHED_BUFFER: case RESOURCE_IN_FILE_ON_DISK: +#if defined(__CYGWIN__) || defined(__WIN32__) + case RESOURCE_WIN32: +#endif BUILD_BUG_ON((void*)<e->file_on_disk != (void*)<e->staging_file_name); BUILD_BUG_ON((void*)<e->file_on_disk != diff --git a/src/lookup_table.h b/src/lookup_table.h index 92428b12..ca418219 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -77,6 +77,10 @@ enum resource_location { * point or not. @ntfs_loc points to a structure containing this * information. */ RESOURCE_IN_NTFS_VOLUME, + + /* Resource must be accessed using Win32 API (may be a named data + * stream) */ + RESOURCE_WIN32, }; /* diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index 8ce3f443..70ce59a9 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -47,140 +47,7 @@ #include #include #include -#include "rbtree.h" - -/* Red-black tree that maps SHA1 message digests of security descriptors to - * security IDs, which are themselves indices into the table of security - * descriptors in the 'struct wim_security_data'. */ -struct sd_set { - struct wim_security_data *sd; - struct rb_root rb_root; -}; - -struct sd_node { - int security_id; - u8 hash[SHA1_HASH_SIZE]; - struct rb_node rb_node; -}; - -static void free_sd_tree(struct rb_node *node) -{ - if (node) { - free_sd_tree(node->rb_left); - free_sd_tree(node->rb_right); - FREE(container_of(node, struct sd_node, rb_node)); - } -} -/* Frees a security descriptor index set. */ -static void destroy_sd_set(struct sd_set *sd_set) -{ - free_sd_tree(sd_set->rb_root.rb_node); -} - -/* Inserts a a new node into the security descriptor index tree. */ -static void insert_sd_node(struct sd_set *set, struct sd_node *new) -{ - struct rb_root *root = &set->rb_root; - struct rb_node **p = &(root->rb_node); - struct rb_node *rb_parent = NULL; - - while (*p) { - struct sd_node *this = container_of(*p, struct sd_node, rb_node); - int cmp = hashes_cmp(new->hash, this->hash); - - rb_parent = *p; - if (cmp < 0) - p = &((*p)->rb_left); - else if (cmp > 0) - p = &((*p)->rb_right); - else - wimlib_assert(0); /* Duplicate SHA1 message digest */ - } - rb_link_node(&new->rb_node, rb_parent, p); - rb_insert_color(&new->rb_node, root); -} - -/* Returns the index of the security descriptor having a SHA1 message digest of - * @hash. If not found, return -1. */ -static int lookup_sd(struct sd_set *set, const u8 hash[SHA1_HASH_SIZE]) -{ - struct rb_node *node = set->rb_root.rb_node; - - while (node) { - struct sd_node *sd_node = container_of(node, struct sd_node, rb_node); - int cmp = hashes_cmp(hash, sd_node->hash); - if (cmp < 0) - node = node->rb_left; - else if (cmp > 0) - node = node->rb_right; - else - return sd_node->security_id; - } - return -1; -} - -/* - * Adds a security descriptor to the indexed security descriptor set as well as - * the corresponding `struct wim_security_data', and returns the new security - * ID; or, if there is an existing security descriptor that is the same, return - * the security ID for it. If a new security descriptor cannot be allocated, - * return -1. - */ -static int sd_set_add_sd(struct sd_set *sd_set, const char descriptor[], - size_t size) -{ - u8 hash[SHA1_HASH_SIZE]; - int security_id; - struct sd_node *new; - u8 **descriptors; - u64 *sizes; - u8 *descr_copy; - struct wim_security_data *sd; - - sha1_buffer((const u8*)descriptor, size, hash); - - security_id = lookup_sd(sd_set, hash); - if (security_id >= 0) /* Identical descriptor already exists */ - return security_id; - - /* Need to add a new security descriptor */ - new = MALLOC(sizeof(*new)); - if (!new) - goto out; - descr_copy = MALLOC(size); - if (!descr_copy) - goto out_free_node; - - sd = sd_set->sd; - - memcpy(descr_copy, descriptor, size); - new->security_id = sd->num_entries; - copy_hash(new->hash, hash); - - descriptors = REALLOC(sd->descriptors, - (sd->num_entries + 1) * sizeof(sd->descriptors[0])); - if (!descriptors) - goto out_free_descr; - sd->descriptors = descriptors; - sizes = REALLOC(sd->sizes, - (sd->num_entries + 1) * sizeof(sd->sizes[0])); - if (!sizes) - goto out_free_descr; - sd->sizes = sizes; - sd->descriptors[sd->num_entries] = descr_copy; - sd->sizes[sd->num_entries] = size; - sd->num_entries++; - DEBUG("There are now %d security descriptors", sd->num_entries); - sd->total_length += size + sizeof(sd->sizes[0]); - insert_sd_node(sd_set, new); - return new->security_id; -out_free_descr: - FREE(descr_copy); -out_free_node: - FREE(new); -out: - return -1; -} +#include "security.h" static inline ntfschar *attr_record_name(ATTR_RECORD *ar) { diff --git a/src/resource.c b/src/resource.c index 8f3ba116..69a531fb 100644 --- a/src/resource.c +++ b/src/resource.c @@ -539,8 +539,8 @@ int read_wim_resource(const struct wim_lookup_table_entry *lte, u8 buf[], case RESOURCE_IN_FILE_ON_DISK: /* The resource is in some file on the external filesystem and * needs to be read uncompressed */ - wimlib_assert(lte->file_on_disk); - wimlib_assert(<e->file_on_disk == <e->staging_file_name); + wimlib_assert(lte->file_on_disk != NULL); + BUILD_BUG_ON(<e->file_on_disk != <e->staging_file_name); /* Use existing file pointer if available; otherwise open one * temporarily */ if (lte->file_on_disk_fp) { @@ -558,6 +558,14 @@ int read_wim_resource(const struct wim_lookup_table_entry *lte, u8 buf[], if (fp != lte->file_on_disk_fp) fclose(fp); break; +#if defined(__CYGWIN__) || defined(__WIN32__) + case RESOURCE_WIN32: + wimlib_assert(lte->file_on_disk_fp != NULL); + DEBUG("Calling win32_read_file()"); + ret = win32_read_file(lte->file_on_disk, lte->file_on_disk_fp, + offset, size, buf); + break; +#endif case RESOURCE_IN_ATTACHED_BUFFER: /* The resource is directly attached uncompressed in an * in-memory buffer. */ diff --git a/src/security.c b/src/security.c index 36f86847..9c55ef2d 100644 --- a/src/security.c +++ b/src/security.c @@ -27,6 +27,223 @@ #include "buffer_io.h" #include "security.h" + +#define SECURITY_DESCRIPTOR_REVISION 1 +#define SECURITY_DESCRIPTOR_REVISION1 1 + +/* inherit AceFlags */ +#define OBJECT_INHERIT_ACE 0x01 +#define CONTAINER_INHERIT_ACE 0x02 +#define NO_PROPAGATE_INHERIT_ACE 0x04 +#define INHERIT_ONLY_ACE 0x08 +#define INHERITED_ACE 0x10 +#define VALID_INHERIT_FLAGS 0x1F + +#define SE_OWNER_DEFAULTED 0x00000001 +#define SE_GROUP_DEFAULTED 0x00000002 +#define SE_DACL_PRESENT 0x00000004 +#define SE_DACL_DEFAULTED 0x00000008 +#define SE_SACL_PRESENT 0x00000010 +#define SE_SACL_DEFAULTED 0x00000020 +#define SE_DACL_AUTO_INHERIT_REQ 0x00000100 +#define SE_SACL_AUTO_INHERIT_REQ 0x00000200 +#define SE_DACL_AUTO_INHERITED 0x00000400 +#define SE_SACL_AUTO_INHERITED 0x00000800 +#define SE_DACL_PROTECTED 0x00001000 +#define SE_SACL_PROTECTED 0x00002000 +#define SE_RM_CONTROL_VALID 0x00004000 +#define SE_SELF_RELATIVE 0x00008000 + +/* Flags in access control entries */ +#define DELETE 0x00010000 +#define READ_CONTROL 0x00020000 +#define WRITE_DAC 0x00040000 +#define WRITE_OWNER 0x00080000 +#define SYNCHRONIZE 0x00100000 +#define STANDARD_RIGHTS_REQUIRED 0x000f0000 + +#define STANDARD_RIGHTS_READ READ_CONTROL +#define STANDARD_RIGHTS_WRITE READ_CONTROL +#define STANDARD_RIGHTS_EXECUTE READ_CONTROL + +#define STANDARD_RIGHTS_ALL 0x001f0000 + +#define SPECIFIC_RIGHTS_ALL 0x0000ffff + +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_ALL 0x10000000 + +#define MAXIMUM_ALLOWED 0x02000000 +#define ACCESS_SYSTEM_SECURITY 0x01000000 + +#define EVENT_QUERY_STATE 0x0001 +#define EVENT_MODIFY_STATE 0x0002 +#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define SEMAPHORE_MODIFY_STATE 0x0002 +#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define MUTEX_MODIFY_STATE 0x0001 +#define MUTEX_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1) + +#define JOB_OBJECT_ASSIGN_PROCESS 0x0001 +#define JOB_OBJECT_SET_ATTRIBUTES 0x0002 +#define JOB_OBJECT_QUERY 0x0004 +#define JOB_OBJECT_TERMINATE 0x0008 +#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES 0x0010 +#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1f) + +#define TIMER_QUERY_STATE 0x0001 +#define TIMER_MODIFY_STATE 0x0002 +#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +#define PROCESS_TERMINATE 0x0001 +#define PROCESS_CREATE_THREAD 0x0002 +#define PROCESS_VM_OPERATION 0x0008 +#define PROCESS_VM_READ 0x0010 +#define PROCESS_VM_WRITE 0x0020 +#define PROCESS_DUP_HANDLE 0x0040 +#define PROCESS_CREATE_PROCESS 0x0080 +#define PROCESS_SET_QUOTA 0x0100 +#define PROCESS_SET_INFORMATION 0x0200 +#define PROCESS_QUERY_INFORMATION 0x0400 +#define PROCESS_SUSPEND_RESUME 0x0800 +#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000 +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xfff) + +#define THREAD_TERMINATE 0x0001 +#define THREAD_SUSPEND_RESUME 0x0002 +#define THREAD_GET_CONTEXT 0x0008 +#define THREAD_SET_CONTEXT 0x0010 +#define THREAD_SET_INFORMATION 0x0020 +#define THREAD_QUERY_INFORMATION 0x0040 +#define THREAD_SET_THREAD_TOKEN 0x0080 +#define THREAD_IMPERSONATE 0x0100 +#define THREAD_DIRECT_IMPERSONATION 0x0200 +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff) + +#define THREAD_BASE_PRIORITY_LOWRT 15 +#define THREAD_BASE_PRIORITY_MAX 2 +#define THREAD_BASE_PRIORITY_MIN -2 +#define THREAD_BASE_PRIORITY_IDLE -15 + +/* predefined authority values for SID's (security identifiers) */ +enum sid_authority_value { + SECURITY_NULL_SID_AUTHORITY = 0, + SECURITY_WORLD_SID_AUTHORITY = 1, + SECURITY_LOCAL_SID_AUTHORITY = 2, + SECURITY_CREATOR_SID_AUTHORITY = 3, + SECURITY_NON_UNIQUE_AUTHORITY = 4, + SECURITY_NT_AUTHORITY = 5, +}; + +/* local administrators group */ +#define SECURITY_BUILTIN_DOMAIN_RID 32 +#define DOMAIN_ALIAS_RID_ADMINS 544 + +/* See ACEHeader. */ +enum ace_type { + ACCESS_ALLOWED_ACE_TYPE = 0, + ACCESS_DENIED_ACE_TYPE = 1, + SYSTEM_AUDIT_ACE_TYPE = 2, +}; + +/* At the start of each type of access control entry. */ +typedef struct { + /* enum ace_type, specifies what type of ACE this is. */ + u8 type; + + /* bitwise OR of the inherit ACE flags #defined above */ + u8 flags; + + /* Size of the access control entry. */ + u8 size; +} ACEHeader; + +/* Grants rights to a user or group */ +typedef struct { + ACEHeader hdr; + u32 mask; + u32 sid_start; +} AccessAllowedACE; + +/* Denies rights to a user or group */ +typedef struct { + ACEHeader hdr; + u32 mask; + u32 sid_start; +} AccessDeniedACE; + +typedef struct { + ACEHeader hdr; + u32 mask; + u32 sid_start; +} SystemAuditACE; + + +/* Header of an access control list. */ +typedef struct { + /* ACL_REVISION or ACL_REVISION_DS */ + u8 revision; + + /* padding */ + u8 sbz1; + + /* Total size of the ACL, including all access control entries */ + u16 acl_size; + + /* Number of access control entry structures that follow the ACL + * structure. */ + u16 ace_count; + + /* padding */ + u16 sbz2; +} ACL; + +/* A structure used to identify users or groups. */ +typedef struct { + + /* example: 0x1 */ + u8 revision; + u8 sub_authority_count; + + /* Identifies the authority that issued the SID. Can be, but does not + * have to be, one of enum sid_authority_value */ + u8 identifier_authority[6]; + + u32 sub_authority[0]; +} SID; + + +typedef struct { + /* Example: 0x1 */ + u8 revision; + /* Example: 0x0 */ + u8 sbz1; + /* Example: 0x4149 */ + u16 security_descriptor_control; + + /* Offset of a SID structure in the security descriptor. */ + /* Example: 0x14 */ + u32 owner_offset; + + /* Offset of a SID structure in the security descriptor. */ + /* Example: 0x24 */ + u32 group_offset; + + /* Offset of an ACL structure in the security descriptor. */ + /* System ACL. */ + /* Example: 0x00 */ + u32 sacl_offset; + + /* Offset of an ACL structure in the security descriptor. */ + /* Discretionary ACL. */ + /* Example: 0x34 */ + u32 dacl_offset; +} SecurityDescriptor; + /* * This is a hack to work around a problem in libntfs-3g. libntfs-3g validates * security descriptors with a function named ntfs_valid_descr(). @@ -342,3 +559,131 @@ void free_security_data(struct wim_security_data *sd) } } } + +#if defined(WITH_NTFS_3G) || defined(__CYGWIN__) || defined(__WIN32__) +struct sd_node { + int security_id; + u8 hash[SHA1_HASH_SIZE]; + struct rb_node rb_node; +}; + +static void free_sd_tree(struct rb_node *node) +{ + if (node) { + free_sd_tree(node->rb_left); + free_sd_tree(node->rb_right); + FREE(container_of(node, struct sd_node, rb_node)); + } +} + +/* Frees a security descriptor index set. */ +void destroy_sd_set(struct sd_set *sd_set) +{ + free_sd_tree(sd_set->rb_root.rb_node); +} + +/* Inserts a a new node into the security descriptor index tree. */ +static void insert_sd_node(struct sd_set *set, struct sd_node *new) +{ + struct rb_root *root = &set->rb_root; + struct rb_node **p = &(root->rb_node); + struct rb_node *rb_parent = NULL; + + while (*p) { + struct sd_node *this = container_of(*p, struct sd_node, rb_node); + int cmp = hashes_cmp(new->hash, this->hash); + + rb_parent = *p; + if (cmp < 0) + p = &((*p)->rb_left); + else if (cmp > 0) + p = &((*p)->rb_right); + else + wimlib_assert(0); /* Duplicate SHA1 message digest */ + } + rb_link_node(&new->rb_node, rb_parent, p); + rb_insert_color(&new->rb_node, root); +} + +/* Returns the index of the security descriptor having a SHA1 message digest of + * @hash. If not found, return -1. */ +int lookup_sd(struct sd_set *set, const u8 hash[SHA1_HASH_SIZE]) +{ + struct rb_node *node = set->rb_root.rb_node; + + while (node) { + struct sd_node *sd_node = container_of(node, struct sd_node, rb_node); + int cmp = hashes_cmp(hash, sd_node->hash); + if (cmp < 0) + node = node->rb_left; + else if (cmp > 0) + node = node->rb_right; + else + return sd_node->security_id; + } + return -1; +} + +/* + * Adds a security descriptor to the indexed security descriptor set as well as + * the corresponding `struct wim_security_data', and returns the new security + * ID; or, if there is an existing security descriptor that is the same, return + * the security ID for it. If a new security descriptor cannot be allocated, + * return -1. + */ +int sd_set_add_sd(struct sd_set *sd_set, const char descriptor[], + size_t size) +{ + u8 hash[SHA1_HASH_SIZE]; + int security_id; + struct sd_node *new; + u8 **descriptors; + u64 *sizes; + u8 *descr_copy; + struct wim_security_data *sd; + + sha1_buffer((const u8*)descriptor, size, hash); + + security_id = lookup_sd(sd_set, hash); + if (security_id >= 0) /* Identical descriptor already exists */ + return security_id; + + /* Need to add a new security descriptor */ + new = MALLOC(sizeof(*new)); + if (!new) + goto out; + descr_copy = MALLOC(size); + if (!descr_copy) + goto out_free_node; + + sd = sd_set->sd; + + memcpy(descr_copy, descriptor, size); + new->security_id = sd->num_entries; + copy_hash(new->hash, hash); + + descriptors = REALLOC(sd->descriptors, + (sd->num_entries + 1) * sizeof(sd->descriptors[0])); + if (!descriptors) + goto out_free_descr; + sd->descriptors = descriptors; + sizes = REALLOC(sd->sizes, + (sd->num_entries + 1) * sizeof(sd->sizes[0])); + if (!sizes) + goto out_free_descr; + sd->sizes = sizes; + sd->descriptors[sd->num_entries] = descr_copy; + sd->sizes[sd->num_entries] = size; + sd->num_entries++; + DEBUG("There are now %d security descriptors", sd->num_entries); + sd->total_length += size + sizeof(sd->sizes[0]); + insert_sd_node(sd_set, new); + return new->security_id; +out_free_descr: + FREE(descr_copy); +out_free_node: + FREE(new); +out: + return -1; +} +#endif /* WITH_NTFS_3G || __CYGWIN__ || __WIN32__ */ diff --git a/src/security.h b/src/security.h index 490a7c33..d6d7d60a 100644 --- a/src/security.h +++ b/src/security.h @@ -6,225 +6,24 @@ */ #include "util.h" +#include "rbtree.h" +#include "sha1.h" #ifndef _WIMLIB_SECURITY_H #define _WIMLIB_SECURITY_H -#define SECURITY_DESCRIPTOR_REVISION 1 -#define SECURITY_DESCRIPTOR_REVISION1 1 - -/* inherit AceFlags */ -#define OBJECT_INHERIT_ACE 0x01 -#define CONTAINER_INHERIT_ACE 0x02 -#define NO_PROPAGATE_INHERIT_ACE 0x04 -#define INHERIT_ONLY_ACE 0x08 -#define INHERITED_ACE 0x10 -#define VALID_INHERIT_FLAGS 0x1F - -#define SE_OWNER_DEFAULTED 0x00000001 -#define SE_GROUP_DEFAULTED 0x00000002 -#define SE_DACL_PRESENT 0x00000004 -#define SE_DACL_DEFAULTED 0x00000008 -#define SE_SACL_PRESENT 0x00000010 -#define SE_SACL_DEFAULTED 0x00000020 -#define SE_DACL_AUTO_INHERIT_REQ 0x00000100 -#define SE_SACL_AUTO_INHERIT_REQ 0x00000200 -#define SE_DACL_AUTO_INHERITED 0x00000400 -#define SE_SACL_AUTO_INHERITED 0x00000800 -#define SE_DACL_PROTECTED 0x00001000 -#define SE_SACL_PROTECTED 0x00002000 -#define SE_RM_CONTROL_VALID 0x00004000 -#define SE_SELF_RELATIVE 0x00008000 - -/* Flags in access control entries */ -#define DELETE 0x00010000 -#define READ_CONTROL 0x00020000 -#define WRITE_DAC 0x00040000 -#define WRITE_OWNER 0x00080000 -#define SYNCHRONIZE 0x00100000 -#define STANDARD_RIGHTS_REQUIRED 0x000f0000 - -#define STANDARD_RIGHTS_READ READ_CONTROL -#define STANDARD_RIGHTS_WRITE READ_CONTROL -#define STANDARD_RIGHTS_EXECUTE READ_CONTROL - -#define STANDARD_RIGHTS_ALL 0x001f0000 - -#define SPECIFIC_RIGHTS_ALL 0x0000ffff - -#define GENERIC_READ 0x80000000 -#define GENERIC_WRITE 0x40000000 -#define GENERIC_EXECUTE 0x20000000 -#define GENERIC_ALL 0x10000000 - -#define MAXIMUM_ALLOWED 0x02000000 -#define ACCESS_SYSTEM_SECURITY 0x01000000 - -#define EVENT_QUERY_STATE 0x0001 -#define EVENT_MODIFY_STATE 0x0002 -#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define SEMAPHORE_MODIFY_STATE 0x0002 -#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define MUTEX_MODIFY_STATE 0x0001 -#define MUTEX_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1) - -#define JOB_OBJECT_ASSIGN_PROCESS 0x0001 -#define JOB_OBJECT_SET_ATTRIBUTES 0x0002 -#define JOB_OBJECT_QUERY 0x0004 -#define JOB_OBJECT_TERMINATE 0x0008 -#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES 0x0010 -#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1f) - -#define TIMER_QUERY_STATE 0x0001 -#define TIMER_MODIFY_STATE 0x0002 -#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) - -#define PROCESS_TERMINATE 0x0001 -#define PROCESS_CREATE_THREAD 0x0002 -#define PROCESS_VM_OPERATION 0x0008 -#define PROCESS_VM_READ 0x0010 -#define PROCESS_VM_WRITE 0x0020 -#define PROCESS_DUP_HANDLE 0x0040 -#define PROCESS_CREATE_PROCESS 0x0080 -#define PROCESS_SET_QUOTA 0x0100 -#define PROCESS_SET_INFORMATION 0x0200 -#define PROCESS_QUERY_INFORMATION 0x0400 -#define PROCESS_SUSPEND_RESUME 0x0800 -#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000 -#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xfff) - -#define THREAD_TERMINATE 0x0001 -#define THREAD_SUSPEND_RESUME 0x0002 -#define THREAD_GET_CONTEXT 0x0008 -#define THREAD_SET_CONTEXT 0x0010 -#define THREAD_SET_INFORMATION 0x0020 -#define THREAD_QUERY_INFORMATION 0x0040 -#define THREAD_SET_THREAD_TOKEN 0x0080 -#define THREAD_IMPERSONATE 0x0100 -#define THREAD_DIRECT_IMPERSONATION 0x0200 -#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff) - -#define THREAD_BASE_PRIORITY_LOWRT 15 -#define THREAD_BASE_PRIORITY_MAX 2 -#define THREAD_BASE_PRIORITY_MIN -2 -#define THREAD_BASE_PRIORITY_IDLE -15 - -/* predefined authority values for SID's (security identifiers) */ -enum sid_authority_value { - SECURITY_NULL_SID_AUTHORITY = 0, - SECURITY_WORLD_SID_AUTHORITY = 1, - SECURITY_LOCAL_SID_AUTHORITY = 2, - SECURITY_CREATOR_SID_AUTHORITY = 3, - SECURITY_NON_UNIQUE_AUTHORITY = 4, - SECURITY_NT_AUTHORITY = 5, +#if defined(WITH_NTFS_3G) || defined(__CYGWIN__) || defined(__WIN32__) +/* Red-black tree that maps SHA1 message digests of security descriptors to + * security IDs, which are themselves indices into the table of security + * descriptors in the 'struct wim_security_data'. */ +struct sd_set { + struct wim_security_data *sd; + struct rb_root rb_root; }; - -/* local administrators group */ -#define SECURITY_BUILTIN_DOMAIN_RID 32 -#define DOMAIN_ALIAS_RID_ADMINS 544 - -/* See ACEHeader. */ -enum ace_type { - ACCESS_ALLOWED_ACE_TYPE = 0, - ACCESS_DENIED_ACE_TYPE = 1, - SYSTEM_AUDIT_ACE_TYPE = 2, -}; - -/* At the start of each type of access control entry. */ -typedef struct { - /* enum ace_type, specifies what type of ACE this is. */ - u8 type; - - /* bitwise OR of the inherit ACE flags #defined above */ - u8 flags; - - /* Size of the access control entry. */ - u8 size; -} ACEHeader; - -/* Grants rights to a user or group */ -typedef struct { - ACEHeader hdr; - u32 mask; - u32 sid_start; -} AccessAllowedACE; - -/* Denies rights to a user or group */ -typedef struct { - ACEHeader hdr; - u32 mask; - u32 sid_start; -} AccessDeniedACE; - -typedef struct { - ACEHeader hdr; - u32 mask; - u32 sid_start; -} SystemAuditACE; - - -/* Header of an access control list. */ -typedef struct { - /* ACL_REVISION or ACL_REVISION_DS */ - u8 revision; - - /* padding */ - u8 sbz1; - - /* Total size of the ACL, including all access control entries */ - u16 acl_size; - - /* Number of access control entry structures that follow the ACL - * structure. */ - u16 ace_count; - - /* padding */ - u16 sbz2; -} ACL; - -/* A structure used to identify users or groups. */ -typedef struct { - - /* example: 0x1 */ - u8 revision; - u8 sub_authority_count; - - /* Identifies the authority that issued the SID. Can be, but does not - * have to be, one of enum sid_authority_value */ - u8 identifier_authority[6]; - - u32 sub_authority[0]; -} SID; - - -typedef struct { - /* Example: 0x1 */ - u8 revision; - /* Example: 0x0 */ - u8 sbz1; - /* Example: 0x4149 */ - u16 security_descriptor_control; - - /* Offset of a SID structure in the security descriptor. */ - /* Example: 0x14 */ - u32 owner_offset; - - /* Offset of a SID structure in the security descriptor. */ - /* Example: 0x24 */ - u32 group_offset; - - /* Offset of an ACL structure in the security descriptor. */ - /* System ACL. */ - /* Example: 0x00 */ - u32 sacl_offset; - - /* Offset of an ACL structure in the security descriptor. */ - /* Discretionary ACL. */ - /* Example: 0x34 */ - u32 dacl_offset; -} SecurityDescriptor; - +void destroy_sd_set(struct sd_set *sd_set); +int lookup_sd(struct sd_set *set, const u8 hash[SHA1_HASH_SIZE]); +int sd_set_add_sd(struct sd_set *sd_set, const char descriptor[], + size_t size); +#endif #endif /* _WIMLIB_SECURITY_H */ diff --git a/src/wim.c b/src/wim.c index 38792a59..bd31c5b3 100644 --- a/src/wim.c +++ b/src/wim.c @@ -599,7 +599,7 @@ void destroy_image_metadata(struct wim_image_metadata *imd, * closes all files associated with the WIMStruct. */ WIMLIBAPI void wimlib_free(WIMStruct *w) { - DEBUG2("Freeing WIMStruct"); + DEBUG("Freeing WIMStruct"); if (!w) return; @@ -635,6 +635,7 @@ WIMLIBAPI void wimlib_free(WIMStruct *w) } #endif FREE(w); + DEBUG("Freed WIMStruct"); } /* Get global memory allocations out of the way. Not strictly necessary in diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 6df94cb3..8a99f30d 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -372,6 +372,10 @@ extern bool exclude_path(const char *path, extern int add_new_dentry_tree(WIMStruct *dest_wim, struct wim_dentry *root, struct wim_security_data *sd); +#if defined(__CYGWIN__) || defined(__WIN32__) +extern FILE *win32_open_fp(const char *path_utf16); +#endif + /* extract_image.c */ /* Internal use only */ @@ -480,6 +484,14 @@ extern int extract_wim_chunk_to_fd(const u8 *buf, size_t len, extern int extract_wim_resource(const struct wim_lookup_table_entry *lte, u64 size, extract_chunk_func_t extract_chunk, void *extract_chunk_arg); + +#if defined(__CYGWIN__) || defined(__WIN32__) +extern int win32_read_file(const char *filename, void *handle, u64 offset, + size_t size, u8 *buf); +extern void *win32_open_handle(const char *path_utf16); +extern void win32_close_handle(void *handle); +#endif + /* * Extracts the first @size bytes of the WIM resource specified by @lte to the * open file descriptor @fd. diff --git a/src/write.c b/src/write.c index 737112f0..c346e61c 100644 --- a/src/write.c +++ b/src/write.c @@ -257,43 +257,55 @@ static int prepare_resource_for_read(struct wim_lookup_table_entry *lte #endif ) { - if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK - && !lte->file_on_disk_fp) - { - wimlib_assert(lte->file_on_disk); - lte->file_on_disk_fp = fopen(lte->file_on_disk, "rb"); + switch (lte->resource_location) { + case RESOURCE_IN_FILE_ON_DISK: if (!lte->file_on_disk_fp) { - ERROR_WITH_ERRNO("Failed to open the file `%s' for " - "reading", lte->file_on_disk); - return WIMLIB_ERR_OPEN; + lte->file_on_disk_fp = fopen(lte->file_on_disk, "rb"); + if (!lte->file_on_disk_fp) { + ERROR_WITH_ERRNO("Failed to open the file " + "`%s'", lte->file_on_disk); + return WIMLIB_ERR_OPEN; + } } - } + break; #ifdef WITH_NTFS_3G - else if (lte->resource_location == RESOURCE_IN_NTFS_VOLUME - && !lte->attr) - { - struct ntfs_location *loc = lte->ntfs_loc; - ntfs_inode *ni; - wimlib_assert(loc); - ni = ntfs_pathname_to_inode(*loc->ntfs_vol_p, NULL, loc->path_utf8); - if (!ni) { - ERROR_WITH_ERRNO("Failed to open inode `%s' in NTFS " - "volume", loc->path_utf8); - return WIMLIB_ERR_NTFS_3G; - } - lte->attr = ntfs_attr_open(ni, - loc->is_reparse_point ? AT_REPARSE_POINT : AT_DATA, - (ntfschar*)loc->stream_name_utf16, - loc->stream_name_utf16_num_chars); + case RESOURCE_IN_NTFS_VOLUME: if (!lte->attr) { - ERROR_WITH_ERRNO("Failed to open attribute of `%s' in " - "NTFS volume", loc->path_utf8); - ntfs_inode_close(ni); - return WIMLIB_ERR_NTFS_3G; + struct ntfs_location *loc = lte->ntfs_loc; + ntfs_inode *ni; + wimlib_assert(loc); + ni = ntfs_pathname_to_inode(*loc->ntfs_vol_p, NULL, loc->path_utf8); + if (!ni) { + ERROR_WITH_ERRNO("Failed to open inode `%s' in NTFS " + "volume", loc->path_utf8); + return WIMLIB_ERR_NTFS_3G; + } + lte->attr = ntfs_attr_open(ni, + loc->is_reparse_point ? AT_REPARSE_POINT : AT_DATA, + (ntfschar*)loc->stream_name_utf16, + loc->stream_name_utf16_num_chars); + if (!lte->attr) { + ERROR_WITH_ERRNO("Failed to open attribute of `%s' in " + "NTFS volume", loc->path_utf8); + ntfs_inode_close(ni); + return WIMLIB_ERR_NTFS_3G; + } + *ni_ret = ni; } - *ni_ret = ni; - } + break; #endif +#if defined(__CYGWIN__) || defined(__WIN32__) + case RESOURCE_WIN32: + if (!lte->file_on_disk_fp) { + lte->file_on_disk_fp = win32_open_handle(lte->file_on_disk); + if (!lte->file_on_disk_fp) + return WIMLIB_ERR_OPEN; + } + break; +#endif + default: + break; + } return 0; } @@ -306,7 +318,8 @@ static void end_wim_resource_read(struct wim_lookup_table_entry *lte ) { if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK - && lte->file_on_disk_fp) { + && lte->file_on_disk_fp) + { fclose(lte->file_on_disk_fp); lte->file_on_disk_fp = NULL; } @@ -320,6 +333,14 @@ static void end_wim_resource_read(struct wim_lookup_table_entry *lte ntfs_inode_close(ni); } #endif +#if defined(__CYGWIN__) || defined(__WIN32__) + else if (lte->resource_location == RESOURCE_WIN32 + && lte->file_on_disk_fp) + { + win32_close_handle(lte->file_on_disk_fp); + lte->file_on_disk_fp = NULL; + } +#endif } static int @@ -1704,6 +1725,7 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, ret = finish_write(w, image, write_flags, progress_func); out: close_wim_writable(w); + DEBUG("wimlib_write(path=%s) = %d", path, ret); return ret; } -- 2.43.0