]> wimlib.net Git - wimlib/blob - src/win32_common.c
Move code from win32_common.c to win32_apply.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 Eric Biggers
7  *
8  * This file is part of wimlib, a library for working with WIM files.
9  *
10  * wimlib is free software; you can redistribute it and/or modify it under the
11  * terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 3 of the License, or (at your option)
13  * any later version.
14  *
15  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17  * A PARTICULAR PURPOSE. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with wimlib; if not, see http://www.gnu.org/licenses/.
22  */
23
24 #ifdef __WIN32__
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include <errno.h>
31
32 #include "wimlib/win32_common.h"
33 #include "wimlib/error.h"
34 #include "wimlib/util.h"
35
36 static int
37 win32_error_to_errno(DWORD err_code)
38 {
39         /* This mapping is that used in Cygwin.
40          * Some of these choices are arbitrary. */
41         switch (err_code) {
42         case ERROR_ACCESS_DENIED:
43                 return EACCES;
44         case ERROR_ACTIVE_CONNECTIONS:
45                 return EAGAIN;
46         case ERROR_ALREADY_EXISTS:
47                 return EEXIST;
48         case ERROR_BAD_DEVICE:
49                 return ENODEV;
50         case ERROR_BAD_EXE_FORMAT:
51                 return ENOEXEC;
52         case ERROR_BAD_NETPATH:
53                 return ENOENT;
54         case ERROR_BAD_NET_NAME:
55                 return ENOENT;
56         case ERROR_BAD_NET_RESP:
57                 return ENOSYS;
58         case ERROR_BAD_PATHNAME:
59                 return ENOENT;
60         case ERROR_BAD_PIPE:
61                 return EINVAL;
62         case ERROR_BAD_UNIT:
63                 return ENODEV;
64         case ERROR_BAD_USERNAME:
65                 return EINVAL;
66         case ERROR_BEGINNING_OF_MEDIA:
67                 return EIO;
68         case ERROR_BROKEN_PIPE:
69                 return EPIPE;
70         case ERROR_BUSY:
71                 return EBUSY;
72         case ERROR_BUS_RESET:
73                 return EIO;
74         case ERROR_CALL_NOT_IMPLEMENTED:
75                 return ENOSYS;
76         case ERROR_CANNOT_MAKE:
77                 return EPERM;
78         case ERROR_CHILD_NOT_COMPLETE:
79                 return EBUSY;
80         case ERROR_COMMITMENT_LIMIT:
81                 return EAGAIN;
82         case ERROR_CRC:
83                 return EIO;
84         case ERROR_DEVICE_DOOR_OPEN:
85                 return EIO;
86         case ERROR_DEVICE_IN_USE:
87                 return EAGAIN;
88         case ERROR_DEVICE_REQUIRES_CLEANING:
89                 return EIO;
90         case ERROR_DIRECTORY:
91                 return ENOTDIR;
92         case ERROR_DIR_NOT_EMPTY:
93                 return ENOTEMPTY;
94         case ERROR_DISK_CORRUPT:
95                 return EIO;
96         case ERROR_DISK_FULL:
97                 return ENOSPC;
98 #ifdef ENOTUNIQ
99         case ERROR_DUP_NAME:
100                 return ENOTUNIQ;
101 #endif
102         case ERROR_EAS_DIDNT_FIT:
103                 return ENOSPC;
104 #ifdef ENOTSUP
105         case ERROR_EAS_NOT_SUPPORTED:
106                 return ENOTSUP;
107 #endif
108         case ERROR_EA_LIST_INCONSISTENT:
109                 return EINVAL;
110         case ERROR_EA_TABLE_FULL:
111                 return ENOSPC;
112         case ERROR_END_OF_MEDIA:
113                 return ENOSPC;
114         case ERROR_EOM_OVERFLOW:
115                 return EIO;
116         case ERROR_EXE_MACHINE_TYPE_MISMATCH:
117                 return ENOEXEC;
118         case ERROR_EXE_MARKED_INVALID:
119                 return ENOEXEC;
120         case ERROR_FILEMARK_DETECTED:
121                 return EIO;
122         case ERROR_FILENAME_EXCED_RANGE:
123                 return ENAMETOOLONG;
124         case ERROR_FILE_CORRUPT:
125                 return EEXIST;
126         case ERROR_FILE_EXISTS:
127                 return EEXIST;
128         case ERROR_FILE_INVALID:
129                 return ENXIO;
130         case ERROR_FILE_NOT_FOUND:
131                 return ENOENT;
132         case ERROR_HANDLE_DISK_FULL:
133                 return ENOSPC;
134 #ifdef ENODATA
135         case ERROR_HANDLE_EOF:
136                 return ENODATA;
137 #endif
138         case ERROR_INVALID_ADDRESS:
139                 return EINVAL;
140         case ERROR_INVALID_AT_INTERRUPT_TIME:
141                 return EINTR;
142         case ERROR_INVALID_BLOCK_LENGTH:
143                 return EIO;
144         case ERROR_INVALID_DATA:
145                 return EINVAL;
146         case ERROR_INVALID_DRIVE:
147                 return ENODEV;
148         case ERROR_INVALID_EA_NAME:
149                 return EINVAL;
150         case ERROR_INVALID_EXE_SIGNATURE:
151                 return ENOEXEC;
152 #ifdef EBADRQC
153         case ERROR_INVALID_FUNCTION:
154                 return EBADRQC;
155 #endif
156         case ERROR_INVALID_HANDLE:
157                 return EBADF;
158         case ERROR_INVALID_NAME:
159                 return ENOENT;
160         case ERROR_INVALID_PARAMETER:
161                 return EINVAL;
162         case ERROR_INVALID_SIGNAL_NUMBER:
163                 return EINVAL;
164         case ERROR_IOPL_NOT_ENABLED:
165                 return ENOEXEC;
166         case ERROR_IO_DEVICE:
167                 return EIO;
168         case ERROR_IO_INCOMPLETE:
169                 return EAGAIN;
170         case ERROR_IO_PENDING:
171                 return EAGAIN;
172         case ERROR_LOCK_VIOLATION:
173                 return EBUSY;
174         case ERROR_MAX_THRDS_REACHED:
175                 return EAGAIN;
176         case ERROR_META_EXPANSION_TOO_LONG:
177                 return EINVAL;
178         case ERROR_MOD_NOT_FOUND:
179                 return ENOENT;
180 #ifdef EMSGSIZE
181         case ERROR_MORE_DATA:
182                 return EMSGSIZE;
183 #endif
184         case ERROR_NEGATIVE_SEEK:
185                 return EINVAL;
186         case ERROR_NETNAME_DELETED:
187                 return ENOENT;
188         case ERROR_NOACCESS:
189                 return EFAULT;
190         case ERROR_NONE_MAPPED:
191                 return EINVAL;
192         case ERROR_NONPAGED_SYSTEM_RESOURCES:
193                 return EAGAIN;
194 #ifdef ENOLINK
195         case ERROR_NOT_CONNECTED:
196                 return ENOLINK;
197 #endif
198         case ERROR_NOT_ENOUGH_MEMORY:
199                 return ENOMEM;
200         case ERROR_NOT_OWNER:
201                 return EPERM;
202 #ifdef ENOMEDIUM
203         case ERROR_NOT_READY:
204                 return ENOMEDIUM;
205 #endif
206         case ERROR_NOT_SAME_DEVICE:
207                 return EXDEV;
208         case ERROR_NOT_SUPPORTED:
209                 return ENOSYS;
210         case ERROR_NO_DATA:
211                 return EPIPE;
212         case ERROR_NO_DATA_DETECTED:
213                 return EIO;
214 #ifdef ENOMEDIUM
215         case ERROR_NO_MEDIA_IN_DRIVE:
216                 return ENOMEDIUM;
217 #endif
218 #ifdef ENMFILE
219         case ERROR_NO_MORE_FILES:
220                 return ENMFILE;
221 #endif
222 #ifdef ENMFILE
223         case ERROR_NO_MORE_ITEMS:
224                 return ENMFILE;
225 #endif
226         case ERROR_NO_MORE_SEARCH_HANDLES:
227                 return ENFILE;
228         case ERROR_NO_PROC_SLOTS:
229                 return EAGAIN;
230         case ERROR_NO_SIGNAL_SENT:
231                 return EIO;
232         case ERROR_NO_SYSTEM_RESOURCES:
233                 return EFBIG;
234         case ERROR_NO_TOKEN:
235                 return EINVAL;
236         case ERROR_OPEN_FAILED:
237                 return EIO;
238         case ERROR_OPEN_FILES:
239                 return EAGAIN;
240         case ERROR_OUTOFMEMORY:
241                 return ENOMEM;
242         case ERROR_PAGED_SYSTEM_RESOURCES:
243                 return EAGAIN;
244         case ERROR_PAGEFILE_QUOTA:
245                 return EAGAIN;
246         case ERROR_PATH_NOT_FOUND:
247                 return ENOENT;
248         case ERROR_PIPE_BUSY:
249                 return EBUSY;
250         case ERROR_PIPE_CONNECTED:
251                 return EBUSY;
252 #ifdef ECOMM
253         case ERROR_PIPE_LISTENING:
254                 return ECOMM;
255         case ERROR_PIPE_NOT_CONNECTED:
256                 return ECOMM;
257 #endif
258         case ERROR_POSSIBLE_DEADLOCK:
259                 return EDEADLOCK;
260         case ERROR_PRIVILEGE_NOT_HELD:
261                 return EPERM;
262         case ERROR_PROCESS_ABORTED:
263                 return EFAULT;
264         case ERROR_PROC_NOT_FOUND:
265                 return ESRCH;
266 #ifdef ENONET
267         case ERROR_REM_NOT_LIST:
268                 return ENONET;
269 #endif
270         case ERROR_SECTOR_NOT_FOUND:
271                 return EINVAL;
272         case ERROR_SEEK:
273                 return EINVAL;
274         case ERROR_SETMARK_DETECTED:
275                 return EIO;
276         case ERROR_SHARING_BUFFER_EXCEEDED:
277                 return ENOLCK;
278         case ERROR_SHARING_VIOLATION:
279                 return EBUSY;
280         case ERROR_SIGNAL_PENDING:
281                 return EBUSY;
282         case ERROR_SIGNAL_REFUSED:
283                 return EIO;
284 #ifdef ELIBBAD
285         case ERROR_SXS_CANT_GEN_ACTCTX:
286                 return ELIBBAD;
287 #endif
288         case ERROR_THREAD_1_INACTIVE:
289                 return EINVAL;
290         case ERROR_TOO_MANY_LINKS:
291                 return EMLINK;
292         case ERROR_TOO_MANY_OPEN_FILES:
293                 return EMFILE;
294         case ERROR_WAIT_NO_CHILDREN:
295                 return ECHILD;
296         case ERROR_WORKING_SET_QUOTA:
297                 return EAGAIN;
298         case ERROR_WRITE_PROTECT:
299                 return EROFS;
300         default:
301                 return -1;
302         }
303 }
304
305 void
306 set_errno_from_win32_error(DWORD err)
307 {
308         errno = win32_error_to_errno(err);
309 }
310
311 void
312 set_errno_from_GetLastError(void)
313 {
314         set_errno_from_win32_error(GetLastError());
315 }
316
317 void
318 set_errno_from_nt_status(NTSTATUS status)
319 {
320         set_errno_from_win32_error((*func_RtlNtStatusToDosError)(status));
321 }
322
323 static bool
324 win32_modify_privilege(const wchar_t *privilege, bool enable)
325 {
326         HANDLE hToken;
327         LUID luid;
328         TOKEN_PRIVILEGES newState;
329         bool ret = FALSE;
330
331         if (!OpenProcessToken(GetCurrentProcess(),
332                               TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
333                               &hToken))
334                 goto out;
335
336         if (!LookupPrivilegeValue(NULL, privilege, &luid))
337                 goto out_close_handle;
338
339         newState.PrivilegeCount = 1;
340         newState.Privileges[0].Luid = luid;
341         newState.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0);
342         SetLastError(ERROR_SUCCESS);
343         ret = AdjustTokenPrivileges(hToken, FALSE, &newState, 0, NULL, NULL);
344         if (ret && GetLastError() == ERROR_NOT_ALL_ASSIGNED)
345                 ret = FALSE;
346 out_close_handle:
347         CloseHandle(hToken);
348 out:
349         return ret;
350 }
351
352 static bool
353 win32_modify_capture_privileges(bool enable)
354 {
355         return win32_modify_privilege(SE_BACKUP_NAME, enable)
356             && win32_modify_privilege(SE_SECURITY_NAME, enable);
357 }
358
359 static bool
360 win32_modify_apply_privileges(bool enable)
361 {
362         return win32_modify_privilege(SE_RESTORE_NAME, enable)
363             && win32_modify_privilege(SE_SECURITY_NAME, enable)
364             && win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable);
365 }
366
367 static void
368 win32_release_capture_and_apply_privileges(void)
369 {
370         win32_modify_capture_privileges(false);
371         win32_modify_apply_privileges(false);
372 }
373
374 HANDLE
375 win32_open_existing_file(const wchar_t *path, DWORD dwDesiredAccess)
376 {
377         return CreateFile(path,
378                           dwDesiredAccess,
379                           FILE_SHARE_READ,
380                           NULL, /* lpSecurityAttributes */
381                           OPEN_EXISTING,
382                           FILE_FLAG_BACKUP_SEMANTICS |
383                                 FILE_FLAG_OPEN_REPARSE_POINT,
384                           NULL /* hTemplateFile */);
385 }
386
387 /* Pointers to dynamically loaded functions  */
388
389 /* kernel32.dll:  Vista and later */
390 BOOL (WINAPI *func_CreateSymbolicLinkW)(const wchar_t *lpSymlinkFileName,
391                                         const wchar_t *lpTargetFileName,
392                                         DWORD dwFlags);
393
394 /* ntdll.dll  */
395
396 NTSTATUS (WINAPI *func_NtOpenFile) (PHANDLE FileHandle,
397                                     ACCESS_MASK DesiredAccess,
398                                     POBJECT_ATTRIBUTES ObjectAttributes,
399                                     PIO_STATUS_BLOCK IoStatusBlock,
400                                     ULONG ShareAccess,
401                                     ULONG OpenOptions);
402
403 NTSTATUS (WINAPI *func_NtReadFile) (HANDLE FileHandle,
404                                     HANDLE Event,
405                                     PIO_APC_ROUTINE ApcRoutine,
406                                     PVOID ApcContext,
407                                     PIO_STATUS_BLOCK IoStatusBlock,
408                                     PVOID Buffer,
409                                     ULONG Length,
410                                     PLARGE_INTEGER ByteOffset,
411                                     PULONG Key);
412
413 NTSTATUS (WINAPI *func_NtOpenFile) (PHANDLE FileHandle,
414                                     ACCESS_MASK DesiredAccess,
415                                     POBJECT_ATTRIBUTES ObjectAttributes,
416                                     PIO_STATUS_BLOCK IoStatusBlock,
417                                     ULONG ShareAccess,
418                                     ULONG OpenOptions);
419
420 NTSTATUS (WINAPI *func_NtQueryInformationFile)(HANDLE FileHandle,
421                                                PIO_STATUS_BLOCK IoStatusBlock,
422                                                PVOID FileInformation,
423                                                ULONG Length,
424                                                FILE_INFORMATION_CLASS FileInformationClass);
425
426 NTSTATUS (WINAPI *func_NtQuerySecurityObject)(HANDLE handle,
427                                               SECURITY_INFORMATION SecurityInformation,
428                                               PSECURITY_DESCRIPTOR SecurityDescriptor,
429                                               ULONG Length,
430                                               PULONG LengthNeeded);
431
432 NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle,
433                                               HANDLE Event,
434                                               PIO_APC_ROUTINE ApcRoutine,
435                                               PVOID ApcContext,
436                                               PIO_STATUS_BLOCK IoStatusBlock,
437                                               PVOID FileInformation,
438                                               ULONG Length,
439                                               FILE_INFORMATION_CLASS FileInformationClass,
440                                               BOOLEAN ReturnSingleEntry,
441                                               PUNICODE_STRING FileName,
442                                               BOOLEAN RestartScan);
443
444 NTSTATUS (WINAPI *func_NtQueryVolumeInformationFile) (HANDLE FileHandle,
445                                                       PIO_STATUS_BLOCK IoStatusBlock,
446                                                       PVOID FsInformation,
447                                                       ULONG Length,
448                                                       FS_INFORMATION_CLASS FsInformationClass);
449
450 NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle,
451                                             SECURITY_INFORMATION SecurityInformation,
452                                             PSECURITY_DESCRIPTOR SecurityDescriptor);
453
454 NTSTATUS (WINAPI *func_NtClose) (HANDLE Handle);
455
456 DWORD (WINAPI *func_RtlNtStatusToDosError)(NTSTATUS status);
457
458 NTSTATUS (WINAPI *func_RtlCreateSystemVolumeInformationFolder)
459                 (PCUNICODE_STRING VolumeRootPath);
460
461 static OSVERSIONINFO windows_version_info = {
462         .dwOSVersionInfoSize = sizeof(OSVERSIONINFO),
463 };
464
465 static bool acquired_privileges = false;
466
467 bool
468 windows_version_is_at_least(unsigned major, unsigned minor)
469 {
470         return windows_version_info.dwMajorVersion > major ||
471                 (windows_version_info.dwMajorVersion == major &&
472                  windows_version_info.dwMinorVersion >= minor);
473 }
474
475 struct dll_sym {
476         void **func_ptr;
477         const char *name;
478         bool required;
479 };
480
481 #define DLL_SYM(name, required) { (void **)&func_##name, #name, required }
482
483 #define for_each_sym(sym, spec) \
484         for ((sym) = (spec)->syms; (sym)->name; (sym)++)
485
486 struct dll_spec {
487         const wchar_t *name;
488         HMODULE handle;
489         const struct dll_sym syms[];
490 };
491
492 struct dll_spec ntdll_spec = {
493         .name = L"ntdll.dll",
494         .syms = {
495                 DLL_SYM(NtOpenFile, true),
496                 DLL_SYM(NtReadFile, true),
497                 DLL_SYM(NtQueryInformationFile, true),
498                 DLL_SYM(NtQuerySecurityObject, true),
499                 DLL_SYM(NtQueryDirectoryFile, true),
500                 DLL_SYM(NtQueryVolumeInformationFile, true),
501                 DLL_SYM(NtSetSecurityObject, true),
502                 DLL_SYM(NtClose, true),
503                 DLL_SYM(RtlNtStatusToDosError, true),
504                 DLL_SYM(RtlCreateSystemVolumeInformationFolder, false),
505                 {NULL, NULL},
506         },
507 };
508
509 struct dll_spec kernel32_spec = {
510         .name = L"kernel32.dll",
511         .syms = {
512                 DLL_SYM(CreateSymbolicLinkW, false),
513                 {NULL, NULL},
514         },
515 };
516
517 static int
518 init_dll(struct dll_spec *spec)
519 {
520         const struct dll_sym *sym;
521         void *addr;
522
523         if (!spec->handle)
524                 spec->handle = LoadLibrary(spec->name);
525         if (!spec->handle) {
526                 for_each_sym(sym, spec) {
527                         if (sym->required) {
528                                 ERROR("%ls could not be loaded!", spec->name);
529                                 return WIMLIB_ERR_UNSUPPORTED;
530                         }
531                 }
532                 return 0;
533         }
534         for_each_sym(sym, spec) {
535                 addr = (void *)GetProcAddress(spec->handle, sym->name);
536                 if (addr) {
537                         *(sym->func_ptr) = addr;
538                 } else if (sym->required) {
539                         ERROR("Can't find %s in %ls", sym->name, spec->name);
540                         return WIMLIB_ERR_UNSUPPORTED;
541                 }
542         }
543         return 0;
544 }
545
546 static void
547 cleanup_dll(struct dll_spec *spec)
548 {
549         const struct dll_sym *sym;
550
551         if (spec->handle) {
552                 FreeLibrary(spec->handle);
553                 spec->handle = NULL;
554
555                 for_each_sym(sym, spec)
556                         *(sym->func_ptr) = NULL;
557         }
558 }
559
560 /* One-time initialization for Windows capture/apply code.  */
561 int
562 win32_global_init(int init_flags)
563 {
564         int ret;
565
566         /* Try to acquire useful privileges.  */
567         if (!(init_flags & WIMLIB_INIT_FLAG_DONT_ACQUIRE_PRIVILEGES)) {
568                 ret = WIMLIB_ERR_INSUFFICIENT_PRIVILEGES;
569                 if (!win32_modify_capture_privileges(true))
570                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_CAPTURE_PRIVILEGES)
571                                 goto out_drop_privs;
572                 if (!win32_modify_apply_privileges(true))
573                         if (init_flags & WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES)
574                                 goto out_drop_privs;
575                 acquired_privileges = true;
576         }
577
578         /* Get Windows version information.  */
579         GetVersionEx(&windows_version_info);
580
581         /* Try to dynamically load some functions.  */
582         ret = init_dll(&kernel32_spec);
583         if (ret)
584                 goto out_drop_privs;
585
586         ret = init_dll(&ntdll_spec);
587         if (ret)
588                 goto out_cleanup_kernel32;
589
590         return 0;
591
592 out_cleanup_kernel32:
593         cleanup_dll(&kernel32_spec);
594 out_drop_privs:
595         win32_release_capture_and_apply_privileges();
596         return ret;
597 }
598
599 void
600 win32_global_cleanup(void)
601 {
602         if (acquired_privileges)
603                 win32_release_capture_and_apply_privileges();
604
605         cleanup_dll(&kernel32_spec);
606         cleanup_dll(&ntdll_spec);
607 }
608
609 #endif /* __WIN32__ */