Update security descriptor setting
authorEric Biggers <ebiggers3@gmail.com>
Sun, 18 Aug 2013 15:37:57 +0000 (10:37 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 18 Aug 2013 15:38:17 +0000 (10:38 -0500)
include/wimlib/apply.h
src/extract.c
src/win32_apply.c

index 31cda98..ef623a6 100644 (file)
@@ -209,6 +209,8 @@ struct apply_ctx {
        tchar *realtarget;
        size_t realtarget_nchars;
        unsigned long invalid_sequence;
+       unsigned long partial_security_descriptors;
+       unsigned long no_security_descriptors;
        u64 num_streams_remaining;
        bool root_dentry_is_special;
        uint64_t next_progress;
index c9a1dca..3b434c4 100644 (file)
@@ -766,11 +766,14 @@ extract_security(const tchar *path, struct apply_ctx *ctx,
                                                 "descriptor on \"%"TS"\"", path);
                                return ret;
                        } else {
+                       #if 0
                                if (errno != EACCES) {
                                        WARNING_WITH_ERRNO("Failed to set "
                                                           "security descriptor "
                                                           "on \"%"TS"\"", path);
                                }
+                       #endif
+                               ctx->no_security_descriptors++;
                        }
                }
        }
@@ -2040,6 +2043,31 @@ do_feature_check(const struct wim_features *required_features,
        return 0;
 }
 
+static void
+do_extract_warnings(struct apply_ctx *ctx)
+{
+       if (ctx->partial_security_descriptors == 0 &&
+           ctx->no_security_descriptors == 0)
+               return;
+
+       WARNING("Extraction of \"%"TS"\" complete, but with one or more warnings:",
+               ctx->target);
+       if (ctx->partial_security_descriptors != 0) {
+               WARNING("- Could only partially set the security descriptor\n"
+                       "            on %lu files or directories.",
+                       ctx->partial_security_descriptors);
+       }
+       if (ctx->no_security_descriptors != 0) {
+               WARNING("- Could not set security descriptor at all\n"
+                       "            on %lu files or directories.",
+                       ctx->no_security_descriptors);
+       }
+#ifdef __WIN32__
+       WARNING("To fully restore all security descriptors, run the program\n"
+               "          with Administrator rights.");
+#endif
+}
+
 /*
  * extract_tree - Extract a file or directory tree from the currently selected
  *               WIM image.
@@ -2346,6 +2374,8 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target,
                              &ctx.progress);
        }
 
+       do_extract_warnings(&ctx);
+
        ret = 0;
 out_free_realtarget:
        FREE(ctx.realtarget);
index 77ff870..b6f2e84 100644 (file)
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 
+#ifdef WITH_NTDLL
+#  include <winternl.h>
+#  include <ntstatus.h>
+NTSTATUS WINAPI
+NtSetSecurityObject(HANDLE Handle,
+                   SECURITY_INFORMATION SecurityInformation,
+                   PSECURITY_DESCRIPTOR SecurityDescriptor);
+#endif
+
 static int
 win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
 {
@@ -478,32 +487,84 @@ error:
        return WIMLIB_ERR_WRITE; /* XXX: need better error code */
 }
 
+static DWORD
+do_win32_set_security_descriptor(HANDLE h, const wchar_t *path,
+                                SECURITY_INFORMATION info,
+                                PSECURITY_DESCRIPTOR desc)
+{
+#ifdef WITH_NTDLL
+       return RtlNtStatusToDosError(NtSetSecurityObject(h, info, desc));
+#else
+       if (SetFileSecurity(path, info, desc))
+               return ERROR_SUCCESS;
+       else
+               return GetLastError();
+#endif
+}
+
 static int
-win32_set_security_descriptor(const wchar_t *path, const u8 *desc, size_t desc_size,
-                             struct apply_ctx *ctx)
+win32_set_security_descriptor(const wchar_t *path, const u8 *desc,
+                             size_t desc_size, struct apply_ctx *ctx)
 {
        SECURITY_INFORMATION info;
+       HANDLE h;
+       DWORD err;
+       int ret;
 
-       info = OWNER_SECURITY_INFORMATION |
-               GROUP_SECURITY_INFORMATION |
-               DACL_SECURITY_INFORMATION  |
-               SACL_SECURITY_INFORMATION;
-retry:
-       if (!SetFileSecurity(path, info, (PSECURITY_DESCRIPTOR)desc)) {
-               if (!(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS) &&
-                   GetLastError() == ERROR_PRIVILEGE_NOT_HELD &&
-                   (info & SACL_SECURITY_INFORMATION))
+       info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+              DACL_SECURITY_INFORMATION  | SACL_SECURITY_INFORMATION;
+       h = INVALID_HANDLE_VALUE;
+
+#ifdef WITH_NTDLL
+       h = CreateFile(path, MAXIMUM_ALLOWED, 0, NULL, OPEN_EXISTING,
+                      FILE_FLAG_BACKUP_SEMANTICS |
+                              FILE_FLAG_OPEN_REPARSE_POINT,
+                      NULL);
+       if (h == INVALID_HANDLE_VALUE) {
+               ERROR_WITH_ERRNO("Can't open %ls (%u)", path, GetLastError());
+               goto error;
+       }
+#endif
+
+       for (;;) {
+               err = do_win32_set_security_descriptor(h, path, info,
+                                                      (PSECURITY_DESCRIPTOR)desc);
+               if (err == ERROR_SUCCESS)
+                       break;
+               if ((err == ERROR_PRIVILEGE_NOT_HELD ||
+                    err == ERROR_ACCESS_DENIED) &&
+                   !(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
                {
-                       info &= ~SACL_SECURITY_INFORMATION;
-                       goto retry;
+                       if (info & SACL_SECURITY_INFORMATION) {
+                               info &= ~SACL_SECURITY_INFORMATION;
+                               ctx->partial_security_descriptors++;
+                               continue;
+                       }
+                       if (info & DACL_SECURITY_INFORMATION) {
+                               info &= ~DACL_SECURITY_INFORMATION;
+                               continue;
+                       }
+                       if (info & OWNER_SECURITY_INFORMATION) {
+                               info &= ~OWNER_SECURITY_INFORMATION;
+                               continue;
+                       }
+                       ctx->partial_security_descriptors--;
+                       ctx->no_security_descriptors++;
+                       break;
                }
                goto error;
        }
-       return 0;
+       ret = 0;
+out_close:
+#ifdef WITH_NTDLL
+       CloseHandle(h);
+#endif
+       return ret;
 
 error:
        set_errno_from_GetLastError();
-       return WIMLIB_ERR_SET_SECURITY;
+       ret = WIMLIB_ERR_SET_SECURITY;
+       goto out_close;
 }
 
 static int