]> wimlib.net Git - wimlib/blob - src/win32_common.c
Move errno translation to win32_replacements.c
[wimlib] / src / win32_common.c
1 /*
2  * win32_common.c - Windows code common to applying and capturing images.
3  */
4
5 /*
6  * Copyright (C) 2013, 2014, 2015 Eric Biggers
7  *
8  * This file is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the Free
10  * Software Foundation; either version 3 of the License, or (at your option) any
11  * later version.
12  *
13  * This file is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this file; if not, see http://www.gnu.org/licenses/.
20  */
21
22 #ifdef __WIN32__
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "wimlib/win32_common.h"
29
30 #include "wimlib/error.h"
31 #include "wimlib/util.h"
32
33 static bool
34 win32_modify_privilege(const wchar_t *privilege, bool enable)
35 {
36         HANDLE hToken;
37         LUID luid;
38         TOKEN_PRIVILEGES newState;
39         bool ret = FALSE;
40
41         if (!OpenProcessToken(GetCurrentProcess(),
42                               TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
43                               &hToken))
44                 goto out;
45
46         if (!LookupPrivilegeValue(NULL, privilege, &luid))
47                 goto out_close_handle;
48
49         newState.PrivilegeCount = 1;
50         newState.Privileges[0].Luid = luid;
51         newState.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0);
52         SetLastError(ERROR_SUCCESS);
53         ret = AdjustTokenPrivileges(hToken, FALSE, &newState, 0, NULL, NULL);
54         if (ret && GetLastError() == ERROR_NOT_ALL_ASSIGNED)
55                 ret = FALSE;
56 out_close_handle:
57         CloseHandle(hToken);
58 out:
59         return ret;
60 }
61
62 static bool
63 win32_modify_capture_privileges(bool enable)
64 {
65         return win32_modify_privilege(SE_BACKUP_NAME, enable)
66             && win32_modify_privilege(SE_SECURITY_NAME, enable);
67 }
68
69 static bool
70 win32_modify_apply_privileges(bool enable)
71 {
72         return win32_modify_privilege(SE_RESTORE_NAME, enable)
73             && win32_modify_privilege(SE_SECURITY_NAME, enable)
74             && win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable);
75 }
76
77 static void
78 win32_release_capture_and_apply_privileges(void)
79 {
80         win32_modify_capture_privileges(false);
81         win32_modify_apply_privileges(false);
82 }
83
84 /* Pointers to dynamically loaded functions  */
85
86 /* ntdll.dll  */
87
88 NTSTATUS (WINAPI *func_NtCreateFile)(PHANDLE FileHandle,
89                                      ACCESS_MASK DesiredAccess,
90                                      POBJECT_ATTRIBUTES ObjectAttributes,
91                                      PIO_STATUS_BLOCK IoStatusBlock,
92                                      PLARGE_INTEGER AllocationSize,
93                                      ULONG FileAttributes,
94                                      ULONG ShareAccess,
95                                      ULONG CreateDisposition,
96                                      ULONG CreateOptions,
97                                      PVOID EaBuffer,
98                                      ULONG EaLength);
99
100 NTSTATUS (WINAPI *func_NtOpenFile) (PHANDLE FileHandle,
101                                     ACCESS_MASK DesiredAccess,
102                                     POBJECT_ATTRIBUTES ObjectAttributes,
103                                     PIO_STATUS_BLOCK IoStatusBlock,
104                                     ULONG ShareAccess,
105                                     ULONG OpenOptions);
106
107 NTSTATUS (WINAPI *func_NtReadFile) (HANDLE FileHandle,
108                                     HANDLE Event,
109                                     PIO_APC_ROUTINE ApcRoutine,
110                                     PVOID ApcContext,
111                                     PIO_STATUS_BLOCK IoStatusBlock,
112                                     PVOID Buffer,
113                                     ULONG Length,
114                                     PLARGE_INTEGER ByteOffset,
115                                     PULONG Key);
116
117 NTSTATUS (WINAPI *func_NtWriteFile) (HANDLE FileHandle,
118                                      HANDLE Event,
119                                      PIO_APC_ROUTINE ApcRoutine,
120                                      PVOID ApcContext,
121                                      PIO_STATUS_BLOCK IoStatusBlock,
122                                      PVOID Buffer,
123                                      ULONG Length,
124                                      PLARGE_INTEGER ByteOffset,
125                                      PULONG Key);
126
127 NTSTATUS (WINAPI *func_NtQueryInformationFile)(HANDLE FileHandle,
128                                                PIO_STATUS_BLOCK IoStatusBlock,
129                                                PVOID FileInformation,
130                                                ULONG Length,
131                                                FILE_INFORMATION_CLASS FileInformationClass);
132
133 NTSTATUS (WINAPI *func_NtQuerySecurityObject)(HANDLE handle,
134                                               SECURITY_INFORMATION SecurityInformation,
135                                               PSECURITY_DESCRIPTOR SecurityDescriptor,
136                                               ULONG Length,
137                                               PULONG LengthNeeded);
138
139 NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle,
140                                               HANDLE Event,
141                                               PIO_APC_ROUTINE ApcRoutine,
142                                               PVOID ApcContext,
143                                               PIO_STATUS_BLOCK IoStatusBlock,
144                                               PVOID FileInformation,
145                                               ULONG Length,
146                                               FILE_INFORMATION_CLASS FileInformationClass,
147                                               BOOLEAN ReturnSingleEntry,
148                                               PUNICODE_STRING FileName,
149                                               BOOLEAN RestartScan);
150
151 NTSTATUS (WINAPI *func_NtQueryVolumeInformationFile) (HANDLE FileHandle,
152                                                       PIO_STATUS_BLOCK IoStatusBlock,
153                                                       PVOID FsInformation,
154                                                       ULONG Length,
155                                                       FS_INFORMATION_CLASS FsInformationClass);
156
157 NTSTATUS (WINAPI *func_NtSetInformationFile)(HANDLE FileHandle,
158                                              PIO_STATUS_BLOCK IoStatusBlock,
159                                              PVOID FileInformation,
160                                              ULONG Length,
161                                              FILE_INFORMATION_CLASS FileInformationClass);
162
163 NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle,
164                                             SECURITY_INFORMATION SecurityInformation,
165                                             PSECURITY_DESCRIPTOR SecurityDescriptor);
166
167 NTSTATUS (WINAPI *func_NtFsControlFile) (HANDLE FileHandle,
168                                          HANDLE Event,
169                                          PIO_APC_ROUTINE ApcRoutine,
170                                          PVOID ApcContext,
171                                          PIO_STATUS_BLOCK IoStatusBlock,
172                                          ULONG FsControlCode,
173                                          PVOID InputBuffer,
174                                          ULONG InputBufferLength,
175                                          PVOID OutputBuffer,
176                                          ULONG OutputBufferLength);
177
178 NTSTATUS (WINAPI *func_NtClose) (HANDLE Handle);
179
180 DWORD (WINAPI *func_RtlNtStatusToDosError)(NTSTATUS status);
181
182 BOOLEAN (WINAPI *func_RtlDosPathNameToNtPathName_U)
183                   (IN PCWSTR DosName,
184                    OUT PUNICODE_STRING NtName,
185                    OUT PCWSTR *PartName,
186                    OUT PRTL_RELATIVE_NAME_U RelativeName);
187
188 NTSTATUS (WINAPI *func_RtlDosPathNameToNtPathName_U_WithStatus)
189                 (IN PCWSTR DosName,
190                  OUT PUNICODE_STRING NtName,
191                  OUT PCWSTR *PartName,
192                  OUT PRTL_RELATIVE_NAME_U RelativeName);
193
194 NTSTATUS (WINAPI *func_RtlCreateSystemVolumeInformationFolder)
195                 (PCUNICODE_STRING VolumeRootPath);
196
197 static bool acquired_privileges = false;
198
199 struct dll_sym {
200         void **func_ptr;
201         const char *name;
202         bool required;
203 };
204
205 #define DLL_SYM(name, required) { (void **)&func_##name, #name, required }
206
207 #define for_each_sym(sym, spec) \
208         for ((sym) = (spec)->syms; (sym)->name; (sym)++)
209
210 struct dll_spec {
211         const wchar_t *name;
212         HMODULE handle;
213         const struct dll_sym syms[];
214 };
215
216 struct dll_spec ntdll_spec = {
217         .name = L"ntdll.dll",
218         .syms = {
219                 DLL_SYM(NtCreateFile, true),
220                 DLL_SYM(NtOpenFile, true),
221                 DLL_SYM(NtReadFile, true),
222                 DLL_SYM(NtWriteFile, true),
223                 DLL_SYM(NtQueryInformationFile, true),
224                 DLL_SYM(NtQuerySecurityObject, true),
225                 DLL_SYM(NtQueryDirectoryFile, true),
226                 DLL_SYM(NtQueryVolumeInformationFile, true),
227                 DLL_SYM(NtSetInformationFile, true),
228                 DLL_SYM(NtSetSecurityObject, true),
229                 DLL_SYM(NtFsControlFile, true),
230                 DLL_SYM(NtClose, true),
231                 DLL_SYM(RtlNtStatusToDosError, true),
232                 DLL_SYM(RtlCreateSystemVolumeInformationFolder, false),
233                 DLL_SYM(RtlDosPathNameToNtPathName_U, true),
234                 DLL_SYM(RtlDosPathNameToNtPathName_U_WithStatus, false), /* Not present on XP  */
235                 {NULL, NULL},
236         },
237 };
238
239 static int
240 init_dll(struct dll_spec *spec)
241 {
242         const struct dll_sym *sym;
243         void *addr;
244
245         if (!spec->handle)
246                 spec->handle = LoadLibrary(spec->name);
247         if (!spec->handle) {
248                 for_each_sym(sym, spec) {
249                         if (sym->required) {
250                                 ERROR("%ls could not be loaded!", spec->name);
251                                 return WIMLIB_ERR_UNSUPPORTED;
252                         }
253                 }
254                 return 0;
255         }
256         for_each_sym(sym, spec) {
257                 addr = (void *)GetProcAddress(spec->handle, sym->name);
258                 if (addr) {
259                         *(sym->func_ptr) = addr;
260                 } else if (sym->required) {
261                         ERROR("Can't find %s in %ls", sym->name, spec->name);
262                         return WIMLIB_ERR_UNSUPPORTED;
263                 }
264         }
265         return 0;
266 }
267
268 static void
269 cleanup_dll(struct dll_spec *spec)
270 {
271         const struct dll_sym *sym;
272
273         if (spec->handle) {
274                 FreeLibrary(spec->handle);
275                 spec->handle = NULL;
276
277                 for_each_sym(sym, spec)
278                         *(sym->func_ptr) = NULL;
279         }
280 }
281
282 /* One-time initialization for Windows capture/apply code.  */
283 int
284 win32_global_init(int init_flags)
285 {
286         int ret;
287
288         /* Try to acquire useful privileges.  */
289         if (!(init_flags & WIMLIB_INIT_FLAG_DONT_ACQUIRE_PRIVILEGES)) {
290                 ret = WIMLIB_ERR_INSUFFICIENT_PRIVILEGES;
291                 if (!win32_modify_capture_privileges(true))
292                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_CAPTURE_PRIVILEGES)
293                                 goto out_drop_privs;
294                 if (!win32_modify_apply_privileges(true))
295                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES)
296                                 goto out_drop_privs;
297                 acquired_privileges = true;
298         }
299
300         ret = init_dll(&ntdll_spec);
301         if (ret)
302                 goto out_drop_privs;
303
304         return 0;
305
306 out_drop_privs:
307         win32_release_capture_and_apply_privileges();
308         return ret;
309 }
310
311 void
312 win32_global_cleanup(void)
313 {
314         if (acquired_privileges)
315                 win32_release_capture_and_apply_privileges();
316
317         cleanup_dll(&ntdll_spec);
318 }
319
320 /*
321  * Translates a Win32-namespace path into an NT-namespace path.
322  *
323  * On success, returns 0.  The NT-namespace path will be stored in the
324  * UNICODE_STRING structure pointed to by nt_path.  nt_path->Buffer will be set
325  * to a new buffer that must later be freed with HeapFree().  (Really
326  * RtlHeapFree(), but HeapFree() seems to be the same thing.)
327  *
328  * On failure, returns WIMLIB_ERR_NOMEM or WIMLIB_ERR_INVALID_PARAM.
329  */
330 int
331 win32_path_to_nt_path(const wchar_t *win32_path, UNICODE_STRING *nt_path)
332 {
333         NTSTATUS status;
334
335         if (func_RtlDosPathNameToNtPathName_U_WithStatus) {
336                 status = (*func_RtlDosPathNameToNtPathName_U_WithStatus)(win32_path,
337                                                                          nt_path,
338                                                                          NULL, NULL);
339         } else {
340                 if ((*func_RtlDosPathNameToNtPathName_U)(win32_path, nt_path,
341                                                          NULL, NULL))
342                         status = STATUS_SUCCESS;
343                 else
344                         status = STATUS_NO_MEMORY;
345         }
346
347         if (likely(NT_SUCCESS(status)))
348                 return 0;
349
350         if (status == STATUS_NO_MEMORY)
351                 return WIMLIB_ERR_NOMEM;
352
353         ERROR("\"%ls\": invalid path name (status=0x%08"PRIx32")",
354               win32_path, (u32)status);
355         return WIMLIB_ERR_INVALID_PARAM;
356 }
357
358 int
359 win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7])
360 {
361         tchar *file_abspath;
362
363         file_abspath = realpath(file_path, NULL);
364         if (!file_abspath)
365                 return WIMLIB_ERR_NOMEM;
366
367         if (file_abspath[0] == L'\0' || file_abspath[1] != L':') {
368                 ERROR("\"%ls\": Path format not recognized", file_abspath);
369                 FREE(file_abspath);
370                 return WIMLIB_ERR_UNSUPPORTED;
371         }
372
373         wsprintf(drive_path, L"\\\\.\\%lc:", file_abspath[0]);
374         FREE(file_abspath);
375         return 0;
376 }
377
378 static void
379 windows_msg(u32 code, const wchar_t *format, va_list va,
380             bool is_ntstatus, bool is_error)
381 {
382         wchar_t _buf[STACK_MAX / 8];
383         wchar_t *buf = _buf;
384         size_t buflen = ARRAY_LEN(_buf);
385         size_t ret;
386         size_t n;
387
388 retry:
389         n = vsnwprintf(buf, buflen, format, va);
390
391         if (n >= buflen)
392                 goto realloc;
393
394         n += snwprintf(&buf[n], buflen - n,
395                        (is_ntstatus ?
396                         L" (status=%08"PRIx32"): " :
397                         L" (err=%"PRIu32"): "),
398                        code);
399
400         if (n >= buflen)
401                 goto realloc;
402
403         ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
404                             NULL,
405                             is_ntstatus ? (*func_RtlNtStatusToDosError)(code) : code,
406                             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
407                             &buf[n],
408                             buflen - n,
409                             NULL);
410         n += ret;
411
412         if (n >= buflen || (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
413                 goto realloc;
414
415         if (buf[n - 1] == L'\n')
416                 buf[--n] = L'\0';
417         if (buf[n - 1] == L'\r')
418                 buf[--n] = L'\0';
419         if (buf[n - 1] == L'.')
420                 buf[--n] = L'\0';
421
422         if (is_error)
423                 ERROR("%ls", buf);
424         else
425                 WARNING("%ls", buf);
426         if (buf != _buf)
427                 FREE(buf);
428         return;
429
430 realloc:
431         if (buf != _buf)
432                 FREE(buf);
433         buflen *= 2;
434         buf = MALLOC(buflen * sizeof(buf[0]));
435         if (buf)
436                 goto retry;
437         ERROR("Ran out of memory while building error message!!!");
438 }
439
440 void
441 win32_warning(DWORD err, const wchar_t *format, ...)
442 {
443         va_list va;
444
445         va_start(va, format);
446         windows_msg(err, format, va, false, false);
447         va_end(va);
448 }
449
450 void
451 win32_error(DWORD err, const wchar_t *format, ...)
452 {
453         va_list va;
454
455         va_start(va, format);
456         windows_msg(err, format, va, false, true);
457         va_end(va);
458 }
459
460 void
461 winnt_warning(NTSTATUS status, const wchar_t *format, ...)
462 {
463         va_list va;
464
465         va_start(va, format);
466         windows_msg(status, format, va, true, false);
467         va_end(va);
468 }
469
470 void
471 winnt_error(NTSTATUS status, const wchar_t *format, ...)
472 {
473         va_list va;
474
475         va_start(va, format);
476         windows_msg(status, format, va, true, true);
477         va_end(va);
478 }
479
480 #endif /* __WIN32__ */