Skip to content

Add support for creating symlinks as an unprivileged user #1184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,16 @@ int mingw_core_config(const char *var, const char *value)

DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateSymbolicLinkW, LPCWSTR, LPCWSTR, DWORD);

#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
#endif

#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2
#endif

static int has_unprivileged_symlinks = 0;

enum phantom_symlink_result {
PHANTOM_SYMLINK_RETRY,
PHANTOM_SYMLINK_DONE,
Expand All @@ -286,6 +296,7 @@ static enum phantom_symlink_result process_phantom_symlink(
const wchar_t *wtarget, const wchar_t *wlink) {
HANDLE hnd;
BY_HANDLE_FILE_INFORMATION fdata;
DWORD symlink_flags = SYMBOLIC_LINK_FLAG_DIRECTORY;

/* check that wlink is still a file symlink */
if ((GetFileAttributesW(wlink)
Expand Down Expand Up @@ -313,8 +324,13 @@ static enum phantom_symlink_result process_phantom_symlink(
if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
return PHANTOM_SYMLINK_DONE;

/* Permit creating symlink as an unprivileged user if supported */
if (has_unprivileged_symlinks == 1) {
symlink_flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
}

/* otherwise recreate the symlink with directory flag */
if (DeleteFileW(wlink) && CreateSymbolicLinkW(wlink, wtarget, 1))
if (DeleteFileW(wlink) && CreateSymbolicLinkW(wlink, wtarget, symlink_flags))
return PHANTOM_SYMLINK_DIRECTORY;

errno = err_win_to_posix(GetLastError());
Expand Down Expand Up @@ -2639,6 +2655,7 @@ int symlink(const char *target, const char *link)
{
wchar_t wtarget[MAX_LONG_PATH], wlink[MAX_LONG_PATH];
int len;
DWORD symlink_flags = 0;

/* fail if symlinks are disabled or API is not supported (WinXP) */
if (!has_symlinks || !INIT_PROC_ADDR(CreateSymbolicLinkW)) {
Expand All @@ -2655,8 +2672,13 @@ int symlink(const char *target, const char *link)
if (wtarget[len] == '/')
wtarget[len] = '\\';

/* Permit creating symlink as an unprivileged user if supported */
if (has_unprivileged_symlinks == 1) {
symlink_flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
}

/* create file symlink */
if (!CreateSymbolicLinkW(wlink, wtarget, 0)) {
if (!CreateSymbolicLinkW(wlink, wtarget, symlink_flags)) {
errno = err_win_to_posix(GetLastError());
return -1;
}
Expand Down Expand Up @@ -3021,6 +3043,18 @@ static void setup_windows_environment(void)
if (!(tmp = getenv("MSYS")) || !strstr(tmp, "winsymlinks:nativestrict"))
has_symlinks = 0;

/* Check if this release of Windows supports creating symbolic links as an
* unprivileged user. The underlying API support was introduced in the
* Windows 10 Creators Update (v1703). Older releases of Windows don't
* understand the new flag to the CreateSymbolicLink family of functions.
*/
struct utsname winver;
if (uname(&winver) == 0) {
if (atoi(winver.version) >= 15063) {
has_unprivileged_symlinks = 1;

This comment was marked as off-topic.

This comment was marked as off-topic.

}
}

if (!getenv("LC_ALL") && !getenv("LC_CTYPE") && !getenv("LANG"))
setenv("LC_CTYPE", "C", 1);
}
Expand Down