Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
0e107665
Commit
0e107665
authored
Apr 09, 2019
by
Vidar Tonaas Fauske
Committed by
Steve Dower
Apr 09, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-31512: Add non-elevated symlink support for Windows (GH-3652)
parent
8709490f
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
53 additions
and
79 deletions
+53
-79
Doc/library/os.rst
Doc/library/os.rst
+7
-8
Misc/NEWS.d/next/Windows/2017-10-04-12-40-45.bpo-31512.YQeBt2.rst
...S.d/next/Windows/2017-10-04-12-40-45.bpo-31512.YQeBt2.rst
+2
-0
Modules/posixmodule.c
Modules/posixmodule.c
+39
-71
Modules/winreparse.h
Modules/winreparse.h
+5
-0
No files found.
Doc/library/os.rst
View file @
0e107665
...
...
@@ -2699,19 +2699,15 @@ features:
as a directory if *target_is_directory* is ``True`` or a file symlink (the
default) otherwise. On non-Windows platforms, *target_is_directory* is ignored.
Symbolic link support was introduced in Windows 6.0 (Vista). :func:`symlink`
will raise a :exc:`NotImplementedError` on Windows versions earlier than 6.0.
This function can support :ref:`paths relative to directory descriptors
<dir_fd>`.
.. note::
On Windows, the *SeCreateSymbolicLinkPrivilege* is required in order to
successfully create symlinks. This privilege is not typically granted to
regular users but is available to accounts which can escalate privileges
to the administrator level. Either obtaining the privilege or running your
application as an administrator are ways to successfully create symlinks.
On newer versions of Windows 10, unprivileged accounts can create symlinks
if Developer Mode is enabled. When Developer Mode is not available/enabled,
the *SeCreateSymbolicLinkPrivilege* privilege is required, or the process
must be run as an administrator.
:exc:`OSError` is raised when the function is called by an unprivileged
...
...
@@ -2729,6 +2725,9 @@ features:
.. versionchanged:: 3.6
Accepts a :term:`path-like object` for *src* and *dst*.
.. versionchanged:: 3.8
Added support for unelevated symlinks on Windows with Developer Mode.
.. function:: sync()
...
...
Misc/NEWS.d/next/Windows/2017-10-04-12-40-45.bpo-31512.YQeBt2.rst
0 → 100644
View file @
0e107665
With the Windows 10 Creators Update, non-elevated users can now create
symlinks as long as the computer has Developer Mode enabled.
Modules/posixmodule.c
View file @
0e107665
...
...
@@ -284,10 +284,7 @@ extern char *ctermid_r(char *);
#include <windows.h>
#include <shellapi.h>
/* for ShellExecute() */
#include <lmcons.h>
/* for UNLEN */
#ifdef SE_CREATE_SYMBOLIC_LINK_NAME
/* Available starting with Vista */
#define HAVE_SYMLINK
static
int
win32_can_symlink
=
0
;
#endif
#endif
/* _MSC_VER */
#ifndef MAXPATHLEN
...
...
@@ -7755,26 +7752,6 @@ os_readlink_impl(PyObject *module, path_t *path, int dir_fd)
#if defined(MS_WINDOWS)
/* Grab CreateSymbolicLinkW dynamically from kernel32 */
static
BOOLEAN
(
CALLBACK
*
Py_CreateSymbolicLinkW
)(
LPCWSTR
,
LPCWSTR
,
DWORD
)
=
NULL
;
static
int
check_CreateSymbolicLink
(
void
)
{
HINSTANCE
hKernel32
;
/* only recheck */
if
(
Py_CreateSymbolicLinkW
)
return
1
;
Py_BEGIN_ALLOW_THREADS
hKernel32
=
GetModuleHandleW
(
L"KERNEL32"
);
*
(
FARPROC
*
)
&
Py_CreateSymbolicLinkW
=
GetProcAddress
(
hKernel32
,
"CreateSymbolicLinkW"
);
Py_END_ALLOW_THREADS
return
Py_CreateSymbolicLinkW
!=
NULL
;
}
/* Remove the last portion of the path - return 0 on success */
static
int
_dirnameW
(
WCHAR
*
path
)
...
...
@@ -7878,33 +7855,57 @@ os_symlink_impl(PyObject *module, path_t *src, path_t *dst,
{
#ifdef MS_WINDOWS
DWORD
result
;
DWORD
flags
=
0
;
/* Assumed true, set to false if detected to not be available. */
static
int
windows_has_symlink_unprivileged_flag
=
TRUE
;
#else
int
result
;
#endif
#ifdef MS_WINDOWS
if
(
!
check_CreateSymbolicLink
())
{
PyErr_SetString
(
PyExc_NotImplementedError
,
"CreateSymbolicLink functions not found"
);
return
NULL
;
}
if
(
!
win32_can_symlink
)
{
PyErr_SetString
(
PyExc_OSError
,
"symbolic link privilege not held"
);
return
NULL
;
}
#endif
#ifdef MS_WINDOWS
if
(
windows_has_symlink_unprivileged_flag
)
{
/* Allow non-admin symlinks if system allows it. */
flags
|=
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
;
}
Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH
/* if src is a directory, ensure target_is_directory==1 */
target_is_directory
|=
_check_dirW
(
src
->
wide
,
dst
->
wide
);
result
=
Py_CreateSymbolicLinkW
(
dst
->
wide
,
src
->
wide
,
target_is_directory
);
/* if src is a directory, ensure flags==1 (target_is_directory bit) */
if
(
target_is_directory
||
_check_dirW
(
src
->
wide
,
dst
->
wide
))
{
flags
|=
SYMBOLIC_LINK_FLAG_DIRECTORY
;
}
result
=
CreateSymbolicLinkW
(
dst
->
wide
,
src
->
wide
,
flags
);
_Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
if
(
windows_has_symlink_unprivileged_flag
&&
!
result
&&
ERROR_INVALID_PARAMETER
==
GetLastError
())
{
Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH
/* This error might be caused by
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE not being supported.
Try again, and update windows_has_symlink_unprivileged_flag if we
are successful this time.
NOTE: There is a risk of a race condition here if there are other
conditions than the flag causing ERROR_INVALID_PARAMETER, and
another process (or thread) changes that condition in between our
calls to CreateSymbolicLink.
*/
flags
&=
~
(
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
);
result
=
CreateSymbolicLinkW
(
dst
->
wide
,
src
->
wide
,
flags
);
_Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
if
(
result
||
ERROR_INVALID_PARAMETER
!=
GetLastError
())
{
windows_has_symlink_unprivileged_flag
=
FALSE
;
}
}
if
(
!
result
)
return
path_error2
(
src
,
dst
);
...
...
@@ -13469,35 +13470,6 @@ static PyMethodDef posix_methods[] = {
{
NULL
,
NULL
}
/* Sentinel */
};
#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
static
int
enable_symlink
()
{
HANDLE
tok
;
TOKEN_PRIVILEGES
tok_priv
;
LUID
luid
;
if
(
!
OpenProcessToken
(
GetCurrentProcess
(),
TOKEN_ALL_ACCESS
,
&
tok
))
return
0
;
if
(
!
LookupPrivilegeValue
(
NULL
,
SE_CREATE_SYMBOLIC_LINK_NAME
,
&
luid
))
return
0
;
tok_priv
.
PrivilegeCount
=
1
;
tok_priv
.
Privileges
[
0
].
Luid
=
luid
;
tok_priv
.
Privileges
[
0
].
Attributes
=
SE_PRIVILEGE_ENABLED
;
if
(
!
AdjustTokenPrivileges
(
tok
,
FALSE
,
&
tok_priv
,
sizeof
(
TOKEN_PRIVILEGES
),
(
PTOKEN_PRIVILEGES
)
NULL
,
(
PDWORD
)
NULL
))
return
0
;
/* ERROR_NOT_ALL_ASSIGNED returned when the privilege can't be assigned. */
return
GetLastError
()
==
ERROR_NOT_ALL_ASSIGNED
?
0
:
1
;
}
#endif
/* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */
static
int
all_ins
(
PyObject
*
m
)
{
...
...
@@ -14105,10 +14077,6 @@ INITFUNC(void)
PyObject
*
list
;
const
char
*
const
*
trace
;
#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
win32_can_symlink
=
enable_symlink
();
#endif
m
=
PyModule_Create
(
&
posixmodule
);
if
(
m
==
NULL
)
return
NULL
;
...
...
Modules/winreparse.h
View file @
0e107665
...
...
@@ -45,6 +45,11 @@ typedef struct {
FIELD_OFFSET(_Py_REPARSE_DATA_BUFFER, GenericReparseBuffer)
#define _Py_MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
// Defined in WinBase.h in 'recent' versions of Windows 10 SDK
#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2
#endif
#ifdef __cplusplus
}
#endif
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment