Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
ac615a7e
Commit
ac615a7e
authored
Sep 13, 2012
by
Andrew Eikum
Committed by
Alexandre Julliard
Sep 14, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
advapi32: Consolidate helper function.
parent
8fb16c95
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
31 additions
and
122 deletions
+31
-122
advapi32_misc.h
dlls/advapi32/advapi32_misc.h
+3
-0
eventlog.c
dlls/advapi32/eventlog.c
+2
-13
lsa.c
dlls/advapi32/lsa.c
+0
-1
security.c
dlls/advapi32/security.c
+23
-107
service.c
dlls/advapi32/service.c
+3
-1
No files found.
dlls/advapi32/advapi32_misc.h
View file @
ac615a7e
...
@@ -20,11 +20,14 @@
...
@@ -20,11 +20,14 @@
#ifndef __WINE_ADVAPI32MISC_H
#ifndef __WINE_ADVAPI32MISC_H
#define __WINE_ADVAPI32MISC_H
#define __WINE_ADVAPI32MISC_H
#include "ntsecapi.h"
const
char
*
debugstr_sid
(
PSID
sid
)
DECLSPEC_HIDDEN
;
const
char
*
debugstr_sid
(
PSID
sid
)
DECLSPEC_HIDDEN
;
BOOL
ADVAPI_IsLocalComputer
(
LPCWSTR
ServerName
)
DECLSPEC_HIDDEN
;
BOOL
ADVAPI_IsLocalComputer
(
LPCWSTR
ServerName
)
DECLSPEC_HIDDEN
;
BOOL
ADVAPI_GetComputerSid
(
PSID
sid
)
DECLSPEC_HIDDEN
;
BOOL
ADVAPI_GetComputerSid
(
PSID
sid
)
DECLSPEC_HIDDEN
;
BOOL
lookup_local_wellknown_name
(
const
LSA_UNICODE_STRING
*
,
PSID
,
LPDWORD
,
LPWSTR
,
LPDWORD
,
PSID_NAME_USE
,
BOOL
*
)
DECLSPEC_HIDDEN
;
BOOL
lookup_local_wellknown_name
(
const
LSA_UNICODE_STRING
*
,
PSID
,
LPDWORD
,
LPWSTR
,
LPDWORD
,
PSID_NAME_USE
,
BOOL
*
)
DECLSPEC_HIDDEN
;
BOOL
lookup_local_user_name
(
const
LSA_UNICODE_STRING
*
,
PSID
,
LPDWORD
,
LPWSTR
,
LPDWORD
,
PSID_NAME_USE
,
BOOL
*
)
DECLSPEC_HIDDEN
;
BOOL
lookup_local_user_name
(
const
LSA_UNICODE_STRING
*
,
PSID
,
LPDWORD
,
LPWSTR
,
LPDWORD
,
PSID_NAME_USE
,
BOOL
*
)
DECLSPEC_HIDDEN
;
WCHAR
*
SERV_dup
(
const
char
*
str
);
#endif
/* __WINE_ADVAPI32MISC_H */
#endif
/* __WINE_ADVAPI32MISC_H */
dlls/advapi32/eventlog.c
View file @
ac615a7e
...
@@ -33,22 +33,11 @@
...
@@ -33,22 +33,11 @@
#include "wine/unicode.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/debug.h"
#include "advapi32_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
advapi
);
WINE_DEFAULT_DEBUG_CHANNEL
(
advapi
);
WINE_DECLARE_DEBUG_CHANNEL
(
eventlog
);
WINE_DECLARE_DEBUG_CHANNEL
(
eventlog
);
static
inline
LPWSTR
SERV_dup
(
LPCSTR
str
)
{
UINT
len
;
LPWSTR
wstr
;
if
(
!
str
)
return
NULL
;
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
str
,
-
1
,
NULL
,
0
);
wstr
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
);
MultiByteToWideChar
(
CP_ACP
,
0
,
str
,
-
1
,
wstr
,
len
);
return
wstr
;
}
/******************************************************************************
/******************************************************************************
* BackupEventLogA [ADVAPI32.@]
* BackupEventLogA [ADVAPI32.@]
*
*
...
...
dlls/advapi32/lsa.c
View file @
ac615a7e
...
@@ -29,7 +29,6 @@
...
@@ -29,7 +29,6 @@
#include "winbase.h"
#include "winbase.h"
#include "winreg.h"
#include "winreg.h"
#include "winternl.h"
#include "winternl.h"
#include "ntsecapi.h"
#include "advapi32_misc.h"
#include "advapi32_misc.h"
#include "wine/debug.h"
#include "wine/debug.h"
...
...
dlls/advapi32/security.c
View file @
ac615a7e
...
@@ -31,7 +31,6 @@
...
@@ -31,7 +31,6 @@
#include "winsafer.h"
#include "winsafer.h"
#include "winternl.h"
#include "winternl.h"
#include "winioctl.h"
#include "winioctl.h"
#include "ntsecapi.h"
#include "accctrl.h"
#include "accctrl.h"
#include "sddl.h"
#include "sddl.h"
#include "winsvc.h"
#include "winsvc.h"
...
@@ -1935,17 +1934,10 @@ GetFileSecurityA( LPCSTR lpFileName,
...
@@ -1935,17 +1934,10 @@ GetFileSecurityA( LPCSTR lpFileName,
PSECURITY_DESCRIPTOR
pSecurityDescriptor
,
PSECURITY_DESCRIPTOR
pSecurityDescriptor
,
DWORD
nLength
,
LPDWORD
lpnLengthNeeded
)
DWORD
nLength
,
LPDWORD
lpnLengthNeeded
)
{
{
DWORD
len
;
BOOL
r
;
BOOL
r
;
LPWSTR
name
=
NULL
;
LPWSTR
name
;
if
(
lpFileName
)
{
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
lpFileName
,
-
1
,
NULL
,
0
);
name
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
);
MultiByteToWideChar
(
CP_ACP
,
0
,
lpFileName
,
-
1
,
name
,
len
);
}
name
=
SERV_dup
(
lpFileName
);
r
=
GetFileSecurityW
(
name
,
RequestedInformation
,
pSecurityDescriptor
,
r
=
GetFileSecurityW
(
name
,
RequestedInformation
,
pSecurityDescriptor
,
nLength
,
lpnLengthNeeded
);
nLength
,
lpnLengthNeeded
);
HeapFree
(
GetProcessHeap
(),
0
,
name
);
HeapFree
(
GetProcessHeap
(),
0
,
name
);
...
@@ -2005,17 +1997,13 @@ LookupAccountSidA(
...
@@ -2005,17 +1997,13 @@ LookupAccountSidA(
{
{
DWORD
len
;
DWORD
len
;
BOOL
r
;
BOOL
r
;
LPWSTR
systemW
=
NULL
;
LPWSTR
systemW
;
LPWSTR
accountW
=
NULL
;
LPWSTR
accountW
=
NULL
;
LPWSTR
domainW
=
NULL
;
LPWSTR
domainW
=
NULL
;
DWORD
accountSizeW
=
*
accountSize
;
DWORD
accountSizeW
=
*
accountSize
;
DWORD
domainSizeW
=
*
domainSize
;
DWORD
domainSizeW
=
*
domainSize
;
if
(
system
)
{
systemW
=
SERV_dup
(
system
);
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
system
,
-
1
,
NULL
,
0
);
systemW
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
);
MultiByteToWideChar
(
CP_ACP
,
0
,
system
,
-
1
,
systemW
,
len
);
}
if
(
account
)
if
(
account
)
accountW
=
HeapAlloc
(
GetProcessHeap
(),
0
,
accountSizeW
*
sizeof
(
WCHAR
)
);
accountW
=
HeapAlloc
(
GetProcessHeap
(),
0
,
accountSizeW
*
sizeof
(
WCHAR
)
);
if
(
domain
)
if
(
domain
)
...
@@ -2237,17 +2225,10 @@ BOOL WINAPI SetFileSecurityA( LPCSTR lpFileName,
...
@@ -2237,17 +2225,10 @@ BOOL WINAPI SetFileSecurityA( LPCSTR lpFileName,
SECURITY_INFORMATION
RequestedInformation
,
SECURITY_INFORMATION
RequestedInformation
,
PSECURITY_DESCRIPTOR
pSecurityDescriptor
)
PSECURITY_DESCRIPTOR
pSecurityDescriptor
)
{
{
DWORD
len
;
BOOL
r
;
BOOL
r
;
LPWSTR
name
=
NULL
;
LPWSTR
name
;
if
(
lpFileName
)
{
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
lpFileName
,
-
1
,
NULL
,
0
);
name
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
);
MultiByteToWideChar
(
CP_ACP
,
0
,
lpFileName
,
-
1
,
name
,
len
);
}
name
=
SERV_dup
(
lpFileName
);
r
=
SetFileSecurityW
(
name
,
RequestedInformation
,
pSecurityDescriptor
);
r
=
SetFileSecurityW
(
name
,
RequestedInformation
,
pSecurityDescriptor
);
HeapFree
(
GetProcessHeap
(),
0
,
name
);
HeapFree
(
GetProcessHeap
(),
0
,
name
);
...
@@ -3486,24 +3467,11 @@ BOOL WINAPI SetAclInformation( PACL pAcl, LPVOID pAclInformation,
...
@@ -3486,24 +3467,11 @@ BOOL WINAPI SetAclInformation( PACL pAcl, LPVOID pAclInformation,
static
DWORD
trustee_name_A_to_W
(
TRUSTEE_FORM
form
,
char
*
trustee_nameA
,
WCHAR
**
ptrustee_nameW
)
static
DWORD
trustee_name_A_to_W
(
TRUSTEE_FORM
form
,
char
*
trustee_nameA
,
WCHAR
**
ptrustee_nameW
)
{
{
DWORD
len
;
switch
(
form
)
switch
(
form
)
{
{
case
TRUSTEE_IS_NAME
:
case
TRUSTEE_IS_NAME
:
{
{
WCHAR
*
wstr
=
NULL
;
*
ptrustee_nameW
=
SERV_dup
(
trustee_nameA
);
if
(
trustee_nameA
)
{
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
trustee_nameA
,
-
1
,
NULL
,
0
);
if
(
!
(
wstr
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
)))
return
ERROR_NOT_ENOUGH_MEMORY
;
MultiByteToWideChar
(
CP_ACP
,
0
,
trustee_nameA
,
-
1
,
wstr
,
len
);
}
*
ptrustee_nameW
=
wstr
;
return
ERROR_SUCCESS
;
return
ERROR_SUCCESS
;
}
}
case
TRUSTEE_IS_OBJECTS_AND_NAME
:
case
TRUSTEE_IS_OBJECTS_AND_NAME
:
...
@@ -3518,42 +3486,13 @@ static DWORD trustee_name_A_to_W(TRUSTEE_FORM form, char *trustee_nameA, WCHAR *
...
@@ -3518,42 +3486,13 @@ static DWORD trustee_name_A_to_W(TRUSTEE_FORM form, char *trustee_nameA, WCHAR *
objW
->
ObjectsPresent
=
objA
->
ObjectsPresent
;
objW
->
ObjectsPresent
=
objA
->
ObjectsPresent
;
objW
->
ObjectType
=
objA
->
ObjectType
;
objW
->
ObjectType
=
objA
->
ObjectType
;
objW
->
ObjectTypeName
=
NULL
;
objW
->
ObjectTypeName
=
SERV_dup
(
objA
->
ObjectTypeName
);
objW
->
InheritedObjectTypeName
=
NULL
;
objW
->
InheritedObjectTypeName
=
SERV_dup
(
objA
->
InheritedObjectTypeName
);
objW
->
ptstrName
=
NULL
;
objW
->
ptstrName
=
SERV_dup
(
objA
->
ptstrName
);
if
(
objA
->
ObjectTypeName
)
{
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
objA
->
ObjectTypeName
,
-
1
,
NULL
,
0
);
if
(
!
(
objW
->
ObjectTypeName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
)))
goto
error
;
MultiByteToWideChar
(
CP_ACP
,
0
,
objA
->
ObjectTypeName
,
-
1
,
objW
->
ObjectTypeName
,
len
);
}
if
(
objA
->
InheritedObjectTypeName
)
{
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
objA
->
InheritedObjectTypeName
,
-
1
,
NULL
,
0
);
if
(
!
(
objW
->
InheritedObjectTypeName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
)))
goto
error
;
MultiByteToWideChar
(
CP_ACP
,
0
,
objA
->
InheritedObjectTypeName
,
-
1
,
objW
->
InheritedObjectTypeName
,
len
);
}
if
(
objA
->
ptstrName
)
{
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
objA
->
ptstrName
,
-
1
,
NULL
,
0
);
if
(
!
(
objW
->
ptstrName
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
)))
goto
error
;
MultiByteToWideChar
(
CP_ACP
,
0
,
objA
->
ptstrName
,
-
1
,
objW
->
ptstrName
,
len
);
}
}
}
*
ptrustee_nameW
=
(
WCHAR
*
)
objW
;
*
ptrustee_nameW
=
(
WCHAR
*
)
objW
;
return
ERROR_SUCCESS
;
return
ERROR_SUCCESS
;
error:
HeapFree
(
GetProcessHeap
(),
0
,
objW
->
InheritedObjectTypeName
);
HeapFree
(
GetProcessHeap
(),
0
,
objW
->
ObjectTypeName
);
HeapFree
(
GetProcessHeap
(),
0
,
objW
);
return
ERROR_NOT_ENOUGH_MEMORY
;
}
}
/* These forms do not require conversion. */
/* These forms do not require conversion. */
case
TRUSTEE_IS_SID
:
case
TRUSTEE_IS_SID
:
...
@@ -3920,20 +3859,13 @@ DWORD WINAPI SetNamedSecurityInfoA(LPSTR pObjectName,
...
@@ -3920,20 +3859,13 @@ DWORD WINAPI SetNamedSecurityInfoA(LPSTR pObjectName,
SE_OBJECT_TYPE
ObjectType
,
SECURITY_INFORMATION
SecurityInfo
,
SE_OBJECT_TYPE
ObjectType
,
SECURITY_INFORMATION
SecurityInfo
,
PSID
psidOwner
,
PSID
psidGroup
,
PACL
pDacl
,
PACL
pSacl
)
PSID
psidOwner
,
PSID
psidGroup
,
PACL
pDacl
,
PACL
pSacl
)
{
{
DWORD
len
;
LPWSTR
wstr
;
LPWSTR
wstr
=
NULL
;
DWORD
r
;
DWORD
r
;
TRACE
(
"%s %d %d %p %p %p %p
\n
"
,
debugstr_a
(
pObjectName
),
ObjectType
,
TRACE
(
"%s %d %d %p %p %p %p
\n
"
,
debugstr_a
(
pObjectName
),
ObjectType
,
SecurityInfo
,
psidOwner
,
psidGroup
,
pDacl
,
pSacl
);
SecurityInfo
,
psidOwner
,
psidGroup
,
pDacl
,
pSacl
);
if
(
pObjectName
)
wstr
=
SERV_dup
(
pObjectName
);
{
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
pObjectName
,
-
1
,
NULL
,
0
);
wstr
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
));
MultiByteToWideChar
(
CP_ACP
,
0
,
pObjectName
,
-
1
,
wstr
,
len
);
}
r
=
SetNamedSecurityInfoW
(
wstr
,
ObjectType
,
SecurityInfo
,
psidOwner
,
r
=
SetNamedSecurityInfoW
(
wstr
,
ObjectType
,
SecurityInfo
,
psidOwner
,
psidGroup
,
pDacl
,
pSacl
);
psidGroup
,
pDacl
,
pSacl
);
...
@@ -4509,22 +4441,17 @@ BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA(
...
@@ -4509,22 +4441,17 @@ BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA(
PSECURITY_DESCRIPTOR
*
SecurityDescriptor
,
PSECURITY_DESCRIPTOR
*
SecurityDescriptor
,
PULONG
SecurityDescriptorSize
)
PULONG
SecurityDescriptorSize
)
{
{
UINT
len
;
BOOL
ret
;
BOOL
ret
=
FALSE
;
LPWSTR
StringSecurityDescriptorW
;
LPWSTR
StringSecurityDescriptorW
;
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
StringSecurityDescriptor
,
-
1
,
NULL
,
0
);
if
(
!
StringSecurityDescriptor
)
StringSecurityDescriptorW
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
));
return
FALSE
;
if
(
StringSecurityDescriptorW
)
{
MultiByteToWideChar
(
CP_ACP
,
0
,
StringSecurityDescriptor
,
-
1
,
StringSecurityDescriptorW
,
len
);
ret
=
ConvertStringSecurityDescriptorToSecurityDescriptorW
(
StringSecurityDescriptorW
,
StringSecurityDescriptorW
=
SERV_dup
(
StringSecurityDescriptor
);
StringSDRevision
,
SecurityDescriptor
,
ret
=
ConvertStringSecurityDescriptorToSecurityDescriptorW
(
StringSecurityDescriptorW
,
SecurityDescriptorSize
);
StringSDRevision
,
SecurityDescriptor
,
HeapFree
(
GetProcessHeap
(),
0
,
StringSecurityDescriptorW
);
SecurityDescriptorSize
);
}
HeapFree
(
GetProcessHeap
(),
0
,
StringSecurityDescriptorW
);
return
ret
;
return
ret
;
}
}
...
@@ -5021,11 +4948,7 @@ BOOL WINAPI ConvertStringSidToSidA(LPCSTR StringSid, PSID* Sid)
...
@@ -5021,11 +4948,7 @@ BOOL WINAPI ConvertStringSidToSidA(LPCSTR StringSid, PSID* Sid)
SetLastError
(
ERROR_INVALID_PARAMETER
);
SetLastError
(
ERROR_INVALID_PARAMETER
);
else
else
{
{
UINT
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
StringSid
,
-
1
,
NULL
,
0
);
WCHAR
*
wStringSid
=
SERV_dup
(
StringSid
);
LPWSTR
wStringSid
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
));
MultiByteToWideChar
(
CP_ACP
,
0
,
StringSid
,
-
1
,
wStringSid
,
len
);
bret
=
ConvertStringSidToSidW
(
wStringSid
,
Sid
);
bret
=
ConvertStringSidToSidW
(
wStringSid
,
Sid
);
HeapFree
(
GetProcessHeap
(),
0
,
wStringSid
);
HeapFree
(
GetProcessHeap
(),
0
,
wStringSid
);
}
}
...
@@ -5417,20 +5340,13 @@ DWORD WINAPI GetNamedSecurityInfoA(LPSTR pObjectName,
...
@@ -5417,20 +5340,13 @@ DWORD WINAPI GetNamedSecurityInfoA(LPSTR pObjectName,
PSID
*
ppsidOwner
,
PSID
*
ppsidGroup
,
PACL
*
ppDacl
,
PACL
*
ppSacl
,
PSID
*
ppsidOwner
,
PSID
*
ppsidGroup
,
PACL
*
ppDacl
,
PACL
*
ppSacl
,
PSECURITY_DESCRIPTOR
*
ppSecurityDescriptor
)
PSECURITY_DESCRIPTOR
*
ppSecurityDescriptor
)
{
{
DWORD
len
;
LPWSTR
wstr
;
LPWSTR
wstr
=
NULL
;
DWORD
r
;
DWORD
r
;
TRACE
(
"%s %d %d %p %p %p %p %p
\n
"
,
pObjectName
,
ObjectType
,
SecurityInfo
,
TRACE
(
"%s %d %d %p %p %p %p %p
\n
"
,
pObjectName
,
ObjectType
,
SecurityInfo
,
ppsidOwner
,
ppsidGroup
,
ppDacl
,
ppSacl
,
ppSecurityDescriptor
);
ppsidOwner
,
ppsidGroup
,
ppDacl
,
ppSacl
,
ppSecurityDescriptor
);
if
(
pObjectName
)
wstr
=
SERV_dup
(
pObjectName
);
{
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
pObjectName
,
-
1
,
NULL
,
0
);
wstr
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
));
MultiByteToWideChar
(
CP_ACP
,
0
,
pObjectName
,
-
1
,
wstr
,
len
);
}
r
=
GetNamedSecurityInfoW
(
wstr
,
ObjectType
,
SecurityInfo
,
ppsidOwner
,
r
=
GetNamedSecurityInfoW
(
wstr
,
ObjectType
,
SecurityInfo
,
ppsidOwner
,
ppsidGroup
,
ppDacl
,
ppSacl
,
ppSecurityDescriptor
);
ppsidGroup
,
ppDacl
,
ppSacl
,
ppSecurityDescriptor
);
...
...
dlls/advapi32/service.c
View file @
ac615a7e
...
@@ -41,6 +41,8 @@
...
@@ -41,6 +41,8 @@
#include "svcctl.h"
#include "svcctl.h"
#include "advapi32_misc.h"
#include "wine/exception.h"
#include "wine/exception.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
service
);
WINE_DEFAULT_DEBUG_CHANNEL
(
service
);
...
@@ -92,7 +94,7 @@ extern HANDLE CDECL __wine_make_process_system(void);
...
@@ -92,7 +94,7 @@ extern HANDLE CDECL __wine_make_process_system(void);
* NOTE: the caller of those functions is responsible for calling HeapFree
* NOTE: the caller of those functions is responsible for calling HeapFree
* in order to release the memory allocated by those functions.
* in order to release the memory allocated by those functions.
*/
*/
static
inline
LPWSTR
SERV_dup
(
LPCSTR
str
)
LPWSTR
SERV_dup
(
LPCSTR
str
)
{
{
UINT
len
;
UINT
len
;
LPWSTR
wstr
;
LPWSTR
wstr
;
...
...
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