]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
win32: shim wopen, and make both open/wopen use _s "secure" variant 2684/head
authorDustin Howett <duhowett@microsoft.com>
Fri, 15 Oct 2021 22:47:53 +0000 (17:47 -0500)
committerDustin L. Howett <dustin@howett.net>
Thu, 26 Jun 2025 17:56:33 +0000 (10:56 -0700)
The new `__la_wopen` wrapper is a copy of `__la_open` that
expects--rather than converts--a wcs parameter.

The `sopen` variants are offered as "more secure" variants of `open` and
`wopen`; I cannot vouch for their security, but some build systems are
strict about the use of "banned insecure APIs".

I've confirmed that `_wsopen_s` and `_open_s` are present in the Windows
Vista SDK.

I did not confirm that they are available in the Windows XP Platform
SDK, in part because in e61afbd463d1 (2016!) Tim says:

> I'd like to completely remove support for WinXP and earlier.

libarchive/archive_windows.c
libarchive/archive_windows.h
tar/bsdtar_windows.h
tar/write.c

index 0ccea0f818b90cd4edd185901131fc74223cad23..67d151da4107ee678d9a524a83c1e25ea53f2e76 100644 (file)
@@ -313,6 +313,10 @@ __la_open(const char *path, int flags, ...)
        pmode = va_arg(ap, int);
        va_end(ap);
        ws = NULL;
+
+       /* _(w)sopen_s fails if we provide any other modes */
+       pmode = pmode & (_S_IREAD | _S_IWRITE);
+
        if ((flags & ~O_BINARY) == O_RDONLY) {
                /*
                 * When we open a directory, _open function returns
@@ -374,7 +378,7 @@ __la_open(const char *path, int flags, ...)
                   TODO: Fix mode of new file.  */
                r = _open(path, flags);
 #else
-               r = _open(path, flags, pmode);
+               _sopen_s(&r, path, flags, _SH_DENYNO, pmode);
 #endif
                if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
                        /* Simulate other POSIX system action to pass our test suite. */
@@ -395,7 +399,7 @@ __la_open(const char *path, int flags, ...)
                        return (-1);
                }
        }
-       r = _wopen(ws, flags, pmode);
+       _wsopen_s(&r, ws, flags, _SH_DENYNO, pmode);
        if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
                /* Simulate other POSIX system action to pass our test suite. */
                attr = GetFileAttributesW(ws);
@@ -410,6 +414,93 @@ __la_open(const char *path, int flags, ...)
        return (r);
 }
 
+int
+__la_wopen(const wchar_t *path, int flags, ...)
+{
+       va_list ap;
+       wchar_t *fullpath;
+       int r, pmode;
+       DWORD attr;
+
+       va_start(ap, flags);
+       pmode = va_arg(ap, int);
+       va_end(ap);
+       fullpath = NULL;
+
+       /* _(w)sopen_s fails if we provide any other modes */
+       pmode = pmode & (_S_IREAD | _S_IWRITE);
+
+       if ((flags & ~O_BINARY) == O_RDONLY) {
+               /*
+                * When we open a directory, _open function returns
+                * "Permission denied" error.
+                */
+               attr = GetFileAttributesW(path);
+#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
+               if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND)
+#endif
+               {
+                       fullpath = __la_win_permissive_name_w(path);
+                       if (fullpath == NULL) {
+                               errno = EINVAL;
+                               return (-1);
+                       }
+                       path = fullpath;
+                       attr = GetFileAttributesW(fullpath);
+               }
+               if (attr == (DWORD)-1) {
+                       la_dosmaperr(GetLastError());
+                       free(fullpath);
+                       return (-1);
+               }
+               if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+                       HANDLE handle;
+#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
+                       if (fullpath != NULL)
+                               handle = CreateFileW(fullpath, 0, 0, NULL,
+                                   OPEN_EXISTING,
+                                   FILE_FLAG_BACKUP_SEMANTICS |
+                                   FILE_ATTRIBUTE_READONLY,
+                                       NULL);
+                       else
+                               handle = CreateFileW(path, 0, 0, NULL,
+                                   OPEN_EXISTING,
+                                   FILE_FLAG_BACKUP_SEMANTICS |
+                                   FILE_ATTRIBUTE_READONLY,
+                                       NULL);
+#else /* !WINAPI_PARTITION_DESKTOP */
+                       CREATEFILE2_EXTENDED_PARAMETERS createExParams;
+                       ZeroMemory(&createExParams, sizeof(createExParams));
+                       createExParams.dwSize = sizeof(createExParams);
+                       createExParams.dwFileAttributes = FILE_ATTRIBUTE_READONLY;
+                       createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
+                       handle = CreateFile2(fullpath, 0, 0,
+                               OPEN_EXISTING, &createExParams);
+#endif /* !WINAPI_PARTITION_DESKTOP */
+                       free(fullpath);
+                       if (handle == INVALID_HANDLE_VALUE) {
+                               la_dosmaperr(GetLastError());
+                               return (-1);
+                       }
+                       r = _open_osfhandle((intptr_t)handle, _O_RDONLY);
+                       return (r);
+               }
+       }
+       _wsopen_s(&r, path, flags, _SH_DENYNO, pmode);
+       if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
+               /* Simulate other POSIX system action to pass our test suite. */
+               attr = GetFileAttributesW(path);
+               if (attr == (DWORD)-1)
+                       la_dosmaperr(GetLastError());
+               else if (attr & FILE_ATTRIBUTE_DIRECTORY)
+                       errno = EISDIR;
+               else
+                       errno = EACCES;
+       }
+       free(fullpath);
+       return (r);
+}
+
 ssize_t
 __la_read(int fd, void *buf, size_t nbytes)
 {
index 4dc8c2b3ad438d6c87d3fd0481ce26b1e646cbda..c528b8f4fad54dd1e74a3462787eadf1d9d15c50 100644 (file)
 #endif
 #define        lstat           __la_stat
 #define        open            __la_open
+#define        _wopen          __la_wopen
 #define        read            __la_read
 #if !defined(__BORLANDC__) && !defined(__WATCOMC__)
 #define setmode                _setmode
@@ -269,6 +270,7 @@ extern int   __la_lstat(const char *path, struct stat *st);
 extern __int64  __la_lseek(int fd, __int64 offset, int whence);
 #endif
 extern int      __la_open(const char *path, int flags, ...);
+extern int      __la_wopen(const wchar_t *path, int flags, ...);
 extern ssize_t  __la_read(int fd, void *buf, size_t nbytes);
 extern int      __la_stat(const char *path, struct stat *st);
 extern pid_t    __la_waitpid(HANDLE child, int *status, int option);
index d18239782ff4a34db2aca4acb5cc9313aa6cbdc1..6bedb37026967d0f50a388bbe805a86895dab0d5 100644 (file)
@@ -11,6 +11,7 @@
 #include <windows.h>
 #include <io.h>
 #include <fcntl.h>
+#include <share.h>
 
 #ifndef PRId64
 #define        PRId64 "I64"
index 21984e980ebd8433ad874bf4d4f9de78d31a287f..92cc0ce574013409c7db44f9e2ea48f20a1e47c7 100644 (file)
@@ -111,7 +111,32 @@ seek_file(int fd, int64_t offset, int whence)
        return (SetFilePointerEx((HANDLE)_get_osfhandle(fd),
                distance, NULL, FILE_BEGIN) ? 1 : -1);
 }
-#define        open _open
+
+static int
+_open_wrap_sopen(char const *const path, int const oflag, ...)
+{
+       va_list ap;
+       int r, pmode;
+
+       pmode = 0;
+       if (oflag & _O_CREAT)
+       {
+               va_start(ap, oflag);
+               pmode = va_arg(ap, int);
+               va_end(ap);
+       }
+
+       _sopen_s(&r, path, oflag, _SH_DENYNO, pmode & 0600);
+       if (r < 0)
+       {
+               /* _sopen_s populates errno */
+               return -1;
+       }
+
+       return r;
+}
+
+#define        open _open_wrap_sopen
 #define        close _close
 #define        read _read
 #ifdef lseek