Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
b83823d6
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
b83823d6
编写于
7月 09, 2014
作者:
W
weijun
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
7150092: NTLM authentication fail if user specified a different realm
Reviewed-by: michaelm
上级
fffb4919
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
46 addition
and
100 deletion
+46
-100
src/share/classes/com/sun/security/ntlm/Client.java
src/share/classes/com/sun/security/ntlm/Client.java
+12
-19
src/share/classes/com/sun/security/ntlm/Server.java
src/share/classes/com/sun/security/ntlm/Server.java
+8
-2
src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java
src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java
+10
-2
src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java
src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java
+4
-2
src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
...es/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
+2
-7
test/com/sun/security/sasl/ntlm/NTLMTest.java
test/com/sun/security/sasl/ntlm/NTLMTest.java
+10
-68
未找到文件。
src/share/classes/com/sun/security/ntlm/Client.java
浏览文件 @
b83823d6
...
@@ -46,7 +46,7 @@ public final class Client extends NTLM {
...
@@ -46,7 +46,7 @@ public final class Client extends NTLM {
final
private
String
hostname
;
final
private
String
hostname
;
final
private
String
username
;
final
private
String
username
;
private
String
domain
;
// might be updated by Type 2 msg
private
String
domain
;
private
byte
[]
pw1
,
pw2
;
private
byte
[]
pw1
,
pw2
;
/**
/**
...
@@ -82,7 +82,7 @@ public final class Client extends NTLM {
...
@@ -82,7 +82,7 @@ public final class Client extends NTLM {
}
}
this
.
hostname
=
hostname
;
this
.
hostname
=
hostname
;
this
.
username
=
username
;
this
.
username
=
username
;
this
.
domain
=
domain
;
this
.
domain
=
domain
==
null
?
""
:
domain
;
this
.
pw1
=
getP1
(
password
);
this
.
pw1
=
getP1
(
password
);
this
.
pw2
=
getP2
(
password
);
this
.
pw2
=
getP2
(
password
);
debug
(
"NTLM Client: (h,u,t,version(v)) = (%s,%s,%s,%s(%s))\n"
,
debug
(
"NTLM Client: (h,u,t,version(v)) = (%s,%s,%s,%s(%s))\n"
,
...
@@ -95,19 +95,13 @@ public final class Client extends NTLM {
...
@@ -95,19 +95,13 @@ public final class Client extends NTLM {
*/
*/
public
byte
[]
type1
()
{
public
byte
[]
type1
()
{
Writer
p
=
new
Writer
(
1
,
32
);
Writer
p
=
new
Writer
(
1
,
32
);
int
flags
=
0x8203
;
// Negotiate always sign, Negotiate NTLM,
if
(
hostname
!=
null
)
{
// Request Target, Negotiate OEM, Negotiate unicode
flags
|=
0x2000
;
int
flags
=
0x8207
;
}
if
(
domain
!=
null
)
{
flags
|=
0x1000
;
}
if
(
v
!=
Version
.
NTLM
)
{
if
(
v
!=
Version
.
NTLM
)
{
flags
|=
0x80000
;
flags
|=
0x80000
;
}
}
p
.
writeInt
(
12
,
flags
);
p
.
writeInt
(
12
,
flags
);
p
.
writeSecurityBuffer
(
24
,
hostname
,
false
);
p
.
writeSecurityBuffer
(
16
,
domain
,
false
);
debug
(
"NTLM Client: Type 1 created\n"
);
debug
(
"NTLM Client: Type 1 created\n"
);
debug
(
p
.
getBytes
());
debug
(
p
.
getBytes
());
return
p
.
getBytes
();
return
p
.
getBytes
();
...
@@ -133,13 +127,10 @@ public final class Client extends NTLM {
...
@@ -133,13 +127,10 @@ public final class Client extends NTLM {
byte
[]
challenge
=
r
.
readBytes
(
24
,
8
);
byte
[]
challenge
=
r
.
readBytes
(
24
,
8
);
int
inputFlags
=
r
.
readInt
(
20
);
int
inputFlags
=
r
.
readInt
(
20
);
boolean
unicode
=
(
inputFlags
&
1
)
==
1
;
boolean
unicode
=
(
inputFlags
&
1
)
==
1
;
String
domainFromServer
=
r
.
readSecurityBuffer
(
12
,
unicode
);
if
(
domainFromServer
!=
null
)
{
// IE uses domainFromServer to generate an alist if server has not
domain
=
domainFromServer
;
// provided one. Firefox/WebKit do not. Neither do we.
}
//String domainFromServer = r.readSecurityBuffer(12, unicode);
if
(
domain
==
null
)
{
domain
=
""
;
}
int
flags
=
0x88200
|
(
inputFlags
&
3
);
int
flags
=
0x88200
|
(
inputFlags
&
3
);
Writer
p
=
new
Writer
(
3
,
64
);
Writer
p
=
new
Writer
(
3
,
64
);
...
@@ -163,7 +154,9 @@ public final class Client extends NTLM {
...
@@ -163,7 +154,9 @@ public final class Client extends NTLM {
if
(
writeLM
)
lm
=
calcV2
(
nthash
,
if
(
writeLM
)
lm
=
calcV2
(
nthash
,
username
.
toUpperCase
(
Locale
.
US
)+
domain
,
nonce
,
challenge
);
username
.
toUpperCase
(
Locale
.
US
)+
domain
,
nonce
,
challenge
);
if
(
writeNTLM
)
{
if
(
writeNTLM
)
{
byte
[]
alist
=
type2
.
length
>
48
?
// Some client create a alist even if server does not send
// one: (i16)2 (i16)len target_in_unicode (i16)0 (i16) 0
byte
[]
alist
=
((
inputFlags
&
0x800000
)
!=
0
)
?
r
.
readSecurityBuffer
(
40
)
:
new
byte
[
0
];
r
.
readSecurityBuffer
(
40
)
:
new
byte
[
0
];
byte
[]
blob
=
new
byte
[
32
+
alist
.
length
];
byte
[]
blob
=
new
byte
[
32
+
alist
.
length
];
System
.
arraycopy
(
new
byte
[]{
1
,
1
,
0
,
0
,
0
,
0
,
0
,
0
},
0
,
blob
,
0
,
8
);
System
.
arraycopy
(
new
byte
[]{
1
,
1
,
0
,
0
,
0
,
0
,
0
,
0
},
0
,
blob
,
0
,
8
);
...
...
src/share/classes/com/sun/security/ntlm/Server.java
浏览文件 @
b83823d6
/*
/*
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
...
@@ -92,7 +93,9 @@ public abstract class Server extends NTLM {
...
@@ -92,7 +93,9 @@ public abstract class Server extends NTLM {
debug
(
"NTLM Server: Type 1 received\n"
);
debug
(
"NTLM Server: Type 1 received\n"
);
if
(
type1
!=
null
)
debug
(
type1
);
if
(
type1
!=
null
)
debug
(
type1
);
Writer
p
=
new
Writer
(
2
,
32
);
Writer
p
=
new
Writer
(
2
,
32
);
int
flags
=
0x80205
;
// Negotiate NTLM2 Key, Target Type Domain,
// Negotiate NTLM, Request Target, Negotiate unicode
int
flags
=
0x90205
;
p
.
writeSecurityBuffer
(
12
,
domain
,
true
);
p
.
writeSecurityBuffer
(
12
,
domain
,
true
);
p
.
writeInt
(
20
,
flags
);
p
.
writeInt
(
20
,
flags
);
p
.
writeBytes
(
24
,
nonce
);
p
.
writeBytes
(
24
,
nonce
);
...
@@ -127,8 +130,9 @@ public abstract class Server extends NTLM {
...
@@ -127,8 +130,9 @@ public abstract class Server extends NTLM {
"Wrong domain: " + incomingDomain +
"Wrong domain: " + incomingDomain +
" vs " + domain); // Needed?
" vs " + domain); // Needed?
}*/
}*/
boolean
verified
=
false
;
boolean
verified
=
false
;
char
[]
password
=
getPassword
(
d
omain
,
username
);
char
[]
password
=
getPassword
(
incomingD
omain
,
username
);
if
(
password
==
null
)
{
if
(
password
==
null
)
{
throw
new
NTLMException
(
NTLMException
.
USER_UNKNOWN
,
throw
new
NTLMException
(
NTLMException
.
USER_UNKNOWN
,
"Unknown user"
);
"Unknown user"
);
...
@@ -179,6 +183,8 @@ public abstract class Server extends NTLM {
...
@@ -179,6 +183,8 @@ public abstract class Server extends NTLM {
}
}
}
}
if
(
incomingNTLM
.
length
>
0
)
{
if
(
incomingNTLM
.
length
>
0
)
{
// We didn't sent alist in type2(), so there
// is nothing to check here.
byte
[]
clientBlob
=
Arrays
.
copyOfRange
(
byte
[]
clientBlob
=
Arrays
.
copyOfRange
(
incomingNTLM
,
16
,
incomingNTLM
.
length
);
incomingNTLM
,
16
,
incomingNTLM
.
length
);
byte
[]
ntlmresponse
=
calcV2
(
nthash
,
byte
[]
ntlmresponse
=
calcV2
(
nthash
,
...
...
src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java
浏览文件 @
b83823d6
...
@@ -160,9 +160,17 @@ final class NTLMClient implements SaslClient {
...
@@ -160,9 +160,17 @@ final class NTLMClient implements SaslClient {
}
}
}
}
try
{
try
{
String
name
=
ncb
.
getName
();
if
(
name
==
null
)
{
name
=
authzid
;
}
String
domain
=
dcb
.
getText
();
if
(
domain
==
null
)
{
domain
=
serverName
;
}
client
=
new
Client
(
version
,
hostname
,
client
=
new
Client
(
version
,
hostname
,
n
cb
.
getName
()
,
n
ame
,
d
cb
.
getText
()
,
d
omain
,
pcb
.
getPassword
());
pcb
.
getPassword
());
}
catch
(
NTLMException
ne
)
{
}
catch
(
NTLMException
ne
)
{
throw
new
SaslException
(
throw
new
SaslException
(
...
...
src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java
浏览文件 @
b83823d6
...
@@ -141,8 +141,10 @@ final class NTLMServer implements SaslServer {
...
@@ -141,8 +141,10 @@ final class NTLMServer implements SaslServer {
server
=
new
Server
(
version
,
domain
)
{
server
=
new
Server
(
version
,
domain
)
{
public
char
[]
getPassword
(
String
ntdomain
,
String
username
)
{
public
char
[]
getPassword
(
String
ntdomain
,
String
username
)
{
try
{
try
{
RealmCallback
rcb
=
new
RealmCallback
(
RealmCallback
rcb
=
"Domain: "
,
ntdomain
);
(
ntdomain
==
null
||
ntdomain
.
isEmpty
())
?
new
RealmCallback
(
"Domain: "
)
:
new
RealmCallback
(
"Domain: "
,
ntdomain
);
NameCallback
ncb
=
new
NameCallback
(
NameCallback
ncb
=
new
NameCallback
(
"Name: "
,
username
);
"Name: "
,
username
);
PasswordCallback
pcb
=
new
PasswordCallback
(
PasswordCallback
pcb
=
new
PasswordCallback
(
...
...
src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
浏览文件 @
b83823d6
...
@@ -77,8 +77,7 @@ public class NTLMAuthentication extends AuthenticationInfo {
...
@@ -77,8 +77,7 @@ public class NTLMAuthentication extends AuthenticationInfo {
static
{
static
{
defaultDomain
=
java
.
security
.
AccessController
.
doPrivileged
(
defaultDomain
=
java
.
security
.
AccessController
.
doPrivileged
(
new
sun
.
security
.
action
.
GetPropertyAction
(
"http.auth.ntlm.domain"
,
new
sun
.
security
.
action
.
GetPropertyAction
(
"http.auth.ntlm.domain"
,
""
));
"domain"
));
};
};
public
static
boolean
supportsTransparentAuth
()
{
public
static
boolean
supportsTransparentAuth
()
{
...
@@ -100,17 +99,13 @@ public class NTLMAuthentication extends AuthenticationInfo {
...
@@ -100,17 +99,13 @@ public class NTLMAuthentication extends AuthenticationInfo {
public
String
run
()
{
public
String
run
()
{
String
localhost
;
String
localhost
;
try
{
try
{
localhost
=
InetAddress
.
getLocalHost
().
getHostName
()
.
toUpperCase
()
;
localhost
=
InetAddress
.
getLocalHost
().
getHostName
();
}
catch
(
UnknownHostException
e
)
{
}
catch
(
UnknownHostException
e
)
{
localhost
=
"localhost"
;
localhost
=
"localhost"
;
}
}
return
localhost
;
return
localhost
;
}
}
});
});
int
x
=
hostname
.
indexOf
(
'.'
);
if
(
x
!=
-
1
)
{
hostname
=
hostname
.
substring
(
0
,
x
);
}
};
};
PasswordAuthentication
pw
;
PasswordAuthentication
pw
;
...
...
test/com/sun/security/sasl/ntlm/NTLMTest.java
浏览文件 @
b83823d6
...
@@ -23,7 +23,7 @@
...
@@ -23,7 +23,7 @@
/*
/*
* @test
* @test
* @bug 6911951
* @bug 6911951
7150092
* @summary NTLM should be a supported Java SASL mechanism
* @summary NTLM should be a supported Java SASL mechanism
*/
*/
import
java.io.IOException
;
import
java.io.IOException
;
...
@@ -59,7 +59,6 @@ public class NTLMTest {
...
@@ -59,7 +59,6 @@ public class NTLMTest {
checkAuthOnly
();
checkAuthOnly
();
checkClientNameOverride
();
checkClientNameOverride
();
checkServerDomainOverride
();
checkClientDomainOverride
();
checkClientDomainOverride
();
checkVersions
();
checkVersions
();
checkClientHostname
();
checkClientHostname
();
...
@@ -116,15 +115,12 @@ public class NTLMTest {
...
@@ -116,15 +115,12 @@ public class NTLMTest {
Map
<
String
,
Object
>
ps
=
new
HashMap
<>();
Map
<
String
,
Object
>
ps
=
new
HashMap
<>();
ps
.
put
(
"com.sun.security.sasl.ntlm.version"
,
vs
);
ps
.
put
(
"com.sun.security.sasl.ntlm.version"
,
vs
);
SaslClient
clnt
=
Sasl
.
createSaslClient
(
SaslClient
clnt
=
Sasl
.
createSaslClient
(
new
String
[]{
MECH
},
USER1
,
PROTOCOL
,
null
,
pc
,
new
String
[]{
MECH
},
USER1
,
PROTOCOL
,
REALM
,
pc
,
new
CallbackHandler
()
{
new
CallbackHandler
()
{
public
void
handle
(
Callback
[]
callbacks
)
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
throws
IOException
,
UnsupportedCallbackException
{
for
(
Callback
cb:
callbacks
)
{
for
(
Callback
cb:
callbacks
)
{
if
(
cb
instanceof
NameCallback
)
{
if
(
cb
instanceof
PasswordCallback
)
{
NameCallback
ncb
=
(
NameCallback
)
cb
;
ncb
.
setName
(
ncb
.
getDefaultName
());
}
else
if
(
cb
instanceof
PasswordCallback
)
{
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
}
}
}
}
...
@@ -159,15 +155,12 @@ public class NTLMTest {
...
@@ -159,15 +155,12 @@ public class NTLMTest {
Map
<
String
,
Object
>
pc
=
new
HashMap
<>();
Map
<
String
,
Object
>
pc
=
new
HashMap
<>();
pc
.
put
(
"com.sun.security.sasl.ntlm.hostname"
,
"this.is.com"
);
pc
.
put
(
"com.sun.security.sasl.ntlm.hostname"
,
"this.is.com"
);
SaslClient
clnt
=
Sasl
.
createSaslClient
(
SaslClient
clnt
=
Sasl
.
createSaslClient
(
new
String
[]{
MECH
},
USER1
,
PROTOCOL
,
null
,
pc
,
new
String
[]{
MECH
},
USER1
,
PROTOCOL
,
REALM
,
pc
,
new
CallbackHandler
()
{
new
CallbackHandler
()
{
public
void
handle
(
Callback
[]
callbacks
)
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
throws
IOException
,
UnsupportedCallbackException
{
for
(
Callback
cb:
callbacks
)
{
for
(
Callback
cb:
callbacks
)
{
if
(
cb
instanceof
NameCallback
)
{
if
(
cb
instanceof
PasswordCallback
)
{
NameCallback
ncb
=
(
NameCallback
)
cb
;
ncb
.
setName
(
ncb
.
getDefaultName
());
}
else
if
(
cb
instanceof
PasswordCallback
)
{
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
}
}
}
}
...
@@ -212,12 +205,8 @@ public class NTLMTest {
...
@@ -212,12 +205,8 @@ public class NTLMTest {
public
void
handle
(
Callback
[]
callbacks
)
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
throws
IOException
,
UnsupportedCallbackException
{
for
(
Callback
cb:
callbacks
)
{
for
(
Callback
cb:
callbacks
)
{
if
(
cb
instanceof
NameCallback
)
{
if
(
cb
instanceof
RealmCallback
)
{
NameCallback
ncb
=
(
NameCallback
)
cb
;
((
RealmCallback
)
cb
).
setText
(
REALM
);
ncb
.
setName
(
ncb
.
getDefaultName
());
}
else
if
(
cb
instanceof
RealmCallback
)
{
RealmCallback
dcb
=
(
RealmCallback
)
cb
;
dcb
.
setText
(
"THIRDDOMAIN"
);
}
else
if
(
cb
instanceof
PasswordCallback
)
{
}
else
if
(
cb
instanceof
PasswordCallback
)
{
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
}
}
...
@@ -255,13 +244,13 @@ public class NTLMTest {
...
@@ -255,13 +244,13 @@ public class NTLMTest {
*/
*/
private
static
void
checkClientNameOverride
()
throws
Exception
{
private
static
void
checkClientNameOverride
()
throws
Exception
{
SaslClient
clnt
=
Sasl
.
createSaslClient
(
SaslClient
clnt
=
Sasl
.
createSaslClient
(
new
String
[]{
MECH
},
null
,
PROTOCOL
,
null
,
null
,
new
String
[]{
MECH
},
"someone"
,
PROTOCOL
,
REALM
,
null
,
new
CallbackHandler
()
{
new
CallbackHandler
()
{
public
void
handle
(
Callback
[]
callbacks
)
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
throws
IOException
,
UnsupportedCallbackException
{
for
(
Callback
cb:
callbacks
)
{
for
(
Callback
cb:
callbacks
)
{
if
(
cb
instanceof
NameCallback
)
{
if
(
cb
instanceof
NameCallback
)
{
NameCallback
ncb
=
(
NameCallback
)
cb
;
NameCallback
ncb
=
(
NameCallback
)
cb
;
ncb
.
setName
(
USER1
);
ncb
.
setName
(
USER1
);
}
else
if
(
cb
instanceof
PasswordCallback
)
{
}
else
if
(
cb
instanceof
PasswordCallback
)
{
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
...
@@ -270,54 +259,7 @@ public class NTLMTest {
...
@@ -270,54 +259,7 @@ public class NTLMTest {
}
}
});
});
SaslServer
srv
=
Sasl
.
createSaslServer
(
MECH
,
PROTOCOL
,
REALM
,
null
,
SaslServer
srv
=
Sasl
.
createSaslServer
(
MECH
,
PROTOCOL
,
"FAKE"
,
null
,
new
CallbackHandler
()
{
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
String
domain
=
null
,
name
=
null
;
PasswordCallback
pcb
=
null
;
for
(
Callback
cb:
callbacks
)
{
if
(
cb
instanceof
NameCallback
)
{
name
=
((
NameCallback
)
cb
).
getDefaultName
();
}
else
if
(
cb
instanceof
RealmCallback
)
{
domain
=
((
RealmCallback
)
cb
).
getDefaultText
();
}
else
if
(
cb
instanceof
PasswordCallback
)
{
pcb
=
(
PasswordCallback
)
cb
;
}
}
if
(
pcb
!=
null
)
{
pcb
.
setPassword
(
getPass
(
domain
,
name
));
}
}
});
handshake
(
clnt
,
srv
);
}
/**
* server side domain provided in props.
* @throws Exception
*/
private
static
void
checkServerDomainOverride
()
throws
Exception
{
SaslClient
clnt
=
Sasl
.
createSaslClient
(
new
String
[]{
MECH
},
USER1
,
PROTOCOL
,
null
,
null
,
new
CallbackHandler
()
{
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
for
(
Callback
cb:
callbacks
)
{
if
(
cb
instanceof
NameCallback
)
{
NameCallback
ncb
=
(
NameCallback
)
cb
;
ncb
.
setName
(
ncb
.
getDefaultName
());
}
else
if
(
cb
instanceof
PasswordCallback
)
{
((
PasswordCallback
)
cb
).
setPassword
(
PASS1
);
}
}
}
});
Map
<
String
,
Object
>
ps
=
new
HashMap
<>();
ps
.
put
(
"com.sun.security.sasl.ntlm.domain"
,
REALM
);
SaslServer
srv
=
Sasl
.
createSaslServer
(
MECH
,
PROTOCOL
,
null
,
ps
,
new
CallbackHandler
()
{
new
CallbackHandler
()
{
public
void
handle
(
Callback
[]
callbacks
)
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
throws
IOException
,
UnsupportedCallbackException
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录