Network Copy등을 하기 위해서 ID와 Password를 알고 있는데, code 상으로 구현하는 방법을 한번 정리.
일단, WindowsIdentify는 win32 dll을 이용하고, Windows Token을 사용한다. Windows Token은 어떤 시스템에 Logon한 이후에, 일정시간 유지가 되는 Windows의 memory안에 자신의 Identity를 저장하게 된다.
먼저, Win32의 [DllImport("advapi32.dll", SetLastError = true)] 를 이용해서 LogonUser method를 dll import 시켜온다.
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
마지막 값인 phToken값을 이용해서 WindowsIdentify를 얻어 내면 타 시스템에 접근이 가능하다. 여기에서 userName은 upn형태로 넣어져야지 되며, 이 형식은 ykyoon@vplex.net 과 같은 email과 같은 형식으로 입력이 되어야지 된다.
다음은 NetworkCopy를 하는 Test code이다.
01.
[DllImport(
"advapi32.dll"
, SetLastError =
true
)]
02.
public
static
extern
bool
LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int
dwLogonType,
int
dwLogonProvider,
ref
IntPtr phToken);
03.
[DllImport(
"kernel32.dll"
, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
04.
private
unsafe
static
extern
int
FormatMessage(
int
dwFlags,
ref
IntPtr lpSource,
int
dwMessageId,
int
dwLanguageId,
ref
String lpBuffer,
int
nSize, IntPtr* Arguments);
05.
06.
[DllImport(
"kernel32.dll"
, CharSet = CharSet.Auto)]
07.
public
extern
static
bool
CloseHandle(IntPtr handle);
08.
[DllImport(
"advapi32.dll"
, CharSet = CharSet.Auto, SetLastError =
true
)]
09.
public
extern
static
bool
DuplicateToken(IntPtr ExistingTokenHandle,
int
SECURITY_IMPERSONATION_LEVEL,
ref
IntPtr DuplicateTokenHandle);
10.
11.
public
unsafe
static
string
GetErrorMessage(
int
errorCode)
12.
{
13.
int
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
14.
int
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
15.
int
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
16.
17.
int
messageSize = 255;
18.
String lpMsgBuf =
""
;
19.
int
dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
20.
21.
IntPtr ptrlpSource = IntPtr.Zero;
22.
IntPtr prtArguments = IntPtr.Zero;
23.
24.
int
retVal = FormatMessage(dwFlags,
ref
ptrlpSource, errorCode, 0,
ref
lpMsgBuf, messageSize, &prtArguments);
25.
if
(0 == retVal)
26.
{
27.
throw
new
Exception(
"Failed to format message for error code "
+ errorCode +
". "
);
28.
}
29.
30.
return
lpMsgBuf;
31.
}
32.
33.
static
void
Main(
string
[] args)
34.
{
35.
const
int
LOGON32_PROVIDER_DEFAULT = 0;
36.
const
int
LOGON32_LOGON_INTERACTIVE = 2;
37.
const
int
SecurityImpersonation = 2;
38.
39.
var tokenHandle = IntPtr.Zero;
40.
bool
returnValue = LogonUser(@
"Administrator@vplex.net"
,
"network ip in here"
,
"this is password"
, 9, 0,
ref
tokenHandle);
41.
Console.WriteLine(
"LogonUser called."
);
42.
if
(
false
== returnValue)
43.
{
44.
int
ret = Marshal.GetLastWin32Error();
45.
Console.WriteLine(
"LogonUser failed with error code : {0}"
, ret);
46.
Console.WriteLine(
"\nError: [{0}] {1}\n"
, ret, GetErrorMessage(ret));
47.
int
errorCode = 0x5;
//ERROR_ACCESS_DENIED
48.
throw
new
System.ComponentModel.Win32Exception(errorCode);
49.
}
50.
else
51.
{
52.
var ykyoonAdmin =
new
WindowsIdentity(tokenHandle);
53.
var wic = ykyoonAdmin.Impersonate();
54.
File.Copy(
"C:\\System.Web.Mvc.dll"
,
"\\\\10.30.3.24\\c$\\abc.dll"
,
true
);
55.
wic.Undo();
56.
wic.Dispose();
57.
}
58.
CloseHandle(tokenHandle);
59.
}