From: Dustin Howett Date: Fri, 15 Oct 2021 22:47:53 +0000 (-0500) Subject: win32: shim wopen, and make both open/wopen use _s "secure" variant X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F2684%2Fhead;p=thirdparty%2Flibarchive.git win32: shim wopen, and make both open/wopen use _s "secure" variant 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. --- diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index 0ccea0f81..67d151da4 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -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) { diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h index 4dc8c2b3a..c528b8f4f 100644 --- a/libarchive/archive_windows.h +++ b/libarchive/archive_windows.h @@ -106,6 +106,7 @@ #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); diff --git a/tar/bsdtar_windows.h b/tar/bsdtar_windows.h index d18239782..6bedb3702 100644 --- a/tar/bsdtar_windows.h +++ b/tar/bsdtar_windows.h @@ -11,6 +11,7 @@ #include #include #include +#include #ifndef PRId64 #define PRId64 "I64" diff --git a/tar/write.c b/tar/write.c index 21984e980..92cc0ce57 100644 --- a/tar/write.c +++ b/tar/write.c @@ -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