Do not add Npcap path if npf.sys service is found
[metze/wireshark/wip.git] / wsutil / file_util.c
1 /* file_util.c
2  *
3  * (Originally part of the Wiretap Library, now part of the Wireshark
4  *  utility library)
5  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 /*
24  * File wrapper functions to replace the file functions from GLib like
25  * g_open().
26  *
27  * With MSVC, code using the C support library from one version of MSVC
28  * cannot use file descriptors or FILE *'s returned from code using
29  * the C support library from another version of MSVC.
30  *
31  * We therefore provide our own versions of the routines to open files,
32  * so that they're built to use the same C support library as our code
33  * that reads them.
34  *
35  * (If both were built to use the Universal CRT:
36  *
37  *    http://blogs.msdn.com/b/vcblog/archive/2015/03/03/introducing-the-universal-crt.aspx
38  *
39  * this would not be a problem.)
40  *
41  * DO NOT USE THESE FUNCTIONS DIRECTLY, USE ws_open() AND ALIKE FUNCTIONS
42  * FROM file_util.h INSTEAD!!!
43  *
44  * The following code is stripped down code copied from the GLib file
45  * glib/gstdio.h - stripped down because this is used only on Windows
46  * and we use only wide char functions.
47  *
48  * In addition, we have our own ws_stdio_stat64(), which uses
49  * _wstati64(), so that we can get file sizes for files > 4 GB in size.
50  *
51  * XXX - is there any reason why we supply our own versions of routines
52  * that *don't* return file descriptors, other than ws_stdio_stat64()?
53  * Is there an issue with UTF-16 support in _wmkdir() with some versions
54  * of the C runtime, so that if GLib is built to use that version, it
55  * won't handle UTF-16 paths?
56  */
57
58 #ifndef _WIN32
59 #error "This is only for Windows"
60 #endif
61
62 #include "config.h"
63
64 #include <glib.h>
65
66 #include <windows.h>
67 #include <errno.h>
68 #include <wchar.h>
69 #include <tchar.h>
70 #include <stdlib.h>
71
72 #include "file_util.h"
73
74 static gchar *program_path = NULL;
75 static gchar *system_path = NULL;
76 static gchar *npcap_path = NULL;
77
78 /**
79  * g_open:
80  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
81  * @flags: as in open()
82  * @mode: as in open()
83  *
84  * A wrapper for the POSIX open() function. The open() function is
85  * used to convert a pathname into a file descriptor. Note that on
86  * POSIX systems file descriptors are implemented by the operating
87  * system. On Windows, it's the C library that implements open() and
88  * file descriptors. The actual Windows API for opening files is
89  * something different.
90  *
91  * See the C library manual for more details about open().
92  *
93  * Returns: a new file descriptor, or -1 if an error occurred. The
94  * return value can be used exactly like the return value from open().
95  *
96  * Since: 2.6
97  */
98 int
99 ws_stdio_open (const gchar *filename, int flags, int mode)
100 {
101     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
102     int retval;
103     int save_errno;
104
105     if (wfilename == NULL)
106     {
107         errno = EINVAL;
108         return -1;
109     }
110
111     retval = _wopen (wfilename, flags, mode);
112     save_errno = errno;
113
114     g_free (wfilename);
115
116     errno = save_errno;
117     return retval;
118 }
119
120
121 /**
122  * g_rename:
123  * @oldfilename: a pathname in the GLib file name encoding (UTF-8 on Windows)
124  * @newfilename: a pathname in the GLib file name encoding
125  *
126  * A wrapper for the POSIX rename() function. The rename() function
127  * renames a file, moving it between directories if required.
128  *
129  * See your C library manual for more details about how rename() works
130  * on your system. Note in particular that on Win9x it is not possible
131  * to rename a file if a file with the new name already exists. Also
132  * it is not possible in general on Windows to rename an open file.
133  *
134  * Returns: 0 if the renaming succeeded, -1 if an error occurred
135  *
136  * Since: 2.6
137  */
138 int
139 ws_stdio_rename (const gchar *oldfilename, const gchar *newfilename)
140 {
141     wchar_t *woldfilename = g_utf8_to_utf16 (oldfilename, -1, NULL, NULL, NULL);
142     wchar_t *wnewfilename;
143     int retval;
144     int save_errno = 0;
145
146     if (woldfilename == NULL)
147     {
148         errno = EINVAL;
149         return -1;
150     }
151
152     wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
153
154     if (wnewfilename == NULL)
155     {
156         g_free (woldfilename);
157         errno = EINVAL;
158         return -1;
159     }
160
161     if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
162         retval = 0;
163     else
164     {
165         retval = -1;
166         switch (GetLastError ())
167         {
168 #define CASE(a,b) case ERROR_##a: save_errno = b; break
169             CASE (FILE_NOT_FOUND, ENOENT);
170             CASE (PATH_NOT_FOUND, ENOENT);
171             CASE (ACCESS_DENIED, EACCES);
172             CASE (NOT_SAME_DEVICE, EXDEV);
173             CASE (LOCK_VIOLATION, EACCES);
174             CASE (SHARING_VIOLATION, EACCES);
175             CASE (FILE_EXISTS, EEXIST);
176             CASE (ALREADY_EXISTS, EEXIST);
177 #undef CASE
178             default: save_errno = EIO;
179         }
180     }
181
182     g_free (woldfilename);
183     g_free (wnewfilename);
184
185     errno = save_errno;
186     return retval;
187 }
188
189 /**
190  * g_mkdir:
191  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
192  * @mode: permissions to use for the newly created directory
193  *
194  * A wrapper for the POSIX mkdir() function. The mkdir() function
195  * attempts to create a directory with the given name and permissions.
196  *
197  * See the C library manual for more details about mkdir().
198  *
199  * Returns: 0 if the directory was successfully created, -1 if an error
200  *    occurred
201  *
202  * Since: 2.6
203  */
204 int
205 ws_stdio_mkdir (const gchar *filename, int mode)
206 {
207     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
208     int retval;
209     int save_errno;
210
211     if (wfilename == NULL)
212     {
213         errno = EINVAL;
214         return -1;
215     }
216
217     retval = _wmkdir (wfilename);
218     save_errno = errno;
219
220     g_free (wfilename);
221
222     errno = save_errno;
223     return retval;
224 }
225
226 /**
227  * g_stat:
228  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
229  * @buf: a pointer to a <structname>stat</structname> struct, which
230  *    will be filled with the file information
231  *
232  * A wrapper for the POSIX stat() function. The stat() function
233  * returns information about a file.
234  *
235  * See the C library manual for more details about stat().
236  *
237  * Returns: 0 if the information was successfully retrieved, -1 if an error
238  *    occurred
239  *
240  * Since: 2.6
241  */
242 int
243 ws_stdio_stat64 (const gchar *filename, ws_statb64 *buf)
244 {
245     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
246     int retval;
247     int save_errno;
248     size_t len;
249
250     if (wfilename == NULL)
251     {
252         errno = EINVAL;
253         return -1;
254     }
255
256     len = wcslen (wfilename);
257     while (len > 0 && G_IS_DIR_SEPARATOR (wfilename[len-1]))
258         len--;
259     if (len > 0 &&
260             (!g_path_is_absolute (filename) || len > (size_t) (g_path_skip_root (filename) - filename)))
261         wfilename[len] = '\0';
262
263     retval = _wstati64 (wfilename, buf);
264     save_errno = errno;
265
266     g_free (wfilename);
267
268     errno = save_errno;
269     return retval;
270 }
271 /**
272  * g_unlink:
273  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
274  *
275  * A wrapper for the POSIX unlink() function. The unlink() function
276  * deletes a name from the filesystem. If this was the last link to the
277  * file and no processes have it opened, the diskspace occupied by the
278  * file is freed.
279  *
280  * See your C library manual for more details about unlink(). Note
281  * that on Windows, it is in general not possible to delete files that
282  * are open to some process, or mapped into memory.
283  *
284  * Returns: 0 if the name was successfully deleted, -1 if an error
285  *    occurred
286  *
287  * Since: 2.6
288  */
289
290 int
291 ws_stdio_unlink (const gchar *filename)
292 {
293     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
294     int retval;
295     int save_errno;
296
297     if (wfilename == NULL)
298     {
299         errno = EINVAL;
300         return -1;
301     }
302
303     retval = _wunlink (wfilename);
304     save_errno = errno;
305
306     g_free (wfilename);
307
308     errno = save_errno;
309     return retval;
310 }
311
312 /**
313  * g_remove:
314  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
315  *
316  * A wrapper for the POSIX remove() function. The remove() function
317  * deletes a name from the filesystem.
318  *
319  * See your C library manual for more details about how remove() works
320  * on your system. On Unix, remove() removes also directories, as it
321  * calls unlink() for files and rmdir() for directories. On Windows,
322  * although remove() in the C library only works for files, this
323  * function tries first remove() and then if that fails rmdir(), and
324  * thus works for both files and directories. Note however, that on
325  * Windows, it is in general not possible to remove a file that is
326  * open to some process, or mapped into memory.
327  *
328  * If this function fails on Windows you can't infer too much from the
329  * errno value. rmdir() is tried regardless of what caused remove() to
330  * fail. Any errno value set by remove() will be overwritten by that
331  * set by rmdir().
332  *
333  * Returns: 0 if the file was successfully removed, -1 if an error
334  *    occurred
335  *
336  * Since: 2.6
337  */
338 int
339 ws_stdio_remove (const gchar *filename)
340 {
341     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
342     int retval;
343     int save_errno;
344
345     if (wfilename == NULL)
346     {
347         errno = EINVAL;
348         return -1;
349     }
350
351     retval = _wremove (wfilename);
352     if (retval == -1)
353         retval = _wrmdir (wfilename);
354     save_errno = errno;
355
356     g_free (wfilename);
357
358     errno = save_errno;
359     return retval;
360 }
361
362 /**
363  * g_fopen:
364  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
365  * @mode: a string describing the mode in which the file should be
366  *   opened
367  *
368  * A wrapper for the POSIX fopen() function. The fopen() function opens
369  * a file and associates a new stream with it.
370  *
371  * See the C library manual for more details about fopen().
372  *
373  * Returns: A <type>FILE</type> pointer if the file was successfully
374  *    opened, or %NULL if an error occurred
375  *
376  * Since: 2.6
377  */
378 FILE *
379 ws_stdio_fopen (const gchar *filename, const gchar *mode)
380 {
381     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
382     wchar_t *wmode;
383     FILE *retval;
384     int save_errno;
385
386     if (wfilename == NULL)
387     {
388         errno = EINVAL;
389         return NULL;
390     }
391
392     wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
393
394     if (wmode == NULL)
395     {
396         g_free (wfilename);
397         errno = EINVAL;
398         return NULL;
399     }
400
401     retval = _wfopen (wfilename, wmode);
402     save_errno = errno;
403
404     g_free (wfilename);
405     g_free (wmode);
406
407     errno = save_errno;
408     return retval;
409 }
410
411 /**
412  * g_freopen:
413  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
414  * @mode: a string describing the mode in which the file should be
415  *   opened
416  * @stream: an existing stream which will be reused, or %NULL
417  *
418  * A wrapper for the POSIX freopen() function. The freopen() function
419  * opens a file and associates it with an existing stream.
420  *
421  * See the C library manual for more details about freopen().
422  *
423  * Returns: A <type>FILE</type> pointer if the file was successfully
424  *    opened, or %NULL if an error occurred.
425  *
426  * Since: 2.6
427  */
428 FILE *
429 ws_stdio_freopen (const gchar *filename, const gchar *mode, FILE *stream)
430 {
431     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
432     wchar_t *wmode;
433     FILE *retval;
434     int save_errno;
435
436     if (wfilename == NULL)
437     {
438         errno = EINVAL;
439         return NULL;
440     }
441
442     wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
443
444     if (wmode == NULL)
445     {
446         g_free (wfilename);
447         errno = EINVAL;
448         return NULL;
449     }
450
451     retval = _wfreopen (wfilename, wmode, stream);
452     save_errno = errno;
453
454     g_free (wfilename);
455     g_free (wmode);
456
457     errno = save_errno;
458     return retval;
459 }
460
461
462 /* DLL loading */
463 static gboolean
464 init_dll_load_paths()
465 {
466     TCHAR path_w[MAX_PATH];
467
468     if (program_path && system_path && npcap_path)
469         return TRUE;
470
471     /* XXX - Duplicate code in filesystem.c:init_progfile_dir */
472     if (GetModuleFileName(NULL, path_w, MAX_PATH) == 0 || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
473         return FALSE;
474     }
475
476     if (!program_path) {
477         gchar *app_path;
478         app_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
479         /* We could use PathRemoveFileSpec here but we'd have to link to Shlwapi.dll */
480         program_path = g_path_get_dirname(app_path);
481         g_free(app_path);
482     }
483
484     if (GetSystemDirectory(path_w, MAX_PATH) == 0) {
485         return FALSE;
486     }
487
488     if (!system_path) {
489         system_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
490     }
491
492     _tcscat_s(path_w, MAX_PATH, _T("\\Npcap"));
493
494     if (!npcap_path) {
495         npcap_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
496     }
497
498     if (program_path && system_path && npcap_path)
499         return TRUE;
500
501     return FALSE;
502 }
503
504 gboolean
505 ws_init_dll_search_path()
506 {
507     gboolean dll_dir_set = FALSE, npf_found = FALSE;
508     wchar_t *program_path_w;
509     wchar_t npcap_path_w[MAX_PATH];
510     unsigned int retval;
511     SC_HANDLE h_scm;
512
513     typedef BOOL (WINAPI *SetDllDirectoryHandler)(LPCTSTR);
514     SetDllDirectoryHandler PSetDllDirectory;
515
516     PSetDllDirectory = (SetDllDirectoryHandler) GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "SetDllDirectoryW");
517     if (PSetDllDirectory) {
518         dll_dir_set = PSetDllDirectory(_T(""));
519         if (dll_dir_set) {
520             /* Do not systematically add Npcap path as long as we favor WinPcap over Npcap. */
521             h_scm = OpenSCManager(NULL, NULL, 0);
522             if (h_scm) {
523                 if (OpenService(h_scm, _T("npf"), SC_MANAGER_CONNECT|SERVICE_QUERY_STATUS)) {
524                     npf_found = TRUE;
525                 }
526                 CloseServiceHandle(h_scm);
527             }
528             if (!npf_found) {
529                 /* npf service was not found, so WinPcap is not (properly) installed.
530                    Add Npcap folder to libraries search path. */
531                 retval = GetSystemDirectoryW(npcap_path_w, MAX_PATH);
532                 if (0 < retval && retval <= MAX_PATH) {
533                     wcscat_s(npcap_path_w, MAX_PATH, L"\\Npcap");
534                     dll_dir_set = PSetDllDirectory(npcap_path_w);
535                 }
536             }
537         }
538     }
539
540     if (!dll_dir_set && init_dll_load_paths()) {
541         program_path_w = g_utf8_to_utf16(program_path, -1, NULL, NULL, NULL);
542         SetCurrentDirectory(program_path_w);
543         g_free(program_path_w);
544     }
545
546     return dll_dir_set;
547 }
548
549 /*
550  * Internally g_module_open uses LoadLibrary on Windows and returns an
551  * HMODULE cast to a GModule *. However there's no guarantee that this
552  * will always be the case, so we call LoadLibrary and g_module_open
553  * separately.
554  */
555
556 void *
557 ws_load_library(const gchar *library_name)
558 {
559     gchar   *full_path;
560     wchar_t *full_path_w;
561     HMODULE  dll_h;
562
563     if (!init_dll_load_paths() || !library_name)
564         return NULL;
565
566     /* First try the program directory */
567     full_path = g_module_build_path(program_path, library_name);
568     full_path_w = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
569
570     if (full_path && full_path_w) {
571         dll_h = LoadLibraryW(full_path_w);
572         if (dll_h) {
573             g_free(full_path);
574             g_free(full_path_w);
575             return dll_h;
576         }
577     }
578
579     /* Next try the system directory */
580     full_path = g_module_build_path(system_path, library_name);
581     full_path_w = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
582
583     if (full_path && full_path_w) {
584         dll_h = LoadLibraryW(full_path_w);
585         if (dll_h) {
586             g_free(full_path);
587             g_free(full_path_w);
588             return dll_h;
589         }
590     }
591
592     return NULL;
593 }
594
595 GModule *
596 ws_module_open(gchar *module_name, GModuleFlags flags)
597 {
598     gchar   *full_path;
599     GModule *mod;
600
601     if (!init_dll_load_paths() || !module_name)
602         return NULL;
603
604     /* First try the program directory */
605     full_path = g_module_build_path(program_path, module_name);
606
607     if (full_path) {
608         mod = g_module_open(full_path, flags);
609         if (mod) {
610             g_free(full_path);
611             return mod;
612         }
613     }
614
615     /* Next try the system directory */
616     full_path = g_module_build_path(system_path, module_name);
617
618     if (full_path) {
619         mod = g_module_open(full_path, flags);
620         if (mod) {
621             g_free(full_path);
622             return mod;
623         }
624     }
625
626     /* At last try the Npcap directory */
627     full_path = g_module_build_path(npcap_path, module_name);
628
629     if (full_path) {
630         mod = g_module_open(full_path, flags);
631         if (mod) {
632             g_free(full_path);
633             return mod;
634         }
635     }
636
637     return NULL;
638 }
639
640 /** Create or open a "Wireshark is running" mutex.
641  */
642 #define WIRESHARK_IS_RUNNING_UUID "9CA78EEA-EA4D-4490-9240-FC01FCEF464B"
643
644 static SECURITY_ATTRIBUTES *sec_attributes_;
645
646 static HANDLE local_running_mutex = NULL;
647 static HANDLE global_running_mutex = NULL;
648
649 void create_app_running_mutex() {
650     SECURITY_ATTRIBUTES *sa = NULL;
651
652     if (!sec_attributes_) sec_attributes_ = g_new0(SECURITY_ATTRIBUTES, 1);
653
654     sec_attributes_->nLength = sizeof(SECURITY_ATTRIBUTES);
655     sec_attributes_->lpSecurityDescriptor = g_new0(SECURITY_DESCRIPTOR, 1);
656     sec_attributes_->bInheritHandle = TRUE;
657     if (InitializeSecurityDescriptor(sec_attributes_->lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)) {
658         if (SetSecurityDescriptorDacl(sec_attributes_->lpSecurityDescriptor, TRUE, NULL, FALSE)) {
659             sa = sec_attributes_;
660         }
661     }
662
663     if (!sa) {
664         g_free(sec_attributes_->lpSecurityDescriptor);
665         g_free(sec_attributes_);
666         sec_attributes_ = NULL;
667     }
668     local_running_mutex = CreateMutex(sa, FALSE, _T("Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID) _T("}"));
669     global_running_mutex = CreateMutex(sa, FALSE, _T("Global\\Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID) _T("}"));
670 }
671
672 void close_app_running_mutex() {
673     if (local_running_mutex) {
674         CloseHandle(local_running_mutex);
675         local_running_mutex = NULL;
676     }
677     if (global_running_mutex) {
678         CloseHandle(global_running_mutex);
679         global_running_mutex = NULL;
680     }
681 }
682
683 /*
684  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
685  *
686  * Local Variables:
687  * c-basic-offset: 4
688  * tab-width: 8
689  * indent-tabs-mode: nil
690  * End:
691  *
692  * ex: set shiftwidth=4 tabstop=8 expandtab:
693  * :indentSize=4:tabSize=8:noTabs=true:
694  */